面灵AI→

深圳初创小厂后端面经:MongoDB 选型、WebSocket 稳定性与重试设计

时间
2026-10
来源
牛客网

《面试题目》

  1. 你的 AI 在线面试平台和编码 Agent 项目是独立开发的吗?具体代码实现是自己写还是 AI 生成?
  2. 你如何看待 AI 写代码?哪些部分可以交给 AI,哪些必须人工 Review?
  3. Redis 等中间件的使用是你自己实操的吗?请列举你用到的 Redis 数据结构及其应用场景。
  4. 为什么选用 MongoDB 而不是 MySQL?依据是什么?
  5. MongoDB 的性能量级是多少?适用场景有哪些?
  6. 对比一下 MySQL 和 Redis 的性能差异(QPS、延迟、瓶颈等)。
  7. WebSocket 的性能、传输机制是怎样的?
  8. 如何保障 WebSocket 的数据一致性?
  9. TCP 的确认重传机制是怎样的?如何应用到 WebSocket 的稳定性中?
  10. 项目中遇到的最大困难或难点是什么?怎么解决的?
  11. 针对 AI 接口不稳定(如 GPT 接口过载),你采用了什么方案?
  12. 超时退避重试具体是怎么设置的?
  13. 两数之和(要求在本地 IDE 实现,可用哈希表优化,避免暴力遍历)。
  14. 你对公司的业务有什么了解?有没有什么疑问?
  15. 公司主营海外独立站电商、数字人、视频转文字、API 中转站等,你对此怎么看?
  16. 实习时间如何安排?薪资和上班时间后续由谁沟通?

《参考解析》

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 中转有现金流)与风险(支付与合规、渠道封禁、同质化竞争),并说明自己更关心哪类业务、能补什么能力。实习时间与薪资按实际回答,问清由谁对接、什么时候给结论。