ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

MySQL主从复制集群搭建与多数据源路由实践指南

MySQL主从复制集群搭建与多数据源路由实践指南 先交代一下背景吧。这段时间一直在帮团队整理一套 MySQL 集群架构的搭建方案顺带把多数据源管理也重新梳理了一遍。起因挺实际的业务量上来之后单库读写混用越来越吃力报表查询和线上事务互相拖后腿主库 CPU 动不动飙到 80% 以上。与其继续加硬件硬扛不如把架构重新理一理。这篇文章就是我这次从零搭建集群、改造多数据源的全过程记录覆盖了主从复制原理、环境搭建、动态数据源路由、连接池调优、常见故障排查这几大块适合已经会基本 MySQL 操作、想往架构方向走一步的同学参考。我不会一上来就丢一堆命令而是先讲清楚每一步是“为什么”要这么干。搞明白原理之后那些命令你就算全忘了也能自己拼出一套合理的方案来。1. 先理清思路集群与多数据源到底解决什么问题很多团队一听到“集群”两个字就觉得要上大方案什么分库分表、分布式事务、MyCat、ShardingSphere 全往上堆。结果业务量可能还不到那个级别先把自己运维复杂度和故障概率搞上去了。这里我建议先冷静下来分清你到底要解决什么问题。1.1 单库读写混用的瓶颈在哪单库出现性能问题通常不是 CPU 不够而是“读写互相干扰”导致的连锁反应。你想想看白天业务高峰期线上订单写入、库存更新这种短事务占着行锁和 redo log后台报表查询却要全表扫、要排序聚合。一条慢查询跑几秒钟binlog 和 buffer pool 都被拖累前台用户就能感觉到接口变慢。更隐蔽的问题是连接数的争抢。MySQL 默认连接上限也就一两百一旦慢查询堆积连接池里的连接全部被占住新请求只能排队。这个时候你去看 CPU 可能并不高但系统就是“卡死”了。解决这类问题最直接有效的手段就是主从复制加读写分离让查询走从库写操作走主库互相不干扰。1.2 你的业务到底需要哪种“集群方案”MySQL 的集群方案有好几个层级我按从简单到复杂排了一下方案核心能力适用场景运维成本主从复制 读写分离读扩展、备份隔离大多数中小团队的第一站低MHA / Orchestrator主库故障自动切换对可用性有要求的业务中MySQL InnoDB ClusterMGR多节点强一致、自动选主对数据一致性要求高的场景高分库分表ShardingSphere等数据水平扩展单表数据量过大极高我这次的方案选的是第一档一主两从主库负责写入两个从库一个负责实时读、一个负责异步报表类和备份。这个搭配对绝大多数业务都够用而且后面要往 MHA 或 MGR 演进基础也完全兼容。与其一开始就上复杂方案不如先把主从复制吃透。原因很简单不管是 MHA 还是 MGR底层都离不开 binlog 和复制线程这套机制。复制链路你都玩不转上什么高可用都是沙地上盖楼。2. 主从复制集群搭建全流程主从复制这个概念说起来就三句话主库把变更写入 binlog从库拉取 binlog 写到自己的 relay log再从 relay log 回放成数据变更。但实际搭的时候细节非常多一个参数写错复制就悄悄断了。2.1 复制链路里的三个关键线程先从原理说起。主从复制之所以能跑起来靠的是主库上的 Binlog Dump 线程、从库上的 IO 线程和 SQL 线程配合工作线程所在节点职责Binlog Dump 线程主库监听 binlog 变更推送给从库IO 线程从库从主库拉取 binlog写入本地 relay logSQL 线程从库读取 relay log按顺序回放事务这里要特别提醒一句IO 线程拉日志和 SQL 线程回放日志是异步解耦的。拉取速度通常很快网络不是瓶颈但回放速度取决于从库的磁盘性能、是否有慢查询、是否在跑大事务。所以你在从库看到Seconds_Behind_Master不等于 0 是正常的持续增长才需要担心。现在搭建复制我强烈建议你用 GTID全局事务标识模式而不是传统基于日志文件的filepos方式。GTID 的好处是主从切换时不用费劲去查“我应该从哪个 binlog 文件的哪个位置开始复制”MySQL 自己会处理。尤其是后续要做主从切换演练GTID 能省掉一大堆手工运维操作。2.2 环境准备与版本说明主从复制要求各节点的 MySQL 大版本一致至少主库不能比从库新。比如主库是 8.0.36从库最好也是 8.0.36 或者更新一点的小版本。跨大版本复制出问题的概率很高特别是 5.7 往 8.0 复制一些默认参数的行为已经变了不建议在生产环境尝试。我这次用的三台 Linux 服务器其实你用虚拟机、云主机或者 Docker 容器都能复现。操作系统层面需要保证几点各节点之间网络互通3306端口能访问每台机器的主机名唯一时钟同步用 chrony 或 ntpd不然复制链路会出各种奇怪问题防火墙或安全组放行 MySQL 端口如果你只是想本地练手Docker 是最快的路径。下面这个命令可以快速起三个 MySQL 8.0 实例docker run \u2014name mysql-master -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDroot123 \ -d mysql:8.0 --server-id1 --log-binmysql-bin \ --gtid-modeON --enforce-gtid-consistencyON docker run \u2014name mysql-slave1 -p 3307:3306 \ -e MYSQL_ROOT_PASSWORDroot123 \ -d mysql:8.0 --server-id2 --log-binmysql-bin \ --gtid-modeON --enforce-gtid-consistencyON docker run \u2014name mysql-slave2 -p 3308:3306 \ -e MYSQL_ROOT_PASSWORDroot123 \ -d mysql:8.0 --server-id3 --log-binmysql-bin \ --gtid-modeON --enforce-gtid-consistencyON注意这里镜像名后面的那些--xxxyyy是传给 MySQL 服务的启动参数不是 docker 的参数所以要放在镜像名之后。每个容器指定不同的server-id是必须的这是复制链路里区分节点的唯一标识。2.3 主库配置与复制账号创建如果用物理机或云主机需要手写配置文件。Linux 下 MySQL 8.0 的配置文件一般是/etc/my.cnf或者/etc/mysql/mysql.conf.d/mysqld.cnf主库的核心配置如下[mysqld] server-id 1 log-bin mysql-bin binlog_format ROW gtid_mode ON enforce_gtid_consistency ON binlog_expire_logs_seconds 604800 max_binlog_size 1G说几个容易忽略的点。binlog_format ROW是必须的。基于 Statement 的复制在遇到now()、uuid()这种非确定性函数时主从数据会不一致。ROW 格式虽然日志体积更大但安全性最好。现在 MySQL 8.0 默认就是 ROW不需要特殊改但检查一下总没错。binlog_expire_logs_seconds 604800表示 binlog 保留 7 天。保留太短从库长时间断连后追不上日志保留太长磁盘会被撑爆。7 天是一个比较折中的值。磁盘充裕的库可以保留 15 天但注意监控磁盘水位。配置改完重启 MySQL然后登录主库创建复制专用账号。这个账号最好只给REPLICATION SLAVE权限不要顺手给一个超级管理员最小权限原则在数据库这里同样适用CREATE USER repl% IDENTIFIED BY Repl123456; GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO repl%; FLUSH PRIVILEGES;2.4 从库配置与初始化数据从库的配置文件相对简单核心是server-id不能重复再加上 relay log 配置[mysqld] server-id 2 relay_log mysql-relay-bin read_only ON gtid_mode ON enforce_gtid_consistency ON log_slave_updates ON这里read_only ON保证从库不接受外部写入防止有人不小心往从库插了一条数据导致复制链路数据不一致。但注意read_only对超级管理员账号无效运维自己操作时还是要小心。log_slave_updates ON这个参数很容易被忽略。它表示从库在回放写入后也把自己的 binlog 记下来。如果你的从库将来要升级为新的主库或者需要级联复制这个参数就是必需品。初始化数据这一步骤非常关键。如果主库已经有一些历史数据你不能直接开复制否则从库会缺数据。正确做法是先锁库导一份一致性快照恢复快照到从库然后再启动复制链路。我通常用mysqldump来做单实例场景下比 Xtrabackup 更简单mysqldump --single-transaction --master-data2 \ --set-gtid-purgedON \ -u root -p --all-databases master_dump.sql--single-transaction在 InnoDB 下用 MVCC 一致性视图导出不加锁--master-data2会在导出的文件里自动记录当前 binlog 位置信息--set-gtid-purgedON会把你导出的数据标记为“这些事务已经存在”从库恢复后不会再重复回放这是 5.7.5 以后的主从环境必须注意的参数。然后把这个 dump 文件传到从库恢复进去mysql -u root -p master_dump.sql2.5 启动复制链路并验证数据恢复完成后登录从库执行复制指令CHANGE REPLICATION SOURCE TO SOURCE_HOST10.0.0.10, SOURCE_PORT3306, SOURCE_USERrepl, SOURCE_PASSWORDRepl123456, SOURCE_AUTO_POSITION1; START REPLICA;MySQL 8.0.23 之前用的是CHANGE MASTER TO和START SLAVE8.0.23 之后改成了SOURCE和REPLICA这种中性叫法。建议新的环境直接用新语法查资料时注意区分版本。验证链路是否正常SHOW REPLICA STATUS\\G;重点看这几个字段Slave_IO_Running: YesSlave_SQL_Running: YesSeconds_Behind_Master: 0或一个很小的值这三个字段都能对上说明复制链路已经通了。我一般还会顺手做一个小验证在主库建一张临时表插入一条数据十秒后再去从库查一下这条数据在不在链路真实可用而不是只看状态字段。3. 多数据源管理从连接池到动态路由集群搭好以后最尴尬的事情就是应用层不知道怎么用。很多人以为配多数据源就是把地址写成多个 IP让框架自己去轮询。实际上完全不是这么回事多数据源管理的核心是“路由”两个字请求进来的时候把它交给正确的数据源。3.1 连接池选型HikariCP 还是 Druid讨论数据源之前先把连接池这个底座选好。HikariCP 是 Spring Boot 的默认选择性能非常好启动快实现上几乎无可挑剔。Druid 最大的优势在监控能力——你可以直接在 Web 界面上看到 SQL 执行统计、慢查询、连接池使用情况、当前活跃连接数。对于国内团队来说Druid 的监控面板对排查生产问题帮助非常大很多公司哪怕用 HikariCP 也会拿 Druid 做监控。我个人的选择是如果团队没有统一的监控平台优先用 Druid如果已有 Prometheus 或者 SkyWalking 这类监控就没必要多维护一个组件用 HikariCP 就好。无论用哪个连接池参数都不能照抄默认值。这里给一份 HikariCP 的参考配置我实测下来的心得是连接池不是越大越好太大反而会拖垮主库spring: datasource: hikari: minimum-idle: 5 maximum-pool-size: 20 connection-timeout: 30000 max-lifetime: 1800000 idle-timeout: 600000说说为什么“连接池越大越好”是错的。每个连接到 MySQL 都是真实的网络连接MySQL 处理每个连接都要分配线程和内存。如果连接池配到 100而你的应用实际并发只需要 20那一堆空闲连接就在白白消耗数据库资源。更重要的是连接池太大时突发请求会瞬间把所有连接全部打到主库直接打挂。宁可让少量请求在应用层排队等待连接释放也不要让数据库被连接洪流冲垮。连接池参数的估算逻辑我习惯这样算单接口平均耗时50ms目标是支持200 QPS那么需要的活跃连接数就是200 * 0.05 10。考虑峰值和慢查询再加两三倍的冗余20左右就是比较合适的值。3.2 动态数据源的核心思路AbstractRoutingDataSource多数据源最经典的做法就是继承 Spring 的AbstractRoutingDataSource在运行时动态决定去哪个数据源拿连接。核心机制一句话总结用 ThreadLocal 保存当前线程的数据源标识路由时读取这个标识切换到对应的 DataSource。如果不想从零写可以直接用社区开源的dynamic-datasource-spring-boot-starter。它的核心 API 非常简洁在 Service 方法上加一个注解就能切换数据源DS(slave) public ListOrder queryRecentOrders() { // 这个方法的查询走从库 }我建议你还是先自己实现一遍不是让你重复造轮子而是把原理吃透。用 starter 虽然省事但遇到问题时要排查“为什么没切过去”不懂底层就会比较痛苦。自己实现的核心代码其实很轻量。第一步定义一个动态数据源类public class DynamicDataSource extends AbstractRoutingDataSource { Override protected Object determineCurrentLookupKey() { return DataSourceContextHolder.getDataSource(); } }第二步用 ThreadLocal 保存上下文public class DataSourceContextHolder { private static final ThreadLocalString CONTEXT new ThreadLocal(); public static void setDataSource(String dsName) { CONTEXT.set(dsName); } public static String getDataSource() { return CONTEXT.get(); } public static void clear() { CONTEXT.remove(); } }第三步加一个 AOP 切面。拦截带有DataSourceSwitch注解的方法根据注解的值动态切换数据源执行完必须清理 ThreadLocal。这一步最容易踩坑我之前见过同事写了set忘记clear结果后续同一个线程内的其他请求全部路由到了从库写操作走错节点数据直接不一致。Aspect Component public class DataSourceAspect { Around(annotation(dataSource)) public Object switchDataSource(ProceedingJoinPoint joinPoint, DataSourceSwitch dataSource) throws Throwable { DataSourceContextHolder.setDataSource(dataSource.value()); try { return joinPoint.proceed(); } finally { DataSourceContextHolder.clear(); } } }最后一步把这个动态数据源配置到 Spring 容器并注册主从两个数据源Bean public DataSource dataSource() { DynamicDataSource dataSource new DynamicDataSource(); MapObject, Object targetDataSources new HashMap(); targetDataSources.put(master, masterDataSource()); targetDataSources.put(slave1, slave1DataSource()); dataSource.setTargetDataSources(targetDataSources); dataSource.setDefaultTargetDataSource(masterDataSource()); return dataSource; }代码本身不复杂但这里的几个关键点要特别注意。一是 ThreadLocal 会不会造成内存泄漏Tomcat 本身用了线程池线程复用时 ThreadLocal 会被下一个任务读到所以finally里的clear()必须写。二是只读事务和写事务的边界要清晰查询类方法强制走从库事务类方法必须走主库不要在事务中间切数据源这是原则。3.3 主从延迟与读写分离的取舍动态数据源落地之后真正的坑不在代码而在业务场景的判断。主从复制是异步的从库数据永远会比主库慢个几百毫秒甚至更久。你刚插入一条订单马上去查从库肯定查不到。这个问题没有一劳永逸的解法只能做取舍。我的经验是按业务类型区分业务类型路由策略原因登录、下单、支付强制走主库数据必须即时可见订单列表、商品详情走从库允许毫秒级延迟报表统计、后台查询走从库前提是容忍分钟级延迟量大不能拖垮主库对账、资金流水强制走主库数据一致性敏感如果实际业务里确实出现了“写后立即读”的场景且无法接受延迟可以把刚才写的DataSourceSwitch加一个withHint能力写入时把主键 ID 记到一个内存队列查询时如果命中这个 ID 就走主库否则走从库。这个方案简单有效比引入中间件成本低很多。3.4 多数据源的配置管理配置管理这一块经常被忽略。多数据源意味着至少两套连接参数要写进配置如果应用还连了其他业务库配置文件能写一长串。切忌把这些配置写死在项目里然后提交到代码仓库。我这边是把数据源配置放到了 Nacos 配置中心动态刷新。为什么这么干因为数据库 IP 变更、密码轮换、扩容节点、从库挂掉切主库时你不可能每次都改代码重新发布。而且配置文件里的spring.datasource.password属于敏感信息交给配置中心统一管也方便做权限控制和审计。这里给一份多数据源的配置示例spring: datasource: dynamic: primary: master strict: false datasource: master: url: jdbc:mysql://10.0.0.10:3306/business?useSSLfalseserverTimezoneAsia/Shanghai username: biz_user password: EncryptedPasswd driver-class-name: com.mysql.cj.jdbc.Driver slave1: url: jdbc:mysql://10.0.0.11:3306/business?useSSLfalseserverTimezoneAsia/Shanghai username: biz_user password: EncryptedPasswd配置分层的思路也值得说说。数据源配置一般分两层连接层和路由层。连接层管 URL、账号、密码、连接池参数路由层管哪个方法走哪个库。连接层问题一般靠配置中心解决路由层问题只能靠代码审查加日志定位。所以我在切数据源的 AOP 切面里加了一条debug级别的日志打印方法名和路由到的数据源名称。排查问题时这些日志能省半天时间。4. 常见故障与排查技巧实录集群架构搭建完之后真正的考验才刚开始。这一章节我把这次实践中遇到的最典型的几类问题整理出来每个问题都附了排查思路和解决方案可以直接当速查表用。4.1 连接层报错Cant connect 与 SSL 错误先说你最常遇到的ERROR 2002 (HY000): Cant connect to local MySQL server through socket /tmp/mysql.sock。这个报错的意思是客户端通过 socket 文件连不上本机 MySQL。排查思路很固定按顺序看三件事一、MySQL 进程到底起没起来。systemctl status mysqld或者ps -ef | grep mysqld看一眼。二、socket 文件的路径对不对。MySQL 默认的 socket 文件位置和客户端找的位置可能不一样用mysql -h 127.0.0.1 -P 3306强制走 TCP 协议能连上就说明 socket 配置有问题。三、如果进程没起来去翻错误日志,大多数情况下报错原因都写在里面。SSL 连接错误也是高频问题尤其是 MySQL 8.0 默认开启 SSL 加密连接后JDBC 连接串里useSSLtrue和驱动版本不匹配就会直接报错。热词里有“mysql ssl连接错误”我猜不少人踩了这个坑。生产环境如果数据库和应用之间走的是内网专线根本不需要 SSL 加密useSSLfalse直接关掉就好。如果对安全要求高需要 SSL配置链路上证书和ssl-mode要按官方文档严格对齐客户端驱动 8.0.x 和 MySQL 8.0 服务端是兼容的但别拿旧驱动去连新服务器。4.2 复制链路中断IO 线程和 SQL 线程状态自查主从复制中断在生产环境是早晚的事。排查逻辑首先要分清楚断在哪一段。如果Slave_IO_Running: Connecting或者No说明从库拉取 binlog 出了问题。依次检查网络、从库能不能ping通主库、3306 端口通不通、复制账号密码是否正确。这里最常见的坑是阿里云或云厂商的安全组只放行了自己的内网 IP从库换 IP 之后安全组变了IO 线程就开始一直重连。如果Slave_IO_Running: Yes但Slave_SQL_Running: No说明 SQL 线程回放时遇到了报错。当场看Last_SQL_Error字段这个字段会告诉你具体哪条 SQL、在哪个库哪个表执行失败。我遇到过最典型的情况是有人手贱在从库上直接跑了DELETE结果主库的 binlog 回放时发现行不复存在复制当场终止。从库意外写入导致的复制中断恢复流程是这样的先确认从库和主库的数据差异有多大然后对这条异常记录做数据订正。如果差异很小可以手动补齐数据后STOP REPLICA; SET GLOBAL SQL_SLAVE_SKIP_COUNTER 1; START REPLICA;跳过这一条错误继续复制。注意跳过错误是权宜之计你得搞清楚为什么会有这条异常数据。如果差异很大说明从库已经彻底污染别硬救了重新全量同步是最靠谱的方案。4.3 锁表与慢查询排查从 SHOW PROCESSLIST 到 performance_schema集群上线后应用偶尔会出现请求卡住的情况表现是接口超时堆积数据库连接池被打满。这个场景十有八九是锁问题或大事务导致的。第一反应是执行SHOW FULL PROCESSLIST看看当前所有连接都在干什么。重点看State字段如果大量连接停在Waiting for table metadata lock说明有人在跑长事务没提交DDL 拿不到元数据锁如果停在Updating或者Sending data说明有慢查询在拖。锁的根因分析我一般直接查performance_schema.data_lock_waits在 MySQL 8.0 里这表能帮你定位到具体的事务 ID 和持锁的会话。定位到会话之后确认如果是排障可以杀掉KILL thread_id;。这里我多说一句从业务层面规避锁问题远比事后杀会话更重要。一是让事务保持短小一个事务里不要塞几十条 SQL特别是不要把外部接口调用塞进事务里二是给高并发更新的行设计好冲突避免策略比如库存扣减用UPDATE ... WHERE stock ?而不是先 SELECT 再 UPDATE三是避免在业务高峰期对热点大表执行 DDL所有 DDL 安排到凌晨窗口。4.4 主从延迟的常见原因Seconds_Behind_Master持续增长经常困扰初学者。多数情况下不是 MySQL 本身故障而是业务行为或从库硬件问题。最常见的原因是主库上有大事务。比如业务跑了一个千万级数据的UPDATE这个事务在 binlog 里可能就有几百 MB从库 SQL 线程串行回放当然需要很长时间。第二个常见原因是从库硬件配置低于主库磁盘 IO 跟不上。第三个是从库上还跑了报表或备份任务把磁盘带宽抢走了。规避方案也是几个方向把大事务拆成小批次执行比如按主键 ID 分段UPDATE从库硬件不要低于主库尤其磁盘 IO 要足够备份任务错峰执行或者用专门的第三台节点做备份完全不碰线上从库。4.5 主从数据不一致的校验数据一致性校验这件事不能在出问题之后再想起来做最好是定期自动跑。pt-table-checksum是 Percona Toolkit 提供的工具用它可以在不影响主库性能的前提下对比主从的表数据是否一致。我建议把它做成一个定时任务在业务低峰期执行。发现不一致之后再用pt-table-sync修复数据。不过这个工具的修复有一定风险执行前一定要备份并且在一个固定节点上演练一遍再上生产。5. 性能调优与后续演进建议集群搭好、多数据源跑通只能算是把架构的地基打完了。要让系统稳定运行还得做参数层面的调优和高可用方面的准备。5.1 影响 MySQL 性能的几个关键参数MySQL 配置参数几百个真正值得你花时间调的就那么十来个。挑几个最关键的聊聊。innodb_buffer_pool_size是最重要的一个参数它决定了 InnoDB 缓存池的大小。理论上设置为物理内存的 50% 到 70% 比较合理。比如服务器有 32G 内存可以把 buffer pool 设成 20G 左右。注意别把所有内存都塞给 MySQL操作系统还得留一部分跑文件缓存。innodb_flush_log_at_trx_commit这个参数控制事务提交时 redo log 的刷盘策略。设置为 1 时性能最差但最安全每个事务提交都要刷盘设置为 2 时只写入操作系统缓存不强制刷盘性能更好但数据库宕机可能丢数据。金融类业务必须用 1普通业务用 2 场景居多。别忘了检查sync_binlog是否也是 1它和innodb_flush_log_at_trx_commit1搭配才是真正的一致性保证。binlog_expire_logs_seconds我刚才在主库配置里提到了。日志保留时间长和磁盘空间是个矛盾建议配合监控报警一起处理。除此之外排序和索引的问题也不可忽视。慢查询日志一定要开起来long_query_time1然后定期去看慢日志把高频慢查询 SQL 捞出来做索引优化。热词里提到过“mysql排序”“mysql将字符串转为日期”这类操作如果出现在高频查询里直接给字段建索引和避免在索引列上做函数运算都是最基本的优化手段。5.2 从主从复制向高可用演进主从复制搭建完成之后下一个要思考的问题是如果主库挂了业务怎么办。没有自动切换机制的话从库只能作为只读副本业务写入直接不可用。这一步的改造方案我建议按团队成熟度分两条路走。第一条路是引入 MHAMaster High Availability Manager。MHA 的思路很清晰监控主库状态异常时将从库提升为新的主库并漂移 VIP应用层几乎无感知。MHA 适合熟悉 Linux 操作和脚本化运维的团队没有额外的组件依赖排查起来相对容易。第二条路是直接用 MySQL 官方的 InnoDB Cluster。它的底层是 MGR支持多主或少主模式自动选主架构上更现代化。但要注意MGR 对网络和节点稳定性要求高对现有版本的兼容性也需要提前验证运维复杂度和故障排查难度比 MHA 高出一截。不管走哪条路强烈建议提前做切换演练。我见过不少团队配置了高可用但从不演练结果主库真挂了才发现在这个“全自动”方案里还有手动步骤没跑通。演练的步骤包括杀掉主库进程、观察自动切换是否正常、从库是否成功提升、VIP 是否漂移、应用是否恢复写入。整套流程至少演练两三次每一次都要记下耗时和出问题的地方。5.3 多数据源架构后续还能扩展什么多数据源这套架构其实还有很大的扩展空间。最常见的一种演进是引入分库分表。当单表数据量过大的时候可以在数据源路由的基础上增加表路由把用户 ID 或订单号作为分片键分散到多个数据库节点。这个阶段可以选择 ShardingSphere 这类成熟的中间件也可以继续自己做一层分片路由。但我的建议是分库分表不要主动引入而是在出现下面几个信号时再考虑单表数据量超过几千万即使加了索引写入性能也在明显下降单库连接数长期处于高位扩容连接已经无法解决问题需要把不同业务模块拆到不同数据库才能物理隔离故障另外一个常见的扩展方向是异构数据同步。你在热搜词里看到“mysql表结构自动转tdengine超级表”这种需求本质上就是把 MySQL 的数据实时同步到其他存储系统比如 ClickHouse、Elasticsearch、TDengine 或者 Redis。这类需求一般用 Canal 监听 MySQL binlog然后把变更事件投递到 MQ 或直接写入目标存储。数据源路由解决的是应用层的读写分离binlog 消费解决的是跨系统的数据流转两套机制可以配合使用不冲突。最后再多说一句我的体感不管架构设计得多完善故障永远会出现在你意想不到的地方。这次从零搭建过程中我最有价值的收获不是那几条命令和配置而是把“主从复制为什么会中断、数据源为什么没切过去、连接池为什么会打满”这类底层机制彻底摸清了。你后面不管是接中间件、上容器化、还是做数据平台这些基本功都会一遍一遍地用上。
返回列表