
1) 【一句话结论】为高并发读写场景,采用分库分表(用户ID哈希分库+时间分表)、读写分离(主从复制)、Redis缓存(登录态、角色数据),并配合缓存击穿(预热+互斥锁)、雪崩(限流+熔断)策略,构建分层数据库架构,平衡性能与一致性。
2) 【原理/概念讲解】
分库分表:数据库水平扩展,解决单库容量、性能瓶颈。类比“大书架拆成多个小书架”,用户表按ID哈希到不同库(分库),每个库再按时间分表(分表),如充值记录按月份分表,便于管理。
读写分离:主库负责写(事务),从库负责读(异步复制),类比“主服务器写数据,从服务器读数据”,减轻主库压力。
缓存策略:Redis作为缓存层,存储热点数据(如登录态、角色信息),减少数据库压力。
缓存击穿:热点key突然失效,所有请求落库,导致雪崩。解决方案:缓存预热(提前存热点数据)、互斥锁(加锁后只查一次,再存缓存)。
缓存雪崩:多个key同时失效,导致大量请求落库。解决方案:过期时间随机(避免同时失效)、限流(熔断)、降级。
3) 【对比与适用场景】
分库分表分片策略对比表:
| 分片策略 | 定义 | 特性 | 使用场景 | 注意点 |
|---|---|---|---|---|
| 哈希分库 | 按用户ID哈希,映射到不同库 | 均匀分布,避免冷热不均 | 用户表(ID分布均匀) | ID分布不均可能导致部分库压力过大 |
| 范围分表 | 按时间范围(如充值记录按月份) | 便于按时间查询 | 日志、订单等时间序列数据 | 需要定期合并旧表 |
| 列表分片 | 按列表(如按角色类型) | 便于按业务类型查询 | 角色表按类型分表 | 类型变化时需迁移 |
读写分离方案对比:
| 方案 | 主从切换方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 热备 | 从库只读,主库写 | 简单,成本低 | 从库延迟 | 读多写少 |
| 读写分离(Proxy) | 从库读,主库写 | 提升读性能 | 需要代理 | 读多写少,延迟敏感 |
4) 【示例】
用户登录流程伪代码:
用户登录请求:
1. 检查Redis缓存:key为 "user:login:userId",value为登录态(token等)
2. 若命中:返回用户信息 + 登录态
3. 否则:
a. 查询数据库(分库分表后的用户表,如库1,表按时间分表)
b. 存入Redis:SET user:login:userId token EX 3600
c. 返回用户信息 + 登录态
分库分表示例:用户表(user)按ID哈希到库1、库2,充值记录(recharge)按时间分表(如表名recharge_202401)。
5) 【面试口播版答案】(约80秒)
“面试官您好,针对高并发读写场景,我设计的数据库架构分为分层:首先,分库分表解决单库瓶颈。用户表按用户ID哈希分库(比如库1存ID哈希后0-32767的用户,库2存32768-65535),每个库再按时间分表(如充值记录按月份分表)。然后,读写分离,主库写,从库读,用ShardingSphere等工具实现,减轻主库压力。缓存方面,用Redis缓存热点数据,比如用户登录态(key为user:login:userId,过期3600秒)和角色数据(key为role:info:roleId),读请求先查缓存,命中则直接返回,不命中再查库并缓存。处理缓存问题,击穿用缓存预热(提前存热点数据)+ 互斥锁(加锁后只查一次,再存缓存);雪崩用过期时间随机(避免同时失效),并配合限流熔断。这样整体架构能支撑高并发,平衡性能与一致性。”
6) 【追问清单】
SET lock:user:login:userId EX 10 NX,加锁成功后查询数据库,再存缓存,释放锁。7) 【常见坑/雷区】