Clipping 微信公众号

阿里面试:分库分表怎么做的?分片键怎么选的?数据迁移怎么保证一致性?

by Fox爱分享 原文 ↗
Created: 2026-07-07

公众号名称:Fox爱分享

作者名称:Fox爱分享

发布时间:2026-07-07 07:00

有个读者找我,说他面阿里后端岗,项目环节聊得还行,结果面试官突然话锋一转,甩了三个连环问:

分库分表怎么做的?分片键怎么选的?数据迁移怎么保证一致性?

他说前两题还能答一点,但都是”按用户 ID 取模""用 ShardingSphere”这种关键词级别的回答。到第三题数据迁移一致性,直接卡死,说了一句”双写”,面试官追了一句”双写过程中老库写成功新库写失败怎么办”,他整个人就傻了。

这三题其实是面试官精心设计的递进陷阱。第一题考你做没做过,第二题考你想没想清楚,第三题考你踩没踩过坑。你第一题答得虚,第二题就接不住,第三题直接露馅。

太多人的分库分表经验是简历上写一句话——“参与订单系统分库分表改造”,面试官一追问,发现就是用了个中间件配了个分片规则,既不知道为什么这么选,也没经历过数据迁移的生死线。

今天我把这三题拆开聊,每一层都给你讲到落地细节,不是给你背概念。

如果你也在准备后端面试,这篇建议存下来反复看。


第一问:分库分表怎么做的?

很多人听到这道题,条件反射就是一句”水平分库,按用户 ID 取模”。

面试官点点头,然后问:“为什么是水平分库不是垂直分库?你的分库分表是分了库还是分了表?单表数据量到多少你决定分的?”

你就卡住了。

因为”分库分表”这四个字,其实包含了四种完全不同的操作。

先搞清楚:你在分什么

垂直分表:把一张宽表拆成多张窄表。比如订单表有 40 个字段,其中 20 个是核心交易字段(订单号、金额、状态),20 个是扩展字段(备注、标签、附加信息)。拆成 order_main 和 order_ext 两张表,用订单号关联。目的是减少单行数据大小,提升 Buffer Pool 命中率。

垂直分库:按业务域拆库。订单库、用户库、商品库各自独立。目的是解耦业务,不同域的数据库可以独立扩容、独立维护。这个事跟数据量关系不大,跟系统架构关系大。

水平分表:同一个库里,把一张大表拆成多张结构相同的小表。比如 order_0、order_1、order_2、order_3。目的是降低单表数据量,提升查询效率。

水平分库:把数据分散到多个数据库实例上。比如 4 个 MySQL 实例,每个实例里再分 4 张表,总共 16 张分表。目的是分摊单库的连接数、IO、CPU 压力。

面试官问”分库分表怎么做的”,他真正想听的是你能不能讲清楚:你面临的是什么瓶颈,所以你选了哪种分法,分了多少库多少表,为什么是这个数量。

什么时候该分

不是数据量一大就分。分库分表是有代价的——跨库 JOIN 没法做、分布式事务复杂、运维成本翻倍。所以在分之前,先确认你真的走到了瓶颈。

几个硬指标:

  • 单表数据量超过 1000 万且持续增长,查询明显变慢,加索引也压不住。注意不是绝对的 1000 万,跟字段数量、行大小、查询模式有关,但这是一个经验阈值。

  • 单库 QPS 打到 5000 以上,连接池开始紧张,主从延迟拉大。

  • 单库磁盘 IO 接近饱和,iostat 看 util% 长期在 80% 以上。

  • DDL 变更影响线上,给一张几亿行的表加个字段,主库阻塞几十分钟,从库延迟更久。

如果只是单表数据量大但 QPS 不高,先试试分区表(MySQL 的 PARTITION BY),或者归档冷数据,把历史数据搬到归档表里。这俩方案比分库分表简单得多,代价小得多。

确认了必须分,再往下走。

怎么分:分片策略

分片策略解决一个问题:一条数据来了,它该落到哪个库哪个表。

常见的有四种。

第一种:取模分片。

最简单最常用。比如分了 4 个库,每个库 4 张表,总共 16 张分表。分片键是用户 ID,分表序号 = user_id % 16。

user_id = 1001  →  1001 % 16 = 9  →  db_2, table_1(库序号 = 9 / 4 = 2,表序号 = 9 % 4 = 1)
user_id = 1002  →  1002 % 16 = 10 →  db_2, table_2
user_id = 1003  →  1003 % 16 = 11 →  db_2, table_3

