← 大纲 第四部分 · 数据库架构 · 第 41~50 题

第四部分:数据库架构(第 41~50 题)

进入「第三阶段架构师能力」。聚焦 MySQL 性能、分库分表、读写分离、在线迁移、连接池、容灾。每题需给出:诊断方法→方案→容量→兜底→成本。

本页目录: #41 慢SQL排查#42 索引设计#43 分库分表 #44 读写分离#45 在线迁移#46 深度分页 #47 连接池调优#48 MySQL vs PG#49 冷热分离 #50 金融容灾

第 41 题:MySQL 慢 SQL 全链路排查 性能

1.【真实企业业务场景】
订单查询接口 P99 从 80ms 飙到 3s,监控显示 MySQL CPU 90%,slow log 一条 SELECT ... WHERE status=? AND create_time BETWEEN ? AND ? ORDER BY id DESC 扫描 800 万行。要求:快速定位根因并根治。
2.【面试官问题】
    1. 排查套路?2. EXPLAIN 关键字段?3. 为什么没走索引?4. 临时止血?5. 根治+防复发?
3.【候选人的标准回答】

第一步:分析。慢 SQL 是性能第一杀手,先定位(慢日志/APM)→ 诊断(EXPLAIN)→ 止血(限流/加索引/改写法)→ 根治

第二步:挑战。全表扫、索引失效、锁等待、临时表。

第三步:架构。①开 slow log + 监控告警;②EXPLAIN 看 type/rows/key/Extra;③发现该 SQL 因 status 区分度低+范围条件致联合索引失效,建 (create_time, status, id) 覆盖索引;④止血:限流+加索引 online(gh-ost);⑤防复发:SQL 审核平台+压测门禁。

第四步:选型。慢日志/Performance Schema + EXPLAIN + gh-ost(在线加索引)+ APM(定位慢调用)。

第五步:一致性。在线加索引不锁表,业务无感;覆盖索引保证一致读。

第六步:高可用。慢 SQL 限流防拖垮;索引 online 不影响写入。

第七步:优化。覆盖索引免回表;避免 SELECT *;分页改用游标。

4.【架构设计】
APM/慢日志 → 定位慢SQL → EXPLAIN诊断 → 建覆盖索引(online) → 验证P99回落 防复发: SQL审核 + 压测门禁 + 慢SQL告警
5.【技术方案深度解析】

EXPLAIN 看什么:type(ALL=全表扫差)、rows(扫描行数)、key(用的索引)、Extra(Using filesort/temporary 危险)。索引失效:范围条件后的列不进索引、函数包裹列、隐式转换。为什么覆盖索引:索引含查询全部字段,免回表,rows 暴降。

6.【关键技术点】
慢日志EXPLAIN覆盖索引gh-ostSQL审核filesort
7.【Java 实现示例】
// 覆盖索引: (create_time, status, id)  避免回表+filesort
// 错误: WHERE status=? AND create_time BETWEEN ? AND ? ORDER BY id  → 范围后列失效
// 正确: 索引顺序 create_time(范围)放前, status, id 供排序
EXPLAIN SELECT id,status FROM orders
  WHERE create_time BETWEEN '2026-01-01' AND '2026-02-01' AND status=1
  ORDER BY id DESC LIMIT 20;
// 在线加索引(gh-ost,不锁表)
// gh-ost --table=orders --alter="ADD INDEX idx_ct_st_id(create_time,status,id)"
8.【面试官可能继续追问】
9.【常见错误回答】
  • ❌ 直接 kill 慢查询——复发。正确:定位根因+索引/改写。
  • ❌ 主库 ALTER 加索引——锁表。正确:gh-ost online。
  • ❌ 只看平均 RT——漏长尾慢 SQL。正确:看 P99+slow log。
10.【架构师评分标准】
初级 0~40
不会 EXPLAIN。
中级 40~60
会加索引,不懂覆盖/失效。
高级 60~80
全链路排查+覆盖索引+online+限流止血。
架构师 80~100
再加:①SQL 审核与门禁体系;②统计信息/锁等待深度;③容量与索引成本权衡;④防复发闭环。

