1. 问题现象与背景分析
今天在维护MySQL Group Replication(MGR)集群时,发现其中一个SECONDARY节点出现异常。查看错误日志发现如下关键报错信息:
code复制2026-03-05T16:54:56.631584+08:00 416624 [ERROR] [MY-010584] [Repl] Slave SQL for channel 'group_replication_applier': Worker 1 failed executing transaction '4bf2afa4-a26c-39c8-ab1b-85378a6903b7:1036296'; Error 'This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)' on query. Default database: 'aradmin'. Query: 'CREATE DEFINER="a" END', Error_code: MY-001418T '';LLATE utf8mb4_bin AS
这个错误发生在MGR的applier线程尝试应用一个包含存储函数创建的DDL事务时。核心问题是MySQL的安全机制阻止了未声明确定性属性的存储函数创建。
注意:在MGR架构中,所有DDL操作都需要通过Primary节点执行并同步到Secondary节点。这个错误表明Primary节点允许执行的DDL在Secondary节点上被安全机制拦截了。
2. 错误原理深度解析
2.1 log_bin_trust_function_creators参数详解
log_bin_trust_function_creators是MySQL中一个关键的全局系统变量,它控制着在二进制日志启用状态下存储函数的创建行为:
- 默认值:OFF(0)
- 可选值:ON(1)
- 动态修改:支持运行时修改(SET GLOBAL)
- 持久化:需要写入配置文件才能重启后生效
当该参数为OFF时,MySQL会强制要求所有存储函数必须声明以下三种属性之一:
DETERMINISTIC:函数是确定性的,相同输入必然产生相同输出NO SQL:函数不包含SQL语句READS SQL DATA:函数只读取数据,不修改数据
2.2 安全机制的设计考量
这个限制主要是为了解决主从复制场景下的数据一致性问题。考虑以下场景:
- 主库执行一个包含
RAND()函数的存储过程,生成随机数A并插入数据 - 二进制日志记录的是函数调用语句,而非生成的随机数A
- 从库重放时再次调用该函数,生成随机数B
- 结果导致主从数据不一致
通过强制声明函数属性,MySQL确保:
- 确定性函数(DETERMINISTIC)在重放时产生相同结果
- 只读函数(READS SQL DATA)不会导致意外的数据修改
- 无SQL函数(NO SQL)完全避免SQL执行风险
2.3 MGR环境下的特殊考量
在Group Replication中,这个机制更为重要,因为:
- MGR使用基于Paxos的共识协议,要求所有节点最终一致
- 任何节点都可能成为Primary,函数行为必须完全一致
- 非确定性函数可能导致集群分裂(脑裂)风险
3. 问题解决方案与实施步骤
3.1 临时解决方案(立即生效)
对于紧急恢复,可以动态调整参数:
sql复制-- 在受影响的SEC节点上执行
SET GLOBAL log_bin_trust_function_creators=1;
然后重启组复制应用线程:
sql复制STOP GROUP_REPLICATION;
START GROUP_REPLICATION;
注意:这种方式只对当前实例有效,重启MySQL后会失效。仅建议用于临时恢复服务。
3.2 永久解决方案(配置持久化)
- 修改MySQL配置文件(my.cnf/my.ini):
code复制[mysqld]
log_bin_trust_function_creators=ON
- 重启MySQL服务使配置生效:
bash复制# Linux系统
systemctl restart mysqld
# Windows系统
net stop mysql
net start mysql
- 验证参数状态:
sql复制SHOW VARIABLES LIKE 'log_bin_trust_function_creators';
3.3 替代方案(推荐做法)
更安全的做法是修改存储函数定义,添加适当的声明:
sql复制CREATE DEFINER=`a` FUNCTION `func_name`()
RETURNS varchar(100)
DETERMINISTIC
BEGIN
-- 函数逻辑
END;
这种方案:
- 不需要修改全局参数
- 符合MySQL安全规范
- 明确表达了函数的行为特性
4. 操作风险与注意事项
4.1 安全风险评估
开启log_bin_trust_function_creators可能带来以下风险:
- 数据不一致风险:非确定性函数导致主从数据差异
- 安全漏洞:恶意函数可能利用高权限执行危险操作
- 审计困难:难以追踪函数内的具体数据变更
4.2 生产环境最佳实践
-
最小权限原则:
- 限制函数创建者的权限
- 使用DEFINER指定低权限账户
-
代码审查:
- 对所有存储函数进行严格审查
- 确保非确定性函数有明确的业务必要性
-
监控措施:
sql复制-- 监控非确定性函数 SELECT * FROM mysql.proc WHERE NOT is_deterministic='YES' AND security_type='INVOKER'; -
备份策略:
- 修改关键参数前备份配置文件
- 创建数据库逻辑备份
4.3 故障排查技巧
当遇到类似错误时,可以按照以下步骤诊断:
-
确认错误是否确实来自存储函数:
sql复制SHOW RELAYLOG EVENTS IN 'relay-bin.000002' FROM 123 LIMIT 1; -
检查函数定义:
sql复制SHOW CREATE FUNCTION function_name; -
分析二进制日志:
bash复制mysqlbinlog /var/lib/mysql/binlog.000123 | grep -A 10 "CREATE FUNCTION" -
检查MGR状态:
sql复制SELECT * FROM performance_schema.replication_group_members;
5. 深入理解MGR中的DDL同步机制
5.1 MGR事务处理流程
在Group Replication中,DDL语句的特殊处理流程:
- Primary节点接收DDL语句
- 语句在本机执行
- 生成对应的二进制日志事件
- 通过Group Communication层广播到所有节点
- 各Secondary节点通过applier线程应用变更
5.2 安全机制差异
不同于普通主从复制,MGR中:
- 所有节点都开启二进制日志:这是MGR的基础要求
- 严格的一致性检查:包括函数安全性验证
- 认证阶段验证:事务在提交前会经过集群认证
5.3 典型问题场景
- 参数不一致:各节点
log_bin_trust_function_creators设置不同 - 权限差异:DEFINER账户在各节点权限不一致
- 版本差异:不同MySQL版本对函数的安全检查标准不同
6. 长期维护建议
6.1 参数管理规范
- 在配置中心统一管理所有节点的参数
- 使用配置管理工具(Ansible/Puppet)确保一致性
- 建立参数变更审批流程
6.2 函数开发规范
-
强制要求所有存储函数声明确定性属性
-
建立函数代码审查清单:
- 是否包含非确定性函数(RAND(), NOW()等)
- 是否有数据修改操作
- DEFINER账户是否合理
-
使用SQL_MODE加强约束:
sql复制SET GLOBAL sql_mode='STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION,STRICT_ALL_TABLES';
6.3 监控体系建设
-
关键指标监控:
- MGR成员状态
- 复制延迟
- 错误日志关键字
-
自动化报警规则:
sql复制-- 监控MGR错误 SELECT * FROM performance_schema.events_errors_summary_global_by_error WHERE error_name LIKE '%replication%' AND count_star > 0; -
定期健康检查:
bash复制# 检查参数一致性 mysql -e "SHOW GLOBAL VARIABLES LIKE 'log_bin%'" >> mgr_check.log
在实际生产环境中,我建议优先采用修改函数定义的方式解决问题,而不是简单地开启log_bin_trust_function_creators。虽然后者操作更简单,但长期来看,明确定义函数行为特性才是更可持续的解决方案。对于已经存在的非确定性函数,可以安排专门的改造计划逐步规范。