ACMUG沙龙分享第二弹,今天主页君给大家分享一下来自腾讯游戏梁飞龙先生的《腾讯游戏MySQL数据一致性校验及在线修复实践》。



梁飞龙,腾讯游戏互动娱乐运营部/存储与计算资源中心任职游戏云存储开发组副组长及端游存储组副组长。(好长......)


前方高能预警

高技术贴有风险

下滑需谨慎




你果然是个有梦想的骚年

既然你坚持

那么


MySQL的主备数据会不一致吗?


存在一定的概率


– slave replication配置跳过了某些表,表引擎改为blackhole

– master-slave配置字符集不一致,utf8与gbk存在81个字符编码无法映射

http://bugs.mysql.com/bug.php?id=67739




– master机器故障导致slave追多了一个binlog event

– 开发或运维误连接slave进行误操作也有可能是一个因素

 


针对主备不一致问题目前业界是这样做的



– binlog_format设置为row模式

– master-slave采用半同步机制

– 5.7采用全同步机制?



有待确认

 

该如何判断master-slave数据是否一致


你可以这样做


When


– 业务停机,master、slave分别checksumtable

– 硬件环境:A5 32G内存、4raid5+8raid10 SAS硬盘


Do


 


不过看到– 200G / 5G * 64s = 2560s

要不要来包瓜子?



请洽洽到我们财务结一下广告费谢谢


 


当然

你也可以这样做


When


– 业务非停机,Master上逐表进行写锁定,Slave也做checksumtable

– 单表仍需写锁定,且时间为分钟级,随着数据量越大,锁表时间越长


Do

 

begin;

       locktables tt2 write; -- 以tt2表为例

       checksumtable tt2;

commit;

 

最后

你还可以这样做


When


– 业务非停机,按数据段(块)做数据校验,保证每个块执行时间足够短


Do



在线校验工具mk-table-checksum的雏形

 

SELECT 'test_checksum', 'tt2', 1 ASchunk_num, '`id` > 0 AND `id` < \'4\'', COUNT(*) AS cnt,

COALESCE(LOWER(CONV(BIT_XOR(CAST(CRC32(CONCAT_WS('#', `id`,`name`,

CONCAT(ISNULL(`name`)))) AS UNSIGNED)),10, 16)), 0) AS crc FROM `test_checksum`.`tt2` FORCE INDEX


(`PRIMARY`) WHERE (`id` > 0 AND `id` < '4')



 

那么讲到mk-table-checksum

它的Binlog顺序性及RR隔离级别的原理是这样的



– 在Master上执行下面两个语句,记录结果到checksum表


REPLACE/*test_checksum.tt2:2/7*/ INTO db_infobase.checksum(db, tbl, chunk,boundaries, this_cnt, this_crc) SELECT

'test_checksum', 'tt2', 1 AS chunk_num,'`id` > 0 AND `id` < \'4\'', COUNT(*) AS cnt,

COALESCE(LOWER(CONV(BIT_XOR(CAST(CRC32(CONCAT_WS('#', `id`,`name`, CONCAT(ISNULL(`name`)))) AS

UNSIGNED)), 10, 16)), 0) AS crc FROM`test_checksum`.`tt2` FORCE INDEX (`PRIMARY`) WHERE (`id` > 0 AND `id` <'4')


UPDATEdb_infobase.checksum SET master_crc = 'e2264bf4', master_cnt = '2' WHERE db = 'test_checksum' AND tbl= 'tt2' AND

chunk = ‘2’


– Slave 获取这两个binlog语句,然后在Slave上进行重放

– Slave 判断master_crc\this_crc,master_cnt\this_cnt是否相等

 

那么问题来了


在高并发场景下,如何保证一致性?


– 假设session1的replace info checksum表的SQL语句正在进行id>0 and id <4


这个数据段(块)的校验,如果此时有session2往该数据段中间插入一条id=2的记录会怎样?




如果session2事务先提交,则会导致master/slave数据的不一致;该情况下