第 42 题:索引设计与最左前缀陷阱 索引

1.【真实企业业务场景】
交易表 5 亿行,索引 (user_id, status, create_time),但「按 status 查全部待支付」全表扫;「按 user_id+create_time」也偶发慢。要求:设计一套既满足多查询模式又不冗余爆炸的索引策略。
2.【面试官问题】
    1. 最左前缀是什么?2. 联合索引列顺序怎么定?3. 索引越多越好吗?4. 区分度低的列能进索引吗?5. 覆盖索引怎么用?
3.【候选人的标准回答】

第一步:分析。索引是「以空间换查询时间」,列顺序决定能否命中(最左前缀)。

第二步:挑战。顺序错致失效、冗余、写放大、区分度。

第三步:架构。①列顺序=高频等值(高区分度)在前,范围在后:如 (user_id, status, create_time) 支持 user_id 等值、user_id+status、user_id+范围;②低区分度列(status)单独查需额外索引或位图/过滤;③控制索引数(写多则少建);④覆盖索引减少回表。

第四步:选型。联合索引 + 覆盖索引 + 必要时函数索引/虚拟列。

第五步:一致性。索引不改变语义;覆盖索引需 INCLUDE 全部查询列。

第六步:高可用。索引 online 维护;避免大表锁。

第七步:优化。区分度评估( Cardinality);冗余索引清理。

4.【架构设计】
查询模式 → 列顺序(等值高区分在前,范围在后) → 覆盖索引 避免: 索引冗余 / 低区分度列单独带队 / 范围列在中段致后续失效
5.【技术方案深度解析】

最左前缀:索引 (a,b,c) 能加速 a、a+b、a+b+c,不能加速 b 或 c 单独。顺序原则:等值条件列(高区分度)放最左,范围列放最后,否则范围后的列用不上。冗余代价:每个索引拖慢写入、占空间;写多读少表应精简。

6.【关键技术点】
最左前缀联合索引覆盖索引Cardinality冗余索引索引选择性
7.【Java 实现示例】
// 查询模式驱动索引设计
// Q1: WHERE user_id=? AND status=? AND create_time>?  → idx(uid,status,ct) ✔
// Q2: WHERE status=? 单查 → 需 idx(status) 或函数索引(低频)
// Q3: 只取 id,status → 覆盖索引 INCLUDE
// MySQL 8 函数索引示例(低频特殊查询)
// CREATE INDEX idx_status ON orders ((status));
8.【面试官可能继续追问】
9.【常见错误回答】
  • ❌ 范围列放索引中段——后续列失效。正确:范围放最后。
  • ❌ 索引越多越好——写放大。正确:按需精简。
  • ❌ 低区分列带队——选择性差。正确:高区分在前。
10.【架构师评分标准】
初级 0~40
不知最左前缀。
中级 40~60
会建索引,顺序乱。
高级 60~80
查询模式驱动+列顺序+覆盖+冗余治理。
架构师 80~100
再加:①区分度量化;②写放大成本;③函数/虚拟列索引;④索引生命周期管理。

第 43 题:分库分表设计与扩容 分片

1.【真实企业业务场景】
订单表单库 5 亿行,写入 2 万 TPS 逼近单实例上限,备份 6 小时,DDL 锁表。要求:分 16 库×64 表,且未来能从 16 库扩到 32 库不停机
2.【面试官问题】
    1. 分片键怎么选?2. 分多少库表?3. 扩容怎么不停机?4. 跨分片查询怎么办?5. 热点分片(大商户)?
3.【候选人的标准回答】

第一步:分析。分库分表=水平拆分降单实例压力,核心在分片键扩容平滑

第二步:挑战。分片键选择、跨分片、扩容停写、热点。

