GreatSQL社区

搜索

[待回复] 主从复制1677,cannot be converted from type 'varchar(96(bytes))' 异常

193 6 4 天前
背景:

公司在做敏感信息加密存储的事情,加密后的字符串长度现在的字段长度放不下(当前:varchar(32)),需要扩充字段长度到varchar(255)。直接操作的话,当前场景Online DDL方式又不支持。一般情况下,为了不影响业务,让用户无感知,不影响使用体验,应当使用pt-osc或gh-ost这些开源工具来做,但是公司性质属于某企,使用的数据库使某云产品,现在杯具了!不允许使用这些开源工具。。。(xxoo),好吧。言归正传,没得办法,上面有要求只好采用备库扩充-HA切换-原主库扩充的方案了。现在备库扩充字段后遇到了 cannot be converted from type 'varchar(96(bytes))' to type 'varchar(765(bytes) utf8)' 错误。过程如下:

备库上临时关闭binlog写入

mysql> set session sql_log_bin=0;
Query OK, 0 rows affected (0.00 sec)


mysql> ALTER TABLE user_base_064 MODIFY COLUMN bank_account VARCHAR(255) DEFAULT NULL COMMENT 'ceshi-account';
Query OK, 368570 rows affected (25.64 sec)
Records: 368570  Duplicates: 0  Warnings: 0



ok,备库操作完毕,HA切换前先检查一波复制延迟情况,然后悲剧了。复制出现了异常。
01.png

检查了error.log发现报错信息
2025-03-27T16:48:41.047694+08:00 600 [ERROR] Slave SQL for channel '': Worker 1 failed executing transaction '498a666b-58cd-11ec-8c73-e8611f2a1bfb:84027231' at master log mysql-bin.004836, end_log_pos 15449089; Column 15 of table 'clw_user_okvo_0016.user_base_064' cannot be converted from type 'varchar(96(bytes))' to type 'varchar(765(bytes) utf8)', Error_code: 1677


好吧,去检查下回放relay log哪个事务异常了
mysqlbinlog -vv --base64-output=decode-rows slave-relay.000006 | less
SET @@SESSION.GTID_NEXT= '498a666b-58cd-11ec-8c73-e8611f2a1bfb:84027231'/*!*/;
# at 6930
#250327 16:47:01 server id 694425475  end_log_pos 15448785 CRC32 0x750e6776     Query   thread_id=17152062      exec_time=0     error_code=0
SET TIMESTAMP=1743065221/*!*/;
BEGIN
/*!*/;
# at 7016
#250327 16:47:01 server id 694425475  end_log_pos 15448954 CRC32 0x1b549b94     Table_map: `clw_user_okvo_0016`.`user_base_064` mapped to number 161
# at 7185
#250327 16:47:01 server id 694425475  end_log_pos 15449089 CRC32 0x7533c912     Write_rows: table id 161 flags: STMT_END_F
### INSERT INTO `clw_user_okvo_0016`.`user_base_064`
### SET
###   @1=228850496 /* LONGINT meta=0 nullable=0 is_null=0 */
###   @2=NULL /* LONGINT meta=96 nullable=1 is_null=1 */
###   @3=NULL /* LONGINT meta=0 nullable=1 is_null=1 */
###   @4=NULL /* LONGINT meta=18 nullable=1 is_null=1 */
###   @5='2' /* VARSTRING(18) meta=18 nullable=1 is_null=0 */
###   @6='80103864118|2006916' /* VARSTRING(765) meta=765 nullable=1 is_null=0 */
###   @7=NULL /* VARSTRING(765) meta=96 nullable=1 is_null=1 */
###   @8=NULL /* VARSTRING(765) meta=96 nullable=1 is_null=1 */
###   @9=NULL /* VARSTRING(765) meta=765 nullable=1 is_null=1 */
###   @10='80103864118' /* VARSTRING(3000) meta=3000 nullable=1 is_null=0 */
###   @11='2006916' /* VARSTRING(96) meta=96 nullable=1 is_null=0 */
###   @12=118 /* INT meta=0 nullable=1 is_null=0 */
###   @13='2025-03-08 08:15:51' /* DATETIME(0) meta=0 nullable=1 is_null=0 */
###   @14=0 /* INT meta=0 nullable=1 is_null=0 */
###   @15=NULL /* INT meta=96 nullable=1 is_null=1 */
###   @16=NULL /* INT meta=96 nullable=1 is_null=1 */
###   @17=NULL /* INT meta=96 nullable=1 is_null=1 */
###   @18=NULL /* INT meta=96 nullable=1 is_null=1 */
###   @19=NULL /* INT meta=18 nullable=1 is_null=1 */
###   @20=NULL /* INT meta=0 nullable=1 is_null=1 */
###   @21=NULL /* INT meta=24 nullable=1 is_null=1 */
###   @22=NULL /* INT meta=384 nullable=1 is_null=1 */
###   @23=1 /* INT meta=0 nullable=1 is_null=0 */
###   @24=NULL /* INT meta=96 nullable=1 is_null=1 */
###   @25=NULL /* INT meta=384 nullable=1 is_null=1 */
###   @26=NULL /* INT meta=0 nullable=1 is_null=1 */
###   @27=0 /* INT meta=0 nullable=1 is_null=0 */
###   @28=1 /* INT meta=0 nullable=1 is_null=0 */
###   @29=NULL /* INT meta=96 nullable=1 is_null=1 */
###   @30=NULL /* INT meta=96 nullable=1 is_null=1 */
###   @31=NULL /* INT meta=96 nullable=1 is_null=1 */
###   @32=NULL /* INT meta=96 nullable=1 is_null=1 */
###   @33='2025-03-08 08:15:51' /* DATETIME(0) meta=0 nullable=1 is_null=0 */
###   @34=NULL /* DATETIME(0) meta=0 nullable=1 is_null=1 */
###   @35='2025-03-08 08:15:51' /* DATETIME(0) meta=0 nullable=1 is_null=0 */
###   @36=1 /* INT meta=0 nullable=1 is_null=0 */
###   @37=NULL /* INT meta=765 nullable=1 is_null=1 */
###   @38=NULL /* INT meta=0 nullable=1 is_null=1 */
###   @39=NULL /* INT meta=48 nullable=1 is_null=1 */
###   @40=NULL /* INT meta=192 nullable=1 is_null=1 */
###   @41=NULL /* INT meta=0 nullable=1 is_null=1 */
# at 7320
#250327 16:47:01 server id 694425475  end_log_pos 15449120 CRC32 0xf5f6b3ba     Xid = 4956006199
COMMIT/*!*/;


