深圳初创小厂后端面经:MongoDB 选型、WebSocket 稳定性与重试设计
- 时间
- 2026-10
- 来源
- 牛客网
《面试题目》
- 你的 AI 在线面试平台和编码 Agent 项目是独立开发的吗?具体代码实现是自己写还是 AI 生成?
- 你如何看待 AI 写代码?哪些部分可以交给 AI,哪些必须人工 Review?
- Redis 等中间件的使用是你自己实操的吗?请列举你用到的 Redis 数据结构及其应用场景。
- 为什么选用 MongoDB 而不是 MySQL?依据是什么?
- MongoDB 的性能量级是多少?适用场景有哪些?
- 对比一下 MySQL 和 Redis 的性能差异(QPS、延迟、瓶颈等)。
- WebSocket 的性能、传输机制是怎样的?
- 如何保障 WebSocket 的数据一致性?
- TCP 的确认重传机制是怎样的?如何应用到 WebSocket 的稳定性中?
- 项目中遇到的最大困难或难点是什么?怎么解决的?
- 针对 AI 接口不稳定(如 GPT 接口过载),你采用了什么方案?
- 超时退避重试具体是怎么设置的?
- 两数之和(要求在本地 IDE 实现,可用哈希表优化,避免暴力遍历)。
- 你对公司的业务有什么了解?有没有什么疑问?
- 公司主营海外独立站电商、数字人、视频转文字、API 中转站等,你对此怎么看?
- 实习时间如何安排?薪资和上班时间后续由谁沟通?
《参考解析》
AI 写代码的边界:可以交给 AI 的是「有明确规格、可验证」的部分:样板代码、CRUD、单元测试、文档、正则与脚本、重构中的机械替换。必须人工把关的是:架构与数据模型、并发与事务边界、安全与权限、计费与资金相关逻辑、对外协议、以及任何「错了很难发现」的地方。Review 的重点不是逐行看语法,而是看它有没有偷偷改需求、有没有引入未处理的异常、边界条件是否覆盖、依赖是否可信。无论谁写,最终责任都在提交者。
Redis 数据结构与场景:String 做缓存、计数器、分布式锁;Hash 存对象字段(用户会话、配置);List 做队列(轻量任务、消息缓冲);Set 做去重、标签、共同好友;ZSet 做排行榜、延迟队列(按时间戳打分);Bitmap 做签到、布隆过滤器;HyperLogLog 做 UV 估算;Stream 做消息流。要说清「为什么选它」:比如延迟队列用 ZSet 是因为按 score 范围取到期任务,比轮询全表高效。
为什么选 MongoDB:依据是数据形态与访问模式——面试会话的消息、工具调用记录、状态快照字段不固定、嵌套深、单条文档大,用 MySQL 要拆很多表且查询需要多次 join;MongoDB 的文档模型一条记录就能表达完整会话,按 sessionId 建索引后读写都直接。强一致的订单、用户、权限仍放 MySQL。如果业务一开始就以关系型数据为主、需要事务和复杂报表,那应该选 MySQL,不要为了「灵活」硬上 MongoDB。
MongoDB 的性能量级:不要报一个绝对数字,它取决于文档大小、索引、读写比例、硬件与副本集配置。量级上,单机按主键/索引点查可以到万级 QPS、延迟毫秒级;写入受限于磁盘与写关注(w 与 journal),批量写比逐条写高一个量级。适用场景是半结构化数据、内容管理、日志与消息、读多写多且查询模式相对固定;不适合强事务、复杂多表关联、频繁全表聚合的场景。
MySQL 与 Redis 的性能差异:Redis 是内存数据库,单线程处理命令(6.0 起 I/O 多线程),点查延迟通常在亚毫秒级,单机 QPS 可到十万级;MySQL 走磁盘与缓冲池,点查延迟毫秒级,单机 QPS 通常千到万级,受索引、锁、事务和磁盘 I/O 限制。瓶颈不同:Redis 受内存容量、网络带宽和单线程 CPU 限制;MySQL 受磁盘随机 I/O、锁竞争、连接数和慢查询限制。所以常见架构是 Redis 挡热点读、MySQL 做持久化与强一致。
WebSocket 的传输与性能:WebSocket 基于 TCP,一次 HTTP Upgrade 握手后建立全双工长连接,之后用帧(frame)传输,开销比每请求都带 HTTP 头小得多,适合高频双向消息。服务端要处理连接保活(ping/pong)、心跳、粘包拆包(WebSocket 本身有帧边界,但应用层消息可能分片)、背压(发送缓冲积压要丢弃或降级)、以及水平扩展时的连接路由(需要网关按 userId 粘性路由或用消息总线广播)。
WebSocket 的数据一致性:连接本身不保证消息不丢、不重、不乱序。做法是:每条消息带单调递增序号,客户端按序号去重与排序,发现缺口就请求补发;服务端维护「最后确认序号」,重连时从该序号之后续传;关键状态写库后再推送,推送失败不影响状态;客户端收到消息后回 ack,服务端超时重发;用会话 ID 隔离多端。最终一致性靠「状态以服务端为准 + 客户端重放」。
TCP 确认重传与 WebSocket 稳定性:TCP 用序列号与确认号(ACK)保证可靠,发送方超时未收到 ACK 就重传,配合滑动窗口做流量控制、拥塞控制(慢启动、拥塞避免、快速重传)。WebSocket 跑在 TCP 上,链路层已经保证字节流可靠,但应用层仍可能丢消息(进程崩溃、消息未持久化、连接中断时正在传输)。所以不能把 TCP 的可靠当成业务可靠:应用层要做序号、ack、重发、幂等,断线重连后按最后确认位置续传,这和 TCP 的重传思想一致,但作用在「业务消息」而不是「字节」。
AI 接口不稳定的应对:分层处理。① 超时:连接超时与读超时分开设,流式接口用首 token 超时 + 整体超时;② 重试:只重试幂等请求,指数退避加随机抖动,限制次数;③ 熔断:连续失败打开断路器,快速失败,避免雪崩;④ 降级:切备用模型/渠道、返回缓存结果、或提示用户稍后重试;⑤ 削峰:队列缓冲、并发限制、按用户配额;⑥ 可观测:记录每次调用的模型、耗时、错误码、token 用量,按渠道统计成功率。
退避重试的参数:常见是「初始 500ms,指数翻倍,上限 8~10s,最多 3~5 次,加 0~30% 随机抖动」。抖动是为了避免大量客户端在同一时刻重试造成二次冲击。还要设总预算(比如整体不超过 30s),超过就放弃;对 429 优先读 Retry-After;对 4xx 参数错误不重试。伪代码:delay = min(cap, base * 2 ** attempt) * (1 + random() * 0.3)。
两数之和:暴力是 O(n²),哈希表一遍扫是 O(n)。遍历数组,对每个 x 查 target - x 是否在 map 里,在就返回下标,不在就把 x 和下标存进去。注意先查后存,避免同一个元素用两次;如果有重复值,存第一个下标即可(题目通常保证唯一解)。
int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> seen = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int need = target - nums[i];
if (seen.containsKey(need)) return new int[]{seen.get(need), i};
seen.put(nums[i], i);
}
return new int[]{-1, -1};
}
公司与业务:海外独立站电商、数字人、视频转文字、API 中转站,本质都是「用技术做跨境流量与工具生意」,共同点是依赖海外支付、渠道与合规,且对成本与稳定性敏感。评价时可以讲机会(出海工具需求真实、API 中转有现金流)与风险(支付与合规、渠道封禁、同质化竞争),并说明自己更关心哪类业务、能补什么能力。实习时间与薪资按实际回答,问清由谁对接、什么时候给结论。