10.14 浪潮软件开发面试:缓存一致性、Kafka 与分页索引优化
- 时间
- 2026-10
- 来源
- 牛客网
《面试题目》
- 缓存数据一致性怎么保证?
- Kafka 在你的项目里是怎么使用的?
- 数据库越来越大怎么办?
- 分库分表和索引是怎么优化的?
- 联合索引怎么优化?
- 多表关联查询的分页怎么优化查询效率?
- 讲一下实习中遇到的问题。
- AI 开发相关的问题。
- 有没有看过开源文档?
- 有没有自己做过 skill?
- 反问环节:你有什么想问面试官的?
《参考解析》
缓存一致性:先说清要哪一档一致,再谈怎么做到
这题的通用答法是先分级再给方案。绝大多数业务要的是最终一致,强一致的读写应该绕开缓存直接落库。主流方案是 Cache Aside:读未命中就回源写缓存,写操作先更新数据库再删除缓存。这里有两个高频追问。为什么是删缓存而不是更新缓存:更新缓存要做序列化与多字段拼装,写多读少时纯属浪费,而且并发写场景下两次更新落库的顺序与落缓存的顺序可能相反,反而把旧值写进缓存;删除则把「下一次读」当成唯一的写入口,靠懒加载保证正确。剩下的窗口期靠三招收:删除失败进重试队列(或直接订阅 binlog 由消费端删缓存,顺序与可靠性都更好);延迟双删应对「读请求在更新前拿到旧值、又在删除之后才回填」的小概率场景;热点键重建时加互斥(单飞),避免大量请求同时回源把数据库打穿。再补一句缓存的经典问题怎么区分与处理:穿透(查不存在的键,用空值缓存或布隆过滤器)、击穿(单个热点键过期,用互斥重建或逻辑过期)、雪崩(大批键同时失效,用随机 TTL 与多级缓存、限流降级兜底)。能主动区分这三个词,比反复强调「加锁」更有说服力。
Kafka 在项目里怎么用:把设计取舍讲出来
答这题不要只说「异步解耦削峰」,那是最低配。按四段讲更完整。第一,为什么要引入:哪些链路原来是同步串行的、引入后主链路耗时或失败率发生了什么变化(例如下单后要同时通知、发券、同步搜索索引,同步做会让接口响应被下游最慢的一环拖住)。第二,怎么设计:Topic 按业务域划分,分区数决定并行度,顺序性靠选 key——同一用户或同一订单的消息路由到同一分区才有局部有序,跨分区不保证;分区数不是越多越好,它会带来 rebalance 与文件句柄成本。第三,可靠性:生产端 acks=all 加幂等生产者,消费端手动提交偏移并在业务侧做幂等(业务唯一键落库或去重表),因为队列本身只能保证至少一次投递;重试要有次数上限和死信主题,否则毒消息会一直卡住分区。第四,可运维:堆积时先看消费 lag,区分是生产突增还是消费变慢,再决定扩分区、扩消费者还是优化消费逻辑(消费者数超过分区数就白扩);还要注意 rebalance 的触发(消费者心跳超时、处理时间超过 max.poll.interval.ms)会让整组短暂停止消费,所以消费逻辑要尽量短,长任务交给线程池并控制提交节奏。
数据量增长、分库分表与索引优化
「数据库越来越大怎么办」要答成有顺序的处置链,而不是直接说分库分表。先量化问题:是单表行数大、还是单库 QPS 或连接数到顶、还是磁盘容量告急——不同症状对应不同手段。单表变大优先做 SQL 与索引优化、冷热数据归档(历史订单迁到归档表或对象存储)、读写分离、以及按时间分区;只有当单表写入或容量确实到瓶颈、且业务能接受分片约束时再分库分表。分片的关键决策是分片键:用户维度用 user_id、交易维度用订单号,分片键决定哪些查询能落到单片,选错了会让所有查询都变成跨片聚合;跨片的分页与排序、全局唯一 ID(雪花或号段)、以及后续扩容的迁移方案都要提前设计,常见补充手段是用异构索引表或搜索引擎承接多维度查询。这些代价要先说出口,因为面试官问「怎么办」时常常在等你主动说「分库分表不是第一步」。
索引优化则按「最左前缀 → 覆盖 → 失效场景」三步答:联合索引的列顺序要按等值条件在前、范围条件在后,区分度高的列优先,最左前缀不满足就用不上索引;能通过覆盖索引把查询字段都包进索引就避免回表,这对深分页尤其关键;失效场景要熟——列上做函数或运算、隐式类型转换、like '%x' 前导模糊、or 连接非索引列、以及区分度太低的列让优化器直接放弃。最后一定落到工具上:用 explain 看 type、key、rows、Extra,用慢查询日志定位真凶,而不是凭感觉加索引——索引多了会拖慢写入并占内存,这是另一个要主动提的取舍。
多表关联分页:深分页的瓶颈与四种优化
深分页慢的根因是 limit offset, n 要先扫描并丢弃前 offset 行,offset 越大扫得越多,而且如果排序字段没有合适索引,还会出现 filesort。优化按代价从低到高排。第一,延迟关联:先用覆盖索引只查主键(select id from t where ... order by ... limit offset, n),拿到少量主键之后再 join 回原表取全部字段,把回表次数从 offset+n 降到 n。第二,游标分页(keyset 分页):用一个单调且有索引的排序键(时间、自增 ID)做条件,每次带上「上一页最后一条的键」——where id < ? order by id desc limit n,它把 offset 变成索引范围扫描,适合信息流这类连续翻页;代价是不能随机跳到第 N 页,所以只适用于「下一页」型交互。第三,减少 join 本身:明确驱动表选择(小表驱动大表)、避免 select *、必要时把多表 join 拆成两次单表查询在应用层拼装,或者用冗余宽表与搜索引擎承接复杂的多维度检索。第四,架构层面:读写分离把报表类分页查询挪到只读库,超大数据量的列表用 ES 之类的检索系统而不是关系库硬扛。答完补一句「分页优化要先看这一页有没有真的需要 count 总数」,因为很多接口的 count(*) 比取数据本身还贵,可以改成缓存总数或不做精确总数。
AI 开发、开源文档与 skill 这类软性提问
二十五分钟的短面里,这三个问题都是在筛「动手能力和兴趣」而不是知识。AI 开发按三段答:在项目里用 AI 做了什么(具体到场景,比如代码生成、日志排查、测试用例构造)、怎么保证正确性(人工评审、用例验证、只读权限、敏感操作不交给它)、收益怎么衡量(周期、返工率、缺陷密度)。开源文档这类问题要能报出具体项目和你真的从里面得到的东西——读过哪个中间件的设计文档、源码里印象最深的一处设计(例如连接池、内存池、协议实现),以及有没有据此改过自己的代码或写过笔记;泛泛说「经常看 GitHub」会被追问到没话说。自己做 skill 就从「解决什么问题、怎么组织(可复用的步骤与约束)、怎么被调用、边界在哪」四个角度讲,并把它和你项目里的实际问题联系起来——重点体现你能把重复的流程沉淀成可复用的东西,而不是只写了一个脚本。反问环节建议问团队的技术栈与业务方向、新人前几个月的任务类型,比问薪资与加班更容易留下好印象。