JavaWDB 2018-08-10
为什么要做数据同步?因为数据很多,还要共享或做它用。举个栗子,你从移动硬盘拷贝一份小小电影到你的Macbook上赏析,也叫数据同步。但系统不比你的单纯,它使用的场景千奇百怪。数据同步,不管爱与不爱,你总会遇见,它会在某个时间等你,不见不散。
哎,不就是A到B么,一个管道,罩得住。
在进入正文之前,顺便给大家推荐一个Java架构方面的交流学习群:725633148,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。相信对于已经工作和遇到技术瓶颈的同学,在这个群里会有你需要的内容。有需要的同学请抓紧时间加入进来。
要在有限的时间里漂亮的完成工作,有时候你关注的并不一定是问题中心,深挖学习了binlog的同步方式,并不会对你的工作进度有任何改善。将它加入到研究列表中,空闲的时间去学习更佳,没必要非要把头闷在水里憋气去体验窒息的味道。好了,问题的中心数据同步,已经由阿里的工程师替你完成了,就叫Canal,解决的是最常用的MySQL数据库同步到别处的问题。今天我们谈一下Canal集成,但不谈Canal细节实现。周边建设别人不舍得告诉你,小姐姐和你聊。
Canal是将自己伪装成一个MySQL从库从其他真正的MySQL库上拉取信息,说白了就是实现了MySQL的一套协议,数据拿过来之后,想怎么把玩就怎么玩喽。东西是好东西,但github上的wiki文档让人看的昏昏欲睡,既然是谈架构,那我们就聊一下如何才能让工程师放心的使用你的Canal。
简单说下Canal的数据格式,根据github的官方文档就能够简单的RUN起来。Canal能够同步大多数DCL、DML、DDL,我们通常也就关心INSERT、UPDATE、DELETE引起的变化。那Canal解释的数据是什么样子呢,我们可以用一张图来说明。
可以看到UPDATE同时包括变更前和变更后的值,需要的信息就都有了。有了这些数据,上天入地,无所不能。
一个通用的架构模式就是只考虑输入和输出。使用者大多数并不关心你的系统是怎么实现的,大家都很忙,而且并不一定都有兴趣。他只需要你告诉他最终的使用方式和输出格式即可。
那么开发使用中有哪些元素需要参与呢?我们同样上一张图(仅考虑集群主从模式,单机和M/M不谈)。
很Easy是不是?ZK控制着HA,同时记录消费的消费进度,怎么看都和Kafka之流一个套路。但这里有几点要说明:
1) 为了保证binlog正常拉取,Canal服务器同时只有一台工作,其他都是影子 lol
2) 为了保证消费能正常进行,Client端同时只有一台能够工作,其他都是影子 lol
3) binlog推荐使用ROW模式,但有可能一个update语句挤爆你的内存、打碎你的蛋蛋
4) Canal本身没有持久化能力,非常耗内存
我们接下来按照顺序模拟它们的死亡。考虑下面一张图。
红色的区块都是可能死亡的点,ZK会死(当然它坚挺的很),MySQL会死,至于Canal,也肯定不能免俗,我们要让它的死轻如鸿毛。
小姐姐,提醒,架构要考虑到每一个交互场景和极端情况。准备的越细,觉睡的越香。除了让挑战你的无聊者碰一鼻子灰(对,就是那些整天将高可用挂在嘴上的货),也能节省更多时间研究些更有意义的事情。
ZK当机
ZooKeeper那么健壮,为什么还要模拟其当机呢?因为不排除机房断电的可能。为什么我们首先谈到ZK?从图中可以看到Zk死亡对系统的影响是巨大的。当然这仅仅是概率而已,最终会推断出SLA服务质量,满足需求即可。
当然不排除有某些强迫症的外部因素影响你去做它的高可用。除了分机房,你可以可以在代码中进行集成,比如ZK死亡,我们去直连Canal。你要考虑开发成本和达到的效益是否合适。
有些公司在屁都没做出来之前,就特别洁癖的关注低概率事件,问题本身倒成了次要的了。这种公司是有问题的,尽量去说服吧。
所以如果ZK当机问题占用你的工作量,主要是其他人的认知问题。
Canal当机
Canal集群模式已经通过ZK做了HA,你要做的,就是模拟一遍。包括:
1) 当机一台,是否有其他实例顶上来
2) 全部当机,上线一台后是否能正常运行
3) 长时间下线后,突然上线是否有其他问题?
4) 内存问题。canal非常耗内存,可以配置参数使其不溢出,但会产生阻塞。
Client当机
Client的当机其实是无所谓的。但由于实现的方式千奇百怪,也会产生千奇百怪的事情。本部分主要是使用方式问题,可以备注在注意事项里。我们通过代码来说明:
1) 代码有两层while循环,如果只有一层的话,会出问题的(想一想问什么)
2) 代码有ACK确认机制,代码显示的进行了确认和回滚。但如果你的处理是放在多线程里,那就有可能漏掉消息
3) 消息有batch,所以不可避免会出现重复消费的情况,你的业务支持幂等么?
MySQL当机
1) MySQL重新上线后Canal是否能够正常拉取binlog?
2) 主从切换后,是否需要修改Canal? 怎么补数据?
要将Canal用起来的话,它本身只能算是一个半成品。只有给它加上翅膀,它才能够自由飞翔。
MQ
考虑到Canal的堆积能力并不强。堆积数据到10W+时,速度会变慢,并会出现假死现象。另外一个场景,就是canal突然上线,这时候已经延后binlog很多了,重新连接后会一次性获取所有数据,卡到死为止~。
对于第一个场景,一个MQ介入是非常有必要的。Kafka等消息队列的堆积能力已经家喻户晓,我们要做的就是将Canal的数据进行一次转发。以后的客户端,打交道的就只有MQ了。MQ介入后,有以下好处:
1) 获得非常好的堆积能力,可以延后消费
2) 能够方便的得到积压数据,进行监控报警
3) 不比引入Canal客户端,客户端开发只与MQ打交道即可
4) MQ支持顺序消息,对于无时序数据而言,非顺序消息能增加处理能力
监控报警
每个节点都会出问题,所以每个节点都需要监控。监控系统也是每个公司的工具链,你可能需要写一些zabbix或者telegraf脚本进行数据收集(监控系统我们后续文章介绍)。
进程监控
监控各组件是否存活,java程序发生内存溢出死亡的概率还是很大的。如果想要进程死亡后自动重启,可以考虑采用supervisor组件。
BTW:如果你找不到进程的死亡原因,执行dmesg命令,大概率会看到死亡原因。
业务监控
1) MySQL binlog位置监控(show master status;)。
2) Canal到MQ的Sink消费位点监控。
3) 业务消费端对于MQ的消费延迟监控(delay)。
自动部署
一个好的持续集成工具能够大量减少上线时间和故障响应时间。此部分与各公司的工具链有关。比如可以使用ansible等命令行工具,也可以使用jenkins等。
这部分的工作量还是比较大的,尤其是当组件增多。有几个容易忽略的点需要考虑:
1) MySQL主从切换时,Canal的配置是否需要变动
2) 当单MySQL实例库表过多时,Canal是否需要分开部署,维护其拓扑结构
3) 各组件启动顺序问题,是否代码做了兼容能够支持
4) 数据同步需求是否线性增长,对应Topic的粒度支持
一个使用了第三方组件的数据同步中间件产品的建设过程,大体是分为以下6个阶段的。很多人还停留在搭起来就OK的阶段。除了搭建验证读源码或者是自己造轮子,还有很多额外的事情要做,这才是架构师应该关注的事情。
基础搭建使用
可以根据文档完成一个quickstart,并能初步应用到业务中。此时的服务基本上是裸跑,有比较多的风险。
API封装易用
根据自己的使用场景剔除或者增加部分功能,根据自己公司的编码和代码风格,编写定制易用的API。这可能是一个适配器,也可能是一个spring-starter等。还有一些坑需要进行屏蔽等,比如开源版本的Canal没有GTID等,呵呵。这个时候适当读下源码是非常有必要的。
整体高可用和应急方案
对于一个重量级的中间产品,此部分的重要度是不言而喻的。数据交互节点,每一个都应该是不信任的。仔细CHECK数据交互中的每一个节点,找出突发情况的应急方案。有条件的,需要线上反复演练,确保系统整体达到高可用。
报警运维机制
完成责任划分和应急处理人员,确保每一条报警信息都能快速响应,将故障影响面降低到最低。此部分涉及流程机制问题,作为架构师是有责任推进其完成的。
内部文档与系统集成
为了达到快速响应的目的,同时让产品更加平滑的加入到公司技术栈中,需要将其集成到公司内部系统中。比如定制的监控系统、继续集成系统等。同时,为了减少其他伙伴的学习使用成本,一个浅显易懂的文档也是必要的(不是doc哦)。对于使用中容易造成故障的点,也要指出,并不是每个人都和你一样聪明能干。
宣传应用检验阶段
如果对你的系统有信心,最大规模的使用去检验其鲁棒性是极好的。一些宣传和支持是必要的,相信到了此阶段,有大量的使用案例,不断的培养用户,对你系统的怀疑会不攻自破。
架构只是做技术么?这是狭义上的理解,技术是个敲门砖。广义上的架构包括技术、流程和人。转变这个观念,愿你的事业更上一层楼。