MySQL高可用改造之数据库开发规范(大事务与数据一致性篇)
文章目录
- 一、前言
- 二、延迟的原因
- 三、大事务处理规范
- 3.1. 删除类操作优化设计
- 3.2. 大事务通用拆分原则
- 四、数据一致性核对规范
- 4.1. 主从变更记录识别方法
- 五、小结
一、前言
MySQL 高可用架构中最基础、最为核心的内容:MySQL 复制(Replication),数据库复制本质上就是数据同步。MySQL 数据库是基于二进制日志(binary log)进行数据增量同步,而二进制日志记录了所有对于MySQL 数据库的修改操作。
很多时候我们会发现,MySQL 的主从复制会存在主从数据延迟的问题,甚至会导致读写分离架构设计在业务层出现较为严重的问题,比如迟迟无法读取到主库已经插入的数据。
所以本文,我们就如何从数据库设计避免这个令人头疼的问题。
二、延迟的原因
MySQL 复制基于的二进制日志是一种逻辑日志,其写入的是每个事务中已变更的每条记录的前项、后项。有了每条记录的变化内容,用户可以方便地通过分析 MySQL 的二进制日志内容。逻辑日志简单易懂,方便数据之间的同步,但它的缺点是:事务不能太大,否则会导致二进制日志非常大,一个大事务的提交会非常慢。
假设有个 DELETE 删除操作,删除当月数据,由于数据量可能有 1 亿条记录,可能会产生 100G 的二进制日志,则这条 SQL 在提交时需要等待 100G 的二进制日志写入磁盘,如果二进制日志磁盘每秒写入速度为 100M/秒,至少要等待 1000 秒才能完成这个事务的提交。
三、大事务处理规范
核心原则:避免大事务(单次操作涉及大量数据或长时间持有锁),以降低提交延迟、减少主从复制延迟风险,并提升系统整体并发能力。
3.1. 删除类操作优化设计
(1)优先采用物理拆分替代逻辑删除
- 适用场景:针对流水表、日志表等历史数据定期清理需求。
- 规范要求:
- 设计阶段将此类表按时间维度分表(如按月分表)或分区(如按天/月分区),例如:
-- 分表示例:按月分表(logs_202401、logs_202402...)CREATE TABLE logs_202401 (...); CREATE TABLE logs_202402 (...);-- 分区表示例:按月份范围分区CREATE TABLE logs (id INT,log_time DATETIME,...) PARTITION BY RANGE (YEAR(log_time)*100 + MONTH(log_time)) (PARTITION p202401 VALUES LESS THAN (202402),PARTITION p202402 VALUES LESS THAN (202403),...);
-
删除操作直接通过 DROP TABLE(分表)或 ALTER TABLE … DROP PARTITION(分区)实现,二进制日志(binlog)仅记录一条元数据操作,写入速度快且不占用大量日志空间。
-- 分表删除:直接删除整月表(瞬时完成)DROP TABLE logs_202312;-- 分区删除:移除指定月份分区(高效且可快速回收空间)ALTER TABLE logs DROP PARTITION p202312;
(2)未分表/分区时的拆分策略(应急方案)
-
若因历史原因无法分表/分区,需通过小事务分批删除替代单条大事务 DELETE:
- 拆分方法:添加 LIMIT 子句限制单次删除条数(如每次1000条),结合时间范围条件逐步清理。
-- 示例:每次删除2024年1月内1000条记录,循环执行直至完成DELETE FROM logs WHERE log_time BETWEEN '2024-01-01 00:00:00' AND '2024-01-31 23:59:59'LIMIT 1000;
-
优势:
- 单次事务量小,减少锁持有时间(避免长时间阻塞其他会话)。
- 降低二进制日志(binlog)体积,避免因大事务日志过大导致主从同步延迟。
- 支持并发执行:可通过多线程/多连接分片删除不同时间范围或ID段的数据(需确保无重叠),提升清理效率。
3.2. 大事务通用拆分原则
-
核心要求:单次事务操作的数据量需控制在合理范围内(建议单事务影响行数≤1万条,具体根据业务负载调整)。
-
典型场景:
- 批量数据插入/更新/删除时,通过循环或分片拆分为多个小事务(如每次处理1000~5000条)。
- 避免在事务中执行耗时操作(如网络请求、复杂计算),减少锁持有时间。
-
示例(批量更新拆分):
-- 原始大事务(风险高):一次性更新10万条记录 -- UPDATE orders SET status = 'completed' WHERE create_time < '2024-01-01';-- 拆分后小事务(推荐):每次更新5000条 UPDATE orders SET status = 'completed' WHERE create_time < '2024-01-01' LIMIT 5000;-- 循环执行直至受影响行数为0(可通过程序控制)
四、数据一致性核对规范
4.1. 主从变更记录识别方法
- 设计要求:所有业务表必须包含 last_modify_date 字段(或类似的时间戳字段,如 update_time),用于记录每条数据的最后修改时间(建议默认值为 CURRENT_TIMESTAMP,并通过触发器或应用逻辑保证更新时自动维护)。
CREATE TABLE example (id INT PRIMARY KEY,data VARCHAR(255),last_modify_date DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP);
-
核对流程:
- 定位变更记录:通过 last_modify_date 过滤出主库上最近一段时间内(如最近1小时/1天)被修改的数据。
-- 示例:查询主库上2024-06-01 00:00:00后更新的所有记录SELECT * FROM example WHERE last_modify_date >= '2024-06-01 00:00:00';
- 逐条比对:将主库查询结果与从库对应表的数据进行字段级比对(可通过程序脚本实现),确认关键字段(如业务状态、金额等)是否一致。
- 异常处理:若发现不一致,需记录差异详情并触发告警,由运维或开发人员排查原因(如主从延迟、业务逻辑错误等)。
五、小结
通过以上规范,可有效控制大事务风险,保障MySQL数据库高可用架构的性能、可用性与数据一致性。