17

MySQL 云原生方案在携程开发测试场景中的实践

 4 years ago
source link: https://www.infoq.cn/article/voi7AjptfRCDokhRNj9P
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

一、背景与使用场景

随着 Kubernetes 平台在容器云计算领域的一统天下,云原生 (Cloud Native) 一词也被提的越来越频繁。各类应用纷纷走上了容器化、云原生化的道路,无状态服务应用在 Kubernetes 平台上的运行,已经得到了大规模生产级别的实践认可。

相比之下,有状态应用就没有那么顺利了,特别是那些十分重要却又 " 历史悠久 "、不是按照分布式架构理念设计的有状态服务,尤其困难。MySQL 就是其中的代表,为此我们做了诸多尝试,从一开始的 MySQL 单实例容器化使用本地存储,到计算存储分离的方案,走了一些弯路。最终在开发测试场景下找了一个合适的切入点,实现了一套计算和存储分离,以 Kubernetes Operator 为核心,以 CEPH RBD 为后端存储,以数据库版本化管理为特性的可行方案。

我们典型的使用场景是这样的:测试人员需要构造一个生产环境批量订单数据异常的测试场景, 他使用安全工具从生产环境拉取大量脱敏后的数据写入测试数据库,但只运行一次测试用例, 数据库就 " 脏了 "。特别是每次上新功能还要回归测试一次这种场景,又要重复耗时在构造新数据库,真的是“构造 2 小时,运行 5 分钟”。

而有了这一套完整的 MySQL 实例服务后,可以快速启动任意版本的数据库实例,前面所述的痛点就彻底消失了。同时有了 MySQL 实例服务,对 CPU 内存资源的使用也可以节省一大笔,毕竟大量的测试数据库都只要以快照的形式存储在集群中即可,实际使用时可以在一两分钟内快速启动。

ZfuqEnY.png!web

二、可行性方案分析和性能评估

首先要解决的是计算和存储分离的问题,如果使用容器宿主机本地磁盘存储的话,MySQL 实例必须和宿主机绑定,这就丧失了资源的灵活性,而且使用本地存储, 对于磁盘容量的规划会是个不小的问题。

我们团队早在 2015 就开始使用 CEPH 存储服务,主要是对象存储和块存储,运维经验和集群稳定性方面相对有保证。结合这一实际情况,我们选择使用了 CEPH 块存储服务作为 MySQL 容器实例的存储。

