本文发表于一年多前。旧文章可能包含过时内容。请检查页面中的信息自发布以来是否已变得不正确。
如何在 Kubernetes 中为 TPR 集成 RollingUpdate 策略
使用 Kubernetes,可以轻松管理和扩展无状态应用程序,如 Web 应用和 API 服务。迄今为止,所有关于 Kubernetes 的讨论几乎都围绕着微服务和无状态应用程序。
随着基于容器的微服务架构的普及,部署和管理关系型数据库管理系统 (RDBMS) 的需求越来越强烈。RDBMS 需要有经验的数据库特定知识才能正确地扩展、升级和重新配置,同时防止数据丢失或不可用。
例如,MySQL(最流行的开源 RDBMS)需要将数据存储在持久且专属于每个 MySQL 数据库存储的文件中。每个 MySQL 数据库都需要独立区分;另一个更复杂的情况是在集群中,需要将集群中的一个 MySQL 数据库区分为不同的角色,例如主库、从库或分片。在机器故障时替换数据库节点,实现高可用性和零数据丢失也很困难。
利用强大的 Kubernetes API 扩展机制,我们可以将 RDBMS 领域知识编码到名为 WQ-RDS 的软件中,它像内置资源一样运行在 Kubernetes 之上。
WQ-RDS 利用 Kubernetes 原生资源和控制器,提供了一系列企业级功能,并带来了显著可靠的方式来自动化耗时的操作任务,如数据库设置、补丁备份和设置高可用集群。WQ-RDS 支持主流版本的 Oracle 和 MySQL(兼容 MariaDB)。
让我们演示如何管理 MySQL 分片集群。
MySQL 分片集群
MySQL 分片集群是一种横向扩展的数据库架构。基于哈希算法,该架构将数据分布在集群的所有分片中。分片对客户端完全透明:代理能够连接到集群中的任何分片,并直接向正确的碎片发出查询。
| ----- |
| |
|
注意:每个分片对应一个 MySQL 实例。目前,WQ-RDS 最多支持 64 个分片。
|
所有分片均使用 Kubernetes Statefulset、Services、Storage Class、configmap、secrets 和 MySQL 构建。WQ-RDS 管理分片集群的整个生命周期。分片集群的优点显而易见:
- 横向扩展每秒查询次数 (QPS) 和每秒事务次数 (TPS)
- 横向扩展存储容量:通过将数据分布到多个节点来获得更多存储空间
创建 MySQL 分片集群
让我们创建一个包含 8 个分片的 Kubernetes 集群。
kubectl create -f mysqlshardingcluster.yaml
接下来,创建一个包含 8 个分片的 MySQL 分片集群。
- TPR:MysqlCluster 和 MysqlDatabase
[root@k8s-master ~]# kubectl get mysqlcluster
NAME KIND
clustershard-c MysqlCluster.v1.mysql.orain.com
从 clustershard-c0 到 clustershard-c7 的 MysqlDatabase 属于 MysqlCluster clustershard-c。
[root@k8s-master ~]# kubectl get mysqldatabase
NAME KIND
clustershard-c0 MysqlDatabase.v1.mysql.orain.com
clustershard-c1 MysqlDatabase.v1.mysql.orain.com
clustershard-c2 MysqlDatabase.v1.mysql.orain.com
clustershard-c3 MysqlDatabase.v1.mysql.orain.com
clustershard-c4 MysqlDatabase.v1.mysql.orain.com
clustershard-c5 MysqlDatabase.v1.mysql.orain.com
clustershard-c6 MysqlDatabase.v1.mysql.orain.com
clustershard-c7 MysqlDatabase.v1.mysql.orain.com
接下来,我们看看两个主要功能:高可用性和滚动更新策略。
为了演示,我们首先运行 sysbench 在集群上生成一些负载。在这个例子中,QPS 指标由 MySQL 导出生成,由 Prometheus 收集,并在 Grafana 中可视化。
功能:高可用性
WQ-RDS 处理 MySQL 实例崩溃,同时保护数据不丢失。
当杀死 clustershard-c0 时,WQ-RDS 将检测到 clustershard-c0 不可用,并在故障机器上替换 clustershard-c0,平均耗时约 35 秒。
同时实现零数据丢失。
功能:滚动更新策略
MySQL 分片集群不仅带来了强大的可扩展性,也带来了一定程度的维护复杂性。例如,当更新 MySQL 配置(如 innodb_buffer_pool_size)时,DBA 必须执行许多步骤:
1. 应用更改时间。
2. 禁用客户端访问数据库代理。
3. 开始滚动升级。
滚动升级需要按顺序进行,是过程中最严苛的步骤。在之前的 MySQL 实例更新运行并准备就绪之前,不能继续滚动升级。
4. 验证集群。
5. 启用客户端访问数据库代理。
滚动升级可能出现的问题包括:
- 节点重启
- MySQL 实例重启
- 人为错误 相反,WQ-RDS 使 DBA 能够自动执行滚动升级。
Kubernetes 中的 StatefulSet 滚动更新
Kubernetes 1.7 包含一个主要功能,为 StatefulSet 添加了自动化更新,并支持一系列更新策略,包括滚动更新。
注意: 有关 StatefulSet 滚动更新 的更多信息,请参阅 Kubernetes 文档。
由于 TPR(目前为 CRD)不支持滚动升级策略,我们需要将滚动更新策略集成到 WQ-RDS 中。幸运的是,Kubernetes 仓库 是一个学习的宝库。在实现过程中,有一些点值得分享:
**MySQL 分片集群已**更改:每个 StatefulSet 都有其对应的 ControllerRevision,记录所有修订数据和顺序(如 git)。每当 StatefulSet 同步时,StatefulSet Controller 将首先将其 spec 与最新的对应 ControllerRevision 数据进行比较(类似于 git diff)。如果发生更改,将生成一个新的 ControllerRevision,修订号将增加 1。WQ-RDS 借鉴了这一过程,MySQL 分片集群对象将记录 ControllerRevision 中的所有修订和顺序。
**如何初始化 MySQL 分片集群以满足请求的**副本:Statefulset 支持两种 Pod 管理策略:Parallel 和 OrderedReady。由于 MySQL 分片集群的初始过程不需要有序创建,我们使用 Parallel 策略来加速集群的初始化。
**如何执行滚动**升级:Statefulset 以严格递减的顺序重新创建 Pod。不同之处在于,WQ-RDS 更新分片而不是重新创建它们,如下图所示:
滚动更新何时结束:Kubernetes 明确发出终止信号。当一个集合的所有 Pod 都已更新到 updateRevision 时,滚动更新完成。状态的 currentRevision 设置为 updateRevision,其 updateRevision 设置为空字符串。状态的 currentReplicas 设置为 updateReplicas,其 updateReplicas 设置为 0。
WQ-RDS 中的控制器修订
修订信息存储在 MysqlCluster.Status 中,与 Statefulset.Status 没有区别。
root@k8s-master ~]# kubectl get mysqlcluster -o yaml clustershard-c
apiVersion: v1
items:
\- apiVersion: mysql.orain.com/v1
kind: MysqlCluster
metadata:
creationTimestamp: 2017-10-20T08:19:41Z
labels:
AppName: clustershard-crm
Createdby: orain.com
DBType: MySQL
name: clustershard-c
namespace: default
resourceVersion: "415852"
uid: 6bb089bb-b56f-11e7-ae02-525400e717a6
spec:
dbresourcespec:
limitedcpu: 1200m
limitedmemory: 400Mi
requestcpu: 1000m
requestmemory: 400Mi
status:
currentReplicas: 8
currentRevision: clustershard-c-648d878965
replicas: 8
updateRevision: clustershard-c-648d878965
kind: List
示例:执行滚动升级
最后,我们现在可以更新“clustershard-c”,将配置“innodb_buffer_pool_size”从 6GB 更新到 7GB 并重启。
此过程需要 480 秒。
升级呈单调递减趋势
结论
滚动升级对数据库管理员来说意义重大。它提供了一种更有效的数据库操作方式。