- 《架构师》2017年10月
- InfoQ中文站
- 177字
- 2020-06-26 06:04:19
MySQL到底能不能放到Docker里跑?
Talk is cheap, show me the demo。MySQL到底能不能放到Docker里跑?同程旅游目前已经有超过一千个MySQL实例安全稳定地跑在Docker平台上。
前言
前几月经常看到有MySQL到底能不能放到Docker里跑的各种讨论。这样做是错的!这样做是对的!说错的理由也说了一大堆,说对的思想也很明确。大家都有道理。但是我本人觉得这样的讨论落地意义不大。因为对与错还是要实践来得出的。
所以同程旅游也很早开始了MySQL的Docker化实践,到目前已经有超一千多个MySQL实例在Docker平台安全稳定地跑着,DB运维能力发生了质的提高(DBA再也不用担心删库跑路了)。
当然这样是不是可以证明之前的讨论结论——是对的。我想也不一定,因为我们还只是一只在学飞行的小鸟,还要更多的学习,所以我们特将我们在MySQL的Docker化上的实践分享给大家。
背景介绍
同程旅游早期的数据库都以MSSQL为主,这个产品有个特点就是UI操作很棒。但是批量和自动化管理很难做,人力的工作很多。后来逐渐替换为MySQL后也是按照传统的运维方式管理。导致大部分的工作需要人肉运维。
当然像我们早期使用过的MSSQL也是有优点的:就是单机性能比较好,在当年那个资源不够的年代里我们常可以在高可用的实例上运行多个库。这种情况下物理机数量与实例数量还是比较可控的,相对数量比较少,人肉运维完全可以应对。
但是MSSQL的缺陷也很多,比如做水平拆分比较困难,导致数据库成为系统中最大的一个瓶颈。但在我们使用MySQL+中间件(我们做这个中间件也是下了不少心思的,以后可以分享一下)做水平拆分后就开始解决了这个瓶颈。
水平拆分的引入也带来了一个小缺点,就是会造成数据库实例数量大幅上升。举个例子我们做1024分片的话一般是做32个node,一主一从是必须的(大部分情况是一主两从),那么至少64个实例,再加上应急扩展和备份用的节点那就更多了(中间件的开发者更希望是1024片就是1024个实例)。
一次上线做一个32node分片扩展从库,两个DBA足足花了4个小时。另外,如果做单机单实例那肯定更不行了,别的不说,成本也会是个大问题,且物理机的资源也未能最大化利用。况且因为MySQL单体的性能没优势所以分片居多所以大部分情况下并不是每个库都能跑满整个物理机的。即使有部分能跑满整机资源的库,它的多节点备份,环境一至性和运维动作统一等问题也会让DBA一头糟,忙碌又容易出错的工作其实是无意义的。
有了单机多实例运行MySQL实例的需求。单机多实例要思考的主要问题就是如果进行资源隔离和限制,实现方案有很多,怎么选?KVM, Docker, Cgroups是目前的可以实现隔离主流方案。
KVM对一个DB的隔离来说太重了,性能影响太大,在生产环境用不合适。这是因为MySQL运行的就是个进程而且对IO要求比较高,所以KVM不满足要求(虽然优化以后IO能有点提升)。
cgroups比较轻,虽然隔离性不是很高,但对于我们的MySQL多实例隔离来说是完全够用了(Docker的资源限制用的就是cgroups)。但是我们还想针对每个MySQL实例运行额外的管理进程(比如监控等等)。用cgroups实现起来会比较复杂,并且我们还想让实例管理和物理机区分开,那cgroups也放弃。
至于Docker,那就很不错了,那些裸用cgroups的麻烦它都给搞定了。并且有API可以提供支持,开发成本低。而且我们可以基于Docker镜像来做部署自动化,那么环境的一至性也可轻松解决。所以最终我们选择了Docker作为云平台的资源隔离方案(当然过程中也做了很多性能、稳定性等的适配工作,这里就不赘述了)。
下面两个图可以形象展示这款产品带来的革命性意义:
当然要能称之为云,那么平台最基本的要求就是具备资源计算、资源调度功能,且资源分配无需人工参与。对用户来讲,拿到的应该是直接可用的资源,并且天生自带高可用、自动备份、监控告警、慢日志分析等功能,无需用户关心资源背后的事情。其次才是各种日常的DBA运维操作需求服务化输出。下面我们就来讲讲我们这个平台是如何一步步实现的。
平台实现过程
站在巨人的肩膀上
我一直认为评价一款数据库的优劣,不能只评价数据库本身。我们要综合它的周边生态是否健全,比如:高可用方案、备份方案、日常维护难度、人才储备等等。当然对于一个云平台也一样,所以我们进行了短平快的试错工作,将平台分为多期版本开发。第一个版本的开发周期比较短,主要用来试验,所以我们要尽可能运用已有的开源产品来实现我们的需求,或者对已有开源产品进行二次开发以后实现定制化的需求。以下是我们当时用到的部分开源产品和技术。
下面选几个产品简单说一下我们通过它实现什么功能:
· Percona:我们的备份、慢日志分析、过载保护等功能都是基于pt-tools工具包来实现的。
· Prometheus:性能优越且功能强大的TSDB,用于实现整个平台实例的监控告警。缺点是没有集群功能,单机性能是个瓶颈(虽然单机的处理能力已经很强了),所以我们在业务层面进行了DB拆分,实现了分布式存储及扩展。
· Consul:分布式的服务发现和配置共享软件,配合prometheus实现监控节点注册。
· Python:管理Docker容器中MySQL实例的agent以及部分操作脚本。
· Docker:承载MySQL实例并实现资源隔离和资源限制。
总体架构
容器调度系统如何选择
容器调度的开源产品主要有Kubernetes和mesos,但是我们并没有选用这两个。主要原因是我们内部已经开发了一套基于Docker的资源管理、调度的系统,至今稳定运行2年多了。这套架构稍作修改是符合需求的。
另外第三方的资源调度系统兼容我们目前的高可用架构,其他自动化管理有些难度,同时资源分配策略也需要定制化。所以最终还是选择采用了自研的资源调度管理。适合自己现状的需求才是最好的。当然后面有机会做到计算调度和存储调度分离的情况下我们可能会转向Kubernetes的方案。
工作原理
我们就拿创建集群来举例吧。当平台发起一个创建集群的任务后,首先会根据集群规模(一主一从还是一主多从,或者是分片集群)确定要创建的实例数量,然后根据这个需求按照我们的资源筛选规则(比如主从不能在同一台机器、内存配置不允许超卖等等),从现有的资源池中匹配出可用资源,然后依次创建主从关系、创建高可用管理、检查集群复制状态、推送集群信息到中间件(选用了中间件的情况下)控制中心、最后将以上相关信息都同步到CMDB。
以上的每一个工作都是通过服务端发送消息到agent,然后由agent执行对应的脚本,脚本会返回指定格式的执行结果,这些脚本是由DBA开发的。这种方式的优势在于,DBA比任何人都了解数据库,所以通过这种方式可以有效提升项目开发效率,也能让DBA参与到项目当中去。开发只需要写前台逻辑,DBA负责后端具体执行的指令。如果未来功能有变更或迭代的话,只需要迭代脚本即可,维护量极小。
资源的调度分配原则
经过对同程多年的DB运维数据分析得到如下经验:
· CPU最大超卖3倍,内存不超卖;
·同一机房优先选择资源最空闲的机器;
·主从角色不允许在同一台机器上;
·若有VIP需求的主从端口需要一致,无VIP需求直接对接中间件的无端口一致的限制;
·分片的集群将节点分布在多台物理机上。
产品分类
核心功能
以上是已经上线的部分核心功能,还有很多功能就不再一一展示。
备份恢复系统
备份工具我们是用percona-xtrabackup。通过流备份的方式将数据备份到远端的备份服务器。备份服务器有多台,分别按照所属机房划分。
我们提供了手工备份和定时备份来满足不同场景的需求。多实例备份一定要关注磁盘IO和网络,所以我们的备份策略会限制单个物理机上并行备份的数量,另外单个机房备份任务队列的并行度也有控制,确保并行备份任务始终保持到我们指定的数量。
假如整个机房并行的是50个任务,那么这50个当中如果有5个提前备份完成,那么会新加入5个等待备份的任务进入这个备份队列。我们后来改造了备份的存储方式,直接将备份流入分式存储。
监控告警系统
在上线这套云平台前,我们还是用传统的zabbix来实现监控告警的。zabbix的功能的确非常强大,但是后端的数据库是个瓶颈,当然可以通过数据库拆分的方式解决。
数据库要监控的指标比较多,如果采集的项目比较多,zabbix就需要加proxy,架构越来越复杂,再加上和我们平台对接的成本比较高,对一些复杂的统计类查询(95值、预测值等)性能比较差。
所以我们选了一款TSDB——prometheus,这是一款性能极强、极其适合监控系统使用的时序性数据库。prometheus优点就是单机性能超强。但凡事又有两面性,它的缺点就是不支持集群架构(不过我们解决了扩展的问题,下面会讲到)。
prometheus的使用应该是从一年前就开始的,那时候我们只是把它作为辅助的监控系统来使用的,随着逐渐熟悉,越来越觉得这个是容器监控的绝佳解决方案。所以在上云平台的时候就选择了它作为整个平台的监控系统。
监控数据采集
prometheus是支持pushgateway和pull的方式。我们选用了pull的方式。因为结构简单,开发成本低的同时还能和我们的系统完美对接。consul集群负责注册实例信息和服务信息,比如MySQL实例主从对应的服务、Linux主从对应的服务、容器注册对应的服务。然后prometheus通过consul上注册的信息来获取监控目标,然后去pull监控数据。监控客户端是以agent的形式存在,prometheus通过HTTP协议获取agent端采集到的数据。
监控指标画图
不得不说grafana是监控画图界的扛把子,功能齐全的度量仪表盘和图形编辑器,经过简单配置就能完成各种监控图形的展示。然后我们打通了云平台和grafana的关联,用户在云平台需要查看实例或集群信息,只要点击按钮即可。
告警管理
告警管理分为:告警发送、告警接收人管理、告警静默等功能。prometheus有一个告警发送模块alertmanager,我们通过webhook的方式让alertmanager把告警信息发送到云平台的告警API,然后在云平台来根据后面的逻辑进行告警内容发送。
alertmanager推过来的只是实例纬度的告警,所以我们结合告警平台的实例相关信息,会拼出一个多维信息的告警内容。让DBA一看就知道是谁的哪个集群在什么时间触发了什么等级的什么告警。告警恢复后也会再发一次恢复的通知。
alertmanager也是功能强大的工具,支持告警抑制、告警路由策略、发送周期、静默告警等等。有需要可以自行配置。但是这种和平台分离的管理方式不是我们想要的,所以就想把alertmanager对告警信息处理的这部分功能集成到云平台内。
但是官方文档并没有提及到alertmanager的API,通过对源码的分析,我们找到了告警管理相关的API。然后alertmanager的原生UI上操作的功能完美移植到了我们的云平台,同时新增了实例相关集群名称、负责人等更多纬度的信息。
下面是一些操作样例:
·当前告警。
·添加告警静默。
·已创建的静默规则。
慢日志分析系统
慢日志的收集是通过pt-query-digest每小时进行本地分析,分析完成以后将结果写入慢日志存储的数据库来完成的。当然如果用户需要立刻查看当前慢日志的情况,也可以在界面点击慢日志分析。分析完成后可以在UI界面点击慢日志查看,就能看到该实例的慢日志分析结果。它同时集成了explain、查看table status等功能。
集群管理
集群管理作为该平台的核心功能之一,占据了整个平台70%的工作。这些功能就是DBA运维中经常需要用到的。我们的设计思路是以集群为单位,所以同时只能操作一个集群上的实例。这样就不会在一个页面上显示过多无用的信息,看着乱还有可能导致误操作。看了下图中的这些功能就能更明白为什么要这么设计了。
图中只是一部分,还有部分未展示出的功能(集成中间件、Dashboard、黑屏诊断窗口等),在后版中功能更多。
高可用
高可用方案我们使用了目前最流行的MySQL高可用方案MHA。MHA的优缺点就不在这里讲了,有DBA同学的应该都已经很熟悉了。这里我说一下我们基于同程业务做的调整。
GTID
因为我们主要使用的MariaDB,但是MHA最新版本也是不能支持MariaDB的GTID切换。所以我们在原有的基础上做了改进,支持了MariaDB的GTID。使用GTID以后灵活切换是一个方面,另外一个方面是sync_master_info和sync_relay_log_info就不需要设置成1了(MariaDB不支持写table,只能写file),极大减少了从库复制带来的IOPS。
切换时调整相关参数
我们在切换时调整sync_binlog和innodb_flush_log_at_trx_commit参数,这两个参数是决定数据落盘方式的,默认大家都是设置双1。这样相对数据最安全,但是IO也最高。
云服务的多实例部署会导致一台物理机上既有master又有slave。我们肯定不希望slave产生太高的IO影响到同机器的其他slave(虽然可以IO隔离,但是优先降低不必要IO才靠谱)。所以理论上来说Master上面设置双1, slave则可以不这样设置。但是切换后原来的salve可能会变成了master。所以我们默认slave非双1,在MHA切换的时候会自动将新master的这两个参数设置为1。
哨兵
我们在多个点部署了哨兵服务。这个哨兵是一个简单的API服务,带上响应的参数可以请求到指定的实例。当MHA manager检测到有Master无法连接时,会触发secondary check机制,带着master相关信息请求哨兵节点的API,根据哨兵节点返回情况,若超过半数无法连接则切换。否则放弃切换。
高可用切换对接DB中间件
DB中间件和DB通过物理IP连接,当发生高可用切换时将最新的Master IP、Master port信息推送到DB中间件控制中心,DB中间件拿到配置后立刻下发并生效。
实例、库迁移
迁移功能初衷是为了将平台外的实例或者库迁移到平台里面来,后来随着逐渐使用发现这个功能可挖掘的空间很大,比如可以做平台内库表拆分等需求。实现原理也很简单,用mydumper将指定数据备份下来以后,再用myloader恢复到指定数据库。
这是一个全量的过程,增量复制用的是用我们自己开发的一个支持并行复制的工具,这个工具还支持等幂处理,使用更灵活。没有用原生复制的原因是,假如要将源实例多个库中的一个库迁移到目标实例,那么原生复制就需要对binlog做复制过滤,这里面涉及到配置修改,实例重启,所以果断不考虑。
实现过程并没有高大上,但是完全满足需求。当然mydumper和myloader也有一些问题,我们也做了小改动以后才实现的。后面我们计划用流的方式去做数据导出导入(类似于阿里开源的datax)。
迁移完成,增量无延迟的情况下,大家会关心迁移前后数据一致性的问题,我们提供了自研的数据校验工具。实测300G的数据校验时间约为2至3分钟,快慢取决于开多少线程。
屏蔽底层物理资源
对用户来讲,平台提供的是一个或一组数据库服务,不需要关系后端的实例是在哪台机器上。资源计算和调度全部由系统的算法进行管理。
提升资源利用率(CPU、内存)
通过单机多实例,CPU资源可超卖,有效提高CPU资源的利用。内存资源未超卖,但是可以控制到每个实例的内存使用,确保每个实例都能有足够的内存。若有剩余内存,则继续分配容器即可,不OOM的情况下压榨内存资源。
提升运维效率
效率的提升得益于标准化以后带来的自动化。批量运维的成本很低。以前部署一套分片集群需要花费将近6个小时(不包含对接中间件的1到2个小时),而现在只需要5分钟即可部署完成。并且部署完成以后会将提供一套中间件+DB分片集群的服务。
精细化管理
平台上线后有效提高了资源利用率,同时我们按照1库1实例的方式,可以有效避免不同库的压力不均导致相互影响的问题。并且性能监控也能精准到库级别。
结语
以上这些只是一个开始,后面还有很多功能需要完善,下面是近期策划的一些功能,其中有些已经在后版中开发完成。随着功能的不断迭代,我们会打造一个更加完美的私有云平台。
数据库私有云平台的上线对同程DB来说,意味着一个时代的结束,也意味着一个时代的开始。结束的是传统运维低效、高成本的运维时代,开始的是一个低成本、高效率、高保障的运维时代。我们相信未来会更美好!
作者介绍
王晓波,同程旅游(LY.com)首席架构师,EGO会员。专注于高并发互联网架构设计、分布式电子商务交易平台设计、大数据分析平台设计、高可用性系统设计。曾设计过多个并发百万以上、每分钟20万以上订单量的电商交易平台,熟悉B2C、B2B、B2B2C、O2O等多种电商形态系统的技术设计,熟悉电子商务平台技术发展特点,拥有十多年丰富的技术架构、技术咨询经验,深刻理解电商系统对技术选择的重要性。