第三步:架构。分片键:选高基且查询必带的列(user_id/order_id);②基因法:order_id 内嵌 user_id 基因,使按订单查也能路由到用户分片;③扩容:一致性 Hash 或「双倍扩容」——新 32 库,仅迁移一半数据(按取模翻倍),用 CDC 双写增量同步;④跨分片:ES/聚合层;⑤热点:基因扰动或独立表。

第四步:选型。ShardingSphere(分片+扩容)+ 一致性 Hash + CDC(增量同步)。

第五步:一致性。双写期以老库为准,校验一致后切读;扩容不丢数据。

第六步:高可用。每分片主从;扩容可回滚。

第七步:优化。分片数留余量(2 的幂利于翻倍);避免跨分片事务。

4.【架构设计】
order_id(基因=uid%16) → 路由 → 16库×64表 扩容: 16→32库, 按 uid%32 重新映射, CDC 双写迁移一半, 校验后切读
5.【技术方案深度解析】

分片键=生命线:选错则大量跨分片查询。常用 user_id(用户维度查询多)。基因法:order_id 低位存 user_id%16,下单与查单同分片,免跨片。扩容:取模翻倍法最简单——uid%16→uid%32,仅一半数据需迁移;配合 CDC 双写保证不停机。

6.【关键技术点】
分片键基因法一致性HashShardingSphereCDC双写双倍扩容
7.【Java 实现示例】
// ShardingSphere 配置(按 user_id 分片)
spring.shardingsphere.rules.sharding.tables.orders.actual-data-nodes=ds$->{0..15}.orders_$->{0..63}
spring.shardingsphere.rules.sharding.tables.orders.database-strategy.standard.sharding-column=user_id
spring.shardingsphere.rules.sharding.tables.orders.database-strategy.standard.sharding-algorithm-name=mod16
// 基因法:生成 order_id 时低位嵌入 user_id 取模结果
long orderId = snowflake() * 16 + (userId % 16);
8.【面试官可能继续追问】
9.【常见错误回答】
  • ❌ 分片键选错——跨片查询爆炸。正确:高基+查询必带。
  • ❌ 扩容停写迁移——业务中断。正确:CDC 双写在线。
  • ❌ 单表无限大——DDL/备份崩。正确:提前分片。
10.【架构师评分标准】
初级 0~40
不知分片键重要。
中级 40~60
会分表,扩容靠停写。
高级 60~80
分片键+基因法+在线扩容+跨片方案。
架构师 80~100
再加:①容量模型定分片数;②热点打散;③跨片事务治理;④扩容可回滚与校验。

第 44 题:读写分离与主从延迟 复制

1.【真实企业业务场景】
主库写 5000 TPS,读 5 万 QPS,单主扛不住读。上读写分离后,用户「刚下单却查不到」(主从延迟 800ms),客诉激增。要求:既分压又解决延迟导致的读不到。
2.【面试官问题】
    1. 读写分离怎么路由?2. 主从延迟怎么治?3. 刚写就读走哪?4. 从库挂了?5. 延迟监控?
3.【候选人的标准回答】

第一步:分析。读写分离用从库扛读,但异步复制有延迟,强一致读必须回主。

第二步:挑战。主从延迟、读不到刚写、从库故障、路由。

第三步:架构。路由:写走主,普通读走从;②延迟敏感读(刚下单查单)强制走主(Hint/注解);③降低延迟:并行复制、半同步、从库提升规格;④从库挂:自动切主或摘除;⑤监控 Seconds_Behind_Master 告警。

第四步:选型。ShardingSphere(读写分离路由)+ MySQL 半同步 + 并行复制。

第五步:一致性。强一致读回主;最终一致读走从;业务标注读重要性。

第六步:高可用。从库故障转移;延迟超阈值降级读主。

第七步:优化。读多写少场景多从库分压;缓存扛热点读。

4.【架构设计】
写 → 主库 → 并行复制 → 从库×N(读) 强一致读(Hint) → 主库; 普通读 → 从库 从库延迟>阈值/挂 → 降级主库
5.【技术方案深度解析】

