
1) 【一句话结论】
系统采用微服务+分布式架构,通过分库分表(ShardingSphere)、Redis缓存、Kafka消息队列、WebSocket实时通信,结合读写分离、动态限流等手段,保障百万级并发下的实时反馈与系统稳定性。
2) 【原理/概念讲解】
老师会解释高并发场景的系统设计逻辑:
3) 【对比与适用场景】
| 技术选型 | 定义 | 特性 | 使用场景 | 注意点 |
|---|---|---|---|---|
| 分库分表(ShardingSphere) | 分布式数据库中间件,支持分库分表、读写分离、分布式事务 | 自动化分库分表,支持复杂分片规则,事务一致性 | 百万级用户/数据量的数据库水平扩展 | 需全局唯一ID,避免数据分散;配置复杂度较高 |
| 缓存(Redis集群) | 多个Redis实例组成的集群,支持高并发读写 | 分片存储,读写分离,高可用 | 热点数据缓存(如成绩、题目库) | 需配置哨兵/集群模式,避免单点故障;数据持久化需额外配置 |
| 消息队列(Kafka) | 分布式消息系统,支持高吞吐、持久化 | 消息持久化,支持消费组,可水平扩展 | 异步通信(成绩推送、日志) | 需配置生产者/消费者组,避免消息丢失;需监控队列状态 |
| WebSocket | 基于TCP的长连接协议 | 实时双向通信,低延迟 | 实时反馈(成绩、题目更新) | 需维护连接状态,处理断连重连 |
4) 【示例】
<!-- 分库规则(用户ID哈希分库) -->
<sharding-rule>
<table-rule>
<table-name>user</table-name>
<sharding-column>user_id</sharding-column>
<sharding-algorithm class="com.shardingjdbc.algorithm.sharding.modulo.ModuloShardingAlgorithm">
<property name="sharding-count">8</property> <!-- 8个数据库实例 -->
</sharding-algorithm>
</table-rule>
<!-- 分表规则(考试ID按月分表) -->
<table-rule>
<table-name>exam</table-name>
<sharding-column>exam_id</sharding-column>
<sharding-algorithm class="com.shardingjdbc.algorithm.sharding.time.modulo.TimeModuloShardingAlgorithm">
<property name="time-unit">month</property> <!-- 按月分表 -->
<property name="sharding-count">12</property> <!-- 12个月份表 -->
</sharding-algorithm>
</table-rule>
</sharding-rule>
import redis
from threading import Lock
r = redis.Redis(host='redis-cluster', port=6379)
lock = Lock()
def get_score(user_id, exam_id):
key = f"score:{user_id}:{exam_id}"
score = r.get(key)
if score:
return int(score)
# 缓存失效,加锁
with lock:
if r.setnx(f"lock:{user_id}:{exam_id}", "1", ex=10): # 10秒锁(2倍缓存过期时间)
score = db.get_score(user_id, exam_id) # 从数据库获取
r.setex(key, 300, score) # 5分钟过期
r.delete(f"lock:{user_id}:{exam_id}")
return score
return None
# 生产者配置
producer:
bootstrap-servers: kafka:9092
acks: all
batch-size: 16384
buffer-memory: 33554432
# 消费者配置(动态调整)
consumer:
group-id: exam-score
auto-offset-reset: earliest
max-poll-records: 1000
partitions: 16 # 初始16个分区,流量大时增加
const socket = new WebSocket('wss://exam.wangfazheng.com/ws');
socket.onmessage = (e) => {
const data = JSON.parse(e.data);
if (data.type === 'score') {
// 批量更新(每秒10条)
if (Date.now() % 1000 < 100) {
updateScore(data.score);
}
}
};
socket.onclose = () => {
setTimeout(() => socket.close(), 5000); // 重连
};
后端(Java):
@ServerEndpoint("/ws")
public class ScoreWebSocket {
@OnMessage
public void onMessage(String message) {
JSONObject json = JSON.parseObject(message);
if ("answer".equals(json.getString("type"))) {
int score = calculateScore(json.getString("questionId"), json.getString("answer"));
// 写入Redis(高优先级)
redisTemplate.opsForValue().set("score:" + json.getString("userId"), score, 5, TimeUnit.MINUTES);
// 发布消息(高优先级)
kafkaProducer.send("score-topic", score, json.getString("userId"));
}
}
}
5) 【面试口播版答案】
“面试官您好,针对百万级学生在线考试系统,我的设计采用微服务+分布式架构。前端用WebSocket实现实时交互,后端拆分为答题、成绩计算、消息队列等微服务。数据库通过ShardingSphere按用户ID分库、考试ID分表,结合读写分离提升并发。缓存用Redis集群缓存成绩,设置5分钟过期时间,采用互斥锁防雪崩。消息队列用Kafka,队列容量100万条,消费端动态限流。实时反馈通过WebSocket长连接,结合Redis高优先级消息,延迟控制在50ms内。数据一致性采用最终一致性,答题记录写入数据库,成绩异步同步。容错方面,数据库主从切换、Kafka持久化,前端降级处理异常,确保考试高峰稳定运行。”
6) 【追问清单】
7) 【常见坑/雷区】