
1) 【一句话结论】
针对好未来数百万用户、数十万课程的场景,采用“分库分表(用户表按ID哈希分库、课程表按ID哈希分表)+ Redis缓存+ 索引优化+ 双一致性模型(关键业务强一致,非关键业务最终一致)”的混合架构,通过水平扩展应对数据增长,缓存提升查询性能,双一致性模型平衡一致性与性能。
2) 【原理/概念讲解】
老师讲解:首先,用户与课程数据量巨大,关系型数据库(如MySQL)适合结构化数据,但单表数据量过大时,需引入分库分表(水平扩展)。分库分表通过哈希算法将数据分散到多个库/表,避免单库负载过高。比如用户表按用户ID哈希分库(如ID % 8,分8库),课程表按课程ID哈希分表(如ID % 16,分16表),每个库/表只存储部分数据,实现水平扩展。然后,针对高频查询(如用户信息、课程详情),引入Redis缓存,减少数据库压力。缓存像“数据中转站”,把热门数据放在缓存,用户访问时直接从缓存获取,避免去数据库。查询性能方面,通过复合索引(如用户表的username索引、课程表的title索引,关联表的user_id+course_id联合索引)优化查询效率,比如查询用户购买课程时,先查缓存,缓存失效再通过分库分表路由到对应库/表。数据一致性方面,采用双一致性模型:关键业务(如支付、订单)需强一致性,通过分布式事务(如Seata两阶段提交)确保数据一致;非关键业务(如用户列表展示)采用最终一致性,通过异步消息队列(如Kafka)传递事件,确保数据最终一致。类比:分库分表像把用户数据分散到不同仓库,每个仓库只存部分用户,避免某个仓库过载;缓存像把热门课程放在货架,用户直接拿,不用去仓库;分布式事务像给关键业务加“锁”,确保操作成功后立即更新数据。
3) 【对比与适用场景】
| 特性 | MySQL (关系型) | Redis (NoSQL缓存) | 分库分表策略 |
|---|---|---|---|
| 定义 | 结构化数据存储,支持ACID事务 | 键值对缓存,高性能读写 | 数据水平拆分(库/表) |
| 数据结构 | 表(如user表:id, username, phone...) | 键值(如user:1 → 用户信息) | 库/表拆分 |
| 事务支持 | 支持(ACID) | 不支持(需结合数据库事务) | 无需事务,通过异步保证最终一致 |
| 查询能力 | 复杂查询(JOIN、聚合) | 简单键值获取 | 分布式查询(分片路由) |
| 扩展性 | 垂直扩展(提升单机性能),分库分表(水平扩展) | 水平扩展(增加实例) | 水平扩展,应对数据增长 |
| 适用场景 | 用户表、课程表(结构化数据,需事务与复杂查询) | 热点数据缓存(用户信息、课程详情,减少数据库压力) | 用户表按ID哈希分库(如用户ID % 8,分8库),课程表按ID哈希分表(如课程ID % 16,分16表) |
| 注意点 | 单表数据量过大时性能下降,需分库分表 | 缓存击穿、雪崩风险,需加互斥锁或预加载 | 热点数据集中(如热门用户/课程),需冷热分离(如用户表按注册时间分表,冷数据归档) |
4) 【示例】
表结构:
索引设计:
缓存策略:
user:userId(5分钟TTL)。course:courseId(10分钟TTL)。user:userId:courses(5分钟TTL)。分布式查询示例(用户购买课程):
伪代码:
def get_user_courses(user_id):
cache_key = f"user:{user_id}:courses"
courses = redis.get(cache_key)
if courses:
return json.loads(courses)
db_index = user_id % 8 # 用户表分8库
table_index = course_id % 16 # 课程表分16表
course_ids = db.query(
"SELECT course_id FROM user_course WHERE user_id = ? AND db = ? AND table = ?",
user_id, db_index, table_index
)
courses = []
for cid in course_ids:
course = db.query(
"SELECT * FROM course WHERE id = ? AND db = ? AND table = ?",
cid, course_id % 8, table_index
)
courses.append(course)
redis.setex(cache_key, 300, json.dumps(courses), ex=300)
return courses
5) 【面试口播版答案】
好的,面试官。针对好未来数百万用户和数十万课程的数据存储需求,我设计的方案是采用“分库分表+缓存+索引优化+双一致性模型”的混合架构。首先,用户表和课程表属于结构化数据,适合用MySQL,但单表数据量过大时,会引入分库分表策略:用户表按用户ID的哈希值分库(如用户ID % 8,分8个库),课程表按课程ID的哈希值分表(如课程ID % 16,分16个表),实现水平扩展,避免热点数据集中。然后,针对高频查询(如用户信息、课程详情),引入Redis缓存热点数据,减少数据库压力,比如用户信息缓存user:userId,课程详情缓存course:courseId,用户购买课程列表缓存user:userId:courses,通过TTL控制过期。查询性能方面,通过复合索引(如关联表的user_id+course_id联合索引)优化查询,比如查询用户购买课程时,先查缓存,缓存失效再通过分库分表路由到对应库/表,避免全表扫描。数据一致性方面,采用双模型:关键业务(如支付、订单)需强一致性,通过分布式事务(如Seata两阶段提交)确保数据一致;非关键业务(如用户列表展示)采用最终一致性,通过异步消息队列(如Kafka)传递事件,确保数据最终一致。整体方案兼顾了数据一致性、扩展性和查询性能。
6) 【追问清单】
7) 【常见坑/雷区】