作者|Roy,携程软件技术专家,负责MySQL双向同步DRC和数据库访问中间件DAL的开发和演进,具有高可用设计感,分布式存储,和分布式系统中数据一致性的兴趣。一、前言在携程国际化战略背景下,海外业务将成为新的关注点。为了保证用户优质的服务体验,底层数据必须就近服务。一套标准通用的数据复制解决方案,可以提高业务决策效率,帮助企业更快触达目标用户。DRC(DataReplicateCenter)作为携程内部数据库上云的标准解决方案,支持包括但不限于即时通讯、用户账号、IBU、国际业务等核心基础业务的平滑上云。2.业务上云场景业务上云前,要考虑两个问题:数据库是否需要上云?如果是云端数据库,海外数据库提供只读还是读写操作?2.1应用到云端对于对延迟或离线服务不敏感的用户,可以不使用云端,只使用应用到云数据库,在国内请求回源。在该方案下,业务需要修改应用中的读写数据库操作,根据应用的部署位置判断流量是否需要转发。不建议海外应用直接连接国内数据库。网络层面的专线距离远,成本太高,不现实;在安全层面,应禁止跨海访问,否则可能导致预期的就近访问流量因意外错误写入国内数据库。从而造成国内数据错误。2.2数据库上云对于线上用户延迟敏感的应用,数据库必须随应用一起上云,请求在海外关闭,就近提供服务响应。在确定数据库云的前提下,根据不同的业务特点,可以细分为海外只读和读写场景。只读场景对于海外只读场景,国内数据只需要单向复制即可。该方案下,业务海外账户默认无写权限或业务转换写操作,避免因写入错误导致境内外数据不一致。读写场景对于海外读写场景,需要将境内外数据进行双向拷贝,业务代码不需要修改。这种方案下,由于有两个master可以写,业务需要在应用层对流量进行切分,比如用户的归属维度,避免两边同时修改同一个数据,这样会造成复制过程中的数据冲突。2.3云成本数据越接近用户,应用直接提供的服务功能越丰富,相应的业务改造量越小,机器资源消耗越大。携程的海外应用部署在AWS公有云上。AWS入口流量不计费,只对出口流量计费。应用在云端,数据库不在云端的场景,请求回国时会产生出口流量费用;只读业务数据单向拷贝,不收费;读写业务数据拷贝回国内产生出口流量费。云场景AWS出口流量数据库成本机器成本业务转化应用云业务请求流量无不转化读写请求数据库云端/只读无RDS费用单向复制转化转化写入请求数据库云端/读写海外→国内复制流量RDS云上双向复制成本主要集中在流量和数据库成本上。AWS出口互联网流量为0.09/GB。当流量较大时,可以通过数据压缩和丢失复制延迟来降低出口流量;RDS按核心数计费,1004元/核心/月,业务流量较小时可使用普通4C16G机型,流量增加后动态升级配置。核心业务RDS配置一主一从,非核心业务可以单主,多个DB共享一个集群,从而降低成本。2.4小结为了提供优质的用户体验,数据必须上云。在解决了要不要上云的问题之后,如何上云又成了新的疑点。下面详细分析携程在内部上云过程中所依赖的数据库复制组件DRC的实现细节。3、数据库云解决方案DRC基于开源模型开发。公司内部生产版本与开源一致。开源地址为https://github.com/ctripcorp/drc,欢迎关注。DRC在异地多活项目中孵化,见《携程异地多活-MySQL实时双向(多向)复制实践》,解决国内异地机房数据库同步问题。当一个或多个机房位置转为公有云时,随着物理距离的扩大,新的问题又出现了。就DRC自身架构实现而言:公有云与国内机房互不相连,同步链路物理阻断。公网传输不如国内跨机房专线质量好,经常丢包。公有云数据库独立运维的灵活性下降,如果获取不到root权限,会直接导致setgtid_next无法正常工作。业务接入方面:境内外数据隔离,按需复制成为公有云数据库的刚性需求。基于以上限制,DRC调整架构,引入代理模块解决网络连接问题,并使用事务表降低复制链路的权限要求。按需复制。3.1架构改造挑战1)架构升级DRC中有两个核心功能需要跨公网传输数据:业务Binlog数据复制DRC内部延时监控探针数据复制以单向复制为例,Binlog拉取模块ReplicatorApplier模块之间引入分析应用Proxy,负责在TCP层将内网/公网流量转发到公网/内网。Proxy绑定公网IP,使用TLS协议加密传输内网流量。针对公网质量不稳定的情况,Proxy采用了BBR拥塞控制算法来优化丢包带来的滞后。Proxy是携程内部针对公网数据传输的统一解决方案,见《携程Redis海外机房数据同步实践?》,开源地址:https://github.com/ctripcorp/x-pipe,欢迎关注。延迟监控延迟监控探针从业务流同侧机房的控制台写入业务数据库的延迟监控表(初始化时创建),接收对端机房的延迟探针side通过一条双向复制链路,从而计算差值得到replicationdelay。为了提高Proxies之间的隔离性,可以配置不同的Proxy实例进行数据复制和延时监听,实现数据传输。由于Applier和Console都需要连接Proxy,如何减少Proxy对DRC系统的侵入成为了一个需要解决的问题。为此,我们采用JavaAgent技术动态修改字节码,实现可插拔的访问方式。接入方只需要导入proxy-client独立Jar包,业务层根据需要实现代理的注册和注销。2)网络优化公网丢包和拥塞频繁发生。为了在弱网络环境下实现平滑复制,需要快速的异常检测和恢复机制。DRC除了在系统层对BBR优化Proxy拥塞控制算法外,还在应用层增加心跳检测,实现连接的自动切换和流量控制,避免流量突然增加导致资源耗尽,影响数据复制。商业线上随机切换心跳检测BinlogproducerReplicator定时对下游consumer进行心跳检测。消费者收到心跳检测需要回复。Replicator根据上次接收时间检测并自动关闭长时间未响应的连接。这是一个需要特殊处理的场景。当下游consumer忙,主动关闭连接的auto_read属性时,应用层无法读取缓存中暂存的心跳包,导致无法响应。这就需要consumer在auto_read变化的时候主动上报producer自己的auto_read状态。流量控制公网质量下降导致复制延迟更大,数据在发送Proxy中堆积,进而导致Replicator和Proxy触发流量控制;MySQL性能波动,应用Binlog变慢,数据堆积在Applier,进而导致Applier触发流控,层层反馈给Replicator。Proxy出口IP,分别配置移动和联通两条运营商线路。当Binlog消费者因空闲检测触发超时重连时,Proxy会随机选择一个运营商的出口IP,实现运营商线路的互联互通。准备。3)在国内机房复制事务表和复制数据时,DBA可以给DRC一个root权限的账号,通过Applier模拟原生Slave节点设置gtid_next工作方式实现Binlog的应用,从而实现复制一个事务从源机房变更到目标机房,并在两端分配给同一个gtid。但是,出于安全考虑,公有云上的RDS无法开放root权限,从原理上直接否定了原有的复制方案。为了找到一个合理的替代方案,我们首先从MySQL服务器的角度来分析setgtid_next的效果:事务提交后会被赋予指定的gtid值,否则MySQL服务器会自动分配一个gtid值和gtid值将添加到全局MySQL服务器变量gtid_executed的根本作用是将DRC指定的gtid值保存到MySQL系统变量中。由于无法使用MySQL系统变量,从业务层添加一个replication变量来保存gtid信息也可以达到同样的效果。其次,切换到DRC复制的角度,设置gtid_next有以下作用:记录Applier的复制消费站点,向Replicator请求Binlog解决循环复制,Replicator根据中的uuid判断是否是DRC复制产生的事件gtid_event,新的替代方案需要引入持久变量,记录复制站点,并提供循环阻塞信息。为此,DRC引入了基于事务表的同步方案来解决海外复制的问题。站点记录海外复制业务集群需要添加一个新的复制库drcmonitordb,其中新建了一个事务表gtid_executed。CREATETABLE`drcmonitordb`.`gtid_executed`(`id`int(11)NOTNULL,`server_uuid`char(36)NOTNULL,`gno`bigint(20)NOTNULL,`gtidset`longtext,PRIMARYKEY(`id`,`server_uuid`))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;server_uuid:源数据库UUID号gno:事务ID。该列值为0的行为汇总行gtidset:对于gno=0的汇总行,该列存储的是批量的gno编号,例如server_uuid:1-10:20:30Applier应用SQL时目标数据库,需要先更新事务表,记录gtid,然后执行事务中的change语句。完整的复制流程如下图所示。事务表中gno=0行的gtidset相当于MySQL系统变量gtid_executed。Applier在执行过程中,定期汇总非零交易gno,实现记录位置的功能。循环阻塞针对的是事务表gtid_executed操作的事务Binlog中第一个写入事件。Replicator判断为DRC复制数据,从而阻止循环复制。否则,一条数据将在双向复制环中无限循环。3.2业务实施的挑战到目前为止,DRC已经从理论上解决了已知的阻碍复制的技术问题。在实际业务实施过程中,出于对数据安全、成本和改造成本的考虑,业务对数据复制提出了更加细化的管控要求。1)数据隔离由于合规要求,业务上云后,需要完成境内外用户数据的隔离。业务上云前,境内外用户数据全部在国内数据库;上云时需要将海外用户数据复制到公有云,过滤掉国内用户数据。库表上云前,国内外数据在同一个主表中。业务为了上云,通过在国内数据库中添加分表,实现国内数据分离。由于海外只有海外数据,所以物理上只需要一张主表,即国内分表对应海外主表,建一个DRC即可实现双向复制。由于父表和子表的表名不同,复制时需要进行数据库表映射,屏蔽应用层对不同表名的感知,减少业务改造量。行过滤数据库表映射不涉及数据过滤,经过DRC的流量会被复制,所以映射在Applier端处理,根据映射规则直接替换表名即可。为此,业务需要进行两次改造:在国内机房人工分离境内外数据,以便将全量数据保存在国内主表中;在境外用户数据通过DRC,需要通过触发器自动同步到主表,进一步减少业务改造DRC提供行过滤功能。用户不需要进行业务改造,只需要保证表中包含Uid字段即可。DRC根据Uid自动判断数据归属,进行数据过滤。在单向复制的链路层添加行过滤配置,包括:过滤式Uid过滤,业务层一般通过Uid维度进行拆分,通过SPI动态加载实现Uid过滤。由于Uid在携程内部没有特殊标记,无法通过Uid名称判断出归属,只能通过SOA远程调用实时判断Uid的归属,获取过滤结果;如果Uid有规则可循,可以使用正则表达式匹配Java正则表达式,支持单个字段的Java正则表达式。简单的匹配计算,适用于规则单维值业务场景下的Aviator表达式,支持多字段Aviator表达式的复杂匹配计算,适用于多维值关联的业务场景过滤参数包括表与表的映射关系过滤字段,以及过滤类型对应的上下文,比如正则表达式。ApplierBinlog请求中携带行过滤配置,Replicator根据过滤类型加载相应的过滤规则,计算过滤结果。行过滤在发送端的复制器上实现。这种实现的好处是大大减少了跨海发送的数据量,但是也带来了解析和重构RowsEvents的复杂度和性能损失,即先解析RowsEvents再根据过滤后的Row数据生成一个新的行事件。RowsEvent的解析需要表结构信息,表结构信息保存在Binlog的header中,必须保证在RowsEvent之前能够获取到对应的表结构;解析后,可以将每一行的过滤字段值应用到过滤规则中。如果匹配到需要过滤的行,则需要根据过滤后的行构造新的RowsEvent发送,否则直接发送。2)随着数据量的扩大,数据库混合部门的核心业务会使用分库来降低数据库的压力。在公有云上部署时,由于云上初始流量不多,而且机器配置可以动态提升,所以DBA会将所有分库部署在同一个RDS集群中,复制从一个变-此时一对一到一对多。表过滤单向复制链路级增加库表过滤配置,支持Aviator表达式。在Replicator发送前,将Binlog解析出的库表名应用到Aviator表达式中得到过滤结果。3.3数据库上云流程完整的业务上云流程一般分为四个步骤:数据库先上云、搭建境内外数据库复制、验证境外数据的可用性和完整性。在海外数据可用的前提下,申请上云,访问海外数据库,验证部署海外应用的可行性。流量路由层灰度业务流量可以在流量接入层根据Uid白名单和流量百分比进行灰度化,验证业务逻辑的正确性。灰度化完成,境内外流量切分。验证境内外业务隔离,做好底层数据离线复制准备。每一步都有数据库云参与。第一步通过DRC解决数据可用性问题,第二步通过数据库访问中间件解决数据可用性问题。针对数据的可访问性问题,第三步是通过精准的流量切分来保证数据的一致性。第四步,实现国内外数据隔离后,DRC数据复制就可以离线了。分析完DRC的原理,接下来我们来分析其他数据库相关的问题。1)数据访问层Dal包括两部分:集中配置管理服务器DalCluster和Dal客户端。在上云之前,同一个数据库只有一个物理集群。上云后,在海外添加了同样的集群。服务器DalCluster需要根据客户端环境下发正确的MySQL配置文件。DalCluster原理DalCluster变更推送功能由分布式配置中心完成。配置中心提供子环境功能。国内数据库配置默认放在父环境,海外数据库在上线过程中会生成对应的子环境数据库配置。这样在启动DalClient时,不同环境配置的客户端会拉取不同的配置,从而实现就近访问数据库。整个过程对业务透明,无需修改代码。2)流量切分业务云一般采用Uid属性进行流量切分。当流量开始灰度化时,两端的数据库开始接收写流量。如果流量灰度不干净,两端同时修改同一个Uid的数据,会在底层DRC数据复制时造成数据冲突。当发生冲突时,Applier默认根据时间戳来处理冲突。连接到DRC的表有一个自动更新的精确到毫秒的时间戳,将使用时间戳最新的数据来实现数据一致性。3)表结构变更通过DRC复制的集群在表结构变更过程中会自动关联到公有云集群,变更操作会在两端同时进行。由于变更是按顺序完成的,假设增加字段的变更先在海外完成,在国内变更完成之前的时间范围内,表从海外复制到国内会出现复制冲突。默认的DRC会捕获异常并将其从异常中移除。列名是从信息中提取出来的,多余的列在执行前从SQL中去除,从而自动处理冲突。国内集群改表结构后,新增加的列的值是两端的默认值,数据还是一致的。3.4业务落地成果海外数据库复制已于2021年11月上线,已接入公司90+个复制集群;上海?新加坡AWS复制平均延迟90ms,上海?法兰克福AWS复制平均延迟260ms;账号集群通过数据库表进行映射,经常出差、收藏等通过行过滤实现用户数据隔离;通过一对多部署,国内机房公有云/MySQL集群比例维持在1/5,DRC复制成本/MySQL集群成本维持在2/5;4、未来计划支持更多的Binlog消费者支持消息传递;DRC目前仅支持增量数据的实时复制,未来将支持存量数据的复制和敏感数据的初始化过滤,覆盖业务上云过程中更多的数据复制场景;Replicator作为一个有效的状态实例,本地磁盘用于保存Binlog。公有云使用的块存储本身就是一个分布式存储系统。Replicator可以探索存储架构的改造,让主备共享同一个存储,从而降低使用成本。