为什么读不到?异步复制下从库落后,刚写主库的数据还在路上。解法:「写后强制读主」窗口(如订单详情)或「写时打标,短时间读主」。半同步:主提交等至少一个从 ACK,降延迟但增写 RT,折中。

6.【关键技术点】
读写分离主从延迟半同步并行复制Hint路由读降级
7.【Java 实现示例】
// ShardingSphere 读写分离 + 强制主库 Hint
// 普通读自动走从;刚下单查单强制主
HintManager hm = HintManager.getInstance();
hm.setWriteRouteOnly(); // 本次读走主库
Order o = orderMapper.selectById(orderId);
hm.close();
// 半同步开启(主库 my.cnf)
// rpl_semi_sync_master_enabled=1
8.【面试官可能继续追问】
9.【常见错误回答】
  • ❌ 所有读走从——刚写读不到。正确:强一致读回主。
  • ❌ 从库挂全崩——无降级。正确:降级主/摘除。
  • ❌ 无延迟监控——客诉才发现。正确:实时告警。
10.【架构师评分标准】
初级 0~40
不知主从延迟。
中级 40~60
会分离,不分类读。
高级 60~80
路由+强一致回主+半同步+降级+监控。
架构师 80~100
再加:①读分类策略;②并行复制调优;③延迟窗口设计;④成本(多从库)权衡。

第 45 题:在线数据迁移与双写校验 迁移

1.【真实企业业务场景】
需把 2 亿用户表从老结构迁到分库分表新结构,要求零停机、不丢数据、可回滚。历史教训:一次夜里停写迁移,漏了增量订单,对账差 3 万条。
2.【面试官问题】
    1. 不停机迁移步骤?2. 增量怎么追?3. 双写一致性?4. 怎么校验不丢?5. 怎么回滚?
3.【候选人的标准回答】

第一步:分析。在线迁移=「全量+增量双写+校验+灰度切+可回滚」经典四步。

第二步:挑战。增量丢失、双写不一、校验、回滚。

第三步:架构。全量:分批迁移历史数据(限速防压主);②增量:CDC(Canal)订阅 binlog 双写新库;③双写:应用同时写新旧(或 CDC 补偿);④校验:全量比对(行数/校验和)+ 增量对账;⑤灰度切读新库,异常回旧;⑥回滚:旧库一直保留到确认无问题。

第四步:选型。Canal/Debezium(CDC)+ 自研迁移 Job + 校验脚本 + 开关切读。

第五步:一致性。双写+校验保证新旧一致;切读前全量+增量均通过。

第六步:高可用。迁移限速保护源库;回滚随时可切。

第七步:优化。分批迁移+限速;校验用抽样+全量结合。

4.【架构设计】
老库 → 全量迁移(分批限速) → 新库 ↓binlog(CDC) 双写新库(增量) → 校验(行数/校验和) → 灰度切读 → 回滚保留旧库
5.【技术方案深度解析】

为什么 CDC?停写迁移会丢增量;CDC 订阅 binlog 实时追平,零停机。双写兜底:应用双写 + CDC 补偿,防止 CDC 中断丢增量。校验:不止行数,还要校验和/关键字段,发现不一致重投。

6.【关键技术点】
CDCCanal双写全量迁移校验灰度切读
7.【Java 实现示例】
// 应用双写(兜底 CDC)
public void createUser(User u) {
  oldRepo.save(u);                 // 旧库
  newRepo.save(convert(u));        // 新库(分片)
  // 任一失败: 记入补偿表, 定时重试
}
// Canal 订阅 binlog 增量同步(防 CDC 中断)
// 校验: SELECT COUNT(*), CHECKSUM 分批比对新老库
8.【面试官可能继续追问】
9.【常见错误回答】
  • ❌ 停写迁移——丢增量。正确:CDC 在线。
  • ❌ 只比对行数——内容差漏。正确:校验和+抽样。
  • ❌ 切完即删旧库——无法回滚。正确:保留观察期。
