把云数据库服务变成黑盒子:ServerlessDB for HTAP 丨 Hacking Camp 进行时
作者: 薛港 - 移动云原文来源:https://tidb.net/blog/ff1d25d5
ServerlessDB for HTAP 的最终目标是要把云数据库服务变成黑盒子,让应用开发者只需要专注于业务如何转化成 SQL,并保证任意时刻,任意 SQL 云数据库服务都能在合理的时间返回正确的结果。我们的用户再也不用操心数据量、业务负载、数据库参数、AP 还是 TP SQL、高可用等这些和业务不相关的事情。
本次参与项目的成员全部来自于移动云数据库团队,主要负责在移动云上基于 TiDB 提供 ServerlessDB 服务。本次参与 ServerlessDB for HTAP 项目成员分工如下:
薛港:负责整体架构设计,以及中间件核心模块开发.
沈政:负责 serverless 模块的设计以及开发工作,实现计算存储 scale up / down, scale in/out
时丕显:负责业务负载模块的设计以及开发工作;完成模块之间的集成测试
金汭:负责所有模块 API 设计开发工作,提供所有组件的容器化方案;负责针对 AP 场景的 serverless 模块开发
要基于 TiDB 实现 serverless 服务,需要解决一系列问题,重点列出几点:
什么时候扩缩容,每次扩缩多少。
如何保证扩容以后,每个节点的负载均衡,以及缩容过程中用户的零感知。
如何区分 AP 和 TP 的 SQL 类型,最终保证运行时,相互干扰减少到最低。
如何提供多个云服务实例。
针对上述问题,我们的解决思路如下:
开发业务负载模块,评估当前提供服务的资源与当前业务负载是否匹配,建立业务负载模型,用于决策扩容还是缩容,扩缩多少。模型参考因子,包括 CPU、SQL 成本、QPS 等。
为了解决扩容后业务负载快速分摊到所有的节点,以及缩容时业务负载从待缩容节点迁移走,因此我们开发了 TiDB 中间件。
当前我们通过 SQL 成本区分 TP 和 AP 类型,底层资源提供多个计算池,负责不同 SQL 成本的 SQL 运行,例如一个 TP 计算池,1 到 N 个 AP 计算池。
基于 TiDB Operator 实现多个实例的云服务管理,我们提供 K8s 本地盘管理,用于解决私有化部署无法提供云盘的问题。我们也通过开发 admission-webhook,保证删除 tidb pod 时,预先删除中间件注册表记录。
一、目前的进展
1、serverless 模块 90%
在 serverless 模块中,我们定义一个指标“算力”,整个过程是通过比较它的变化来决定 TiDB 扩容或缩容,1 算力近似等于 1 个 CPU 和 2 GB 内存的计算资源,算力的增加对应的 CPU 和内存是 1:2 的关系。
1) 针对 AP、TP 不同类型 TiDB 节点的扩缩容模块 90%
TP 类型节点的扩缩容
标注:TC 指 tidbclusters.pingcap.com 的 crd,多个 tc 对象管理不同规格切换,副本指实例数
proxy 模块给 serverless 模块发送基于当前 TP 类型节点的总成本计算出的算力值,同时 serverless 模块自身也会从 promethues 读取 CPU 使用量再计算成算力值,当几个节点的 CPU 平均使用量超过 50%,则认为需要翻倍扩容,我们遵循扩容自由缩容谨慎的原则。对于扩容,serverless 会比较两个算力值(proxy 和 promethues),取较大值作为目标值来进行扩容;缩容则较为钝感,只有当中间件发送算力值时带有缩容的标签,则对应算力值做缩容。
扩容算法:
为了计算出目标值需要的 TIDB 节点的规格以及数量,事先定好一个列表包含多个规格,例如 [0.5,1,2,4],该列表最大值和最大副本数可动态配置,目前配置的最大副本数为 8,那么该规格列表即可覆盖最大 4*8=32 算力(32C),每个规格对应的算力范围为 [0.5,1-8,2-16,4-32],0.5 为最小保护算力,即始终起一个 0.5 算力的 tidb 作为业务备用,其他算力范围则为 8 的倍数,如果当前算力值为 4(1C*4 副本),需要扩到 8,目标值 8 刚好依然在 1 核的范围之内(1-8),则直接扩大副本数为 8 即可,若目标算力为 16,此时需注意我们起 TC 都是遵循先起小 TC 的原则,因为经过测试同样算力的小 TC 性能更高,所以从小到大选择规格,优先选择 2C 乘以 8 副本的方式起 TC,如果目标值是 9,通过计算需要起 2C 乘以 4 副本后,还剩一个算力,此时会计算剩余值是否大于该规格的 50%,如果大于等于则再起一个副本,如果小于则忽略,在这个例子中,剩余值 1 大于等于 1C,则再起一个副本,那么目标值是 9 会起 2C 乘以 5 副本。
缩容算法:
和扩容算法类似,也同样去计算确认规格区间和副本数,不同点是,如果目标算力小于等于当前规格最大算力的 25%,则重新由小到大挑选规格,因为同等算力下小规格的 TiDB 性能更好,例如当前算力是 16(2C*8 副本),目标算力是 3,3 小于 16 的 25%,所以在规格表 [0.5,1,2,4] 中,按照从小到大的挑选原则,即缩小为 1C 乘以 3 副本,如果目标值是 9,9 大于 16 的 25%,则只需修改副本数,缩到 2C 乘以 5 副本。
AP 类型节点的扩缩容
目前 AP 不会跨规格扩缩容,只会起一个规格(4C16G)的 TC,proxy 模块会基于 AP 类型节点的总成本计算出算力值,根据该算力值去增删副本数。
此外还会建一个大规格(16C32G)的 TC 去处理成本高、耗时久的 SQL,即用即停,当收到代价较高的 SQL 请求后,proxy 模块通知 serverless 新增一个 Pod 去处理它,处理完成后再删除。
2)根据存储容量对 TiKV 节点进行扩容 100%
对于 TiKV,serverless 只会对其扩容,不会缩容,扩的原则是 tikv 本地存储实际使用量占 tikv 存储规格的 70%,tikv 横向增加一个实例,当横向扩容的 tikv 实例数达到环境变量配置的上限如 10 个 tikv 时,进行纵向扩容,因为我们组件含有本地盘且实现了存储扩容,直接修改 tikv 的存储 request 每次增加 20G,就可实现所有 tikv 实例存储自动增加 20G。
3)规则模块 100%
为了应对业务负载激增的特殊情况、保持服务的持续稳定,因此在基于负载进行动态扩缩容之外,我们还设置了规则系统,每个规则描述一个时间段的资源规格。在规则生效时间内,计算资源不会发生任何变化。在规则时间外,还是会基于负载实现扩缩容。目前规则时间最小粒度为小时,支持按天、周、月作为重复周期(重复周期不支持跨天设置,仅一次性周期支持跨天设置。)
2、proxy 模块 80%
基于 TiDB 改造,开发支持代理和计算的混合中间件。当业务负载低时,中间件节点退化成纯 TiDB 节点,承载所有 TP 类型的业务流量。随着业务负载变高,会扩容出其它 1-N 个 TP 类型的计算节点,业务负载会按照 CPU 比例分配业务流量到中间件以及其它计算节点。
如果业务负载流量达到一定的上限,中间件会升级成纯粹的代理节点,把业务流量打散到所有后台计算节点。 部分功能模块如下:
1) 中间件代理框架开发 80%
针对不同的 mysql cmd 以及 SQL 类型,保存运行时上下文,转发请求到后台计算节点,得到计算节点的计算结果,最终通过中间件返回结果给客户端,整个过程用户完全感受不到连接的是中间件
2) 针对不同类型 TiDB 节点分配实现负载均衡 90%
为了避免不同类型的 SQL 互相影响,因此我们将后台的 TiDB 节点分为三种类型:
TP 类型
其中 proxy 节点本身也属于 TP 类型,当 TP 类型只有一个节点,即 proxy 节点时,则 proxy 节点作为纯计算的节点,所有的 TP 请求都在 proxy 节点进行处理;当 TP 类型有多个节点并且 proxy 节点的负载不高时,则 proxy 节点作为一个普通的 TP 类型计算节点;当 proxy 节点负载非常高时,则 proxy 节点只负责转发请求,不再作为计算节点。而所有 TP 的请求采用平滑的加权轮询算法均匀的分发到不同的计算节点,并且计算节点的权重值是基于该节点的规格。
AP 类型
所有 AP 的请求采用平滑的加权轮询算法均匀的分发到不同的计算节点,并且计算节点的权重值是基于该节点的规格,目前 AP 类型的计算节点规格只有一种类型。
超大规格类型(用于处理单条成本很大的 SQL)
当收到一条很复杂的 SQL 请求时,proxy 模块会通知 serverless 模块起一个超大规格的 pod,当 pod 可以提供服务后,proxy 模块会将该 SQL 转发到新起的大规格 pod 上,等 SQL 执行完成后,proxy 模块通知 serverless 模块删除该 pod。
3、本地盘模块 100%
1) 实现 K8s 本地盘的动态管理 100%
本地盘主要基于 K8s 开放的标准 CSI 存储接口以及 LVM 技术实现,主要实现了本地存储容量管理以及 PV 动态创建、删除、pv 扩缩容以及本地存储剩余容量参与容器调度。
实现步骤
主要实现 CSI Identity、CSI Node、CSI control 的接口功能,在 pod 未调度到具体节点前,pv 与 pvc 的 Bound 不关联具体存储介质,待 pod 调度具体节点时,然后使用 lvm 相关命令 lvcreate 在 vg 卷组中动态创建逻辑卷,将 pv 关联到逻辑卷,同时将 pv 上打节点标签信息,以便 pv 在后续使用过程中能找到具体节点。另外,pod 的调度我们开发 lvm-scheduler 调度器组件容器,该组件容器同时兼容 k8s 原生的 cpu、memory 调度并加入剩余本地存储容量作为调度因子,每个节点上管理本地存储的 CSI-hostpath-plugin 组件定期更新本地剩余存储容量,lvm-scheduler 调度器选择 cpu、memory、存储空间最优的节点作为调度节点。pv 的扩容,k8s 监控 PVC 的容量变化后,CSI Node 组件容器通过 lvextend 实现对逻辑卷的动态扩容。pv 的删除,最终触发 CSI Node 组件容器进行 lvremove 进行逻辑卷删除。
实际效果
本地盘部署完成后,与使用云盘块存储一样方便,我们只需要在创建 PVC 时关联我们提供的 storageclass,应用容器使用本地存储时,本地盘容器会自动分配相应容量给应用容器。
4、admission-webhook 模块 100%
1) 实现节点缩容时对用户无感知 100%
主要通过 admission-webhook 模块实现在缩容时对用户无感知的目标。在进行缩容时,借助 advanced-statefulset,决定哪些节点将被删除,然后 admission-webhook 可以拦截删除 tidb pod 的请求。首先,admission-webhook 模块向 proxy 模块发送删除该 pod 的请求,proxy 模块将停止转发请求到该 pod 上,并确保以执行的 sql 顺利结束,当该节点没有待执行的 SQL 时,proxy 模块将通知 admission-webhook 模块释放该删除请求,最终 admission-webhook 允许删除该 pod,实现用户无感知的缩容。
二、issue 列表
1、https://github.com/tidb-incubator/Serverlessdb-for-HTAP/issues/2:judge whether a SQL is AP or TP
2、https://github.com/tidb-incubator/Serverlessdb-for-HTAP/issues/3:How to evaluate whether to scale-out or scale-in, and what is the number of nodes to scale-out or scale-in
3、https://github.com/tidb-incubator/Serverlessdb-for-HTAP/issues/4:Performance problems when the cluster is running on a small hashrate
4、https://github.com/tidb-incubator/Serverlessdb-for-HTAP/issues/5:TiDB nodes assignment algorithm when receiving a request
5、https://github.com/tidb-incubator/Serverlessdb-for-HTAP/issues/6:For AP process, elegant start and stop auto-scaling
6、https://github.com/tidb-incubator/Serverlessdb-for-HTAP/issues/7:Users will not be affected at all when auto-scaling
三、后续规划
优化减少因为引入中间件对性能造成的影响
业务负载模块的精细化,两个方向,一是运行前各类资源使用评估(例如每个算子评估资源使用量) 二是实际运行过程中的资源评估(CPU,内存,网络)
如何加速扩容时间,当前我们基于容器方案,启动时间 10-20s,如果优化新增节点的时间,例如优化到 1s。节点启动时间对 serverless 至关重要,从发现业务负载到完成节点启动,时间越长,对服务影响越大
如何解决小算力场景下,业务负载暴增的问题
版权声明: 本文为 InfoQ 作者【TiDB 社区干货传送门】的原创文章。
原文链接:【http://xie.infoq.cn/article/ac0be3f8357dd1efdf0a45e0c】。文章转载请联系作者。
评论