GreatSQL 8.0回流MySQL 5.7主从复制中断分析排查过程

1. 问题描述

某银行客户从MySQL 5.7迁移到GreatSQL 8.0,要求迁移完成后生产数据回流到MySQL 5.7一段时间,以备紧急回切和数据对比。在进行回流测试时,在 GreatSQL 8.0 侧执行的存储过程,其 binlog 中记录了 SET @@session.character_set_client=255,255 对应的排序规则 utf8mb4_0900_ai_ci ,是 MySQL/GreatSQL 8.0 新引入的排序规则,MySQL 5.7 不能识别,导致slave端MySQL 5.7的SQL线程中断。

报错信息如下:

SQL 复制代码
mysql > select * from performance_schema.replication_applier_status_by_worker limit 1\G
*************************** 1. row ***************************
         CHANNEL_NAME: 
            WORKER_ID: 1
            THREAD_ID: NULL
        SERVICE_STATE: OFF
LAST_SEEN_TRANSACTION: 195bbb58-b72a-11f1-9e63-fa163e5eebc2:6
    LAST_ERROR_NUMBER: 22
   LAST_ERROR_MESSAGE: Worker 1 failed executing transaction '195bbb58-b72a-11f1-9e63-fa163e5eebc2:6' at master log binlog.000928, end_log_pos 119877602; Error 'Character set '#255' is not a compiled character set and is not specified in the '/data/actiondb/base/5.7.44/share/charsets/Index.xml' file' on query. Default database: 'xxx_yyy_batch'. Query: 'TRUNCATE TABLE OOOOO_ORDER'
 LAST_ERROR_TIMESTAMP: 2026-10-15 04:29:20
1 row in set (0.00 sec)

解析该事务对应的binlog,信息如下:

SQL 复制代码
SET @@SESSION.GTID_NEXT= '195bbb58-b72a-11f1-9e63-fa163e5eebc2:6'/*!*/;
# at 119877488
#261015  4:29:20 server id 1034607900  end_log_pos 119877602 CRC32 0x774776ac   Query   thread_id=3623014       exec_time=0     error_code=0    Xid = 13469999
use `xxx_yyy_batch`/*!*/;
SET TIMESTAMP=1792009760/*!*/;
SET @@session.pseudo_thread_id=3623014/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1168113664/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8mb4 *//*!*/;
SET @@session.character_set_client=255,@@session.collation_connection=45,@@session.collation_server=46/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
/*!80011 SET @@session.default_collation_for_utf8mb4=45*//*!*/;
TRUNCATE TABLE OOOOO_ORDER
/*!*/;
SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/;
DELIMITER ;
# End of log file
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;

存储过程proc_rept_ooooo_order的创建信息如下:

SQL 复制代码
GreatSQL > show create procedure proc_rept_ooooo_order\G 
*************************** 1. row ***************************
           Procedure: PROC_REPT_OOOOO_ORDER
            sql_mode: STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
    Create Procedure: CREATE DEFINER=`run_batch`@`%` PROCEDURE `PROC_REPT_OOOOO_ORDER`( IN PETLDATE CHAR(8),OUT PCODE INT,OUT PMSG VARCHAR (80))
BEGIN
......
CALL PPPP_SSS_RUN_BATCH_LOG ( PETLDATE, PRC_NAME, PRC_STEP, PRC_DESC );
TRUNCATE TABLE OOOOO_ORDER;
......
END
character_set_client: utf8mb4
collation_connection: utf8mb4_general_ci
  Database Collation: utf8mb4_general_ci
1 row in set (0.00 sec)

2. 问题分析

2.1 实验验证:探究binlog中字符集信息的来源

  1. 在GreatSQL中,直接设置character_set_client、collation_connection、collation_server为特定的值(224,225,226),检查存储过程执行后的binlog信息。
SQL 复制代码
GreatSQL > select * from information_schema.collations where CHARACTER_SET_NAME='utf8mb4';
+----------------------------+--------------------+-----+------------+-------------+---------+---------------+
| COLLATION_NAME             | CHARACTER_SET_NAME | ID  | IS_DEFAULT | IS_COMPILED | SORTLEN | PAD_ATTRIBUTE |
+----------------------------+--------------------+-----+------------+-------------+---------+---------------+
| utf8mb4_general_ci         | utf8mb4            |  45 |            | Yes         |       1 | PAD SPACE     |
| utf8mb4_bin                | utf8mb4            |  46 |            | Yes         |       1 | PAD SPACE     |
| utf8mb4_unicode_ci         | utf8mb4            | 224 |            | Yes         |       8 | PAD SPACE     |
| utf8mb4_icelandic_ci       | utf8mb4            | 225 |            | Yes         |       8 | PAD SPACE     |
| utf8mb4_latvian_ci         | utf8mb4            | 226 |            | Yes         |       8 | PAD SPACE     |
| utf8mb4_romanian_ci        | utf8mb4            | 227 |            | Yes         |       8 | PAD SPACE     |
| utf8mb4_slovenian_ci       | utf8mb4            | 228 |            | Yes         |       8 | PAD SPACE     |
......