10.【架构师评分标准】
初级 0~40
只会停写迁移。
中级 40~60
会 CDC,无校验/回滚。
高级 60~80
全量+增量+双写+校验+灰度+回滚。
架构师 80~100
再加:①限速保护源库;②校验策略(和/抽样);③切换观测指标;④回滚演练。

第 46 题:深度分页与游标优化 查询

1.【真实企业业务场景】
运营后台「订单列表翻到第 5000 页」,LIMIT 100000,20 扫 10 万行再丢弃,接口 4s 超时,DB 压力飙升。要求:优化深翻页且支持千万级数据导出。
2.【面试官问题】
    1. 为什么 LIMIT 深翻慢?2. 游标分页怎么做?3. 跳页(任意页)怎么办?4. 大数据导出?5. 一致性(翻页期间有新数据)?
3.【候选人的标准回答】

第一步:分析。深翻页 LIMIT offset,N 要扫 offset+N 行再丢弃,offset 越大越慢。改用游标(基于有序键)

第二步:挑战。扫全丢弃、跳页、导出、游标稳定性。

第三步:架构。游标WHERE id < lastId ORDER BY id DESC LIMIT 20(索引定位,免扫);②跳页:前端禁任意跳,或「估算页+游标」;③导出:游标分批流式导出(避免一次性);④一致性:游标基于稳定有序键,新增数据不影响已读。

第四步:选型。覆盖索引(id 有序)+ 游标 API + 流式导出。

第五步:一致性。游标基于单调键(id/时间),翻页期间插入不重复不漏。

第六步:高可用。游标查询走索引,DB 压力恒定。

第七步:优化。禁用深 offset;导出异步任务化。

4.【架构设计】
传统: LIMIT 100000,20 → 扫10万行丢弃(慢) 游标: WHERE id<{lastId} ORDER BY id DESC LIMIT 20 → 索引定位(快) 导出: 游标分批流式 → 文件/消息
5.【技术方案深度解析】

游标本质:用上一页最后一条的有序键值作为下一页起点,索引直接定位,O(页大小) 而非 O(offset)。跳页:真实业务极少需要任意跳页,限制即可;非要则估算+游标近似。导出:游标分批,避免 SELECT 全量撑爆内存。

6.【关键技术点】
游标分页覆盖索引流式导出避免深offset有序键分批
7.【Java 实现示例】
// 游标分页:基于上一页最大 id
public List<Order> page(Long lastId, int size) {
  return orderMapper.select(
    "WHERE id < ? ORDER BY id DESC LIMIT ?", lastId, size);
}
// 导出:游标流式分批写文件
try (Writer w = ...) {
  Long last = Long.MAX_VALUE;
  while ((list = page(last, 1000)).size() > 0) {
    last = list.get(list.size()-1).id();
    w.write(list); // 分批, 不撑内存
  }
}
8.【面试官可能继续追问】
9.【常见错误回答】
  • ❌ 继续 LIMIT 100000,20——慢且崩。正确:游标。
  • ❌ 一次性导出全量——内存爆。正确:游标流式。
  • ❌ 任意深跳页——无必要且慢。正确:限制/估算。
10.【架构师评分标准】
初级 0~40
只会 LIMIT offset。
中级 40~60
知游标,不懂跳页/导出。
高级 60~80
游标+复合键+流式导出+一致性。
架构师 80~100
再加:①跳页业务取舍;②导出异步化;③游标稳定性(插入不重不漏);④索引配合。

第 47 题:数据库连接池调优 连接

1.【真实企业业务场景】
大促订单服务连接池 HikariCP 设 200,DB 最大连接 800,但 50 个实例×200=10000 远超 DB 上限,DB 连接被打满,新请求全超时。要求:给出连接池容量模型。
2.【面试官问题】
    1. 连接池设多大?2. 实例数×池 > DB 上限怎么办?3. 获取连接等待超时?4. 连接泄漏?5. 慢 SQL 与连接池关系?
3.【候选人的标准回答】

第一步:分析。连接池不是越大越好。公式:池大小 ≈ (核心数×2) / 事务阻塞比;总量受 DB 连接上限硬约束。

