Java 大厂一面模拟:从活动发奖到消息幂等的分布式一致性拷问

张开发
2026/4/14 4:25:31 15 分钟阅读

分享文章

Java 大厂一面模拟:从活动发奖到消息幂等的分布式一致性拷问
开场说明这是一场面向 1-3 年 Java 后端候选人或校招高阶候选人的模拟大厂一面时长约 30 分钟。面试围绕一个典型的电商活动发奖业务场景展开串联缓存设计、消息可靠性、事务一致性及分布式协调等核心模块。问题设计兼顾广度与深度重点考察候选人对技术原理的理解、边界条件的把握以及线上落地能力。追问风格贴近真实大厂节奏强调“原理 → 边界 → 线上问题 → 取舍落地”的递进逻辑。本场面试覆盖以下五大模块Redis热点 Key 处理、缓存一致性、分布式锁MQ / 消息队列幂等消费、消息可靠性、延迟消息Spring / Spring Boot事务传播、AOP 代理、Bean 生命周期MySQL事务隔离、锁机制、binlog 与主从延迟分布式系统最终一致性、补偿机制、对账设计我们将从一个“春节红包雨活动”的真实业务场景切入逐步深入技术细节。主问题部分1. 你在项目中负责过哪些高并发活动系统比如发奖、发券这类参考回答我负责过公司春节期间的“红包雨”活动系统用户点击页面按钮即可领取随机金额红包每日限领 3 次。高峰期 QPS 达到 3000奖品包括现金券、积分、实物等。系统采用 Spring Boot Redis Kafka MySQL 架构通过多级缓存、异步发奖、消息幂等保障高可用与一致性。追问点预判面试官会关注你如何设计发奖流程、如何防重、如何保证不超发。2. 红包雨活动中你是怎么防止用户重复领取的参考回答我采用了“本地缓存 Redis 分布式锁 数据库唯一索引”三重防重机制。首先在 Controller 层用 Caffeine 做本地缓存缓存用户当日已领取次数TTL 1 分钟减少 Redis 压力然后在 Service 层用 Redisson 的RLock对用户 ID 加锁防止并发请求穿透最后在 MySQL 的user_reward_record表上对用户 ID 活动 ID 日期建立联合唯一索引作为最终防重屏障。追问点预判面试官会追问锁的粒度、锁超时、本地缓存与 Redis 不一致等问题。3. 你说用了 Redis 分布式锁如果锁超时了但业务还没执行完会发生什么你怎么解决参考回答这是一个经典问题。如果锁超时释放而发奖逻辑还在执行另一个线程可能重复进入导致重复发奖。我的解决方案是设置合理的锁超时时间如 10 秒并评估业务最大耗时使用 Redisson 的看门狗机制WatchDog自动续期锁默认每 10 秒续一次在业务逻辑中增加状态检查比如先查数据库是否已发奖避免重复执行。追问点预判面试官可能追问看门狗原理、续期失败场景、是否用 Lua 脚本保证原子性。4. 发奖逻辑是同步还是异步为什么参考回答采用异步发奖。用户点击后立即返回“领取成功”实际发奖通过 Kafka 消息异步处理。原因有三发奖涉及积分、券包、短信通知等多个子系统同步调用链太长影响用户体验异步可削峰填谷应对突发流量便于后续扩展比如增加风控审核、人工干预等流程。追问点预判面试官会追问消息丢失、重复消费、顺序性等问题。5. Kafka 消息如何保证不丢失、不重复参考回答不丢失生产者开启acksall确保消息写入所有 ISR 副本Broker 配置min.insync.replicas2消费者手动提交 offset处理完再提交。不重复消费者端实现幂等。我采用“消息 ID 业务唯一键”存入 MySQL消费前先查是否已处理。消息 ID 由 Snowflake 生成保证全局唯一。追问点预判面试官会追问 Snowflake 时钟回拨、幂等表设计、高并发下幂等性能。6. 幂等表在高并发下会不会成为性能瓶颈你怎么优化参考回答确实可能。我的优化策略包括幂等表按用户 ID 分表16 张分散写入压力使用 Redis 做一级幂等缓存缓存已处理的消息 IDTTL 7 天命中则直接返回幂等表只存必要字段msg_id, user_id, status, create_time并建联合索引定期归档历史数据避免单表过大。追问点预判面试官可能追问 Redis 缓存与 DB 不一致、分表策略、归档机制。7. 如果发奖过程中某个子系统比如积分系统挂了你怎么保证最终一致性参考回答我设计了一套“本地事务表 定时任务补偿”机制。发奖服务在本地事务中同时写入“发奖记录”和“待发送消息”两张表保证原子性。然后由定时任务扫描“待发送消息”表重试发送 Kafka 消息。如果积分系统恢复消息可重新消费如果长时间失败则触发告警人工介入。此外我们还做了对账系统每天凌晨比对发奖记录与积分变动发现不一致则自动补偿或告警。追问点预判面试官会追问本地事务表如何防重、定时任务频率、对账粒度。8. 对账系统是怎么设计的比对哪些数据参考回答对账系统基于 MySQL binlog Kafka 构建。我们使用 Canal 监听发奖记录表的变更发送到 Kafka由对账服务消费。对账服务每天凌晨执行以下比对发奖记录中“已发放”状态的记录数 vs 积分系统当日积分增加记录数按用户维度比对积分变动总额是否一致发现差异则生成对账异常单支持手动重试或自动补偿。追问点预判面试官可能追问 Canal 原理、对账延迟、补偿策略。追问部分追问 1你说用 Canal 监听 binlog如果 Canal 挂了或者延迟很高对账会不准你怎么监控和应对考察点分布式系统可观测性、故障恢复能力参考回答我们做了三层监控Canal 实例存活监控Prometheus Grafana挂了自动告警Kafka 消息堆积监控如果 lag 超过 10 万条触发告警对账服务自身记录“最后处理时间”如果超过 24 小时未更新说明卡住了。应对措施Canal 挂了自动重启K8s 托管延迟高时临时增加对账任务并行度极端情况下支持手动触发全量对账按天回溯。追问 2Redis 缓存用户领取次数如果 Redis 挂了本地缓存也失效会不会导致超发考察点缓存高可用、降级策略参考回答这是个关键风险点。我们的降级策略是Redis 挂了本地缓存失效但数据库唯一索引仍有效最多导致少量重复请求打到 DB由于有唯一索引重复插入会失败不会超发同时我们配置了 Redis 集群哨兵模式单点故障自动切换极端情况下可临时关闭活动入口避免雪崩。补充我们还在 Nginx 层做了限流单用户每秒最多 5 次请求进一步降低风险。追问 3你说用 Redisson 看门狗续期如果 GC 停顿导致续期失败锁被释放会怎样考察点JVM 与分布式系统交互、GC 影响参考回答Redisson 看门狗通过一个后台线程每 10 秒续一次锁默认 leaseTime30s。如果发生 Full GC线程暂停续期失败锁被释放。此时另一个线程可能获取锁并执行发奖。我们的应对在业务逻辑中增加“状态检查”执行前先查数据库是否已发奖发奖记录表有唯一索引重复插入会抛异常被捕获后忽略监控 GC 时间避免长时间停顿我们用的是 G1MaxGCPauseMillis200ms。面试点评本场面试主要考察候选人在高并发活动场景下的系统设计能力重点包括防重设计从本地缓存到分布式锁再到数据库唯一索引的多层防御消息可靠性Kafka 生产消费配置、幂等实现、补偿机制最终一致性本地事务表、定时补偿、对账系统边界与容错锁超时、缓存失效、GC 影响、主从延迟等极端场景应对。候选人容易卡壳的点看门狗续期原理不清楚幂等表设计未考虑分表与性能对账系统只提概念无具体实现细节忽略 GC 对分布式锁的影响。整体强度适中适合 1-3 年候选人既能展示广度也有深度追问空间。技术补丁包Redis 分布式锁Redisson原理基于 Lua 脚本实现原子加锁看门狗线程自动续期默认每 10 秒续一次leaseTime30s。 设计动机解决锁超时导致并发安全问题。 边界条件GC 停顿可能导致续期失败锁粒度应尽量细如 userId。 落地建议结合业务状态检查避免依赖锁作为唯一防重手段。消息幂等消费原理通过唯一消息 ID 业务键判断是否已处理。 设计动机防止网络重试或消费者重启导致重复消费。 边界条件幂等表可能成为热点Redis 缓存与 DB 不一致。 落地建议采用“Redis 缓存 DB 唯一索引”二级幂等分表分散压力。本地事务表 异步消息原理在本地事务中同时写入业务数据和待发送消息保证消息不丢失。 设计动机解决分布式事务难题实现最终一致性。 边界条件定时任务可能延迟消息重复发送。 落地建议消息表需有状态字段pending/sent/failed支持重试与告警。对账系统设计原理基于 binlog 监听 Kafka 定时比对发现数据不一致。 设计动机保障跨系统数据最终一致。 边界条件binlog 延迟对账任务性能瓶颈。 落地建议按天分片对账支持手动触发异常单需有处理流程。Canal 监听 binlog原理伪装成 MySQL 从库接收 binlog 事件并转发至 Kafka。 设计动机解耦数据变更与业务逻辑实现数据同步。 边界条件Canal 实例单点故障网络延迟导致 lag。 落地建议部署多个 Canal 实例监控 lag 与存活状态。缓存降级策略原理当 Redis 不可用时依赖数据库唯一索引兜底。 设计动机保障系统基本可用性。 边界条件数据库压力增大短暂不一致。 落地建议结合限流如 Nginx 层控制请求量。Kafka 消息可靠性原理生产者acksallBroker 多副本消费者手动提交 offset。 设计动机防止消息丢失。 边界条件ISR 副本不足时写入失败消费者处理慢导致 lag。 落地建议监控 ISR 数量与 lag合理设置副本数。GC 对分布式系统影响原理Full GC 导致线程暂停影响看门狗续期。 设计动机理解 JVM 与分布式组件的交互风险。 边界条件长时间 GC 停顿30s。 落地建议使用 G1 垃圾回收器控制 MaxGCPauseMillis业务层增加状态检查。数据库唯一索引防重原理利用唯一约束阻止重复插入。 设计动机作为最终防重屏障。 边界条件高并发下唯一索引可能成为热点。 落地建议合理设计索引字段如 user_id activity_id date避免全表扫描。多级缓存一致性原理本地缓存Caffeine 分布式缓存Redis DB。 设计动机提升读取性能降低 DB 压力。 边界条件缓存与 DB 不一致缓存雪崩。 落地建议本地缓存设置短 TTL如 1 分钟Redis 做主缓存DB 为数据源。定时任务补偿机制原理扫描未处理消息重试发送。 设计动机应对子系统临时故障。 边界条件任务执行频率与性能重复处理。 落地建议任务分片执行记录最后处理 ID避免全表扫描。Snowflake 消息 ID 生成原理基于时间戳 机器 ID 序列号生成全局唯一 ID。 设计动机保证消息唯一性。 边界条件时钟回拨导致 ID 重复。 落地建议使用开源实现如 Hutool或引入 Zookeeper 协调机器 ID。Redis 集群高可用原理哨兵模式或 Cluster 模式自动故障转移。 设计动机避免单点故障。 边界条件主从切换期间短暂不可用。 落地建议监控主从状态配置合理超时时间。Nginx 限流原理基于 IP 或用户 ID 限制请求频率。 设计动机防止恶意刷奖。 边界条件误杀正常用户。 落地建议结合业务场景设置合理阈值如 5 req/s。对账异常处理流程原理发现不一致后生成异常单支持自动补偿或人工处理。 设计动机保障资金安全。 边界条件自动补偿可能失败。 落地建议异常单需有状态流转待处理/已补偿/已关闭并通知相关人员。G1 垃圾回收器调优原理分代收集可预测停顿时间。 设计动机减少 Full GC 对业务影响。 边界条件Region 大小配置不当。 落地建议设置-XX:MaxGCPauseMillis200监控 GC 日志。消息表状态机设计原理定义消息状态pending/sent/failed/retrying。 设计动机支持重试与监控。 边界条件状态流转逻辑复杂。 落地建议使用状态模式避免 if-else 泛滥。分表策略原理按用户 ID 哈希分表。 设计动机分散写入压力。 边界条件跨分片查询困难。 落地建议分表数取 2 的幂如 16便于扩展。缓存穿透防护原理对不存在的数据也缓存空值。 设计动机防止恶意查询不存在 key。 边界条件空值缓存可能占用内存。 落地建议设置较短 TTL如 5 分钟。最终一致性 vs 强一致性原理允许短暂不一致通过补偿达到一致。 设计动机提升系统可用性。 边界条件对账周期内数据不一致。 落地建议根据业务容忍度选择金融类业务慎用。

更多文章