本文根据朱进卓老师在2018年4月14日【3306π 北京站】现场演讲内容整理而成。
朱进卓
滴滴资深DBA
主要负责专车、快车等核心业务线数据库维护,数据库架构设计、优化、高可用维护,滴滴内部自动化平台RDS部分模块开发。
先后就职于搜狐畅游和金山,技术涉猎MySQL 、Redis、MongoDB、OpenStack、Python、Go。
滴滴现在主要使用的数据库是MySQL。滴滴的业务扩展很快,目前DB服务器大致有3000-4000台,实例就很恐怖了,整体有7、8千。在这种情况,靠纯人工去做运维是不可能的了,所以说我今天就和大家分享一下我们自动化运维从0到1的实践。
分享大纲:一.滴滴DB架构介绍
一般来说,自动化运维都会根据自己原有的架构来设计自动化运维平台,上图是滴滴DB的架构图,最上面是TGW LVS,也就是大家所熟悉的VIP,接下来是代理层dbproxy。代理层下面是MySQL的主从关系,一般情况是一主、一备主和一个从库,如果读取操作多,QPS会比较高,从库也需相应的增多。
同时还要有MySQL高可用的监控来应对主库挂了等等的异常情况。运维监控,我们是使用最常见的ZABBIX来做的。除此之外,我们还做了备份模块和性能优化的模块。
dbproxy相当于一个入口,连接应用,它是分布式的,因此每台上都会有自己的原始配置,所有的访问DB的流量都要经过dbproxy层,dbproxy会记录正常的访问日志,还有一些错误日志,例如没有加白名单或者是SQL语法错误等等都会在dbproxy层拦截,产生错误日志。
上图的架构就是我们在做自动化运维的初始部署,我们希望能够完成从业务申请到部署完成的一系列连贯动作。
二.主要工作
我们平时的工作内容如上图所示,基本包括部署、工单处理、扩容拆分、监控报警处理以及其它任务。
一周时间,RD申请30—50个实例在我们的工作中是很常见的,这时如果没有自动化运维,单纯靠自己手工部署的话,是很消耗时间的;工单处理的工作内容基本就是做一些DDL、表结构的变更,白名单以及其它需求;随着业务的发展,数据量会猛增,由于单机磁盘的存储是有限的,这时我们就要思考扩容、拆分的问题了,还有一种情况是磁盘可能足够存储,但是你的TPS/QPS单机可能撑不住,这时也要去做扩容;监控报警处理指的是我们前面提到的SQL错误,白名单没有加以及其它一些报警。
其中,部署和工单处理是我们日常工作的重头,其占比大约为70%。但是这一部分工作很容易自动化,一旦实现自动化,我们的工作强度会大大降低。
其实我们的工作痛点前面也提到了一部分,第一个就是因为量大,我们每周都会有很多的新申请,所以这部分工作的自动化是迫在眉睫的。
其次,我们的业务还有一个特点就是峰值比较集中,因为打车一般都集中发生在早高峰或晚高峰,所以系统的瓶颈也集中在这两个时间段。
第三个是数据库的延时,业务一般都会有超时时间的设置,数据库的延时是非常敏感的,一个查询进入到数据库再到返回结果的延时,这里的延迟指的不是我们平常意义上的主从同步数据的延时,指的是对业务SQL的响应时间,在线DDL的表结构修改也会影响到延时。
最后就是工作的多样性。
三.主要关注的模块
做自动化运维,之前的模块肯定是不能丢掉的。之前,我们的高可用、数据备份、监控报警、在线DDL系统等重点关注模式是使用PT,现在我们改用了ghost。
在完成整个运维自动化的过程中,我们做的第一步是DBA的自动化运维,其次是数据库系统服务化,当然现在我们的功能还达不到云服务商提供的那样,但是业务如果需要申请一个DB,相关人员在平台上操作几步就可以自己完成。
既然要做自动化运维,那么所有的东西就必须要标准化。我们根据之前的架构做了一些标准化的工作,例如OS初始化的标准化(文件系统,内核设置,磁盘挂载目录等)和数据库层面的标准化(配置文件、部署路径、多实例目录命名规则以及ID的命名规则)。
这张图是滴滴DB自动化架构的细节展示。
在线业务系统的最左侧是VIP,第二列是代理层中间件,第三列是MySQL,在这一层我们一般是用mha来保证MySQL的高可用。第四列是数据总线,很多人可能不理解数据总线,我举个简单的例子,如果乘客或者司机想要查询历史订单,那么你当然不能直接去线上的订单库里查询。线上订单库一般是按城市来分的,所以你还需要按照司机或乘客的ID将订单数据哈希到另一张表里,并且在这个新的库里进行历史数据的查询,相当于对数据重新做了一次分发和哈希。
在线辅助系统主要包括MySQL集群meta信息、在线DDL、SQL审计、SQL统计等。
自动化运维系统的Web层更多的是前端、界面化的东西,接下来是API层、调度层和执行层。
API层联动着很多操作,假设我现在去Web端申请了一个实例,那么接下来API层就会有一些动作,例如新建实例、新建MySQL集群、新建dbproxy,之后还需要做备份相关的东西。
四.自动化模块
中间件的扩容指的是dbproxy层,可能我们最开始只有三台,但是随着访问的增多,它本身也需要扩容。
DB层,就如我们刚才看到的mha那一块,一开始我们可能申请了三台,一个主库、一个备主库和一个从库,我们需要进行部署、扩容和备份。上图中的拆分主要是根据QPS/TPS来进行拆分,还有就是一些故障机的下线。
数据链路层,这一层做的功能还是比较强大的,因为好多东西都依赖这一层。我们是利用了开源的canal+Kafka+zookeeper,对数据重新做哈希,比如我上游可能是根据城市来分表的,那我下游就有可能把多个城市的表聚合起来。
在线辅助系统就是之前说的备份系统、高可用、SQL审计以及它的优化建议,监控报警、定时任务、数据链路的耗时分析。
定时任务怎么理解?实际应用可能会有一些按天数分表的情况,一般来说,业务肯定不会每天去建一个新表,所以这些操作都会由定时任务调度来处理,还有一些监控脚本、备份脚本、历史数据删除脚本都会在定时任务里。
数据链路的耗时分析,如果前端要访问数据库,那么需要经过的层比较多,先要通过dbproxy,再要通过MySQL,MySQL回包……这整个过程中,哪个过程是最耗时的?我们会绘制一个整个过程的时间序列图,这样就可以一目了然的看出哪里耗时最严重。
自动化运维系统的调度层我们是基于Python和tornado,底层执行是用saltstack。
上面这张图片有tornado和saltstack的官网链接,大家可以参考。
下面我再讲几个案例。根据架构,我们首先要去细分需要做哪些东西?分析完之后,我们还需要从中挑选出更为重要的模块,例如占用工时较久的部署,优先自动化。
在线DDL是一个比较重要的模块,它的业务峰值是比较集中的,有可能一个表是非常大的,你想避开高峰期,例如想在晚10点到早8点做完,但是有可能是做不完的。时间跨度大一直是在线DDL的一个痛点,而且有些大表的业务修改是很敏感的。
在线DDL的一般逻辑就是先创建一个空表,修改空表的表结构,把历史数据和增量数据同步到新表中,最后一步就是rename table,对新表和旧表做一次交换。
我们之前数据量不是很大的时候使用的是pt。pt的话,历史数据一般就是通过INSERT LOW_PRIORITY IGNORE INTO ,而增量数据是通过trigger来做的。
但是这种方法会有个问题,你对原表的操作都会通过触发器来触发一个相应的操作,它对于QPS来说是双倍的,而且是同时。例如你在对一个表访问,它上面100多个TPS,对于业务来说,正常情况可能是100毫秒或者是几毫秒的耗时,但你在修改这个的时候,耗时会很长,甚至有可能会访问不成功。
后来,我们经过调研就选择了inception+ghost,没有触发器。它的原理是先去建一个新表,对新表进行表结构的修改,再去解析一个从库对旧表操作的binlog来回放增量数据的处理,原有的老数据也是通过单个chunk的方式复制到新表中,新数据通过回放从库对旧表的操作binlog来回写到新表中,所以对于主库的压力比较低,主库上旧表和新表的写入也是异步的,避免了触发器同步执行的弊端,比如新加一个字段或者修改字段的类型。
当然它也是有版本迭代的,大家可以 根据自己的需求来进行修改。
这个是前面提到的saltstack实例,如何通知底层来做相关的新建任务?其实就是通过saltstack来去调用底层执行。
假设我现在要新建一个MySQL的主从实例,最上面是服务名称,这个服务名称就是一般来说都是以用途来命名,接下来是选择版本和port,还要选择主库、备主库、从库,如果你的QPS非常高,那三台机器是不够的,需要增加几台,直接加在后面就可以了。
针对MySQL的新建,我们会有一个模板一样的数据文件,其中已经包含了mha所需要的用户信息,类似于连接信息、授权等等都会在这个demo的文件里。
新建MySQL,相当于我先去拷一个模板文件,调用接口,新建端口,这个端口一般来说是多实例的。dst一般是根据你申请的数据库或者服务名来去定义目标机器的目录名称。传进来之后,就要判断机器上这个端口是否存在,如果存在的话,是不可以再新建一个同样的端口。如果不存在的话,我们下一步就是判断目录是否存在。
这里需要强调的一点是,salt是一步一步开始执行的,一旦哪个步骤出现错误,那就是直接失败,不再接着往下继续了。
原数据的demo数据文件建好了,下一步就是建立模板的配置文件。配置文件和数据文件有很多相似之处,都是先去判断端口是否存在,数据文件目录是否存在,创建目录,salt其实在系统里面内置了很多命令可供用户调用,最后判断MySQL版本来拉取模板配置文件。
因为模板配置文件是通用的,所以下一步就是修改配置文件,比如port信息,datadir、binlogdir等等。这个部分其实也是一个salt模块,其实就是把模板文件中的port替换成你传进来的port。
下一步就是启动MySQL,数据文件拉取过来了,配置文件修改完成了,直接去启动MySQL就可以了。
启动之后,因为你建立的是一个主从复制关系的集群,假设现在建立了三个实例,而复制关系还没有配置,这个地方就是相当于传一些参数来配置复制关系的。
以上是MySQL新建的过程,dbproxy的新建过程大致也是差不多的。一般都会做demo的东西拉取过来,之后修改配置文件,再去启动。
五.后续补充项
MySQL、dbproxy和mha 的搭建备份都已经实现自动化了。但是我们现在还有一些东西没有实现自动化。
资源管理和分配,申请一个实例,资源池中的机器如何选择还没有自动化。
VIP自动分配其实在我司是运维来做的,VIP是绑定在后端dbproxy机器上的,没有自动化的原因是因为我们不太好推动。
细粒度的监控报警,服务器的动态或者数据库的连接信息或者状态,你是可以看到的。但是如果线上新上线了一个东西,但是库里还没有新加字段。如果是不重要的模块,可能直接跑一个脚本。我们希望做到dbproxy层的报警都可以直接发给集群的创建者。
慢查分析,优化建议,现在我们有搜集慢查分析的相关信息,但是没有做到自动化的页面上去。
资源下载
关注公众号:数据和云(OraNews)回复关键字获取
‘2017DTC’,2017 DTC 大会 PPT
‘DBALIFE’,“DBA 的一天”海报
‘DBA04’,DBA 手记4 经典篇章电子书
‘RACV1’, RAC 系列课程视频及 PPT
‘122ARCH’,Oracle 12.2 体系结构图
‘2017OOW’,Oracle OpenWorld 资料
‘PRELECTION’,大讲堂讲师课程资料