第二步:挑战。总量超限、等待超时、泄漏、慢 SQL 占连接。

第三步:架构。容量:单实例池 = min(DB上限/实例数, 经验值 10~50);②DB 侧:max_connections 留余量(含运维);③超时:connectionTimeout 短(如 300ms)快速失败而非堆积;④泄漏:leakDetection(如 5s 未还报警);⑤慢 SQL:占连接久→池耗尽,需限流+优化。

第四步:选型。HikariCP(默认最优)+ 配置按容量模型 + 监控。

第五步:一致性。连接池是资源约束,不影响数据一致;但耗尽致请求失败需降级。

第六步:高可用。池满快速失败+限流;DB 连接留余量防 OOM。

第七步:优化。缩短事务/SQL;连接复用;读走从库减主连接。

4.【架构设计】
DB(max=800,留200运维) → 每实例池 = 600/50实例 ≈ 12 池满: connectionTimeout 快速失败 + 限流; 泄漏: leakDetection 告警
5.【技术方案深度解析】

为什么不大?连接是 DB 资源,过多→上下文切换+内存+锁竞争反而降吞吐;且实例数×池必须 < DB 上限。容量模型:池大小 ≈ QPS×平均占用时长;或 CPU 核×2(IO 等待型)。等待超时:不设=线程无限等=雪崩;设短=快速失败+降级。

6.【关键技术点】
HikariCP连接池容量connectionTimeoutleakDetectionDB max_connections快速失败
7.【Java 实现示例】
// HikariCP 容量模型配置
HikariConfig c = new HikariConfig();
c.setMaximumPoolSize(12);          // ≈ DB上限/实例数
c.setConnectionTimeout(300);       // 拿不到连接 300ms 快速失败
c.setLeakDetectionThreshold(5000); // 5s 未还连接报警(泄漏)
c.setIdleTimeout(600000); c.setMaxLifetime(1800000); // 防长连接老化
8.【面试官可能继续追问】
9.【常见错误回答】
  • ❌ 池设 200 不乘实例数——超 DB 上限。正确:总量约束。
  • ❌ 无 connectionTimeout——线程堆积雪崩。正确:快速失败。
  • ❌ 不查泄漏——连接渐耗尽。正确:leakDetection。
10.【架构师评分标准】
初级 0~40
池越大越好。
中级 40~60
会设数,不论证容量。
高级 60~80
容量模型+超时+泄漏+DB上限约束。
架构师 80~100
再加:①总量硬约束与 ProxySQL;②与慢 SQL/限流联动;③生命周期防老化;④监控指标。

第 48 题:MySQL vs PostgreSQL 选型 选型

1.【真实企业业务场景】
新业务要存「JSON 配置 + 地理空间 + 复杂分析报表」,团队纠结用 MySQL 8 还是 PostgreSQL。要求:给出选型依据,而非「习惯用 MySQL」。
2.【面试官问题】
    1. 两者核心差异?2. 何时选 PG?3. 何时选 MySQL?4. JSON/地理/分析谁强?5. 混合使用?
3.【候选人的标准回答】

第一步:分析。选型看数据模型与查询特征:MySQL 主打简单 OLTP 高并发,PG 主打复杂类型/分析/扩展。

第二步:挑战。场景匹配、团队能力、生态。

第三步:架构。选 PG:JSONB 复杂查询、PostGIS 地理、窗口函数/CTE 复杂分析、需要扩展(时序/图);②选 MySQL:纯 OLTP 高并发写、团队熟练、云托管成熟;③混合:OLTP 用 MySQL,分析/地理用 PG 或 ClickHouse;④本场景 JSON+地理+分析 → 倾向 PG。

第四步:选型。PG(JSONB/PostGIS/分析)+ MySQL(高并发 OLTP)+ ClickHouse(海量分析)。

第五步:一致性。两者均 ACID;PG 更强约束(如 CHECK/窗口);按场景。

第六步:高可用。两者主从/集群;PG 用 Patroni,MySQL 用 MGR。