另一个考量则是受益于 Kubernetes 这个强大的平台基座,社区已经定义好了容器存储接口 (CSI),且实现了 CSI driver for CEPH ( https://github.com/ceph/ceph-csi ),其中 RBD 部分早已 GA,还有提供了 snapshot,resize 等功能,完全满足我们的使用场景。

为了验证 MySQL 实例后端挂载 CEPH 块存储服务能否满足开发测试环境的数据库基本使用需求,我们基于已有的硬件情况, 做了两个场景的性能压测。主要是对比使用本地 SAS 磁盘存储的 MySQL 实例和使用 CEPHRBD 的 MySQL 实例,在性能方面是否有明显差异。其次则是测试 MySQL 实例后端挂载 CEPH RDB 存储的性能上限。

基本硬件信息如下 :

使用本地磁盘的容器宿主机 CEPH 集群所用物理机 CPU 2Socket / 32Core / 64Thread Intel® Xeon® CPU E5-2650 v3 @ 2。30GHz 2Socket / 32Core / 64Thread Intel® Xeon® Gold 6130 CPU @ 2。10GHz Memory 188GB 256GB Disk 2*300G,10K(1)
8*900G,10K(10) 2*240G,SSD(10)
12*8T,7。2K(JBOD)

构造了两个测试场景,使用 sysbench 执行压测:

sysbench 参数如下:

参数名 参数值 备注 oltp-tables-count 64 测试表的个数 64 张 oltp-table-size 1000000 单表数据量 100W num-threads [8,16,32,64,128,256] 测试线程数 times of test 3 每个线程下的测试次数 warmup time 120 预热时间,避免冷数据对测试结果的影响 max-time 120 每次压测耗时 120s,重复 3 次

测试场景 A:分别压测 MySQL docker with CEPH RBD 和 MySQL docker with local disk,并发数 threads 从低到高,8→256,对比 QPS。

测试场景 B:同时压测五个 MySQL docker with CEPH RBD,保持并发数恒定在 256,观察 CEPH 集群 IOPS 和最终 MySQL QPS。

nmqUZjb.png!web

测试场景 A 结果:

OLTP 模式压测 MySQL,对于磁盘主要是随机读写操作,CEPH RBD 使用了 SSD 作为缓存盘,随机写速度约 110MB/s,而本地机械磁盘随机写速度只有 48.6MB/s,所以最终性能指标 QPS,使用了 CEPH RBD 的容器实例反而更好。

测试场景 B 结果:

压测 CEPH RBD 集群的磁盘 IO 上限,约算测试环境的集群能提供的 QPS 上限为 80K。

结论是在开发测试环境使用 CEPH RBD 为后端存储的 MySQL 实例服务,不会比使用本地磁盘更差,可以满足应用功能测试的性能需求。

三、MySQL 容器化实例方案及实现细节

介绍一下这套方案的简单架构设计和基本工作原理,如下图:

zEJnm2e.png!web

所有相关服务都部署在 Kubernetes 集群上,这里只重点描述我们开发的 MySQL-Operator 和自定义资源 CRD。关于 CSI driver 以及 provisioner,attacher, snapshotter 等组件都是使用原生官方镜像,在这里不做详细表述,可以参考文档 ( https://kubernetes-csi.github.io/docs/ )。

MySQL-Operator 作为自定义的控制器,管理两种自定义资源 (CRD),通过 Kube-api 为上层的 PAAS 平台和 CI 等系统提供 MySQL 实例服务。两个 CRD 分别是 MySQLInstance 和 DatabaseSnapshot。其中 MySQLInstance 是基于 StatefulSet 的一层封装,添加了一些 metadata,MySQL-Operator 只需要根据 MySQLInstance 的声明来创建对应的 StatefulSet 和 PVC 即可, 所以 MySQLInstance 暴露出来的 spec 并不多,大致如下:

aEjMreU.png!web

根据 spec.init 的类型,MySQLInstance 既可以是基于生产数据库 Schema 生成的空数据库实例,也可以是基于已有的 DatabaseSnapshot 生成的带有基准数据的实例。

在创建的过程中,MySQL-Operator 会为这个 MySQLInstance 申请域名,同步账户密码以及 Schema 等。一个 MySQLInstance 的整个生命周期在有限的七个状态之间跳转。需要特别提一下 Paused 状态,当基于该实例的 DatabaseSnapshot 创建时,MySQLInstance 会进入 Paused 状态。状态机如下:

Bj2qmeZ.png!web

另一个 CRD,DatabaseSnapshot 则是基于 VolumeSnapshot 的封装,其中 VolumeSnapshot 是 Kubernetes 官方定义的持久卷快照声明 ( https://kubernetes.io/zh/docs/concepts/storage/volume-snapshots/ )。MySQL-Operator 根据它的声明来关联 MySQLInstance 和 PVC 即可。

fMbUzuI.png!web

由于 CEPH RBD 的读写独占模式 RWO(read write once), 我们为 DatabaseSnapshot 定义了两个常态 InUse 和 Ready。简单来讲就是一个数据库快照同一时间只允许一个数据库实例使用,并且 DatabaseSnapshot 在创建过程中需要暂停对应的 MySQLInstance,状态机如下:

mE7zaiZ.png!web

四、小结与展望

在有了 MySQLIntance 服务之后,数据库的版本管理变得和代码版本管理一样灵活。特别是重复构造测试数据的场景,节省了大量的时间和管理成本。另外用户也不再需要长期占用计算资源,仅在有使用需求时即可快速创建 MySQLInstance,有效提高了整体容器宿主机资源的使用率。除此之外,上层 CI/CD 平台服务也可以通过 Kube API 调用的方式来管理这两种 CRD,进一步提升测试自动化程度。

一般来说,应用云原生化完成后最重要的是获得两个能力:弹性和分布式,目前我们的这套方案落地于 Kubernetes 平台,释放出了一部分平台计算和存储的弹性,让用户对于数据库实例有了更多的选择和灵活管理的能力。

何谓云原生 (Cloud Native), 字面上早已经有了明确的定义 ( https://github.com/cncf/toc/blob/master/DEFINITION.md ),但是在工程实践中,基于 Kubernetes 这个巨大的平台,仍然有大量的宝藏等着我们去持续探索挖掘。

作者介绍:

Alex,专注于云计算领域数年,目前主要从事容器云平台的建设,推进各类基础设施服务的云原生化。

小石川,目前主要从事容器云平台监控系统建设,对分布式、性能以及优化感兴趣。

本文转载自公众号携程技术(ID:ctriptech)。

原文链接:

https://mp.weixin.qq.com/s?__biz=MjM5MDI3MjA5MQ==&mid=2697269592&idx=2&sn=2ebc6e51909422ae573fafcf943500c7&chksm=8376ee6cb401677a803bd57cb8e3859ee0a635ce965449d7cf3b81b6a2b7cb1f14b973580da2&scene=27#wechat_redirect


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK