高可用与扩展:主从复制、读写分离与分库分表

各位架构师、数据库的"领航员",大家好!今天我们来聊聊数据库架构的"终极进化论"。

  • 当你的业务从"小作坊"变成"大工厂",单台数据库就像一辆满载的拖拉机,拉不动了。这时候,你需要的不是给拖拉机换个更大的轮胎(加内存、加CPU),而是把它变成一列高铁。

这就是我们今天要讲的主题:高可用与扩展------从主从复制到分库分表,看MySQL如何从"单兵作战"进化为"集团军"。

第一站:主从复制------老板与秘书的"猫鼠游戏"

底层解剖:Binlog的"三生三世"

主从复制的本质,就是日志的传输与回放

  • 老板(Master) :负责处理写操作,并把每一次修改记录在**Binlog(二进制日志)**里。
  • 秘书(Slave):负责从老板那里拷贝日志,并在自己家里重演一遍。

底层流程(三步走):

  1. Dump线程(老板的秘书):Master 为每个 Slave 启动一个 Dump 线程,专门负责发送 Binlog。
  2. I/O线程(Slave的搬运工) :Slave 连接 Master,请求日志,收到后写入本地的中继日志(Relay Log)
  3. SQL线程(Slave的执行者):读取 Relay Log,重放 SQL 操作,让 Slave 的数据与 Master 保持一致。
延迟的痛:为什么秘书总是抄得慢?

主从延迟是架构师最头疼的问题。

  • 原因
    • 单线程回放:在 MySQL 5.7 之前,Slave 的 SQL 线程是单线程的。Master 多线程写入,Slave 单线程回放,必然积压。
    • 大事务:Master 上执行一个删除 100 万行数据的操作只需几秒,Slave 回放时可能要几分钟。
  • 解决方案
    • MySQL 5.7+ 并行复制 :基于 LOGICAL_CLOCK,允许不同表或无冲突的事务并行回放。
    • 半同步复制:Master 写完日志后,必须等至少一个 Slave 收到并写入 Relay Log 才返回成功。虽然牺牲了写性能,但保证了数据不丢。

第二站:读写分离------中间件的"交通指挥"

当读请求远大于写请求时,我们需要把读流量分摊到从库。这时候,中间件(如 ShardingSphere、MyCat、ProxySQL)就登场了。

中间件的工作原理

它就像一个智能路由器,挡在应用和数据库之间。

  • SQL解析 :中间件拦截 SQL,判断是读还是写。
    • SELECT → 路由到 Slave。
    • INSERT/UPDATE/DELETE → 路由到 Master。
  • 负载均衡:如果有多个 Slave,中间件会根据策略(轮询、权重)分配读请求。
致命Bug:主从延迟导致的数据不一致

场景

  1. 用户在 Master 下单(写)。
  2. 用户立即刷新订单列表(读)。
  3. 请求被路由到 Slave,但 Slave 还没同步刚才的订单。
  4. 用户大喊:"我的订单呢?!"

架构师解法

  • 强制读主库:对于核心业务(如订单详情、支付状态),在写操作后的短时间内(如 1 秒),强制走主库。
  • 延迟双删:在更新数据时,先删缓存,再更新数据库,延时(如 500ms)后再删一次缓存。

第三站:分库分表------图书馆的"大迁徙"

当单表数据突破 500w-1000w,索引树太高,磁盘 I/O 太慢,这时候必须进行分库分表

垂直拆分:把"胖子"拆成"瘦子"
  • 垂直分库:按业务拆分。用户库、订单库、商品库分开部署。
  • 垂直分表 :把大字段(如 textblob)拆分到扩展表,主表只留核心字段。
  • 底层收益:减少单页数据量,提高缓存命中率。
水平拆分:把"长队"拆成"多窗口"

这是真正的"核武器"。将一张表的数据分散到多个库/表中。

分片策略(Sharding Strategy):

  • 取模(Hash)user_id % 4。数据分布均匀,但扩容难(需要数据迁移)。
  • 范围(Range) :按时间或 ID 范围。扩容容易,但容易产生数据热点(最新数据都在一个表)。
  • 一致性Hash:解决扩容迁移问题的进阶算法。
分布式 ID:雪花算法(Snowflake)

分库分表后,自增 ID 不能用了(不同表 ID 会重复)。
Snowflake 原理

生成一个 64 位的 Long 型 ID:

  • 1 位:符号位(固定为 0)。
  • 41 位:时间戳(毫秒级,可用 69 年)。
  • 10 位:机器 ID(区分不同节点)。
  • 12 位:序列号(同一毫秒内的自增序号)。

优点:全局唯一、趋势递增、高性能。

跨库 Join 的痛

分库后,JOIN 操作失效了。
解决方案

  • 字段冗余:在订单表里冗余用户名字段,避免 Join 用户表。
  • 应用层组装:先查订单,再批量查用户,在代码里组装(两次查询)。
  • 绑定表:将关联紧密的表(如订单主表和订单详情表)按相同规则分片,保证它们在同一个库,可以直接 Join。

总结

分库分表是架构演进的"核武器",威力大但副作用也大(运维复杂、跨库查询难)。不到万不得已(单表 500w-1000w+),不要轻易使用。

最后,送上金句

"分库分表是架构演进的'核武器',威力大但副作用也大(运维复杂、跨库查询难)。不到万不得已(单表 500w-1000w+),不要轻易使用。"

相关推荐
一几文10 小时前
2026年上半年软考高级-系统架构设计师考试真题回顾与解析-综合知识选择题6
小程序·架构·系统架构·软考高级·软考·it证书
m0_5873830011 小时前
社区家政系统开发实战:从需求分析到上线部署全指南
java·spring boot·spring·需求分析
海水冷却12 小时前
私有化 vs 混合云 vs 公有云:双录系统架构怎么选
系统架构·双录
【赫兹威客】浩哥13 小时前
【无标题】
python·spring·django·pyqt
Cicada12814 小时前
为什么从 demo 到生产路还很长?一次数据拉取功能的复杂度演进复盘
系统架构
cfm_291415 小时前
Spring AI Tool 调用架构全解
java·人工智能·spring
sun༒15 小时前
Spring @Scheduled 定时任务详解:Cron表达式、执行顺序、优先级与并行调度
java·后端·spring
xcl092518 小时前
树洞社交应用的系统架构设计与匿名实现
java·spring boot·系统架构
小的~~18 小时前
面试被问懵了?为什么 Redis 单线程还能保证 Lua 脚本原子性,却偏偏选了 Lua?
redis·面试·lua
AI多Agent协作实战派18 小时前
AI多Agent协作系统实战(四十六):改了十次规则,AI员工还是老样子——会话缓存的坑
java·spring·缓存