又通过审计日志查到了原始的SQL语句
replace INTO user_base ( user_type, phone, password, ou_code, reg_channel, reg_time, is_id_checked, user_state, is_internal_employee, is_order_charge, create_time, update_time, state ) VALUES ( '2', '80103864118|2006916', '80103864118', '2006916', 118, '2025-03-08 08:15:50.623', 0, 1, 0, 1, '2025-03-08 08:15:50.623', '2025-03-08 08:15:50.623', 1 ) ;

又检查了主备库的表结构情况,字符集,数据库版本等情况,完全一致。表结构如下:
CREATE TABLE `user_base` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT ,
  `user_code` varchar(32) DEFAULT NULL,
  `merge_userid` bigint(20) DEFAULT NULL,
  `merge_type` varchar(6) DEFAULT NULL,
  `user_type` varchar(6) DEFAULT NULL,
  `phone` varchar(255) DEFAULT NULL,
  `login_alias` varchar(32) DEFAULT NULL,
  `user_name` varchar(32) DEFAULT NULL,
  `real_name` varchar(255) DEFAULT NULL,
  `password` varchar(1000) DEFAULT NULL,
  `ou_code` varchar(32) DEFAULT NULL,
  `reg_channel` int(6) DEFAULT NULL,
  `reg_time` datetime DEFAULT CURRENT_TIMESTAMP,
  `is_id_checked` int(6) DEFAULT '0',
  `bank_code` varchar(32) DEFAULT NULL,
  `bank_account` varchar(32) DEFAULT NULL,
  `bank_account_no` varchar(32) DEFAULT NULL,
  `bank_account_phone` varchar(32) DEFAULT NULL,
  `user_level` varchar(6) DEFAULT NULL,
  `cancel_time` datetime DEFAULT NULL,
  `cancel_reason` varchar(8) DEFAULT NULL,
  `cancel_content` varchar(128) DEFAULT NULL,
  `user_state` int(6) DEFAULT '1',
  `record_phone` varchar(32) DEFAULT NULL,
  `token` varchar(128) DEFAULT NULL,
  `operator_id` int(11) DEFAULT NULL,
  `is_internal_employee` int(6) DEFAULT '0',
  `is_order_charge` int(6) DEFAULT '1',
  `referee_name` varchar(32) DEFAULT NULL,
  `referee_phone` varchar(32) DEFAULT NULL,
  `referee_unit` varchar(32) DEFAULT NULL,
  `build_operator` varchar(32) DEFAULT NULL,
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP ,
  `updater` int(11) DEFAULT NULL ,
  `update_time` datetime DEFAULT NULL ,
  `state` int(6) DEFAULT '1' ,
  `remark` varchar(255) DEFAULT NULL ,
  `is_proprietary_merchant` int(6) DEFAULT NULL ,
  `stop_code` varchar(16) DEFAULT NULL,
  `corp_bank` varchar(64) DEFAULT NULL ,
  `channel_type` int(6) DEFAULT NULL ,
  PRIMARY KEY (`id`),
  KEY `phone` (`phone`),
  KEY `login_alias` (`login_alias`),
  KEY `token` (`token`),
  KEY `Phone_UserType` (`phone`,`user_type`),
  KEY `oucode` (`ou_code`) USING BTREE,
  KEY `oucode_usertype` (`user_type`,`ou_code`) USING BTREE,
  KEY `ubase_uptime_id` (`update_time`),
  KEY `reg_time_ind` (`reg_time`),
  KEY `phone_ind` (`phone`),
  KEY `reg_channel_ind` (`reg_channel`),
  KEY `id_type_ind` (`id`,`user_type`)
) ENGINE=InnoDB AUTO_INCREMENT=228874244 DEFAULT CHARSET=utf8;