优点是数据分布均匀,实现简单。缺点是扩容麻烦——你从 16 张表扩到 32 张表,几乎所有数据都要重新迁移,因为取模结果全变了。

第二种:范围分片。

按分片键的范围切。比如 user_id 0-1000万 在分表 0,1000万-2000万在分表 1,以此类推。

优点是扩容方便,新数据直接落到新分表,老数据不用动。缺点是数据分布不均匀——最新的分表可能数据量最大,热点集中。而且按范围查询虽然友好,但跨范围查询还是得扫多张表。

第三种:一致性哈希分片。

把分片节点映射到一个 0 到 2^32 的哈希环上,数据按分片键的哈希值顺时针找到最近的节点。扩容时只影响哈希环上相邻的一小段数据,迁移量小。

缺点是实现复杂,而且在节点较少时数据分布可能不均匀,需要引入虚拟节点。

第四种:路由表。

维护一张路由表,记录每条数据在哪个分片上。写入时查路由表决定落哪里,读取时也查路由表。

极其灵活,想怎么分怎么分,扩容时只改路由表不动数据。但路由表本身是个单点瓶颈,每次读写都要多一次查询,一般配合缓存用。

实际生产中最常见的是取模分片,简单可靠,配合合理的分片键设计,大部分场景够用。一致性哈希适合节点数经常变化的场景,路由表适合分片规则复杂且需要灵活调整的场景。

分多少库多少表

这是面试官特别爱追问的细节。很多人说”分了 8 个库 64 张表”,问他为什么是 8 和 64,说不出来。

分库分表的数量不是拍脑袋定的,要算。

分表数量:预估未来 3-5 年的数据总量,除以每张表期望的数据量。比如订单系统,预计 3 年后总订单量 10 亿,期望单表不超过 2000 万,那分表数量至少 50 张,往上取 2 的整数次幂,64 张。

分库数量:看 QPS 和连接数。假设峰值 QPS 5 万,单库能扛 5000 QPS,那至少 10 个库。再考虑冗余,往上取 16 个库。

总数据量:10亿
单表上限:2000万  →  分表数:10亿 / 2000万 = 50 → 取 64 张表

峰值QPS:5万
单库QPS:5000     →  分库数:5万 / 5000 = 10 → 取 16 个库

最终方案:16库 × 4表/库 = 64张分表

选 2 的整数次幂是为了取模运算高效,也能让分库和分表的路由计算更简洁——分表序号 = hash(分片键) % 64,分库序号 = 分表序号 / 4。

用什么中间件

Java 生态里主流的就两个:

ShardingSphere-JDBC:客户端模式,作为一个 JDBC 的增强层嵌入到应用里。不需要额外部署中间件,性能好,零额外网络开销。缺点是每个应用实例都要维护分片规则,多语言环境不友好。

ShardingSphere-Proxy:代理模式,独立部署一个中间件,应用连它就像连一个普通 MySQL。多语言友好,应用无感知。缺点是多了一层网络转发,性能有损耗,而且代理本身是个单点,需要做高可用。

如果技术栈纯 Java,团队规模不大,优先选 ShardingSphere-JDBC。如果有多语言需求,或者想让应用层完全不感知分片逻辑,选 Proxy。


第二问:分片键怎么选的?

这题是第一问的自然延伸。面试官已经知道你怎么分了,现在要听你选的分片键合不合理。

太多人在这题上翻车,翻车的方式高度一致——说”按用户 ID 分的”,然后讲不出为什么是用户 ID,不能用别的。

分片键的选择,直接决定了你的分库分表方案能不能用。选对了,大部分查询都能精准路由到单表;选错了,几乎所有查询都要跨库扫描,分了还不如不分。

选择原则:三个必须

第一,必须能覆盖核心查询场景。

你的系统里最高频的查询是什么?分片键必须能直接定位这些查询的数据。

比如订单系统,最核心的查询是”查某个用户的订单列表”。那分片键就应该是 user_id,查询时直接 user_id % 64 路由到对应分表,一次命中。

如果你选了 order_id 做分片键,那”查某个用户的订单”就完蛋了——你不知道这个用户的订单散落在哪些分表上,只能广播到所有 64 张表去查,这就是全表扫描的分布式版本,性能比分之前还差。

第二,必须分布均匀。