GreatSQL > SET @@session.character_set_client=224,@@session.collation_connection=225,@@session.collation_server=226;
Query OK, 0 rows affected (0.02 sec)

GreatSQL > show variables like '%colla%';
+-------------------------------+----------------------+
| Variable_name                 | Value                |
+-------------------------------+----------------------+
| collation_connection          | utf8mb4_icelandic_ci |
| collation_database            | utf8mb4_bin          |
| collation_server              | utf8mb4_latvian_ci   |
| default_collation_for_utf8mb4 | utf8mb4_general_ci   |
+-------------------------------+----------------------+
4 rows in set (0.06 sec)

GreatSQL > drop PROCEDURE testchar3;
Query OK, 0 rows affected (0.16 sec)

GreatSQL > CREATE PROCEDURE testchar3() truncate table test2 ;
Query OK, 0 rows affected (0.01 sec)

GreatSQL > show procedure status like 'testchar3';
+------+-----------+-----------+-----------+---------------------+---------------------+---------------+---------+----------------------+----------------------+--------------------+
| Db   | Name      | Type      | Definer   | Modified            | Created             | Security_type | Comment | character_set_client | collation_connection | Database Collation |
+------+-----------+-----------+-----------+---------------------+---------------------+---------------+---------+----------------------+----------------------+--------------------+
| test | testchar3 | PROCEDURE | greatdb@% | 2026-10-19 16:25:43 | 2026-10-19 16:25:43 | DEFINER       |         | utf8mb4              | utf8mb4_icelandic_ci | utf8mb4_bin        |
+------+-----------+-----------+-----------+---------------------+---------------------+---------------+---------+----------------------+----------------------+--------------------+
1 row in set (0.03 sec)

执行testchar3后的binlog信息:

SQL 复制代码
SET @@SESSION.GTID_NEXT= '684af664-79a4-11f1-9869-00163e883d79:68'/*!*/;
# at 5739
#261019 16:26:54 server id 1004003306  end_log_pos 5838 CRC32 0x3be26de4        Query   thread_id=93    exec_time=0     error_code=0    Xid = 484
use `test`/*!*/;
SET TIMESTAMP=1792398414/*!*/;
SET @@session.pseudo_thread_id=93/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1168113696/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8mb4 *//*!*/;
SET @@session.character_set_client=224,@@session.collation_connection=225,@@session.collation_server=226/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
/*!80011 SET @@session.default_collation_for_utf8mb4=45*//*!*/;
truncate table test2
/*!*/;

可看出:binlog中character_set_client来自存储过程创建时,指定的系统变量character_set_client的数字值(排序规则224)。

  1. 重新登录数据库,在collation_server=utf8mb4_bin(46)下运行存储过程testchar3,解析后binlog信息,binlog中其他信息未改变,只改变了@@session.collation_server=46 。
SQL 复制代码
SET @@session.character_set_client=224,@@session.collation_connection=225,@@session.collation_server=46/*!*/;

可以得出:

binlog中记录的字符集排序规则信息来源:

  • character_set_client-- 存储过程定义时 的客户端排序规则(client_collation_id)。
  • collation_connection -- 存储过程定义时 的连接排序规则(connection_collation_id)。
  • collation_server-- 存储过程运行时 的服务器排序规则(collation_server)。

2.2 检查表routines的数据来源

那 information_schema.routines 里为什么只看到 character_set_client: utf8mb4(字符集名称),却看不到 224 这个数字?

检查information_schema.routines的创建信息:

SQL 复制代码
GreatSQL > show create table information_schema.routines\G
*************************** 1. row ***************************
                View: ROUTINES
         Create View: CREATE ALGORITHM=UNDEFINED DEFINER=`mysql.infoschema`@`localhost` SQL SECURITY DEFINER VIEW `ROUTINES` AS select `rtn`.`name` AS `SPECIFIC_NAME`,(`cat`.`name` collate utf8mb3_tolower_ci) AS `ROUTINE_CATALOG`,(`sch`.`name` collate utf8mb3_tolower_ci) AS `ROUTINE_SCHEMA`,`rtn`.`name` AS `ROUTINE_NAME`,`rtn`.`type` AS `ROUTINE_TYPE`,if((`rtn`.`type` <> 'FUNCTION'),'',substring_index(substring_index(`rtn`.`result_data_type_utf8`,'(',1),' ',1)) AS `DATA_TYPE`,internal_dd_char_length(`rtn`.`result_data_type`,`rtn`.`result_char_length`,`coll_result`.`name`,0) AS `CHARACTER_MAXIMUM_LENGTH`,internal_dd_char_length(`rtn`.`result_data_type`,`rtn`.`result_char_length`,`coll_result`.`name`,1) AS `CHARACTER_OCTET_LENGTH`,`rtn`.`result_numeric_precision` AS `NUMERIC_PRECISION`,`rtn`.`result_numeric_scale` AS `NUMERIC_SCALE`,`rtn`.`result_datetime_precision` AS `DATETIME_PRECISION`,(case `rtn`.`result_data_type` when 'MYSQL_TYPE_STRING' then if((`cs_result`.`name` = 'binary'),NULL,`cs_result`.`name`) when 'MYSQL_TYPE_VAR_STRING' then if((`cs_result`.`name` = 'binary'),NULL,`cs_result`.`name`) when 'MYSQL_TYPE_VARCHAR' then if((`cs_result`.`name` = 'binary'),NULL,`cs_result`.`name`) when 'MYSQL_TYPE_TINY_BLOB' then if((`cs_result`.`name` = 'binary'),NULL,`cs_result`.`name`) when 'MYSQL_TYPE_MEDIUM_BLOB' then if((`cs_result`.`name` = 'binary'),NULL,`cs_result`.`name`) when 'MYSQL_TYPE_BLOB' then if((`cs_result`.`name` = 'binary'),NULL,`cs_result`.`name`) when 'MYSQL_TYPE_LONG_BLOB' then if((`cs_result`.`name` = 'binary'),NULL,`cs_result`.`name`) when 'MYSQL_TYPE_ENUM' then if((`cs_result`.`name` = 'binary'),NULL,`cs_result`.`name`) when 'MYSQL_TYPE_SET' then if((`cs_result`.`name` = 'binary'),NULL,`cs_result`.`name`) else NULL end) AS `CHARACTER_SET_NAME`,(case `rtn`.`result_data_type` when 'MYSQL_TYPE_STRING' then if((`cs_result`.`name` = 'binary'),NULL,`coll_result`.`name`) when 'MYSQL_TYPE_VAR_STRING' then if((`cs_result`.`name` = 'binary'),NULL,`coll_result`.`name`) when 'MYSQL_TYPE_VARCHAR' then if((`cs_result`.`name` = 'binary'),NULL,`coll_result`.`name`) when 'MYSQL_TYPE_TINY_BLOB' then if((`cs_result`.`name` = 'binary'),NULL,`coll_result`.`name`) when 'MYSQL_TYPE_MEDIUM_BLOB' then if((`cs_result`.`name` = 'binary'),NULL,`coll_result`.`name`) when 'MYSQL_TYPE_BLOB' then if((`cs_result`.`name` = 'binary'),NULL,`coll_result`.`name`) when 'MYSQL_TYPE_LONG_BLOB' then if((`cs_result`.`name` = 'binary'),NULL,`coll_result`.`name`) when 'MYSQL_TYPE_ENUM' then if((`cs_result`.`name` = 'binary'),NULL,`coll_result`.`name`) when 'MYSQL_TYPE_SET' then if((`cs_result`.`name` = 'binary'),NULL,`coll_result`.`name`) else NULL end) AS `COLLATION_NAME`,if((`rtn`.`type` <> 'FUNCTION'),NULL,`rtn`.`result_data_type_utf8`) AS `DTD_IDENTIFIER`,'SQL' AS `ROUTINE_BODY`,if(can_access_routine(`sch`.`name`,`rtn`.`name`,`rtn`.`type`,`rtn`.`definer`,true),`rtn`.`definition_utf8`,NULL) AS `ROUTINE_DEFINITION`,NULL AS `EXTERNAL_NAME`,`rtn`.`external_language` AS `EXTERNAL_LANGUAGE`,'SQL' AS `PARAMETER_STYLE`,if((`rtn`.`is_deterministic` = 0),'NO','YES') AS `IS_DETERMINISTIC`,`rtn`.`sql_data_access` AS `SQL_DATA_ACCESS`,NULL AS `SQL_PATH`,`rtn`.`security_type` AS `SECURITY_TYPE`,`rtn`.`created` AS `CREATED`,`rtn`.`last_altered` AS `LAST_ALTERED`,`rtn`.`sql_mode` AS `SQL_MODE`,`rtn`.`comment` AS `ROUTINE_COMMENT`,`rtn`.`definer` AS `DEFINER`,`cs_client`.`name` AS `CHARACTER_SET_CLIENT`,`coll_conn`.`name` AS `COLLATION_CONNECTION`,`coll_db`.`name` AS `DATABASE_COLLATION` from ((((((((`mysql`.`routines` `rtn` join `mysql`.`schemata` `sch` on((`rtn`.`schema_id` = `sch`.`id`))) join `mysql`.`catalogs` `cat` on((`cat`.`id` = `sch`.`catalog_id`))) join `mysql`.`collations` `coll_client` on((`coll_client`.`id` = `rtn`.`client_collation_id`))) join `mysql`.`character_sets` `cs_client` on((`cs_client`.`id` = `coll_client`.`character_set_id`))) join `mysql`.`collations` `coll_conn` on((`coll_conn`.`id` = `rtn`.`connection_collation_id`))) join `mysql`.`collations` `coll_db` on((`coll_db`.`id` = `rtn`.`schema_collation_id`))) left join `mysql`.`collations` `coll_result` on((`coll_result`.`id` = `rtn`.`result_collation_id`))) left join `mysql`.`character_sets` `cs_result` on((`cs_result`.`id` = `coll_result`.`character_set_id`))) where (0 <> can_access_routine(`sch`.`name`,`rtn`.`name`,`rtn`.`type`,`rtn`.`definer`,false))
