一次由于字符集问题引发的MySQL主从同步不一致问题追查

 

近期业务准备上线一个新功能,灌入数据之后突然发现主从同步停止,报错如下:

Error 'Duplicate entry '66310984-2014-04-18 00:00:00--122815.sh' for key 'PRIMARY'' on query. Default database: 'bill'. Query: 'INSERT INTOBOND3311(OBJECTID,BONDID,BONDNAME,DECLAREDATE,F001D,F002D,F003N,F004N,F005D,F006D,F007D,F008D,MEMO,RECTIME,MODTIME,ISVALID,F009N,SEQID,SECNAME,F010N,F014V,F011D,F013N,SECCODE)VALUES(0x373236313333373339,0x3636333130393834,0x32303131C4EAD0C2BDAEB9E3BBE3CAB5D2B5CDB6D7CA28BCAFCDC529D3D0CFDED4F0C8CEB9ABCBBEB9ABCBBED5AEC8AF,'2014-04-14 00:00:00',NULL,NULL,0x352E3833,0x35382E33,'2014-04-18 00:00:00',NULL,NULL,NULL,0xBBD8CADBB2BFB7D6B6D2B8B6,'2014-04-14 13:48:56','2014-04-14 13:48:56',0x31,0x3230,0x31373430333831393837,0x3131B9E3BBE3D5AE,0x352E3833,0xB6D2B8B6,'2014-04-21 00:00:00',0x3130352E3833,0x3132323831352E7368)'

从报错信息可以看到,很多ID(int类型)字段的values被转换成了ASCII码执行,这也就导致了同步的中断。第一反应是字符集问题,由于MySQL的字符集设置有多个参数,而在使用中文的时候,字符集的转换会受到cline,connection,server,table都多处字符集的影响,所以经常会有一些乱码的情况出现。

于是我们先去检查主库的数据是否正常写入,结果是正常的。然后根据如下结构:

cline ——> master ——> slave

既然主库数据写入正常,那么只能怀疑在master和slave做replication的时候发生了字符的转义,导致了上述情况发生。我们先后检查了如下参数设置,全部都一致。

  • 表字符集设置
  • server的字符集设置
  • 数据库版本
  • sql mode

如此诡异的问题,只好求助万能的搜索引擎了,最终找到如下这篇blog,解释的非常清晰。按照blog中的解释,这个问题发生的前提有2个:

  • 程序使用prepared statement
  • 字符集使用多字节字符集,比如GBK

根据博客中提供的解决方案,我们先将同步中止,修改binlog format,然后将主库的数据复制到从库中保证数据一致性,在开启同步,最终问题得以解决。

ps:如此诡异的问题,真是不遇到不知道,这才是赤裸裸的经验问题。

posted @ 2015-01-11 10:49  billy鹏  阅读(1606)  评论(0编辑  收藏  举报