技术点
- 使用确定性函数属性:在定义自定义函数时,确保函数标记为
DETERMINISTIC
,表示相同输入总会产生相同输出。如果函数本身不是严格确定性的,需要重构使其满足该特性,例如避免使用像 NOW()
等非确定性函数。
- 二进制日志格式:
- ROW 格式:主库采用
ROW
格式的二进制日志。在 ROW
格式下,主库记录的是数据行的更改,而不是 SQL 语句本身。这减少了因函数执行环境差异导致的结果不一致问题,因为从库直接应用这些数据行的变更,而无需再次执行自定义函数。
- MIXED 格式:若函数在某些情况下无法完全做到确定性,可考虑
MIXED
格式。MIXED
格式会根据 SQL 语句的特性自动选择是使用 ROW
格式还是 STATEMENT
格式记录日志。对于确定性函数,采用 STATEMENT
格式记录;对于非确定性函数,采用 ROW
格式记录。
- 参数化查询:在调用自定义函数时,尽量使用参数化查询。这样可以避免由于 SQL 语句中硬编码值在主从库环境下解析不同导致的结果差异。
配置修改
- 主库配置:
- 在主库的
my.cnf
配置文件中,设置 log - bin = /var/log/mysql/mysql - bin.log
开启二进制日志。
- 根据需要设置
binlog - format = ROW
或 binlog - format = MIXED
。例如:
[mysqld]
log - bin = /var/log/mysql/mysql - bin.log
binlog - format = ROW
- 从库配置:
- 确保从库与主库的 MySQL 版本兼容,避免因版本差异导致函数执行不一致。
- 配置从库的
my.cnf
文件,设置 server - id
为唯一值,例如:
[mysqld]
server - id = 2
- 启动从库复制线程,通过
CHANGE MASTER TO
语句配置主库连接信息,如:
CHANGE MASTER TO
MASTER_HOST ='master_host_ip',
MASTER_USER ='replication_user',
MASTER_PASSWORD ='replication_password',
MASTER_LOG_FILE ='master_binlog_file',
MASTER_LOG_POS = master_binlog_position;
START SLAVE;
可能面临的挑战与应对措施
- 函数重构难度:
- 挑战:如果自定义函数依赖于非确定性因素,如系统时间、随机数等,重构为确定性函数可能比较困难,甚至需要对业务逻辑进行较大调整。
- 应对措施:分析函数中的非确定性因素,寻找替代方案。例如,对于依赖系统时间的业务需求,可以通过传递参数的方式,将固定时间值作为参数传入函数,而不是在函数内部使用
NOW()
等函数。对于随机数需求,如果只是为了模拟某种分布,可以使用固定的种子值来生成伪随机数,确保相同输入产生相同输出。
- 性能影响:
- 挑战:
ROW
格式的二进制日志会比 STATEMENT
格式产生更多的日志量,可能会对主库的性能和磁盘空间造成压力。
- 应对措施:定期清理过期的二进制日志文件,通过设置
expire_logs_days
参数来控制二进制日志文件的保留天数。例如,在 my.cnf
文件中设置 expire_logs_days = 7
,表示保留最近 7 天的二进制日志。同时,可以对主库的硬件进行优化,如增加磁盘空间、提高磁盘 I/O 性能等。
- 版本兼容性:
- 挑战:不同版本的 MySQL 对自定义函数的实现细节和二进制日志格式的处理可能存在差异,可能导致主从库执行结果不一致。
- 应对措施:在部署主从复制环境前,仔细查阅 MySQL 官方文档,了解不同版本间的兼容性问题。尽量保持主从库版本一致,并且在版本升级时,进行充分的测试,包括自定义函数在主从库的执行结果一致性测试。
- 数据一致性验证:
- 挑战:即使采取了上述措施,仍可能因一些未知因素导致主从库数据不一致,需要有效的方法来验证数据一致性。
- 应对措施:可以定期使用工具如
pt - table - checksum
来对比主从库的数据。该工具通过计算表数据的校验和来检测数据是否一致。同时,在关键业务操作后,通过应用层逻辑进行数据一致性检查,例如对自定义函数计算结果相关的数据进行对比验证。