1) 【一句话结论】
采用微服务+分布式架构,通过负载均衡分散请求压力,结合多级缓存(如Redis)减少数据库访问,数据库分片(如ShardingSphere)处理百万级数据,消息队列(如Kafka)解耦异步任务,并辅以容灾、监控等机制,确保系统高可用与低延迟。
2) 【原理/概念讲解】
- 负载均衡:像交通枢纽的调度员,将用户请求分发到多个后端服务器,避免单点过载。常见L7(如Nginx)通过URL、用户IP等策略分发,L4(如HAProxy)处理TCP层。
- 缓存:像超市的“热销商品货架”,将高频访问的数据(如用户信息、题目库)存入内存(如Redis),用户请求时优先从缓存获取,减少数据库压力。
- 数据库分片:将海量数据水平拆分到多个数据库实例(如ShardingSphere),每个实例负责部分数据,提升查询和写入性能。
- 消息队列:像快递中转站,解耦系统间的依赖,比如用户提交答案后,将答题记录存入队列,由消费者异步处理,避免阻塞主流程。
3) 【对比与适用场景】
| 组件 | 定义/作用 | 特性/特点 | 使用场景 | 注意点 |
|---|
| 负载均衡 | 分发请求到后端服务器 | L4(TCP) vs L7(HTTP) | 高并发请求分发 | 需要考虑会话保持、健康检查 |
| 缓存(Redis) | 内存数据库,存储高频数据 | 高速读写,支持持久化 | 用户信息、题目库、考试状态 | 需要考虑缓存击穿、雪崩 |
| 数据库分片 | 水平拆分数据到多个数据库 | 按业务维度(如用户ID、考试ID)分片 | 海量数据存储与查询 | 分片键设计影响性能,需考虑跨分片查询 |
| 消息队列 | 异步通信中间件,解耦系统 | 支持持久化、事务、消费组 | 答题记录提交、成绩计算、邮件通知 | 需要考虑消息积压、消费延迟 |
4) 【示例】
用户请求“开始考试”接口(URL:/exam/start?examId=123)。
- 负载均衡(Nginx)将请求分发到后端服务(如ExamService)。
- 后端检查用户是否已登录,若未登录,跳转登录页;若已登录,从Redis缓存中获取用户信息(若缓存未命中,查询数据库并缓存)。
- 从题目库(缓存或数据库)获取考试题目(按分片键分库查询,如用户ID模运算确定分片)。
- 用户提交答案后,将答题记录(如用户ID、题目ID、答案)存入消息队列(Kafka),由成绩计算服务异步处理。
5) 【面试口播版答案】
“设计百万级高并发考试系统,核心是分布式架构。首先用负载均衡(如Nginx)分发请求到多台后端服务器,避免单点过载。缓存用Redis存储用户信息、题目库,减少数据库压力。数据库分片(如ShardingSphere)按用户ID或考试ID拆分数据,提升查询效率。消息队列(如Kafka)解耦答题记录的异步处理,比如用户提交答案后,先存入队列,由成绩计算服务异步计算。高可用方面,负载均衡做健康检查,数据库分片部署多实例,缓存有主从备份,消息队列持久化存储。这样能保证系统低延迟和高可用。”
6) 【追问清单】
- 问:如何保证高可用?
答:负载均衡做健康检查,数据库分片部署多实例(如3台),缓存主从复制,消息队列持久化,并配置监控告警。
- 问:缓存击穿怎么办?
答:设置缓存过期时间(如10秒),并加互斥锁(如Redis的SETNX),避免热点数据同时过期。
- 问:数据库分片策略?
答:按用户ID模运算分片(如用户ID%4=0到分片0),考试数据按考试ID分片,避免热点数据集中。
- 问:消息队列选型?
答:Kafka适合高吞吐,RabbitMQ适合低延迟,根据业务需求选,比如答题记录用Kafka保证持久化。
- 问:如何处理跨分片查询?
答:通过分片键聚合数据,或者将数据复制到主库,但会增加数据一致性成本。
7) 【常见坑/雷区】
- 缓存穿透:未命中时直接查询数据库,导致热点数据查询压力过大。
- 分片策略不合理:分片键选择不当(如按时间分片,导致数据热点集中)。
- 消息队列积压:消费者处理能力不足,导致消息堆积,影响系统性能。
- 负载均衡会话保持:未正确配置,导致用户请求被分发到不同服务器,会话丢失。
- 数据库分片后跨库查询复杂:未考虑业务场景,导致查询效率下降。