线上服务 CPU 正常却卡死的场景中,90% 的问题根源是频繁 GC。
问题定位:视频通过订单服务卡死案例,指出需用 jps、jstat、jmap 三板斧:jstat 看 FGC 频率与耗时,jmap 看存活对象统计。
内存泄露分析:以 OrderCache 对象为例,解释内存泄露本质是对象被 GC Root 意外引用;需用 MAT 工具分析 Dominator Tree 和 GC Root 路径。
解决方案:建议用软引用 / 弱引用替代强引用缓存,通过引用队列清理无用引用;还需选择合适 GC 收集器(如 G1)并调整 JVM 参数。
面试重点:强调大厂考察的是定位 - 分析 - 解决的完整方法论,而非工具使用或理论背诵。
视频给出了从问题定位到根治调优的四阶段完整流程。
视频通过实操演示和规则拆解,揭示 MVCC 解决读写冲突的底层逻辑及三大局限性。
核心目标:为解决数据库读写冲突而生,实现写操作不阻塞读、读操作不阻塞写。
三大组件:隐藏字段记录事务 ID 与回滚指针,Undo Log 形成历史版本链,Read View 通过活跃事务快照判断数据可见性。
隔离级差异:RC 级别每次查询生成 Read View 导致不可重复读,RR 级别仅第一次生成保证事务内结果一致。
局限性:仅解决读写冲突,写写冲突仍需加锁;RR 级别幻读需 Next-Keylock 配合;长事务会导致 Undo Log 版本链膨胀。
视频强调日常开发应避免大事务以减少 Undo Log 空间开销。
5 年经验后端开发者用 Spring 定时任务扫表的方案,在千万级未支付订单场景下被面试官指出三大致命问题。
常规方案缺陷:面试官针对扫表方案提出三个问题,包括千万级数据全表扫描可能导致数据库崩溃、取消时间存在近两分钟误差引发用户投诉、定时任务机器宕机导致任务丢失。
方案升级路径:视频给出延迟任务设计的三个层级,青铜级为 Spring @Scheduled 扫表,白银级为 Redis ZSet 存储超时时间戳并每秒捞取,王者级为 ZSet 结合 Ack 机制,通过 Lua 脚本原子移动任务到处理队列,配合守护线程重试防止任务丢失。
压测与防御设计:压测需验证延迟精度、高并发原子性和数据量承载能力;代码层需通过 Ack 机制、消费端限流、监控告警和分层超时策略保证系统可靠。视频指出该问题考察的是开发者从基础定时任务到分布式延迟任务设计思想的认知升级。
该视频以京东秒杀商品为背景,通过具体技术方案解释秒杀支付链路的关键节点设计。
核心考察点:分布式链路一致性、高并发处理与容错设计。
秒杀资格校验:使用 Redis 预扣库存并通过队列削峰,同时发送下单消息到 MQ 异步生成订单,标记库存为锁定状态。
并发控制:采用 Redis 或 ZK 分布式锁防止同一商品超卖。
支付处理:支付成功后支付通道异步回调通知业务系统,回调接口做幂等处理,结合本地消息表和 MQ 确保支付结果可靠同步。
扣费同步:通过可靠消息队列调用扣费接口,采用事务消息机制,扣费成功后更新订单状态为已支付、已扣费;扣费失败触发三次重试,间隔 10/30/60 秒,重试失败标记为异常并人工介入。
订单闭环:使用延迟队列实现 15 分钟超时自动处理,未支付订单触发 Redis 库存回滚和数据库订单状态更新为已取消,通过订单状态校验避免误回滚已支付订单。
视频提供了针对面试场景题的详细技术方案,覆盖秒杀支付链路的关键节点设计。
横向扩容 Redis 集群无法解决百万 QPS 热 Key 问题。
热 Key 问题本质:Redis Cluster 通过 CRC16 (key)%16384 算法将同一 Key 路由到固定节点,百万 QPS 会集中打向单节点,导致网卡带宽耗尽、数据库穿透熔断。
散列分片法:给热 Key 加随机后缀(如 1-100),将流量均匀打散到集群节点,但存在内存浪费和数据一致性维护成本高的问题。
多级缓存架构:引入 JVM 本地缓存(如 Caffeine),请求优先查本地缓存,拦截 99% 读流量,仅少量穿透请求到达 Redis。
热 Key 动态发现:通过客户端滑动窗口统计(如 1 秒访问过千)识别热 Key,经 MQ 推送到业务节点自动写入本地缓存,实现自动防御。
一致性与熔断:本地缓存设置 3 秒 TTL 或通过 MQ 广播清空保证最终一致性;用互斥锁限制数据库查询线程,配合 Sentinel 熔断非核心流量。
视频给出应对百万 QPS 热 Key 的四步解决方案:探测发现、多级缓存、互斥保底、降级熔断。
核心参数设计:短信推送为 IO 密集型任务,初始线程数可按 "CPU 核数 ×2" 经验值设定,后续通过压测微调;生产环境需手动声明有界队列,避免 FixedThreadPool 或 CachedThreadPool 导致的内存或 CPU 问题。
动态调优策略:核心参数不写死,接入 Apollo 或 Knox 配置中心实现动态下发,配合 Hippo4j 框架监控,队列容量超 80% 时触发告警或扩容。
拒绝策略选择:推荐 CallerRunsPolicy,利用其背压机制,当队列塞满时让主线程参与执行,降低任务产生速度,避免 OOM。
任务可靠性保障:入队前在 DB/Redis 写入状态位,执行完毕回调更新;通过定时任务扫描超时未发送数据重新投递,确保任务零丢失。
视频最后提出集群分工、宕机接管、分布式限流等进阶问题,引导从单机调优转向集群架构设计。
数据库索引优化的核心认知并非 "加索引",而是建立 "索引即负债" 的意识。
索引设计原则:需以查询需求为驱动,而非单纯按字段建索引。需明确核心查询的 WHERE 条件、排序方式及覆盖字段,才能设计出有效的联合索引,例如针对 "某用户最近 10 条已完成订单" 的查询,需建立(user-id、status、create-time)的联合索引,甚至可通过覆盖索引避免回表。
索引成本意识:索引并非越多越好,字段区分度低时数据库可能放弃使用索引;每次写入操作需同步更新所有索引,索引数量会直接影响写入性能。
索引治理机制:需定期清理长期未使用的 "僵尸索引",新索引上线前必须通过压力测试验证其对写入性能的影响。
视频通过具体面试场景,展示了普通开发者与高级工程师在索引使用上的认知差异。