分片键的值要尽量均匀分布,不能有严重的数据倾斜。

user_id 一般没问题,因为它通常是自增的或雪花算法生成的,天然均匀。但如果你选了 create_time 的日期做分片键,那同一天的所有数据都落在同一个分表上,热点问题会比不分还严重。

第三,必须有明确的业务边界,不会频繁变更。

分片键一旦确定,数据落到了哪个分表就固定了。如果分片键的值会变,比如用户换了手机号、订单换了归属人,数据就得迁移到新分表,这个迁移成本极高且容易出问题。

所以分片键必须是业务上稳定不变的属性。

常见场景的分片键选择

业务场景推荐分片键核心查询为什么
电商订单user_id查用户订单列表用户维度查询最高频
社交 Feeduser_id查用户的时间线每个用户的数据独立
即时通讯conversation_id查会话消息会话维度查询,且会话 ID 天然分散
物流轨迹tracking_no查运单轨迹运单号唯一且高频查询
IoT 设备数据device_id查设备数据设备维度查询,数据量大且分散

注意一个关键点:分片键不一定是主键,但分片键必须是大多数查询的过滤条件。

终极难题:跨片查询怎么办

这是面试官一定会追问的点。不管你分片键选得多好,总有查询不包含分片键的时候。

比如订单系统按 user_id 分片,但商家要查”我这个店铺最近的所有订单”,这个查询的过滤条件是 merchant_id,不是 user_id。同一个商家的订单散落在所有 64 张分表上,怎么办?

三种解法,各有代价。

解法一:广播查询。

把查询发到所有分片上,各自查完再合并结果。

简单粗暴,但代价巨大。64 张表全查一遍,数据库压力直接翻 64 倍。只能用于偶尔的管理后台查询,绝对不能用于 C 端高频场景。而且分页会变成噩梦——你需要在应用层做归并排序,第二页意味着每张分表都要查前两页的数据再合并去重,越往后翻越慢。

解法二:异构索引。

用另一套存储来维护非分片键到分片键的映射。比如用 Elasticsearch 建一个 merchant_id 到 order_id 的索引,查询时先从 ES 查出这个商家所有订单的 order_id 列表,再拿着 order_id 去分片表里精确查。

查询流程:
1. 商家查订单 → 先查 ES:SELECT order_id FROM es_index WHERE merchant_id = ?
2. 拿到 order_id 列表 → 路由到对应分表:SELECT * FROM order WHERE order_id IN (...)
3. 合并结果返回

这个方案是生产环境最常用的。代价是需要维护 ES 和 MySQL 之间的数据同步,多了一层存储和一致性保障的成本。

解法三:双写异构表。

换一个维度再存一份数据。比如订单按 user_id 分片存一份,再按 merchant_id 分片存一份,两份数据通过消息队列异步同步。

查询的时候,用户维度查 user_id 分片,商家维度查 merchant_id 分片,各自都能精准路由。

代价是存储成本翻倍,且要保证两份数据的最终一致性。适用于查询场景明确且数据量可控的场景。

分片键嵌入业务 ID:基因法

这是一个高级技巧,面试时说出来能加分。

问题场景:订单按 user_id 分片,但很多查询只带了 order_id,不知道 user_id,没法路由。

常规做法是建一张 order_id 到 user_id 的映射表,但映射表本身又是个瓶颈。

基因法的设计思路是:把 user_id 的分片信息”种”进 order_id 里。

具体做法是,生成 order_id 的时候,取 user_id 的低 N 位作为”基因”,嵌入到 order_id 中。

user_id = 1001234(二进制:...0001 1110 1010 0011 0010 0100 10)

取低 4 位作为基因:0010(即 2)

order_id 的结构:
[时间戳 41位] [机器ID 10位] [基因 4位] [序列号 8位]

                              user_id 的低 4 位种在这里

最终 order_id = 7293847562102(其中低 4 位 = 2)

查询时,不管你手里拿的是 user_id 还是 order_id,都能算出分表位置:

  • 有 user_id → user_id % 64 直接路由

  • 有 order_id → 取 order_id 低 4 位,再 % 64 路由

因为 order_id 低 4 位就来自 user_id 的低 4 位,所以两者的分片结果一致。

基因位数取决于你的分表数量。16 张表取 4 位(2^4 = 16),64 张表取 6 位(2^6 = 64),256 张表取 8 位。

