面灵AI→

CVTE 一面面经:Kafka、Redis 与 SSE 选型

轮次
一面
结果
已挂
时间
2026-10
来源
牛客网

《面试题目》

  1. Kafka 消息丢失怎么解决?
  2. 在项目中遇到的难点是什么?
  3. 项目中用到的 Redis Bitmap 是怎么设计的?
  4. 文档为什么要分块?
  5. 为什么用 SSE 流式解析,不用 WebSocket,两者有什么区别?
  6. 让你设计一个 Agent,如何理解客户意图?
  7. 遇到 OOM 怎么排查,不借助 AI?
  8. 慢索引怎么排查?
  9. 了解过哪些设计模式?
  10. 浏览器输入一个网址到返回数据中间的过程是怎样的?

《参考解析》

Kafka 消息丢失:生产、存储、消费三段各堵一次

生产者侧先把可靠性拉满:acks=all 配合 retries 让网络抖动后的重试真正生效,同时开启幂等(enable.idempotence=true)避免重试写出重复消息;另外别忽略发送回调里的失败,缓冲区满而调用方又不处理异常时,消息就静默丢了。Broker 侧靠副本兜底:replication.factor 至少 3、min.insync.replicas 至少 2,并关闭 unclean.leader.election,否则落后副本可能被选成 leader 并用旧数据覆盖新数据。消费侧的关键是位点提交时机:关掉自动提交,业务处理成功后再手动提交,先提交后处理等于「处理失败即丢消息」;反过来按「至少一次」投递就必然有重复,消费端要自己幂等。

Redis Bitmap 的设计要点,以及 RAG 为什么要分块

Bitmap 本质是 String 上的位操作(SETBIT / GETBIT / BITCOUNT / BITOP),把一个用户映射成一个 bit 偏移,签到、活跃、去重这类「一人一天一个状态」的场景最合适。设计时要先定 key 的粒度:按天或按月分片,不要把全量用户塞进一个 key 变成大 key;再算内存,1 亿用户一个位图约 12MB,比 Set 省一到两个数量级。统计时注意 BITCOUNT 是 O(N),按时间分片后统计才能用;如果用户 id 极度稀疏,直接按 id 当偏移会浪费大量空间,可以取模拆成多个 key 再 BITOP 合并。顺便说一句布隆过滤器也是位图思想,能带出「误判率与位数组大小的取舍」这个加分点。

文档分块是 RAG 检索粒度与向量表达能力共同决定的:块太大,一个向量要概括多个主题,语义被稀释、召回不准,还挤占 prompt 预算;块太小,上下文被切碎,答案容易只有半截。工程上优先按文档结构切(标题、段落、表格、代码块),比按固定字数硬切更贴合语义,块与块之间留一成到两成的重叠,防止关键句正好被切在边界上。块大小没有普适最优值,要用自己的评测集试,还要看 embedding 模型的输入上限。

SSE 与 WebSocket 的选型,以及 Agent 怎么理解意图

SSE 是架在 HTTP 上的单向流(服务端到客户端),浏览器原生 EventSource 自带断线重连和 Last-Event-ID 续传,纯文本、对代理和网关友好;WebSocket 是全双工、可传二进制,代价是协议升级、心跳、重连和消息序号都得自己实现。LLM 场景是「客户端发一次请求、服务端持续推 token」,单向且要简单,SSE 完全够用;真需要双向实时(语音对话、协同编辑、随时打断)才是 WebSocket 的主场。回答时补一句「选型看的是通信模型,不是哪个更新」,比罗列 API 更有说服力。

Agent 理解意图的关键是别让模型从零自由发挥:前面加一层意图分类或路由(规则兜底加小模型分类到有限枚举),命中哪类就走哪条流程;参数用 function calling 或结构化输出约束成 schema,而不是事后解析自由文本;多轮对话里维护槽位,缺哪个字段就追问哪个;置信度低于阈值就澄清或转人工,别硬猜。这套东西上线后要靠真实对话 trace 建评测集,量化分类准确率和误路由率,而不是凭感觉改 prompt。

OOM、慢索引、设计模式与浏览器全链路

OOM 排查先确认「是谁杀的」:容器退出码 137、dmesg 里的 OOM Killer、K8s 的 OOMKilled,都说明是限额或堆内外总占用超了,不一定只是堆的问题。进程还活着就往下钻:jstat -gcutil 看老年代在 Full GC 后是否降不下来,jmap -histo:live 看对象占比,必要时 dump 下来用 MAT 找支配树,区分是内存泄漏(对象一直被引用)还是容量不够(缓存、一次性大查询)。堆外还要看元空间、直接内存(NIO / Netty)和线程数。最后别只把 -Xmx 调大——限流、分页、修未关闭的资源、给缓存设上限,才是根因处理。

慢索引排查的顺序是「先定位语句,再看执行计划」:从慢查询日志、APM 或 show processlist 找到具体 SQL,再用 EXPLAIN 看 type / key / rows / Extra,出现 filesort、temporary 要警惕。常见病因是没建索引、索引失效(列上做函数运算、隐式类型转换、前导模糊匹配),或者回表次数太多。解法通常是建联合索引(遵循最左前缀,区分度高的列靠前)、做覆盖索引、改写 SQL,深分页改延迟关联或游标翻页。索引本身有写放大和空间成本,不是越多越好。

设计模式这道题,面试官要的是「这个模式解决了什么问题」,不是背 23 个名字。好讲且高频的有:策略(消除成片 if-else,支付、算法可替换)、责任链(过滤器、审批流)、观察者与发布订阅(事件解耦)、代理(Spring AOP、RPC)、模板方法(各类 Template 基类)、单例与工厂、建造者(连接池、复杂对象构造)。能顺手指到 Spring 里的落地(Bean 默认单例、AOP 用动态代理)会显得是真用过。

浏览器从输入网址到返回数据,完整链路是:URL 解析 → DNS 解析(浏览器缓存、系统缓存、hosts,再到递归与权威服务器)→ TCP 三次握手,HTTPS 再加 TLS 握手 → 发 HTTP 请求,途中先判断强缓存、协商缓存能不能直接用本地副本 → 服务端处理后返回响应 → 浏览器解析 HTML 构建 DOM 与 CSSOM、合成渲染树 → 布局、绘制、合成上屏,其间遇到 JS 会阻塞解析。再补一句 CDN、HTTP/2 多路复用、keep-alive 对耗时的影响,这道题就答满了。

这场面试没有手撕,问题在八股与项目之间来回跳,作者最终止步一面。复盘来看,Kafka、OOM、慢索引这类线上排查题最容易问穿,答的时候把「我在项目里怎么用的、踩过什么坑」讲出来,比背结论稳得多。