关于otter高可用在设计之初,提供了这样几个基本的需求:
1.网络不可靠,异地机房尤为明显.
2.manager/node的jvm不可靠,需要考虑异常crash情况
3.node的jvm不可靠,需要考虑异常crash的情况
4.数据库不可靠,需要考虑数据库切换,比如binlog获取和数据载入时,都需要考虑数据库HA机制
5.系统发布时,排除正常的jvm关闭和启动
接下来我们一起看看为了实现这些需求,otter研发团队做了哪些方面的努力;
一、部署上
首先otter manager和node节点分开部署,node节点负责完成真正的同步任务,同时自身汇总同步任务统计数据,将统计数据推送给manager,由manager完成统计数据的落库,node节点除了在首次启用时需要获取manager上的配置信息外,后续的同步任务不再依赖于manager;所以node节点的同步任务可以说是独立于manager了,所以启动后后续的任务理论上不受manager影响。
其次manager在otter的架构中主要是完成同步任务配置管理、同步进度收集逻辑查阅、数据源维护、系统信息维护、cannal维护等等,相当于一个后台管理系统。
二、完善的异常处理机制(引用otter官方)
otter调度系统在设计的时候,会有个假定,认为90%的情况都是正常工作的,所以一旦出现异常处理的代价相对比较高,会使用分布式锁机制。
仲裁器设计了三种异常机制指令:
(1)WARNING : 只发送报警信息,不做任何S/E/T/L调度干预
(2)ROLLBACK : 尝试获取分布式锁,避免并发修改,其次修改分布式Permit为false,停止后续的所有S/E/T/L调度,然后删除所有当前process调度信息,通过zookeeper watcher通知所有相关node,清理对应process的上下文,Pipeline的数据存储会通过TTL来进行清理,不需要ROLLBACK干预。完成后,释放锁操作
(3)RESTART : 前面几个步骤和ROLLBACK基本类似,唯一不同点在于,在释放锁之前会尝试修改分布式Permit为true,重新开启同步,然后释放锁.
罗列了一下不同异常对应的处理机制:
两个节点通讯时网络异常,节点发起ROLLBACK
节点执行S/E/T/L模块,比如写数据库出现网络异常,节点发起ROLLBACK
节点发生了CRASH,由manager进行监听,manager发现后发起RESTART
三、manager监控
manager对node的节点监控室基于zookeeper的发布定于机制,node节点在启动时会在zookeeper上创建node的临时节点信息,manager会订阅node节点变化,若出现临时节点被删除的事件,会触发manager上的异常告警处理机制,在异常处理机制中会尝试重启对应的同步任务。
manager还支持多种监控配置,比如延迟、Pipeline延迟、Position延迟......,详情可参考我的另外一篇关于otter监控的博文:关于otter监控告警使用-CSDN博客
四、 支持数据库切换
otter内部配置中称之为主备配置(media配置),为一对主备IP,定义一个groupKey。然后在各个地方使用该groupKey。
1.比如jdbc url使用group后为:jdbc:mysql://groupKey=xxxx
2.canal中可以选择HA机制为media,然后填入对应的groupKey即可
3.切换后需要1分钟或者node重启生效(HA机制需要开启心跳)
在需要切换时,在主备设置列表页面点击切换就可以可以完成对应的操作。
五、otter中node节点的负载均衡机制
otter支持三种负载均衡机制:
1)Random : 随机算法
2)RoundRbin : 轮询算法
3)Stick : 类似于session stick技术,一旦第一次选择了node,下一次选择会继续使用该node. (有一个好处,资源上下文缓存命中率高).
注意点:每个node节点,都会在zookeeper中生成Ephemeral节点,每个node都会缓存住当前存活的node列表,node节点消失,通过zookeeper watcher机制刷新每个node机器的内存。然后针对每次负载均衡选择时只针对当前存活的节点,保证调度的可靠性。
负载均衡机制是node节点在执行一个stage数据处理前,就会提提前获取当前存活的所有node(缓存中获取)节点,然后这些可用的node节点会根据Pipeline配置的负载均衡算法选出最终执行下一个节点的node然后再处理完成后推送给下一个node执行。