这个方案的好处是零额外存储,查询时不需要映射表。代价是 order_id 的生成逻辑变复杂了,且基因位数受限(雪花算法的 64 位里要挤进去)。


第三问:数据迁移怎么保证一致性?

这题是三连问的终章,也是淘汰率最高的一题。

前两题你答得再好,这题接不住,面试官会判定你”没真正做过分库分表”。因为只有亲手迁移过几亿行数据的人,才知道这中间有多少坑。

先理解问题:为什么迁移会不一致

你有一张老订单表,5000 万行数据,现在要把它拆到 16 张新分表里。

迁移过程中,老表还在正常提供服务,不断有新数据写入、旧数据更新。你的迁移程序把老表的数据读到新表,但读的那一刻和写的那一刻之间,可能已经有新数据写进老表了。

时间线:
T1: 迁移程序读到老表 user_id=1001 的记录,金额=100
T2: 业务系统更新老表 user_id=1001,金额=200
T3: 迁移程序把金额=100 写入新表
T4: 切流,业务系统开始读写新表
T5: 查询新表 user_id=1001,金额=100 ← 丢了 100 块

这就是迁移一致性的核心矛盾:数据在搬家的过程中,家里的东西还在变。

完整迁移方案:六步走

生产级别的数据迁移,不是写个脚本批量 INSERT 就完事的。它是一个有严格流程的工程,分六步。

第一步:全量同步

把老表的数据全量同步到新分表。这一步通常用离线任务跑,按主键范围分批 SELECT 出来,路由到对应分表后批量 INSERT。

关键细节:

  • 分批处理,每批 1000-5000 条,避免大事务锁表。

  • 按主键有序扫描,避免跳页和重复读取。

  • 限流,控制读取速度,别把老库的 IO 打满影响线上业务。

全量同步伪代码:

long minId = 0;
long maxId = getMaxId(oldTable);
int batchSize = 2000;

while (minId <= maxId) {
    // 按主键范围分批读取
    List batch = oldDao.selectBatch(minId, minId + batchSize);
    
    if (batch.isEmpty()) {
        minId += batchSize;
        continue;
    }
    
    // 按 user_id 路由到新分表
    Map> routed = batch.stream()
        .collect(Collectors.groupingBy(
            o -> o.getUserId() % 64
        ));
    
    // 批量写入新分表
    for (Map.Entry> entry : routed.entrySet()) {
        newDao.batchInsert(entry.getKey(), entry.getValue());
    }
    
    minId = batch.get(batch.size() - 1).getId() + 1;
    
    // 限流
    Thread.sleep(50);
}

全量同步跑完,新分表里有了老表的快照数据。但这只是起点,因为这个快照在生成的下一秒就过时了。

第二步:增量同步

全量同步过程中和完成后,老表还在不断写入新数据。这些增量数据怎么追上?

两种方案。

方案 A:基于 Binlog 的 CDC 同步。

用 Canal 或 Debezium 监听老库的 MySQL Binlog,解析出 INSERT/UPDATE/DELETE 事件,路由到对应新分表回放。

老库 MySQL → Canal → 解析Binlog → 路由计算 → 写入新分库

Binlog事件:
  INSERT INTO old_order (id, user_id, amount) VALUES (1001, 888, 200)
  → user_id=888, 888%64=48 → 写入新分表 table_48

这是生产环境最常用的方案。优点是实时性好,延迟通常在秒级;对业务无侵入,不需要改代码。缺点是 Canal 本身需要保证高可用,且 Binlog 解析的顺序性必须严格保证。

方案 B:应用层双写。

改业务代码,在写老库的同时也写新库。双写可以同步做,也可以异步通过消息队列做。

同步双写的伪代码:

@Transactional
public void createOrder(Order order) {
    // 写老库
    oldDao.insert(order);
    
    // 写新分库
    int shardIndex = order.getUserId() % 64;
    newDao.insert(shardIndex, order);
}

优点是可控性强,你可以精确控制写入逻辑。缺点是对业务有侵入,且双写的事务一致性是个大问题——老库写成功后新库写失败,怎么办?后面专门讲。

生产实践里通常是组合使用:先上 Binlog 增量同步追平数据,同时灰度开启双写作为兜底。 两套机制互相校验,任何一套出了问题另一套还能补。

第三步:数据校验

全量同步完了,增量也追上了,怎么确认新老数据一致?

不能跳过这一步。你以为同步完了,实际上可能丢了一批数据,或者有些字段映射错了。

校验方案:

全量对账:跑一个离线任务,按主键范围分批比对老表和新分表的每一条记录,逐字段比较。

对账伪代码:

long minId = 0;
int mismatchCount = 0;

while (minId <= maxId) {
    List oldBatch = oldDao.selectBatch(minId, minId + 5000);
    
    for (Order old : oldBatch) {
        int shardIndex = old.getUserId() % 64;
        Order newOrder = newDao.selectByPk(shardIndex, old.getId());
        
        if (newOrder == null || !old.equals(newOrder)) {
            mismatchCount++;
            // 记录不一致的记录,后续修复
            logMismatch(old, newOrder);
        }
    }
    
    minId += 5000;
}

System.out.println("总不一致记录数:" + mismatchCount);

采样对账:全量对账太慢的话,可以按比例采样,比如随机抽 1% 的数据比对。不能完全替代全量对账,但能快速发现系统性问题。

实时对账:在增量同步运行期间,持续比对 Binlog 事件和新分表的实际状态。发现不一致立即告警。

对账发现的不一致记录,单独走修复流程——重新从老表读取最新数据,覆盖写入新分表。

第四步:灰度切流

数据对齐了,接下来开始把读流量从老库切到新库。不能一把切,必须灰度。

切流策略:

阶段1:0% 读新库,100% 读老库    → 影子模式,只读不切
阶段2:1% 读新库,99% 读老库     → 试探性切流
阶段3:10% 读新库                → 小范围验证
阶段4:50% 读新库                → 半量切流
阶段5:100% 读新库               → 全量切流

每一步之间观察一段时间(通常几小时到一天),看有没有报错、慢查询、数据不一致的告警。有问题立刻回退到上一阶段。

灰度的实现方式通常是网关层做流量比例控制,或者按用户 ID 取模来分流——比如 user_id % 100 < 1 的用户走新库,其余走老库。

// 切流判断逻辑
public Order queryOrder(Long userId, Long orderId) {
    if (userId % 100 < grayPercent) {
        // 走新库
        int shardIndex = userId % 64;
        return newDao.selectByPk(shardIndex, orderId);
    } else {
        // 走老库
        return oldDao.selectByPk(orderId);
    }
}

灰度期间,双写不能停。不管是 Binlog 同步还是应用层双写,必须保证老库和新库同时在写,否则一旦回退,回退期间写到新库的数据在老库里不存在,又会不一致。

第五步:写流量切换

读流量全量切到新库后,观察一段时间确认稳定,再切写流量。

写流量切换是整个迁移过程中风险最高的一步。因为一旦写切换到新库,老库就不再接收新的写入了,回退的代价会很高。

稳妥的做法是:

  1. 先停止双写中的”写老库”部分,只写新库。但老库的 Binlog 同步保留,让新库的变更继续同步到老库,作为反向兜底。

  2. 观察一段时间(通常 1-3 天),确认新库写入稳定,没有数据丢失。

  3. 如果一切正常,关闭 Binlog 同步,老库正式下线。如果发现问题,立刻切回双写模式。

写切换前:  写老库 + 双写新库  +  Binlog同步  →  两个库都有完整数据
写切换中:  写新库 + 双写老库  +  反向Binlog   →  两个库都有完整数据(反向兜底)
写切换后:  只写新库                        →  老库可下线

注意这个”反向 Binlog”的细节。很多人切写流量的时候只想着”不再写老库了”,但如果新库出了问题要回退,回退期间写到新库的数据在老库里没有。反向 Binlog 就是解决这个问题的——新库的变更也同步回老库,保证任何时候回退都有数据。

第六步:老库下线

写流量切到新库且稳定运行一段时间后,老库可以下线。但别急着删数据,先离线归档,保留一段时间(通常 1-3 个月)以备万一。

双写一致性怎么保证

前面提到,应用层双写最大的问题是:老库写成功了,新库写失败了,怎么办?

这取决于你用的是同步双写还是异步双写。

同步双写的一致性方案:

同步双写意味着老库和新库的写入在同一个事务里。但这有个前提——两个库必须支持分布式事务。MySQL 的 XA 事务可以做到,但性能损耗极大,生产环境几乎没人用。

实际生产中,同步双写的一致性保障通常靠本地消息表 + 重试机制