第七步:优化。避免单一库包打天下;按域选最优。

4.【架构设计】
OLTP高并发 → MySQL JSONB+地理+复杂分析 → PostgreSQL(PostGIS) 海量分析报表 → ClickHouse 按域选型, 不强行统一
5.【技术方案深度解析】

PG 强项:JSONB 索引查询、PostGIS、CTE/窗口函数、MVCC 更优(无 undo 膨胀)、扩展生态。MySQL 强项:极简 OLTP、高并发写成熟、云厂商支持好。本场景:JSON+地理+分析三需求 PG 全覆盖,且分析免额外 ETL,选 PG 更省。

6.【关键技术点】
MySQLPostgreSQLJSONBPostGISOLTP按域选型
7.【Java 实现示例】
// PG JSONB 查询 + GIN 索引
// CREATE INDEX idx_cfg ON t USING gin(cfg jsonb_path_ops);
// SELECT * FROM t WHERE cfg @> '{"role":"admin"}';
// PG 地理: SELECT * FROM shop ORDER BY geom <-> ST_MakePoint(116,39) LIMIT 10;
// Java: 用 JDBC/MyBatis 直接映射, 类型用 String(JSON)或 PGobject
8.【面试官可能继续追问】
9.【常见错误回答】
  • ❌ 一律 MySQL——复杂查询硬扛。正确:按场景选 PG。
  • ❌ 一律 PG——高并发简单写无优势。正确:OLTP 用 MySQL。
  • ❌ 靠习惯选型——无依据。正确:数据模型驱动。
10.【架构师评分标准】
初级 0~40
只会 MySQL。
中级 40~60
知 PG,无场景论证。
高级 60~80
场景驱动+差异对比+混合架构。
架构师 80~100
再加:①团队/运维成本;②扩展性(扩展插件);③高可用方案对比;④演进策略。

第 49 题:亿级数据归档与冷热分离 归档

1.【真实企业业务场景】
订单表 3 年累计 20 亿行,热数据(近 3 月)每日查询,冷数据(>1 年)仅审计偶尔查。单表巨大致备份 8 小时、DDL 锁表。要求:冷热分离降成本保性能。
2.【面试官问题】
    1. 冷热怎么分?2. 冷数据存哪?3. 归档不停机?4. 冷数据查询?5. 成本怎么降?
3.【候选人的标准回答】

第一步:分析。冷热分离=把低频数据迁出主库,主库只留热数据,性能↑成本↓

第二步:挑战。归档不停机、冷存选型、查询、成本。

第三步:架构。:按时间(>1 年为冷)或访问频率;②冷存:低成本存储(对象存储/历史库/TiDB/列存);③归档:定时任务迁冷数据(CDC/分批),主库 DELETE(或分区 DROP);④查询:冷数据走独立查询服务/ES;⑤成本:冷存用廉价介质+压缩。

第四步:选型。分区表(按时间 DROP 旧分区)+ 对象存储/历史库 + ES 冷查。

第五步:一致性。归档后主库删,冷存保留;查询路由按时间。

第六步:高可用。分区 DROP 瞬时释放;归档限速保护。

第七步:优化。分区表免 DELETE 锁;冷存压缩降本。

4.【架构设计】
热(近3月): 主库分区表(高性能) 冷(>1年): 历史库/对象存储/列存(低成本) 归档: 定时分批迁移 → 主库DROP旧分区; 冷查路由独立服务
5.【技术方案深度解析】

分区表优势:归档旧数据用 DROP PARTITION 瞬时释放,比 DELETE 不锁表。冷存选型:对象存储(S3/OSS)最廉,配合 Parquet+压缩;或历史库降配实例。成本:冷数据占 90% 存储却 1% 查询,迁出后主库缩容,月费大降。