master生成的binlog:

Session2: insert into tt2 (id, name)values(2, ‘liang’);

Session1: replace into db_infobase.checksumselect * from tt2 where id >0 and id< 4;


由于事务隔离性,master上的session1会话的replace对id=2的记录完全不可见;但slave里边由于binlog的顺序,replace语句是能看到id=2的记录的。此时校验存在逻辑性问题。



 

那么重点来了


MySQL可重复读隔离级别可避免session2先提交的问题


#session 1

begin;

REPLACE /*test_checksum.tt2:1/3*/ INTOdb_infobase.checksum(db, tbl,

chunk, boundaries, this_cnt, this_crc) SELECT'test_checksum', 'tt2', 0 AS

chunk_num, 'id >=1 and id < 4', COUNT(*) AS cnt,

LOWER(CONV(BIT_XOR(CAST(CRC32(CONCAT_WS('#', 'id','name'))

as UNSIGNED)), 10, 16)) AS crc FROM `test_checksum`.`tt2`where id

>=1 and id < 4;

commit;

#session 2

begin;

insert into tt2 values(2,‘liang’); -- 阻塞直到session1提交,这里因为session1对id>=1 and id<4上了锁,后面会讲到如何降低这个锁阻塞的时间

commit;



 


为什么

mk-table-checksum精确数据切分是很有必要的


原因如下



•数据分布不均会带来“”的问题




按数据分块的原理,5000M的表,chunk-size=10M时,只有两个区间包含数

据:第1个区间包含5行数据(id>=0 and id < 20),第500个区间包含1行数据

(id=10000000)。

•现网出现过100w行记录,在机械硬盘上跑校验SQL需要43秒!

 

具体方法在此



•源码改造两个核心函数的代码片段


_chunk_char_exact,引入辅助变量@i

qq#select `$args{chunk_col}` from $args{db}.$args{tbl} where (\@i :=\@i +1) > 0and (\@i

% $chunk_rows) = 1order by `$args{chunk_col}` asc #


recursive_dynamic_calculate_chunks,二分递归切分

"EXPLAINSELECT* FROM $db_tbl where $col >= " . $q->quote_val($from_pos) ." AND

$col< " . $q->quote_val($end_pos)


–增加参数:--chunk-size-excat=yes|no



那么有宝宝问了

发现了m-s数据不一致

为什么不重做slave


业务重做slave成本太高

周边统计有依赖/沟通成本



数据校验仅修复不一致的数据块


问我怎么办


马上用


pt-table-sync数据在线修复


 


数据修复源码改造原则


–利用校验的结果,只做差异性修复,不做全量数据重新比对

–修复SQL只能放到slave上执行(程序bug导致误修改数据)

–小粒度多次进行,尽可能保证每次修复在1秒钟

–限时控制以免影响现网服务(select for update锁)


数据修复的核心点


–同时在master-slave上加for update锁,每次处理一个范围

–表有唯一键

•逐行比较,M有S没有,生成insert语句

•逐行比较,M有S有但行不一致,生成delete + insert语句

•逐行比较,M没有S有,生成delete语句

–表有索引,但没有唯一键

•范围比较,M-S范围不一致即生成delete + insert语句


数据修复流程

腾讯游戏是这样做的


waterbinlin http://tencentdba.com/blog/tencent-game-data-self-healing/

 

再来看看MySQL M-S数据最终一致性的实践

 


•现状

–M-S的数据可能存在一定概率的过程不一致,但周期性一致


•应对策略


–流程上

•M提供读写、S只做备份或非关键路径的数据统计


–技术上

•全自动的数据校验及数据修复

–数据校验内置在DB监控程序,每天低峰期运行

–数据修复集成到自动化平台,DBA触发执行


•GCS-DBHA故障自动切换

–M-S数据一致性是切换的大前提

–数据不一致一定触发机器切换


•监控自动化检验, GCS游戏云存储输出校验结果


•DBA触发执行



话不多说

鼓掌

!!!

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