上一篇提出了一种改进主从延迟的方案。虽然能够实现主从无延迟同步,但在维护上比较复杂,还存在网络消耗问题,这里是一个改进的版本。
一、之前方案简述及问题分析
方案如图。其中用多个MySQL充当transfer的角色。每个transfer负责同步master的一部分表。在我的试验中有8个transfer,也就是有8个MySQL实例。
问题: 1、维护复杂。在从库及其上需要增加8个实例,增加维护成本,而且不利于加表操作。
2、增加网络开销。虽然在transfer的IO线程作了过滤,减少每个transfer的写盘量和SQL线程的空转,但master还是向每个tranfer发了所有的数据。网络传输的日志量是原来的n倍。
二、改进方案
基于上述的两个问题考虑,考虑将transfer的多进程改成多线程。
如图:
1、用一个MySQL充当transfer。 transfer设置为master的主库。IO线程负责接收Master传过来的日志。但不是写到一套relay-log文件,而是SLAVE_THREAD套。每个表的日志固定分配到一套relay-log中
2、相应地起SLAVE_THEAD个SQL线程,负责读取对应目录下的relaylog,发送给slave。
三、方案对比
从上面描述中看出,master发给transfer的日志总量只有一份。只需要增加SLAVE_THREAD 和 slave信息的配置,维护简单。
两个方案的相同点是使用文件队列(多套relaylog),保证在transfer出现异常时不丢数据。
效果对比,原生版本
上个方案
改进方案
说明:改进方案也能保证无延迟同步,性能都是原生版本的7倍左右。由于线程更少,从库的QPS表现很稳定,cpu idle也比上个方案高。
四、两个为什么
1、为什么不直接把transfer当slave用?
实际上是可以的,作了简单实验发现与“改进方案”的从库QPS相同,好处是减少了一层transfer的逻辑。一般来说这种工具也不会放到和slave一个机器,直接用作slave就少了一个机器。
不过直接改slave的代码还是推广比较麻烦。而且不得不承认的是,这个方案存在一个硬伤:跨表更新的语句顺序无法严格保证。――这也是这两个方案的应用前提:没有跨表语句或者对这种出现的情况要求不严格。
2、为什么不直接写一个工具而用MySQL?
其实作transfer的MySQL并不像想象的那么庞大。不需要的引擎可以都不编译进去,其实只需要框架层的逻辑和一个myisam引擎即可。而它提供了很多管理命令,比如一个现成的客户端,能够方便的stop slave、change master,能够用show slave status看同步状态。这些作为这个工具的基本功能,自己一个个实现重复*太多了。