小红书后端开发岗面经合集(二):分布式锁、Redis 主从切换与网络调优
- 轮次
- 多轮面试合集
- 时间
- 2026-09
- 来源
- 牛客网
《面试题目》
面经 02 · 小红书后端开发岗(2026-03-26)
- 手撕:删除链表倒数第 N 个节点,考虑边界情况(本轮无自我介绍)
- Redis 的 zset 查询 score 在 10-k 之间的数据的时间复杂度是多少?查询 score 等于 10 的时间复杂度是多少?
- MySQL 的索引、联合索引、最左匹配原则
面经 03 · 小红书后端开发岗(2026-03-23)
- 线程池核心参数
- 核心线程数怎么根据场景选择配置?
- 说下数据库的分库分表,什么情况下分?
- 算法题:动态规划或多线程打印,2 选 1
面经 04 · 小红书后端开发岗(2026-03-19)
- 项目里 MinIO 的使用
- defer 的写法:一般用 defer func(){}(),还是直接用 defer func()?
- 两个协程交叉输出字母和数字
- 长度为 2n 的合法括号串
面经 05 · 小红书后端开发岗(2026-03-18)
- 在美团主要是做哪一块的?可以展开讲讲
- 接入层的异步化改造为什么要做?之前的同步是有什么问题吗?
- 改成了监听 binlog,是怎么解决一致性问题的?
- 缓存迁移当时用的整体 SOP 大概是怎样的?
- 迁移过程中怎么保证新集群上的数据一定是最准确的?
- 告警系统的动态阈值是怎么设置的?阈值和 CAT 埋点怎么定?怎么判断应该设置多少,有什么模型或算法来判断吗?线上环境可能抖动,怎么降低误告警的概率?
- 场景:线上集群请求量一会跌零、一会又只有两三个请求,有些集群一直有流量、有些没有流量,这种正常跌零怎么把它剔除掉?
- 实习过程中对 MySQL 分库分表中间件有使用或者了解吗?
- 限流策略里面令牌桶大概是怎么设计的?
- 为什么用 AT 的分布式事务?分布式事务相对来说比较重,为什么一定要用,不能用别的手段规避分布式事务?
- AT 大概的实现逻辑
- undo_log 表多久清一次?
- 有学过其他语言吗?
- 算法:合并区间
面经 06 · 小红书后端开发岗(2026-03-11)
- instanceof 是干什么的?了解 Java 字符串压缩吗?
- 写个 HTTP 响应类
- 设计个接口,用于判断用户是否能评论,要求 1 小时内用户不能多次发相同评论,用户量几千万,用 Redis 什么数据结构?
- 设计个房间列表接口,QPS 几百
面经 07 · 小红书后端开发岗(2026-03-02)
- 实现最长严格递增子序列的长度(要求阐述思路、编写代码并说明时间复杂度)
- 用递归方式实现将二叉树左节点值放到右边并连接到根节点右节点(编写代码)
- TCP 和 UDP 最主要的区别是什么?
- TCP 的拥塞控制是为了解决什么问题?
- 操作系统中进程和线程的区别和联系是什么?
- 串行程序改并行,多进程相比于多线程有什么优势?
- 代码调用中,同步调用和异步调用分别指的是什么?
- 异步调用中,调用方怎么拿到执行结果?有哪些方式?
- 平时用得最多的 AI 编程工具是什么?
- 用 AI 辅助编程过程中,有哪些发挥 AI 编码能力的经验?
- 编写提示词时,有针对大模型幻觉做过哪些处理?
- 是否试用过 Open Cloud?使用的 Open Cloud 基于哪家大模型?主要用来做什么?是安装在自己电脑还是服务器上?
- 是否了解 Go、Python、前端相关技术?掌握程度如何?
- 自己开发的项目中遇到过哪些比较奇怪的问题?如何解决的?
- 如果发 offer,大概什么时候可以入职?
- 有什么想要向面试官提问的?
面经 08 · 小红书后端开发岗(2026-03-02)
- Redis 实现分布式锁的底层做法是什么?
- Redisson 对分布式锁的封装,除了命令和过期时间,还有哪些额外机制?
- 什么场景下需要在 Redis 中使用 Lua 脚本?
- Redis 执行 Lua 脚本会中途失败吗?失败后有什么处理措施?
- 你开发中 Redis 用的单节点还是主从?主从故障是怎么切换部署的?
- Redis 哨兵的选主流程是怎样的?
- Redis 主从切换期间,代码里怎么处理连接不上的情况?
- 若要设计优化 Redis 主从切换的代码,缓存场景与分布式锁场景分别怎么做?
- 你当前的 Redis 实现中,主节点故障连不上会有什么影响?
- 抛异常后上层调用会持续尝试获取锁吗?怎么避免下游影响上游?
- 程序无法判断 Redis 是短暂还是长时间故障时,怎么保证快速恢复且避免频繁重连?
- MySQL 中索引失效的场景有哪些?是不是只要用 like 语法索引就会失效?索引失效的根本原因是什么?
- 现场编写单向链表删除倒数第 N 个节点的代码(需先讲思路)
- 毕业时间、是否能处理学校事务、年后能否实习、预期实习时长?
面经 09 · 小红书后端开发岗(2026-02-22)
- 说说 HTTP 的发展历程,HTTP/2 和 HTTP/3 有什么区别?
- TCP 的滑动窗口机制是什么?它能变小或者向左移动吗?接收方处理不过来、窗口为 0 时怎么办?
- 如果网络波动很大,TCP 协议有什么问题?如何优化?
- TCP 第一次真正发送数据是在什么时候?
- TCP 连接建立过程
- 为什么第三次握手可以带数据?为什么前两次握手不能带数据?
- 通过 Cookie 机制验证客户端
- 如果你是微信的开发工程师,如何设计「检测当前网络」功能?
《参考解析》
面经 08 · Redis 分布式锁与主从切换
-
分布式锁的正确实现与失败处理:加锁用
SET key value NX PX ttl一条命令搞定,value 必须是本机唯一标识(客户端 ID + 线程 ID),释放时先比对 value 再删,这两步要用 Lua 合成原子操作,否则可能删掉别人刚抢到的锁。Redisson 在命令之外补的是:可重入(Hash 记录重入次数)、看门狗续期(默认每 10 秒把 30 秒 TTL 续回来,只有不显式指定 leaseTime 时才生效)、阻塞等待与公平锁。Lua 会中途失败吗?会——脚本执行期间 Redis 不会插入其他命令,但可能因为脚本本身报错、超时或实例故障中断,所以「原子」指的是不被并发插队,不等于「一定成功」。处理措施是:脚本要写成幂等的、先做参数校验;客户端要能区分「脚本报错」(业务逻辑问题,别重试)和「连接断了」(状态未知,必须回查锁是否还在);失败后锁可能已被部分写入,所以业务侧必须幂等,并且要有兜底的过期时间。 -
主从切换期间应用侧怎么扛:哨兵选主流程要讲清:多个哨兵通过发布订阅发现节点、对被判定主观下线的 master 做多数派确认(客观下线)、由 leader 哨兵按优先级与复制偏移量挑出新主,其余从节点指向新主,最后通过发布订阅通知客户端新地址。切换期间应用侧会遇到连接失败和写入落到旧主(脑裂)两类问题。代码层的处理思路是:缓存场景可以降级——读失败回源数据库,写失败短暂忽略,靠 TTL 与后续回填恢复一致性;分布式锁场景必须保守——获取锁失败就直接拒绝业务(fail-closed),绝不能「连不上就当作拿到锁」,否则并发保护直接失效。抛异常后上层不要无限重试获取锁,要有超时与熔断,并在下游失败时快速返回而不是把请求堆积在上游。「无法判断 Redis 是短暂还是长时间故障」这个问题的标准思路是:客户端做带退避与抖动的重连(避免雪崩式同时重连)、用熔断器在半开状态少量试探、把健康检查与业务超时分开,同时把「缓存不可用」和「锁不可用」的降级策略分开配置。
面经 02 / 03 / 05 · 存储、并发与分布式事务
-
索引与线程池的细节点:联合索引的最左匹配是回答一切索引题的地基,要能主动补一句「前导列用了范围查询之后,后面的列无法继续用于定位,只能做索引条件下推过滤」。索引失效的常见原因归到一句根本话:优化器判断走索引的代价比全表扫描更高——包括索引列被函数或表达式包裹、字段与参数类型不一致引发隐式转换、违反最左前缀、以 % 开头的 LIKE、OR 连接了没有索引的列、以及区分度太低(比如性别这种字段,优化器宁愿全扫)。所以「用了 like 就一定失效」是错的:只有前缀通配
%xxx才用不上,xxx%可以走范围扫描,覆盖索引下甚至能只扫索引避免回表。线程池的参数要能说出「核心线程数怎么按场景定」:CPU 密集型按核数上下取整并留出余量,IO 密集型按「核数 × (1 + 等待时间 / 计算时间)」估算,但真正的做法是先压测再定,并配合有界队列、明确的拒绝策略、可观测的活跃线程数与队列长度;线上更稳的是动态调整(配置中心下发,改 core/max/队列容量并让线程池生效)而不是写死在代码里。分库分表的判断依据是单表数据量与写入压力:单表超过几千万行或索引已经放不进内存、写入成为瓶颈时考虑分,垂直拆分先做(按业务域拆库),水平分片后要处理路由、全局唯一 ID、跨片查询与聚合、分布式事务这几个必然出现的问题。 -
AT 模式与一致性保障:为什么用 AT 这类分布式事务?因为跨库跨服务的「本地事务 + 远程调用」无法靠单机事务覆盖,而有业务语义要求几步要么都成、要么都不成。AT 的实现逻辑是:代理数据源,执行业务 SQL 前后记录 undo_log(更新前的镜像)与全局锁,第一阶段各分支本地提交(这也是它与 2PC 的区别,不长时间占锁),第二阶段全局提交就异步删日志、全局回滚就按 undo_log 反向补偿。更该主动说的是它的边界:AT 只保证最终一致,期间数据可见;全局锁带来性能损耗;undo_log 需要定期清理(按已完成的全局事务时间归档删除,同时要防止清理掉还在等回滚的记录);对不支持的表结构与某些 SQL 有约束。规避分布式事务的手段优先级更高:能用一个库/一个服务解决的就不拆;跨服务的场景用本地消息表 + 定时补偿、事务消息(RocketMQ)、或状态机 + 对账把「强一致」换成「可收敛的最终一致」;确实需要强一致时再上 TCC 或 AT,并接受相应的复杂度与性能代价。
面经 06 · 接口设计题
- 两道设计题的答法:判断用户能否评论(1 小时内不能重复发相同评论、用户量几千万)用 Redis 的 string + TTL 最直接:key 设计成
comment:limit:{userId}:{contentHash},写入用SET NX EX 3600,成功即允许、失败即拦下,一次操作完成「判重 + 计数 + 过期」,天然原子且内存可控;要防刷得更严就叠一层按用户的频率计数(INCR + EXPIRE 或用 zset 存时间戳、按滑动窗口清理),再做内容归一化(去空格、大小写、表情与标点的相似判定)避免改一个字就绕过;几千万用户不可能全量常驻内存,靠 TTL 自然淘汰即可,别用全量 set。房间列表接口(QPS 几百)的重点不在数据库而在缓存与分页:先明确排序字段与分页方式(游标分页优于 offset),用 Redis 的 zset 按热度或更新时间维护房间 ID 的有序集合,取一页只需一次范围查询,再用 pipeline 批量拿房间详情(或本地缓存 + Redis 两级);几百 QPS 对缓存来说压力很小,真正的坑是缓存与数据库的一致性、翻页时的数据抖动(新房间插入导致重复或遗漏,游标分页能缓解)、以及热点房间的缓存击穿(加互斥重建或逻辑过期)。答题时把「数据结构选择、key 设计、容量估算、失效与一致性、异常兜底」这条线走完,比给出一个方案就结束更完整。
面经 07 / 09 · 网络与编程基础
-
TCP 滑动窗口、握手与网络优化:滑动窗口是接收方通过通告窗口做流量控制:窗口只能整体向右滑动(随 ACK 前进),不能左移——左移意味着要重新接收已确认的数据,会造成数据混乱与协议错误;窗口可以变小(接收方缓冲区被占用时),极端情况缩到 0,此时发送方必须停止发送,靠持续发送窗口探测报文等待窗口恢复,而不是盲目重传。TCP 第一次真正发送数据要区分阶段:三次握手的前两个报文不携带数据(第三个 ACK 可以携带),所以严格意义上的第一批应用数据通常随第三次握手的 ACK 一起发出。为什么前两次不能带:第一次若带数据,服务端在未确认客户端可达前就要为它分配资源,容易被伪造源 IP 的攻击者耗尽;第二次同理,且此时客户端尚未确认自己的序列号被正确接收。网络波动大时 TCP 的问题是丢包被当成拥塞信号——RTO 翻倍退避、拥塞窗口骤降,延迟抖动明显,而且 TCP 层的队头阻塞会让一个丢包卡住整条连接上的所有请求。优化方向分两层:协议层换 QUIC(基于 UDP、流级独立重传、无 TCP 队头阻塞)、KCP(牺牲带宽换延迟,适合弱网实时交互)、MPTCP(多路径并用);参数层调初始拥塞窗口、开启 TCP Fast Open、合理设置重传超时与应用层超时。
-
「检测当前网络」的功能设计(微信场景):把它拆成「可达性、质量、可用性」三问。可达性检测用对业务服务器(而不是第三方)的探测:应用层 HTTP 探测接口最贴近真实链路(能同时覆盖 DNS、TLS、网关),ping 只能证明 ICMP 通、很多网络会屏蔽 ICMP 所以不能单用,同时检查本地网络接口是否有地址、是否连着 WiFi 还是蜂窝。质量检测看延迟(多次探测取分位数而不是单次,避免被一次抖动带偏)、丢包率、带宽与首包时间,并区分「内网延迟」和「到服务器的延迟」来判断是本地网络问题还是服务端问题。可用性判断要给出分级结论而不是一个布尔值:直连是否可用、是否需要切换到备用域名或备用 IP、是否应该降级到弱网模式(降低图片质量、拉长超时、暂停后台同步)。工程上还要注意:探测要异步且低频、失败要退避,避免探测本身变成流量;结果要缓存并做成状态机(好 / 弱 / 断),状态切换需要连续多次采样确认,否则会在临界点来回抖动;上报的指标要能按运营商与地域聚合,方便定位区域性故障。