
1) 【一句话结论】
采用微服务解耦架构,结合分布式ID(Snowflake)、低延迟消息队列(Kafka)、缓存预热+雪崩防护的Redis、分库分表数据库及动态扩容(如K8s HPA),在合理配置下支撑百万级用户同时参与,实现高可用与低延迟(假设系统单实例QPS 2万,缓存预热覆盖80%热门红包,动态扩容阈值QPS>10万)。
2) 【原理/概念讲解】
老师口吻解释核心组件逻辑:
3) 【对比与适用场景】
以“消息队列(Kafka) vs 数据库(MySQL)”为例:
| 对比项 | 消息队列(Kafka) | 数据库(MySQL) |
|---|---|---|
| 定义 | 分布式消息系统,用于异步通信、解耦业务,支持高吞吐、持久化 | 关系型数据库,存储结构化数据,支持ACID事务 |
| 特性 | 高吞吐(百万级消息/秒)、持久化、可扩展,支持消费重试;通过调整参数(如副本数、批处理大小)优化延迟 | 事务支持(ACID),数据一致性高,但并发下锁竞争严重,单表数据量过大时性能下降 |
| 使用场景 | 业务解耦(如用户拉取红包后,消息进入队列,后台异步发送通知);异步任务(如统计红包数据) | 存储核心数据(如红包状态、用户余额,需强一致性);用户拉取红包时的状态查询(缓存未命中时) |
| 注意点 | 需考虑消息积压(如流量突发时,需增加消费者数量);需配置消费者数量与生产者速率匹配 | 并发下锁竞争导致性能瓶颈(如乐观锁或悲观锁);分库分表复杂,需设计合理的分片策略 |
4) 【示例】
用户拉取红包的伪代码流程:
用户请求拉取红包:GET /activity/redpack/pull?userId=123&count=1
1. 服务端处理:
a. 检查用户是否已参与(缓存/数据库,缓存优先)
b. 从Redis缓存获取用户剩余次数(key: userId:pullCount)
c. 若缓存命中且次数>0:
i. 调用Snowflake生成红包ID(如id=123456789)
ii. 更新缓存:扣减次数(Redis `decr` key: userId:pullCount)
iii. 插入数据库:记录红包信息(`insert into redpack_table (id, userId, amount, status) values (123456789, 123, 10, 'sent')`)
iv. 发送消息到Kafka:`topic=redpack_pull, key=userId, value=红包信息(id, amount, status)`
v. 返回成功:`{code:200, data:{redpackId:123456789, amount:10}}`
d. 否则:返回错误(已拉取完)
2. Kafka消费者(后台任务,每5秒轮询消费):
a. 消费消息:`topic=redpack_pull`
b. 调用第三方短信/短信服务发送通知
c. 更新数据库:标记红包为“已通知”(`update redpack_table set status='notified' where id=123456789`)
5) 【面试口播版答案】
(约90秒)
面试官您好,设计百万级用户参与的活动系统,核心是构建高并发、低延迟的分布式架构。系统采用微服务解耦,关键组件包括分布式ID(Snowflake保证唯一性)、低延迟消息队列(Kafka异步解耦)、预热+雪崩防护的Redis缓存、分库分表数据库及动态扩容。高可用通过负载均衡(Nginx分发请求)、缓存+数据库读写分离、消息队列持久化实现;低延迟通过活动前预热热门红包到缓存(设置随机过期时间5-10秒)、分阶段拉取(用户先拉取部分红包,后续消息通知获取剩余)实现。具体流程:用户拉取时,先查缓存,命中则直接返回;未命中则查数据库,结果存入缓存。拉取成功后,消息进入Kafka队列,后台任务异步发送通知,避免用户等待,支撑百万级并发。比如,活动前1小时,系统会加载前1000个热门红包到Redis,用户拉取时优先从缓存获取,减少数据库压力,同时通过K8s HPA根据QPS自动扩容,应对流量突发。
6) 【追问清单】
7) 【常见坑/雷区】