CVTE 一面面经:Kafka、Redis 与 SSE 选型
- 轮次
- 一面
- 结果
- 已挂
- 时间
- 2026-10
- 来源
- 牛客网
《面试题目》
- Kafka 消息丢失怎么解决?
- 在项目中遇到的难点是什么?
- 项目中用到的 Redis Bitmap 是怎么设计的?
- 文档为什么要分块?
- 为什么用 SSE 流式解析,不用 WebSocket,两者有什么区别?
- 让你设计一个 Agent,如何理解客户意图?
- 遇到 OOM 怎么排查,不借助 AI?
- 慢索引怎么排查?
- 了解过哪些设计模式?
- 浏览器输入一个网址到返回数据中间的过程是怎样的?
《参考解析》
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、慢索引这类线上排查题最容易问穿,答的时候把「我在项目里怎么用的、踩过什么坑」讲出来,比背结论稳得多。