优步工程团队对容器化MySQL的应用

优步工程团队的Schemaless存储系统驱动着优步内部一些最大规模的服务,例如Mezzanine。Schemaless是一种基于MySQL[1]集群的可缩放、高可用数据存储。当我们最初只有16个集群时,这些集群的管理工作相当简单,但是目前我们有超过1000个集群,其中承载了超过4000个数据库服务器,我们的管理工具也需要与时俱进了。

最初所有集群都通过Puppet管理,我们根据需要陆续编写了大量脚本,但这种手工的操作方式已经无法跟上优步快速扩张的节奏。在为数量逐渐增加的MySQL集群选择更适合的管理方式时,我们也确立了一些基本需求:

  • 在每台宿主机上运行多个数据库进程
  • 一切操作实现自动化
  • 跨越多个数据中心,通过一个位置管理并监控所有集群

我们设计了一种名为Schemadock的解决方案。所有MySQL均运行在Docker容器内,我们通过在配置文件中定义的集群拓扑为目标状态(Goal state)对其进行管理。集群拓扑决定了MySQL集群的组成方式,例如集群A应包含3个数据库,其中某个数据库为主数据库。随后通过代理(Agent)将定义好的拓扑应用给每个数据库。我们会通过一个集中化的服务维持并监视每个实例的目标状态,并对偏差做出响应。

相关厂商内容

打造58千亿级分布式存储平台

跟技术大牛,侃侃容器那些事儿!

UCloud UCan技术夜,与“老司机”共侃云服务技术实践与风向

解读关联关系挖掘技术背后的实践与演进

看明略任鑫琦如何谈关系挖掘算法

Schemadock包含多个组件,其中的Docker虽小但很重要。换为使用缩放性更强的解决方案,这样的过程需要付出诸多努力,本文将介绍我们如何借助Docker实现这个目标。

为何一开始就选择使用Docker?

以容器化的方式运行进程,使得我们可以轻松地用一台宿主机同时运行多个不同版本和配置的MySQL进程。此外我们也可以将多个小规模群集共置在一台宿主机上,这样即可在确保集群数量不变的情况下减少宿主机数量。最终,我们可以消除对Puppet的依赖,将所有宿主机以相同的角色进行供应。

对于Docker本身,我们的工程师已经开始全面采用Docker构建无状态(Stateless)服务。这意味着我们针对Docker积累了大量工具和知识。Docker虽不完美,但至少目前比其他备选技术更优秀。 为何不使用Docker?

可以取代Docker的技术包括完整虚拟化技术、LXC容器,以及通过Puppet等工具管理宿主机上直接运行的MySQL进程。对我们来说,选择Docker是一种很自然的做法,因为该技术可以融入我们现有的基础架构。然而如果你目前尚未开始使用Docker,单纯为了MySQL就上马Docker这样的做法有些得不偿失:需要处理镜像的构建和分发,监控,Docker的升级,日志收集,网络等一系列繁琐工作。

这一切也意味着,只有在愿意投入不菲的资源前提下,Docker对你来说才是可行的。此外你应该将Docker视作一种技术,而非应对所有问题的终极解决方案。优步通过大量慎重的规划设计才使得Docker能够成为MySQL数据库管理这一庞大系统中的一个小组件,然而并非所有公司能有优步这样的规模,对这些公司来说,也许更简单直接的Puppet或Ansible等方式是最适合的做法。

Schemaless MySQL Docker镜像

作为其他所有内容的基础,我们的Docker镜像会下载并安装Percona Server,然后启动mysqld—这一过程与现有的Docker MySQL镜像相差无几。然而在下载和启动过程之间我们的镜像会执行很多其他操作:

  • 如果挂载的卷中不包含数据,则可以确定这是一个自举(Bootstrap)场景。对于主数据库(Master),将运行mysql_install_db并创建一些默认用户和表。对于从属数据库(Minion),将会通过备份或集群中的其他节点发起数据同步操作。
  • 容器包含数据后,将会启动mysqld。
  • 如果数据复制过程失败,容器将重新关闭。

容器的角色可通过环境变量来配置。这里比较有趣的地方在于,角色仅控制了初始数据的获取方式,Docker镜像本身不包含用于设置复制拓扑或执行状态检查等操作的任何逻辑。由于逻辑的变化可以比MySQL自身的变化更频繁,因此将两者区分开来是一种合理的做法。