之前,作者多使用gh-ost或gh-ost工具,再不济了使用Online DDL方式,备库操作-HA切换方式接触不多,现在请求各方大佬给点提示,需要往哪方面注意下。不胜感激!


全部回复(6)
yejr 3 天前
受限,varchar类型从30扩展到255应该是可以支持online ddl的

其次,你遇到这个报错,大概率是主从服务器的字符集(或校验集)设置不一致,可以从server层、database层、table层、字段层、连接层等多个角度分别排查下
lizibin 3 天前
yejr 发表于 2025-3-28 10:24
受限,varchar类型从30扩展到255应该是可以支持online ddl的

其次,你遇到这个报错,大概率是主从服务器的 ...

叶老师,varchar(30) -> varchar(255),使用的是utf8字符集,跨越了255字节分界线,Online 方式会返回not support xxx的错误信息。
这个问题也排查到了原因,进行了复现,是slave_type_conversions参数设置为空的原因。设置为ALL_NON_LOSSY就OK了。
yejr 3 天前
lizibin 发表于 2025-3-28 17:29
叶老师,varchar(30) -> varchar(255),使用的是utf8字符集,跨越了255字节分界线,Online 方式会返回not ...

临时设置 slave_type_conversions = ALL_NON_LOSSY 看起来似乎可行,但从本上还是要保证主从字符集、校验集及表结构全部一致的吧。

你的主从环境为啥会出现不一致的问题呢。
lizibin 3 天前
yejr 发表于 2025-3-28 17:39
临时设置 slave_type_conversions = ALL_NON_LOSSY 看起来似乎可行,但从本上还是要保证主从字符集、校验 ...

字符集这些核对过是一致的。主从为啥不一致,是因为要扩字段,在主库上操作会锁表,只能备库操作-HA切换这样子进行,备库上不加这个参数就复制异常了。
yejr 3 天前
lizibin 发表于 2025-3-28 18:54
字符集这些核对过是一致的。主从为啥不一致,是因为要扩字段,在主库上操作会锁表,只能备库操作-HA切换 ...

终于看明白了,为啥某企就不让用开源的第三方工具呢
reddey 前天 09:43
当前场景不支持在线DDL,又不让用第三方开源工具。
一个学艺不精的国产数据库爱好者
lizibin

10

主题

0

博客

69

贡献

注册会员

Rank: 2

积分
100

助人为乐(铜)

合作电话:010-64087828

社区邮箱:greatsql@greatdb.com

社区公众号
社区小助手
QQ群
GMT+8, 2025-3-31 06:42 , Processed in 0.025436 second(s), 20 queries , Redis On.
快速回复 返回顶部 返回列表