// 在老库的同一个事务里写入业务数据和消息记录
@Transactional("oldTx")
public void createOrder(Order order) {
    oldDao.insert(order);
    // 在老库的消息表中插入一条迁移消息
    msgDao.insert(new MigrationMsg("ORDER_INSERT", order.getId(), JSON.toJSONString(order)));
}

// 异步任务扫描消息表,写入新库
@Scheduled(fixedDelay = 100)
public void syncToNewDb() {
    List msgs = msgDao.selectPending(100);
    for (MigrationMsg msg : msgs) {
        try {
            Order order = JSON.parseObject(msg.getData(), Order.class);
            int shardIndex = order.getUserId() % 64;
            newDao.insert(shardIndex, order);
            msgDao.markDone(msg.getId());
        } catch (Exception e) {
            msgDao.incrementRetry(msg.getId());
            if (msg.getRetryCount() > MAX_RETRY) {
                alertService.send("迁移消息重试超限: " + msg.getId());
            }
        }
    }
}

这个方案的本质是:把分布式问题降级为本地问题。 业务数据和迁移消息在老库的同一个本地事务里,要么都成功要么都失败。异步任务保证最终一致,失败有重试,重试超限有告警。

异步双写的一致性方案:

异步双写是通过消息队列做的。业务系统写完老库后,发一条消息到 MQ,消费者负责写入新库。

业务系统 → 写老库 → 发MQ消息 → 消费者 → 写新库

这个方案的一致性依赖 MQ 的可靠投递。关键点:

  • 写老库和发 MQ 必须保证原子性。可以用本地消息表(同上),也可以用事务消息(RocketMQ 的事务消息)。

  • 消费者必须幂等。因为 MQ 可能重复投递,消费者重复写入新库不能出问题。

  • 消费失败要重试,重试超限要进死信队列人工处理。

迁移过程中最常见的三个坑

坑一:自增主键冲突。

老表的自增 ID 是连续的,迁移到新分表后,如果新分表也用自增 ID,不同分表之间会产生主键冲突。

解法:迁移前就把主键策略改成分布式 ID(雪花算法、号段模式等),新分表的主键由 ID 生成器统一分配,不依赖数据库自增。

坑二:Binlog 格式不对。

Canal 解析 Binlog 要求 MySQL 的 binlog_format 必须是 ROW 格式。如果你的老库用的是 STATEMENT 或 MIXED 格式,Canal 解析出来的 SQL 语句没法精准还原数据变更。

解法:迁移前先检查并修改 binlog_format = ROW,且 binlog_row_image = FULL。

坑三:迁移过程中老表 DDL。

迁移进行到一半,业务侧突然要给老表加个字段。老表结构变了,但新分表还是旧结构,增量同步的 Binlog 解析直接报错。

解法:迁移期间冻结老表的所有 DDL 操作。如果必须加字段,先在新分表上加,再在老表上加,中间保证 Binlog 同步的兼容性(新字段在老表 Binlog 里不存在时用默认值填充)。


回到面试:面试官到底在考什么

聊了这么多,回到开头那三个问题。

面试官问分库分表怎么做的,他不是在等你背出”水平分库取模分片”八个字。他想看的是你有没有想清楚瓶颈在哪、为什么选这个方案、分多少库多少表是算出来的还是拍脑袋的。

他问分片键怎么选的,不是在等你列几个候选键。他想看的是你有没有想过跨片查询怎么处理、数据倾斜怎么避免、业务 ID 和分片键的关系怎么设计。

他问数据迁移怎么保证一致性,更不是在等你一句”双写”。他想看的是你有没有经历过全量同步、增量追赶、数据校验、灰度切流这一整套流程,中间踩过哪些坑,怎么兜底的。

这三题串在一起,面试官真正在评估的是一件事:你做架构决策的时候,是想清楚了再做的,还是照着网上的教程抄了一遍。

分库分表不是一个技术点,是一套系统工程。从分片策略的选择到分片键的设计,从全量迁移到增量同步,从灰度切流到数据校验,每一步都有坑,每一步都有代价。你能说出这些代价,面试官就知道你是真做过的。

说不出来,那他只能判定你是简历上写了,实际没碰过。

这一步不能靠背,得靠做。


以上,既然看到这里了,如果觉得不错,随手点个赞、在看、转发三连吧,如果想第一时间收到推送,也可以给我个星标。

我是 Fox,持续分享后端面试硬核解析。我们,下次再见。


内容效果不满意?点此反馈

输入关键词开始搜索