【IT168 专稿】本文根据沈金堤2018年5月11日在【第九届中国数据库技术大会】上的演讲内容整理而成。
讲师介绍:
沈金堤,滴滴杰出工程师, 现在担任滴滴基础架构团队以及滴滴云的研发负责人。在加入滴滴之前,负责过旺旺、来往、钉钉等产品后台技术架构工作,曾担任阿里云开源小组负责人。在网络编程、Python等领域都有比较丰富的工作经验。
分享大纲:
● MySQL在滴滴实践
● 我们使用了更多的开源数据库
● 融合数据库的尝试
● 以MySQL为入口的融合数据库实践
文章摘要:
经过多年的发展,MySQL已经成为了开源数据库里面最重要的产品,拥有成熟的应用场景、生态工具。实践过程当中,在不同的领域使用不同的存储技术来处理问题也是共识,所以HBase、ElasticSearch、Redis等产品也纷纷被应用在不同的生产线上。以往,工程师们需要把数据分别写入到各种NoSQL存储系统里,不仅导致了技术实现的难度增加,同时相应的成本也增加了。现在,围绕MySQL的结构化数据,通过BinLog做ETL,只需要通过MySQL的数据更新,将数据分发到不同的存储服务,单元化、同城双活等场景就变得更加的自然和简单。本次将分享围绕MySQL的生态工具做融合数据库的实践。通过开源协作,围绕MySQL为中心的融合数据库技术将大幅降低企业使用开源数据库的成本。
正文演讲:
大家好,我是沈金堤,来自滴滴出行,主要服务于基础架构团队和滴滴云产品技术团队。今天我会和大家分享滴滴在数据库层面的实践。时至今日,滴滴的整个规模和体量都比较大了,如何提升效率、低成本却又快速的实现业务目标就成为了技术团队的核心价值。
“融合数据库”是我今天要分享的主题,我一开始觉得这个题目可能有点太大了,但是我又一想,我要把这个观点分享给各位。因为滴滴在从一个比较小的互联网公司成长为高速成长的互联网公司的过程中,也向很多前辈公司学习借鉴了许多技术方面的经验和知识。
一.MySQL在滴滴实践
滴滴现在所有的核心业务场景都在用MySQL,订单、支付、余额等都放在MySQL中,这是非常安全的。为什么说是安全的?因为我们有专门的MySQL运维跟研发团队,我们用了一年的时间,将MySQL 5.5、5.6版本全面升级到MySQL 5.7。虽然我们也在关注MySQL 5.8,但MySQL 5.7作为一个基准版本会存在很长一段时间。
我们在MySQL方面做了一些非常有意思的实践。如今云服务已经非常成熟了,大家已经习惯了使用RDS,所以我们的工程师在第一天使用MySQL时就问有没有RDS产品使用。说实话,一开始是没有的,2015年我们开始着手建立RDS团队,希望把云服务理念、基础设施服务化理念带到整个滴滴的基础设施建设里。所以,MySQL是我们做的第一个基础设施服务化产品。
我们的数据库研发+中间件+自动化运维团队大概是3到4人,当然这其中也会有DBA支持,基本上实现了全工程师的自助化服务,95%左右的工单都是自动化完成,主管审批、DBA确认之后就自动执行了。
我们国内外所有流程都是一致的,几乎全部是基于Docker和Saltstack,例如备份、监控、配套设施都已经Docker化,只除了数据库部分还是物理机混合部署。滴滴的目标是在一两年内实现全平台的容器化。当然这个目标实现也有挑战性,因为滴滴的代码模块量比较大,尤其是数据库层面要实现容器化需解决的问题很多。
一年前,我们团队解决了IO隔离、稳定性等一系列问题,接下来将致力于整个数据库向Docker的迁移。
目前滴滴的日均订单是3000万单,订单数量规模在国内还算是比较靠前的,峰值订单是每秒6万笔,这个数值可能跟阿里没法比,但我们的复杂度也不在订单数量,而是如何在很大的乘客需求和司机运力之间找到最合理的订单。
以下是MySQL在滴滴实践的一些情况。
整个用户控制台包括有DDL权限管理、 SQL异常统计、审计、黑名单等等。相信做过DBA运维工作的朋友对于申请数据库白名单的繁琐都感同身受,而我们把所有的服务、组织架构通过API和白名单串行起来,工程师只要发布了应用就自然可以访问自己的数据库。
我们有一名前端和两名工程师做了自动化运维控制台,所以DBA有更多的精力集中在做数据校验和机房搬迁的工作。
上图是简单的数据架构,分为三个场景:在线业务系统、在线辅助系统和自动化运维系统。滴滴从一开始就考虑到了分库分表,这是由订单决定的,单机要存储这么大量的数据是比较有挑战的。
所以DBProxy从最早就存在,我们有两名工程师专门维护DBProxy的开发工作。数据库是标准的一主两从组成架构,MHA切换,同时我们还做了一些有意思的能力,在分库分表情况下实现二级索引;类似备份、审计系统、慢日志等由辅助业务系统实现;而自动化运维系统我们是当做云产品在开发和设计。
做一个好的中间件是现在数据库里最核心的一件事,如果没有一个中间件,那么以后自动化运维、扩容、甚至是业务上的特性等都会很难开展。举个例子,主从是有延时的,读写分离是一个天然场景,但有些业务容忍不了延迟。 如果你读了备库,一致性会有问题,所以在中间件层面我们会在SQL前加备注,强制读主库来解决一致性问题,其他业务再去读从库。而如果没有DBProxy支持的话,审计自动化运维会带来很大挑战。
除了DBProxy,滴滴还有几个关键的能力,例如内置二级索引、单元化等。单元化在滴滴中的应用还是比较明显的,现在滴滴既有国内业务,也有国外业务,而这两种业务的数据是完全隔离开的,我们用一套代码,一套技术实现了国内和国外的并行。接下来,我们会在国内推行单元化,将南北方整个业务拆分开来,北方用户的订单数据会放在北方机房,而南方用户的数据则会放在南方机房。
二.我们使用了更多的开源数据库
滴滴的每个产品都有用户控制台,所有的基础设施服务化都贯彻得很彻底,从数据库服务发现到缓存消息队列再到长链接,只要你想得到的全是自助化服务。我们希望整个运维效率大幅提升,尽量减少人工干预和决策。
ElasticSeach集群我们仍然当做离线场景、MIS场景在使用,但正在向主存储方向去发展 ,目前也有主业务在使用了,这是因为它的多维索引很好用,工程师用得也比较顺手,规模大概在数千台左右。
主流的开源数据库滴滴都有在使用,例如MongoDB、Redis、RocksDB、elasticsearch、HBase、PostgreSQL。除了标准的关系型数据库,在不同的场景下还有两个自研的NoSQL系统,一个是RocksTable,我们用来存储特征引擎,例如订单、司机等的特征引擎。
滴滴早期大量在使用Redis,工程师通常是把它当做存储服务而不是缓存服务来用,但这给滴滴带来了很大的困扰,在成本特别高、全内存、数据量特别大的情况下,一台机器只能存几百G。于是,引入了另一个NoSQL系统——基于RocksDB的Fusion。Fusion系统实现了单元化、跨机房一致性,我们最核心的数据也在尝试使用自研引擎提供服务。
滴滴现在全部是在用开源,从数据库层面到编程语言到框架等一系列都是用开源实现,我们热爱开源,也会回馈开源,Fusion系统在未来会开源出来。
三.融合数据库的尝试
为什么要在分库分表的情况下做二级索引?举个例子,集群中有partition key,以订单ID做了分库分表,如果想查询乘客或司机的订单时怎么办?工程师觉得再建一个索引就可以了,但分库表时的难度就很大了。所以工程师就花很大精力写两份表,先写一个订单库,写完再写一个司机索引,再写一个乘客索引,这样还不够,MIS还需要用一、两个维度。工程师写的大部分代码都在去确保把所有索引写成功,但有时发布还会丢数据,这个问题困扰我们很久了。
当然这个问题我们使用了分布式事务产品也可以在技术层面解决,但使用起来有些繁琐,所以我们从另一个维度进行了尝试。假设仍然是订单ID和乘客ID的两个维度,我们实现了分身系统,把所有的来自于主库的数据更新完之后,通过binlog复制到另外一个表里面去。逻辑是自动完成的,也就相当于在做创建表的时候,创建一个索引,在分库分表情况下创建一个主key,然后在索引Key的情况下,自动把数据复制到另外一张表里,在DBProxy往下查询时,自动识别,直接查询。
这对于工程师来说是很大的解放,一张表里两个索引一样可以工作,当然这个也是有限制的,但它至少解决了写两张表的问题。这是我们第一个基于MySQL binlog的尝试,解决了很多业务问题,整个代码复杂度大幅下降。
第二次尝试是MySQL和ES的融合,上图是典型的架构图,业务代码从DBProxy到MySQL。这其中,我们用了canal,canal是阿里巴巴开源的binlog server的一个中间件。我们把数据通过canal同步到kafka,kafka写到ES里。
这样做的好处是MySQL创建表在ES里,在分钟级别甚至是秒级就可以查询到数据,体验很好。但是也会有问题,我们大部分代码都是PHP和Go,所以工程师就会觉得很麻烦,能不能提供一个MySQL协议的ES查询引擎。
也因为此,诞生了YASE的MySQL引擎,支持MySQL通过DBProxy去访问ES。我们曾希望所有东西都以MySQL为入口,但事实证明这并不是一个好的方案。因为ES API原生的客户端和访问协议都有其优势,灵活性和定制性都更强,如果降为MySQL标准SQL协议,反而损失很多能力,得不偿失。
四.以MySQL为入口的融合数据库
于是我们开始尝试融合数据库,最典型的就是业务代码会同时写入Redis、MySQL或者ES。绝大部分公司都是依次把数据写入各个数据库,写完之后MySQL中还有很多产品,例如我们虽然只有两个从库,但还有很多binlog应用程序,例如canal、Naruto、YAES等的。
Binlog要写到各种分身系统、canal、异构存储系统中去,给MySQL运维也带来很大的困扰,DBA觉得光运维MySQL就已经够复杂了,现在还让我把binlog同步多份。
于是我们提了一个新的想法,在MySQL层面把所有的binlog屏蔽掉,只提供一个服务,把所有的binlog消费给DDMQ。DDMQ是我们基于阿里巴巴的RocketMQ实现的一个带事务的MQ引擎,至少可以消费一次的消息队列。预计在2018年,我们会完成DDMQ的完整开源。
我们把所有的canal和DDMQ整合在一起,换句话说,MySQL可以直接把消息发送到DDMQ,其实这就是一个canal的升级版。因为DDMQ的存在,我们整个延时性,包括事务性有了很大的保证。
同时,在此基础上我们实现了DDMQ的ETL工作。滴滴现在的ETL工作还比较原始,但我们一些业务线已经开始尝试使用规则引擎来实现ETL工作,如果验证通过就会迅速切到binlog上,通过DDMQ把数据同步给Redis和ES,应用程序无需实现写多份了,业务工程师看起来只写一张表,就可以访问多种数据源,整个访问方式没有变化。
接下来介绍一下MySQL融合数据库的场景。
第一个是分身系统,MySQL二级索引值只写一次,但它可以支持很多索引,不过也要做限制,因为索引多的话会影响整个时延,目前来看三四个索引问题不大。
第二个是缓存反冲,我们大量的代码是PHP代码,它有一个特点就是随时会被杀掉,一旦被杀掉之后缓存可能就会更新失效,而业务代码又对缓存依赖非常重,如果没有带事务性的缓存更新,那么工程师写的代码会越来越多。
第三个是单元化,跨机房跨大洲的同步数据。2017年,滴滴开始做国际化,2018年,正式把国际业务在南美和北美跑起来。我们就用了这套技术来做数据同步,数据从南美搬迁到北美都是自动化的,北美数据机房跑起来自动完成数据复制,一边写一边复制,时间到了,按城市切过去。
第四个支持ES索引,MIS数据更新延迟到秒级;
第五个实时的据同步,MySQL所有的表都是实时复制到HDFS。去年,我们的方式还是一到12点就开始拉数据库,拉完之后,整个数据中心都处于非常繁忙的状态。但现在12点一过就可以开始计算数据了。 整个计算数据的时间大幅降低,但中间为了确保数据可靠性,我们花了很多精力在做数据的校验和可靠性。
以实时业务监控为例,滴滴一天可能有两三千万订单,如何知道一个城市的交易同比环比是下跌还是上涨了?我们把实时监控接到了DTS平台中实时消费binlog、实时解析,延时性非常低,可以在秒级发现交易是否下跌。
我们有个理念是Binlog as Service,涵盖支持了OLTP和OLAP两种场景。我们的目标是以MySQL为入口,写一份数据,多种访问形式。
上图是我们理解的DTS Binlog as Service形成融合存储服务。DTS也在不断演进的过程中,下一个目标我们希望能够使用规则和脚本的方式实现ETL。在OLAP 大数据场景下,我们使用了DataX,在实时链路层我们也做过如何做实时的大数据同步的分享,除了数据库问题,我们还解决了部分日志问题…..我们热爱开源,拥抱开源,同时也乐于分享。