专栏名称: 分布式实验室
最专业的Docker文章,最权威的Docker新闻。关注容器生态圈的发展。
目录
相关文章推荐
51好读  ›  专栏  ›  分布式实验室

容器化MySQL集群在Uber系统中的应用

分布式实验室  · 公众号  · 后端  · 2017-01-29 07:46

正文

Uber使用的Schemaless存储系统支撑了Uber最重要的服务,如,Mezzanine等。Schemaless 是一个构建在MySQL集群上,可扩展高可用的数据存储。但管理Uber数据量庞大的数据库集群服务需要应用Docker技术。

当集群节点数为16个时,集群管理非常容易,但若集群规模超过1000,并运行了4000多个数据库服务,就需要另一种工具了。之前所有的集群都由 Puppet来管理。大量的临时脚本,以及人工操作已无法满足Uber业务扩展的要求。我们开始寻找一个管理规模递增的MySQL集群工具,工具必须具备以下基本需求:

  • 在每个节点上运行多个数据库进程

  • 自动化

  • 整个数据中心通过单一的入口管理和监控所有集群

解决方案被命名为Schemadock,采用Docker容器运行MySQL,目标是将管理集群拓扑定义在配置文件中。集群拓扑定义了MySQL集群,例如,一个集群内应用3个数据库,其中一个是主,代理应用这些拓扑定义在每个数据库上,一个集中服务用来维护和监控各实例的目标状态,并及时纠正偏差。

Schemadock 由几个部件组成,Docker是其中一小部分但却是最重要的部分。转型到这种可扩展的方案需要付出相当大的努力,本文将介绍Docker如何帮助系统达成目标:

为何Docker成为首选?

容器化进程可实现不同版本及配置的MySQL进程运行在同一台主机上,也可以在同一个主机上配置不同小集群用来实现在更少的主机上运行同样规模集群的目的。最终,可实现不依赖Puppet,并且所有主机都可配置成一样的角色。

对于Docker自身,工程师可在Docker上构建微服务。关于Docker已经有大量的工具及知识累积,虽然Docker肯定不是最好的,但目前来讲是最佳选择。

为何不使用Docker呢?

选择Docker包括全虚拟化、LXC容器、或通过类似Puppet工具来管理运行在主机上的MySQL进程。对我们而言,选择Docker是因为简单,因为它很适合现有的架构。但如果没准备好使用Docker,而只想使用MySQL,这便是一个巨大的工程:包括完成镜像建立、发布、监控、升级Docker、日志收集、网络设置、等等工作。

这意味着,若要使用大量资源,就只能选择Docker。此外,Docker只是一种技术,而不是一个解决方案。在Uber的方案中详细规划了一个以Docker为核心部件的大型系统,用于管理 MySQL数据库。但并不是所有公司都像Uber一样广泛使用Docker,因为一些更简单的方案例如Puppet 或Ansible可能更适合。

Schema无关的MySQL Docker镜像

在这些基础上,Docker镜像只用下载、安装 Percona Server、启动mysqld,仿佛Docker镜像已经在那一般。然而,在下载和启动之间,会出现很多问题:

  • 若mounted卷中没有数据,则使用引导模式。对于主节点,运行mysql_install_db。并创建默认的用户和表。对于从节点,从集群的备份或其他节点初始化数据同步。

  • 一旦容器有了数据,mysqld 就完成启动了。

  • 若任何数据拷贝失败,容器都会再次宕机。

容器的角色通过环境变量来定义。而这个角色仅负责接收初始化数据,Docker镜像本身不包含任何建立复制拓扑、状态检查等逻辑。由于这些逻辑比MySQL 本身变动更为频繁。因此需要花大力气实现分离。

MySQL 数据目录通过主机的文件系统实现挂载,意味着Docker没有任何写开销,实际部署时将MySQL 的配置考入了镜像来固化配置。也就是说,当修改配置时无法生效。若容器因为某种原因宕机,不是重启容器,而是删除容器,再使用同样的参数,从最新版本镜像(若目标变更,则从新镜像)重新创建一个新容器,并启动它。

这种做法的好处是:

  • 配置的核心容易被管理。配置融入了Docker镜像,可实现实时监控;

  • 升级MySQL 是一件简单的事情,建立一个新的镜像,按计划停止老的容器;

  • 若出现任何异常仅需重启,而省去了打补丁的过程,只需使用新的容器接管便可。

Uber 通过建立镜像支持微服务架构,此架构从数据中心复制镜像到本地激活注册使用。

但在一个节点上运行多个容器也有缺点,因为在每个容器之间没有合适的隔离I/O的功能,一个容器可能占满所有I/O带宽,导致其他容器故障。Docker 1.10 新增了I/O限额功能,但是目前还没有应用过。不过我们通过降低主机负载和持续监控数据库性能来预防此问题。

规划Docker容器及配置拓扑

现在我们有一个可以启动的Docker主或从节点镜像,为了启动这些容器并将它们配置到正确的复制拓扑,每台数据库节点上需要运行一个代理,用来接收不同节点上的所有数据库的目标信息。典型的目标状态信息实例如下:

“schemadock01-mezzanine-mezzanine-us1-cluster8-db4”: {

“app_id”: “mezzanine-mezzanine-us1-cluster8-db4”,

“state”: “started”,

“data”: {

 “semi_sync_repl_enabled”: false,

 “name”: “mezzanine-us1-cluster8-db4”,

 “master_host”: “schemadock30”,

 “master_port”: 7335,

 “disabled”: false,

 “role”: “minion”,

 “port”: 7335,

 “size”: “all”

}

}

这段信息表明:在节点schemadock01 上需在7335端口上运行一个 Mezzanine 数据库从节点,并启动schemadock30:7335的数据库主节点。这里的‘all’参数是说该节点上只运行数据库,因此需要分配所有的内存给数据库使用。

创建目标状态对另一个请求来说就是一个会话,下一步:主机上运行的代理接收到这个信息后存储在本地,并开始处理。

处理方式是一个周期为30秒的无线循环,类似每30秒运行Puppet 一样。通过以下步骤每隔30秒循环检查系统实际状态同目标状态记录的信息是否一致:







请到「今天看啥」查看全文