讲师介绍数据库
陈永庭,饿了么框架工具部高级架构师,主要负责MySQL异地双向数据复制,支撑饿了么异地多活项目。曾就任于WebEx、Cisco、腾讯等公司。后端
今天我主要分享饿了么多活的底层数据实施,会和你们介绍在整个多活的设计和实施过程当中咱们是怎么处理异地数据同步的,而这个数据同步组件在咱们公司内部称之为DRC。安全
异地多活背景服务器
在讲DRC或者讲数据复制以前,先跟你们回顾一下异地多活的背景。数据结构
去年咱们在作多活调研的时候,整个公司全部的业务服务都是部署在北京机房,服务器大概有四千多台,灾备的机器是在云端,都是虚拟机,大概有三千多台。当时咱们峰值的业务订单数量已经接近了千万级别,可是基本上北京机房(IDC)已经没法再扩容了,也就是说咱们没有空余的机架,没有办法添加新的服务器了,必需要再建一个新的机房,因而咱们在上海建一个新的机房,上海机房要在今年的4月份才会投入使用,因此须要在上海机房建成以后,异地多活项目能具有在生产环境上进行灰度。架构
异地多活的底层数据同步实施并发
这是异地多活的底层数据同步实施的一个简单的概要图,你们能够看到,咱们有两个机房,一个是北京机房,一个是上海机房。在这个时候,咱们指望目标是北方全部的用户请求、用户流量所有进入北京机房,南方全部的用户请求、用户流量进入上海机房。困难的地方是,这个用户有可能今天在北方,明天在南方,由于他在出差,还有就是存在一些区域在咱们划分南北shard的时候,它是在边界上面的,这种状况会加重同一个用户流量在南北机房来回漂移的发生。还有个状况,当咱们某个机房出现故障,如核心交换机坏掉致使整个机房服务不可用,咱们但愿能够把这个机房的全部流量快速切到另外的数据中心去,从而提升整个饿了么服务的高可用性。框架
以上全部的因素,都须要底层数据库的数据之间是打通的。而今天我所要分享的DRC项目就是饿了么异地MySQL数据库双向复制的组件服务,即上图中红色框标记的部分。运维
异地多活对底层数据的要求工具
咱们在前期调研DRC实现的时候,主要总结了的三点,而在后续的设计和实施当中,基本上也是围绕这三点来去解决问题。
第一个咱们以为是延迟要低,当时给本身定的目标是秒级的,咱们但愿在北京机房或上海机房写入的数据,须要在1秒钟以内同步到上海或者北京机房。整个延迟要小于1秒钟。
第二个就是咱们要确保数据的一致性,数据是不能丢也不能错的,若是出现数据的不一致性,可能会给上层的业务服务、甚至给产品带来灾难性的问题。
第三个就是保证整个复制组件具有高吞吐处理能力,指的是它能够面对各类复杂的环境,比方说业务正在进行数据的批量操做、数据的维护、数据字典的变动状况,这些会产生瞬间大量的变动数据,DRC须要面对这种状况,须要具有高吞吐能力去扛住这些状况。
数据低延迟和一致性之间,咱们认为主要从数据的并发复制这个策略上去解决,安全、可靠、高效的并发策略,才能保证数据是低延迟的复制,在大量数据须要复制时,DRC并发处理才能快速在短期内解决。数据一致性,用户的流量可能被路由到两个机房的任何一个机房去,也就是说一样一条记录可能在两个机房中被同时更改,因此DRC须要作数据冲突处理,最终保持数据一致性,也就是数据不能出错。若是出现冲突且DRC自身没法自动处理冲突,咱们还提供了一套数据冲突订正平台,会要求业务方一道来制定数据订正规则。
高吞吐刚才已经介绍了,正常状况用户流量是平稳的,DRC是能应对的,在1秒钟以内将数据快速复制到对端机房。当DBA对数据库数据进行数据归档、大表DDL等操做时,这些操做会在短期内快速产生大量的变动数据须要咱们复制,这些数据可能远远超出了DRC的最大处理能力,最终会致使DRC复制出现延迟,因此DRC与现有的DBA系统须要进行交互,提供一种弹性的数据归档机制,如当DRC出现大的复制延迟时,终止归档JOB,控制每轮归档的数据规模。如DRC识别属于大表DDL产生的binlog events,过滤掉这些events,避免这些数据被传输到其余机房,占用机房间带宽资源。
以上是咱们在实施异地多活的数据层双向复制时对DRC项目提出的主要要求。
数据集群规模(多活改造前)
这是咱们在作多活以前的北京数据中心的数据规模,这个数据中心当时有超过250套MySQL的集群,一千多台MySQL的实例,Redis也超过四百个集群。
DRC服务的目标对象就是这250套MySQL集群,由于在正在建设的第二个数据中内心将来也会有对应的250套MySQL集群,咱们须要把两个机房业务对等的集群进行数据打通。
多活下MySQL的用途分类
咱们按照业务的用途,给它划分了多种DB服务类型。为何要总结这个呢?由于有一些类型,咱们是不须要复制的,因此要甄别出来,首先第一个多活DB,咱们认为它的服务须要作多活的。
比方说支付、订单、下单,一个机房挂了,用户流量切到另外新的机房,这些业务服务在新的机房是工做的。咱们把这些多活服务依赖的DB称为多活DB,咱们优先让业务把DB改形成多活DB,DRC对多活DB进行数据双向复制,保障数据一致性。多活DB的优点刚才已经讲了,若是机房出现故障、核心交换机出问题,整个机房垮了,运维人员登不进机房机器,那么咱们能够在云端就把用户流量切到其它的机房。有些业务对数据有强一致性要求,后面我会讲到其实DRC是没有办法作到数据的强一致性要求的,它是有数据冲突发生的,须要引入数据订正措施。
业务若是对数据有强一致性要求,比方说用户注册,要求用户登陆名全局惟一(DB字段上可能加了惟一约束),两个机房可能会在同一时间接收了相同用户登陆名的注册请求,这种状况下,DRC是没法自身解决掉这个冲突,并且业务方对这个结果也是没法接受的,这种DB咱们会把它概括到GlobalDB里面,它的特性是什么呢?
它的特性是单机房可写,多机房可读,由于你要保证数据的强一致性的话,必须让全部机房的请求处理结果,最终写到固定的一个机房中。这种DB的上层业务服务,在机房挂掉以后是有损的。比方说机房挂了,用户注册功能可能就不能使用了。
最后一个非多活DB,它是不多的,主要集中于一些后端的管理平台,这种项目自己基本上不是多活的,因此这种DB咱们不动它,仍是采用原生的主备方式。
DRC整体架构设计
这是DRC复制组件的整体架构设计。咱们有一个组件叫Replicator,它会从MySQL集群的Master上把binlog日志记录抽取出来,解析binlog记录并转换成咱们自定义的数据,存放到一个超大的event buffer里面,event buffer支持TB级别的容量。
在目标机房里咱们会部署一个Applier服务,这个服务启一个TCP长链接到Replicator服务,Replicator会不断的推送数据到Applier,Applier经过JDBC最终把数据写入到目标数据库。咱们会经过一个Console控制节点来进行配置管理、部署管理以及进行各个组件的HA协调工做。
DRC Replicator Server
这是DRC Replicator Server组件比较细的结构描述,主要是包含了一个MetaDB模块,MetaDB主要用来解决历史的Binlog的解析问题。
咱们成功解析Binlog记录以后,会把它转换成咱们本身定义的一种数据结构,这种结构相对于原生的结构,Size更小,MySQL binlog event的定义在size角度上考虑事实上已经很极致了,可是能够结合咱们本身的特性,咱们会把不须要的event所有过滤掉(如table_map_event),把能够忽略的数据所有忽略掉。咱们比对的结果是须要复制的event数据只有原始数据size的70%。
DRC Applier Server
往目标的MySQL集群复制写的时候,由DRC Applier Server负责,它会建一个长链接到Replicator上去,Replicator PUSH数据给Applier。Applier把数据拿到以后作事务的还原,最后经过JDBC把事务从新写到目标DB里面,写的过程中,咱们应用了并发的策略。
并发策略在提供复制吞吐能力,下降复制延迟起到决定的做用,还有幂等也是很是重要的,后面有不少运维操做,还有一些Failover回退操做,会致使发生数据被重复处理的状况,幂等操做保障重复处理数据不会发生问题。
DRC防止循环复制
在作复制的时候,你们确定会碰到解决循环复制的问题。咱们在考虑这个问题的时候,查了不少资料,也问了不少一些作过相似项目的前辈,当时咱们认为有两大类办法,第一大类办法一开始否决了,由于咱们对MySQL的内核原码不熟悉,并且时间上也来不及,虽然咱们知道经过MySQL的核内解决回路复制是最佳的、最优的。
靠DRC自身解决这个问题,也有两种办法,一种办法是咱们在Apply数据到目标DB的时候把binlog关闭掉,另一种办法就是写目标DB的时候在事物中额外增长checkpoint表的数据,用于记录源DB的server_id。
后来咱们比较了一下,第一个办法是比较简单,实现容易,可是由于Binlog记录没有产生,致使不支持级联复制,也对后续的运维带来麻烦。因此咱们最后选择的是第二个办法,经过把事务往目标DB复制的时候,在事务中hack一条checkpoint的数据来标识事务产生的原始server,DRC在解析MySQL binlog记录时就能正确分辨出数据的真正来源。
DRC数据一致性保障
在刚开始研发、设计的时候,数据一致性保障是咱们很头疼的问题。并非在一开始就把全部的点都想全了,是在作的过程中出现了问题,一步步解决的,回顾一下,咱们大概从三个方面去保证数据的一致性:
首先,由于数据库是多活的,咱们必须从数据中心层面尽量把数据冲突发生的几率降到最低,避免冲突,怎么避免呢?就是合理的流量切分,你能够按照用户的维度,按照地域的维度,对流量进行拆分。刚才咱们讲的,北方用户的全部数据在北京机房,这些北方用户的下单、支付等的全部操做数据都是在北方机房产生的,因此用户在同一个机房中发生的数据变动操做绝对是安全的。咱们最怕的是同一个数据同时或者是在相近的时间里同时在两个机房被修改,咱们怕的是这个问题,由于这种状况就会引起数据冲突。因此咱们经过合理的流量切分,保证绝大部分时候数据是不会冲突的。
第二个咱们认为你要保障数据一致性,首先你要确保数据不丢,一旦发生可能数据丢失的状况,咱们会作一个比较保险的策略,就是把数据复制的时间位置回退,即便重复处理数据,也避免丢数据的可能,可是这个时候会带来数据重复处理的问题,因此数据的幂等操做特别重要。
这些都是咱们避免数据发生冲突的方法,那冲突其实是不可避免的,冲突发生后,咱们怎么解决?最终采用的办法是在数据库表上隐含地加一个时间字段(数据最后更新时间),这个字段对业务是透明的,主要用来辅助DRC复制,一旦数据发生冲突,DRC复制组件能够经过这个时间来判断两个机房或者三个机房中的哪条数据是最后被更新的,最新优先的原则,谁最后的修改时间是最新的,就以它为准。
DRC数据复制低延迟保障
刚才咱们讲的是数据的一致性,还有一个点很是重要,就是数据复制的低延迟保障。咱们如今延迟包括用户高峰时间也是小于1秒的,只有在凌晨以后,各类归档、批量数据处理、DDL变动等操做会致使DRC延迟出现毛刺和抖动。若是你的延迟很高的话,第一在作流量切换时,由于运维优先保障产品服务的可用性,在不得以的状况会不考虑你的复制延迟,不会等数据复制追平以后再切流量,因此你的数据冲突的几率就变的很大。
为了保证复制低延迟,咱们认为主要策略、或者你在实施时主要的作法仍是并发,由于你只有用高效的安全的并发复制策略,服务才有足够的吞吐处理能力,而不至于你的复制通道由于遇到“海量”数据而致使数据积压,从而加重了复制延迟的产生。
咱们一开始采用的基于表级别的并发,可是表级别的并发在不少状况下,并发策略没办法被有效的利用,比方说有的业务线的数据库可能90%的数据集中在一张表或者是几个表里面,而大部分表数据量很小,那基于表的并发策略就并发不起来了。咱们如今跑的是基于行级别的并发,这种并发它更能容忍和适应不少场景。
DRC & MySQL Master切换
这个是DRC复制组件与MySQL集群的关系关联图,一旦MySQL集群里面的Master发生了主备切换,原来的Master挂了,DRC怎么处理?目前的解决方案是DBA系统的MHA工具会通知DRC控制中心,DRC的控制中心会找到对应的复制链路,而后把复制链路从老的Master切到新的Master,可是关键点是MHA在通知以前先把老的Master设置为不可写,阻断DRC可能往老的Master继续写数据。
DRC线上运行情况(规模)
这个是咱们DRC上线以后的运行情况。如今大概有有将近400多条复制链路。这个复制链路是指单向的链路。咱们提供的消息订阅大概有17个业务方接入,天天产生超过1亿条的消息。
DRC线上运行情况(性能)
这是DRC线上运行的一个性能监控快照,咱们能够看到,它是上午11点多到12点多的一个小时的性能,你会发现其实有一个DB是有毛刺的,有一个复制链路有毛刺,复制延迟最高达到4s,可是大部分的复制链路的延迟大概也是在1秒或1秒如下。
个人分享到此结束了,谢谢你们。
Q&A
**Q1:**你好,想问一下饿了么是怎么避免各个机房中的PK冲突的?
**A1:**主键自增的步长在各个机房中是固定相同的,可是每一个机房的增加offset是不一样的,因此不会出现PK冲突。
**Q2:**DRC复制会不会对目标数据库形成性能影响?
**A2:**有影响。由于DRC会占用目标DB的IOPS。DRC Apply自己就是目标DB的上层服务。
**Q3:**DRC Applier采用JDBC去写目标DB,除了这个办法还有其它途径吗?
**A3:**目前咱们分析binlog还原事务,而后经过JDBC把事务写到目标DB。咱们曾经模拟过MySQL的binlog server,让目标DB启动一个Replication链接到咱们伪造的binlog server上,咱们的binlog server会把binlog记录发给目标DB,这个办法会存在不少问题,咱们就放弃了这个办法。
**Q4:**有监测数据一致性的工具吗?
**A4:**这个是有的。DBA团队开发了一套checksum工具来实时监测数据一致性。
**Q5:**饿了么作异地双活主要的缘由就是刚刚提到的单个机房是没法扩容吗?
**A5:**是的。
**Q6:**双向同步后期的运维成本高吗?
**A6:**对DBA的运维会形成影响,DBA的归档job、DDL发布等操做都须要考虑DRC的双向同步因素。
End.