character_set_client: utf8mb3
collation_connection: utf8mb3_general_ci
1 row in set (0.00 sec)

由视图的构建可知:

information_schema.routines是源于mysql.routines,在mysql.routines中存储的是client_collation_id(客户端排序规则),但在information_schema.routines中CHARACTER_SET_NAME 显示的不是client_collation_id(排序规则),而是其对应的字符集名称。

SQL 复制代码
information_schema.routines(CHARACTER_SET_CLIENT)
                                       ▲
                                       │  select  cs_client.name  AS CHARACTER_SET_CLIENT
mysql.character_sets(character_set_id,name)  cs_client
                      ▲  on  cs_client.id = coll_client.character_set_id
                      │
    mysql.collations(id)  coll_client
                      ▲  on  coll_client.id = rtn.client_collation_id
                      │
mysql.routines(client_collation_id)  rtn

2.3 处理方法

解决存储过程使用utf8mb4_0900_ai_ci(255)导致无法回流到MySQL 5.7的问题,可以在GreatDB中,在MySQL 5.7识别的character_set_client下,重新创建存储过程。

如:在utf8mb4_bin下重新创建存储过程:

SQL 复制代码
-- 1、设置会话的character_set_client
set names utf8mb4 collate utf8mb4_bin; 
-- 或者直接设置character_set_client
SET @@session.character_set_client=46; -- 排序规则utf8mb4_bin


-- 2、重新编译存储过程和函数
drop procedure xxxx ;
create procedure xxxx ....

3. 总结

由于GreatSQL与MySQL高度兼容,MySQL 5.7迁移到GreatSQL 8.0的步骤比较简单,可以使用GreatSQL 8.0软件可以直接打开MySQL 5.7的数据库文件,GreatSQL 8.0实例启动时会自动完成数据库字典的升级。

升级后,如果需要异步复制方式从GreatSQL 8.0回流到MySQL 5.7,请注意不能在GreatSQL 8.0执行MySQL5.7不识别的命令、不能使用MySQL 5.7 不识别的字符集和排序规则。由于升级后的存储程序(包括:存储过程procedure、函数function、自动调度事件event)中记录的排序规则是 utf8mb4 的默认排序规则utf8mb4_0900_ai_ci(编号255),属于MySQL 5.7不识别的排序规则,这些存储程序需要在MySQL 5.7识别的排序规则下重新创建。

相关推荐
数据库小学妹2 小时前
MySQL磁盘IO瓶颈:iostat与刷脏fsync
数据库·mysql·性能优化
Umi·3 小时前
MySQL之DQL使用实例
数据库·mysql
贾公子4 小时前
检测结果怎么落库——表结构、状态机与三类对账
后端·mysql
z06.4 小时前
Linux系统中MySQL的安装
linux·mysql
Small-Young5 小时前
数据库乐观锁深度解析:MySQL、PostgreSQL 实战 + Spring Boot 集成指南
数据库·spring boot·mysql·postgresql·乐观锁·并发控制
浮生若城5 小时前
MySQL 数据库基础
数据库·mysql
香蕉大香蕉(06敬畏市场)6 小时前
MySQL 单点详解(09)
java·数据库·mysql·面试·八股·大厂实习
lqbzlll7 小时前
MySQL 慢查询日志开了但看不懂?从 slow_query_log 到 EXPLAIN ANALYZE 一步步定位
数据库·mysql·adb