作者通过一个主从复制过程中 1590 的谬误,阐明了 MySQL 8.0 在创立用户受权过程中的注意事项。
作者:王祥
爱可生 DBA 团队成员,次要负责 MySQL 故障解决和性能优化。对技术执着,为客户负责。
本文起源:原创投稿
- 爱可生开源社区出品,原创内容未经受权不得随便应用,转载请分割小编并注明起源。
故障形容
DMP 收到告警:从库的 SQL 线程进行工作,MySQL 版本为 5.7.32,登录到从库查看复制信息报错如下:
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
……
Last_Errno: 1590
Last_Error: The incident LOST_EVENTS occured on the master. Message: REVOKE/GRANT failed while granting/revoking privileges in databases.
Skip_Counter: 0
Exec_Master_Log_Pos: 12531
Relay_Log_Space: 69304
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: NULL
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 1590
Last_SQL_Error: The incident LOST_EVENTS occured on the master. Message: REVOKE/GRANT failed while granting/revoking privileges in databases.
……
从库谬误日志信息如下:
[ERROR] Slave SQL for channel '': The incident LOST_EVENTS occured on the master. Message: REVOKE/GRANT failed while granting/revoking privileges in databases. Error_code: 1590
[ERROR] Error running query, slave SQL thread aborted. Fix the problem, and restart the slave SQL thread with "SLAVE START". We stopped at log 'mysql-bin.000003' position 12531.
解析对应 Binlog 信息如下:
# Incident: LOST_EVENTS
RELOAD DATABASE; # Shall generate syntax error
主库错误信息如下:
[ERROR] REVOKE/GRANT failed while granting/revoking privileges in databases. An incident event has been written to the binary log which will stop the slaves.
客户反馈执行了一些受权操作而后复制就呈现报错,执行的语句如下:
mysql> create user test@'%',app@'%' identified by 'Root@123';
ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
mysql> grant all on test.* to test@'%',app@'%';
ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
故障剖析
依据以上报错信息可知:在做权限变更时产生了谬误,主库在 binlog 里写一条 INCIDENT_EVENT,备库在解析到 INCIDENT_EVENT 就间接报错。
那在什么状况下执行受权语句会导致主库在 binlog 写 INCIDENT_EVENT 呢?
当权限变更操作只解决了一部分并产生谬误时,主库会在 binlog 里写一条 INCIDENT_EVENT。
那什么状况下会产生权限变更只解决一部分而有一部分没解决完呢?
上面举例说明两种相干场景。
MySQL 5.7 的问题
在 MySQL 5.7 里应用 GRANT 语句新建用户,其中有局部权限有问题。
应用 GRANT 创立 test
用户(MySQL 8.0 版本曾经不反对应用 GRANT 创立用户):
mysql> grant select,insert,file on test.* to test@'%' identified by 'Q1w2e3E$';
ERROR 1221 (HY000): Incorrect usage of DB GRANT and GLOBAL PRIVILEGES
mysql> select user,host from mysql.user where user='test' and host='%';
+------+--------+
| user | host |
+------+--------+
| test | % |
+------+--------+
1 row in set (0.00 sec)
mysql> show grants for test@'%';
+--------------------------------------------+
| Grants for test@% |
+--------------------------------------------+
| GRANT USAGE ON *.* TO 'test'@'%' |
+---------------------------------------------+
1 row in set (0.00 sec)
在创立用户时对 test
库授予 SELECT、INSERT、FILE 权限,因 FILE 权限不能授予某个数据库而导致语句执行失败。但最终后果是:test@'%'
创立胜利,受权局部失败。从下面的测试可知,应用 GRANT 创立用户其实是分为两个步骤:创立用户和受权。权限有问题并不影响用户的创立,上述语句会导致主库在 binlog 写 INCIDENT_EVENT,从而导致主从复制报错。
GRANT 对两个用户同时受权
应用一条 GRANT 语句,同时给 test@'10.186.63.5'
与 test@'10.186.63.29'
用户受权,其中 test@'10.186.63.5'
用户存在,而 test@'10.186.63.29'
不存在。
mysql> create user test@'10.186.63.5' identified by '123';
Query OK, 0 rows affected (0.00 sec)
mysql> grant all on test.* to test@'10.186.63.5',test@'10.186.63.29';
ERROR 1133 (42000): Can't find any matching row in the user table
mysql> show grants for test@'10.186.63.5';
+----------------------------------------------------------+
| Grants for test@10.186.63.5 |
+----------------------------------------------------------+
| GRANT USAGE ON *.* TO 'test'@'10.186.63.5' |
| GRANT ALL PRIVILEGES ON `test`.* TO 'test'@'10.186.63.5' |
+----------------------------------------------------------+
2 rows in set (0.00 sec)
依据下面的试验可知:test@'10.186.63.5'
用户存在故受权胜利,而 test@'10.186.63.29'
用户不存在受权失败。上述语句也会导致主库在 binlog 写 INCIDENT_EVENT,从而导致主从复制报错。
但以上两种状况仿佛都不合乎客户执行语句状况,从报错来看是因为明码复杂度不够而导致创立用户失败了,那到底是什么起因导致从库呈现 1590 谬误呢?上面咱们来看看在应用了明码复杂度插件后应用 create 语句同时创立两个用户会有什么问题。
mysql> show global variables like '%validate%';
+--------------------------------------+--------+
| Variable_name | Value |
+--------------------------------------+--------+
| query_cache_wlock_invalidate | OFF |
| validate_password_check_user_name | OFF |
| validate_password_dictionary_file | |
| validate_password_length | 8 |
| validate_password_mixed_case_count | 1 |
| validate_password_number_count | 1 |
| validate_password_policy | MEDIUM |
| validate_password_special_char_count | 1 |
+--------------------------------------+--------+
mysql> select user,host from mysql.user;
+---------------+-----------+
| user | host |
+---------------+-----------+
| universe_op | % |
| root | 127.0.0.1 |
| mysql.session | localhost |
| mysql.sys | localhost |
| root | localhost |
+---------------+-----------+
5 rows in set (0.00 sec)
mysql> create user test@'%',app@'%' identified by 'Root@123';
ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
mysql> select user,host from mysql.user;(app@'%' 创立胜利,test@'%' 创立失败)+---------------+-----------+
| user | host |
+---------------+-----------+
| app | % |
| universe_op | % |
| root | 127.0.0.1 |
| mysql.session | localhost |
| mysql.sys | localhost |
| root | localhost |
+---------------+-----------+
6 rows in set (0.00 sec)
上述测试应用 CREATE USER 同时创立 test@'%'
、app@'%'
。但因为明码复杂度不合符要求而失败报错(屡次测试发现并不是明码复杂度不够,只有同时创立两个用户都会报明码复杂度不符合要求。在未应用明码复杂度插件时是能够同时创立两个用户),失常的话这两个用户应该都会创立失败。但实际上 app@'%'
用户创立胜利了。
到这里咱们就明确文章开始形容故障的触发起因:数据库实例开启了明码复杂度插件,应用 CREATE USER 同时创立两个用户,因为明码复杂度不符合要求而报错,但 app@'%'
是曾经创立了,test@'%'
用户未创立,紧接着又执行了 GRANT 语句给两个用户同时受权,此时因为 test@'%'
用户不存在,而导致 GRANT 语句局部执行的问题,最终导致了主从复制报错。
故障解决
当主从复制呈现 1590 报错时,能够先解析 binlog,找到 INCIDENT_EVENT(搜寻关键字 LOST_EVENTS)和对应的 GTID,而后通过跳过这个 GTID 的形式来复原主从复制。在跳过 GTID 之前还须要先将数据补全,因为主库有一个用户是曾经受权胜利从库这部分受权是没有执行的。具体操作如下(在从库执行):
mysql>set global super_read_only=0;
mysql>set sql_log_bin=0;
mysql>grant all on test.* to test@'10.186.63.5';
跳过报错对应的 GTID,具体操作如下:
解析 binlog 找到 INCIDENT_EVENT。
mysqlbinlog --no-defaults -vv --base64-output=decode-rows mysql-bin.000016 > /root/bin.log
跳过 LOST_EVENTS
对应的 GTID(在从库执行):
stop slave sql_thread;
set gtid_next='9d2e7089-2774-11ee-99d6-02000aba3f05:4198564';
begin;commit;
set gtid_next='automatic';
start slave sql_thread;
总结
- 权限变更操作只解决了一部分并产生谬误时,会导致 binlog 写一条 INCIDENT_EVENT,从而导致主从复制报错。
- 在应用明码复杂度插件时,应用 CREATE 语句同时创立两个用户,会呈现一个用户创立胜利另外一个用户创立失败的状况。
倡议
- 应用了明码复杂度插件,创立用户时一条 CREATE 语句只创立一个用户。
- 受权时一条 GRANT 语句只对一个用户受权,避免因权限谬误导致局部受权胜利的问题。
更多技术文章,请拜访:https://opensource.actionsky.com/
对于 SQLE
爱可生开源社区的 SQLE 是一款面向数据库使用者和管理者,反对多场景审核,反对标准化上线流程,原生反对 MySQL 审核且数据库类型可扩大的 SQL 审核工具。
SQLE 获取
类型 | 地址 |
---|---|
版本库 | https://github.com/actiontech/sqle |
文档 | https://actiontech.github.io/sqle-docs/ |
公布信息 | https://github.com/actiontech/sqle/releases |
数据审核插件开发文档 | https://actiontech.github.io/sqle-docs/docs/dev-manual/plugin… |