6.【关键技术点】
冷热分离分区表DROP PARTITION对象存储归档任务成本优化
7.【Java 实现示例】
// 分区表按月份: orders_202601, orders_202602...
// 归档: 每月 DROP 最旧分区(瞬时)
jdbcTemplate.execute("ALTER TABLE orders DROP PARTITION p_202401");
// 冷数据迁对象存储(Parquet 压缩)
archiveJob.exportToOSS("orders_202401"); // 分批限速
// 冷查: 路由到历史库/ES
8.【面试官可能继续追问】
9.【常见错误回答】
  • ❌ 全量留主库——备份/DDL 崩。正确:冷热分离。
  • ❌ DELETE 旧数据——锁表慢。正确:DROP 分区。
  • ❌ 冷数据也用高配——浪费。正确:廉价介质。
10.【架构师评分标准】
初级 0~40
不分冷热。
中级 40~60
会归档,用 DELETE 锁表。
高级 60~80
分区+DROP+冷存+路由+成本。
架构师 80~100
再加:①动态冷热判定;②入湖与计算引擎;③成本量化;④归档校验与回滚。

第 50 题:金融级高可用与容灾 容灾

1.【真实企业业务场景】
支付核心库要求 RPO=0(零数据丢失)、RTO<30s,监管要求「同城双活 + 异地灾备」。当前单机房,一次机房断电损失千万。要求:设计数据库容灾架构。
2.【面试官问题】
    1. RPO/RTO 是什么?2. 同城双活怎么实现?3. RPO=0 怎么保证?4. 异地灾备数据延迟?5. 容灾演练?
3.【候选人的标准回答】

第一步:分析。容灾=「数据不丢(RPO)+ 快速恢复(RTO)」。RPO=0 需同步复制

第二步:挑战。同步延迟、脑裂、演练、成本。

第三步:架构。同城双活:主从半同步/同步复制(RPO≈0),应用双活、流量可切;②异地灾备:异步复制(RPO 秒级),灾备可起;③防脑裂: fencing/多数派(MGR/raft);④演练:定期切换演练(混沌);⑤成本:灾备平时降配或承载只读。

第四步:选型。MySQL MGR(多主/单主,多数派)/ 半同步 + 异地异步 + 容灾管控。

第五步:一致性。同步复制保证提交即多副本;异步灾备允许秒级 RPO。

第六步:高可用。自动故障转移;fencing 防双写;演练验证。

第七步:优化。灾备承载只读/报表降本;同步复制限同城(延迟低)。

4.【架构设计】
同城: 主 ↔ 半同步从(多数派, RPO≈0) 双活 异地: 异步复制(RPO秒级) 灾备可起 故障: 自动转移 + fencing; 定期切换演练
5.【技术方案深度解析】

RPO vs RTO:RPO=丢失数据量,RTO=恢复时长。RPO=0:必须同步复制(提交等从库 ACK),但增写延迟、依赖网络;跨城同步延迟高,故同城同步、异地异步。脑裂:网络分区时两主都写=数据冲突,用多数派+fencing 杀掉少数派。

6.【关键技术点】
RPO/RTO同步复制半同步MGRfencing容灾演练
7.【Java 实现示例】
// MySQL 半同步(同城 RPO≈0)
// rpl_semi_sync_master_enabled=1; rpl_semi_sync_master_timeout=1000
// MGR 单主模式(多数派防脑裂)
// group_replication_single_primary_mode=ON
// 应用: 写主, 同城从同步; 异地异步灾备
// 容灾切换: 管控平台检测主宕 → 选新主(fencing 旧主) → 流量切
8.【面试官可能继续追问】
9.【常见错误回答】
  • ❌ 异步复制当 RPO=0——丢数据。正确:同城同步。
  • ❌ 不防脑裂——双写冲突。正确:多数派+fencing。
  • ❌ 建了不演练——切换必失败。正确:定期演练。
10.【架构师评分标准】
初级 0~40
不知 RPO/RTO。
中级 40~60
知主从,无同步/脑裂。
高级 60~80
同城同步+异地异步+fencing+演练。
架构师 80~100
再加:①RPO/RTO 量化与告警;②多数派一致性;③灾备降本(承载只读);④演练 SOP 与复盘。