作者: li_zhenhuan 原文来源: https://tidb.net/blog/a55c1d14
使用多租户
有很多文章介绍技术上如何使用多租户,在这里简单说明:
CREATE RESOURCE GROUP rg_oltp RU_PER_SEC=4000;
ALTER USER app1 RESOURCE GROUP "rg_oltp";
如上面 SQL 显示,业务1使用 app1 连接到 TiDB 之后可以控制业务1最多只使用 4000 RU 的负载,实现资源隔离。资源控制效果有很多文章已经有说明此处不再赘述。
多租户方案
使用 TiDB 多租户技术完成多业务系统使用统一 TiDB 集群,确保不同业务负载隔离,再利用 TiFlash 的 实时 HTAP 能力,实现跨业务数据关联查询,方案架构图如下:
- 根据多个业务负载分别设置不同资源组和 RU(Request Unit),当 TiDB 整体资源繁忙时实现不同业务基于 RU 限流和负载隔离;
- 为错峰且重要业务设置资源组 BURSTABLE 属性,实现跨业务错峰资源借用;
- 设置重要业务优先级为 HIGH,确保集群优先保证重要业务资源可用;
- 使用 TiFlash 完成跨业务统一视图和实时数据分析需求;
方案优势
-
节约硬件成本
- MySQL 主从架构从节点利用率低,TiDB 多活架构所有节点平等且资源利用率高;
- 当 TiDB 统一资源池资源不够时可以随时在线扩展,无需为业务预留太多闲置资源,提升整体资源利用率;
- 借助多租户 BURSTABLE 特性,实现不同业务资源借用,进一步提升整体资源利用率。
-
降低开发和运维成本
- TiDB对应用透明无侵入,可降低开发成本,缩短业务上线周期。从管理多套 MySQL 到管理一套 TiDB 集群,大幅降低了数据库运维成本。
-
解决数据孤岛问题
- 使用 TiFlash 支持跨业务强一致性数据查询,支持统一视图、实时数据分析、实时风控等业务。
评估业务 RU
根据 RU 的计算公式可以看到读取 RU 权重为 1/64,写入权重为 1 ,这是因为写入数据还需要进行多副本复制并且开启事务提交事务等操作,此过程涉及到更多资源开销。因此对于不同的业务读写占比差异大时会导致集群总 RU 评估差异巨大。
以云上标准 8C/64G TiKV * 3 的集群为例,使用 oltp_read_only 方式评估 RU 为1.4W,oltp_read_write 方式评估 RU 为2.9W,oltp_write_only 方式评估 RU 为 7.3W。不同负载的瓶颈点不同,消耗各模块的资源比例也不一样 。但是这个差异给用户带来 RU 评估的困惑,某个业务读写流量占比存在差异,无法直接参考Sysbench测试得到真实 RU 资源,在无法运行实际负载的时候,可以作为一个初始设置,之后再观察调整。具体方式如下:
给各个业务分配不同的用户,绑定不同的 Resource Group 并且设置 BURSTABLE 属性,业务跑一两天之后在观察 DashBroad 上业务真实 RU 消耗情况,比如业务1 这一两天峰值消耗最大的 RU 为 1000,则修改业务1 对应 Resource Group RU 为 1300 并且删除 BURSTABLE 属性,完成业务1资源评估和控制。建议只给集群中最重要且错峰的1-2个业务设置 BURTABLE 属性,保证重要业务资源借用。不建议给不重要的业务设置 BURTABLE 属性,以免不重要业务出现异常流量时超限额使用集群资源。
通过 DashBroad 观察业务 RU 消耗情况
补充:如果单机多实例部署 TiKV 需要使用 NUMA 或者 cgroup 等方式给每个实例加上资源限制,否则通过CALIBRATE RESOURCE资源评估时会返回过大的 RU 评估结果。
小结:读写RU权重不同,无法事前准确评估,先上业务观察 RU 消耗,再配置 RU 大小。
QoS 资源控制逻辑
TiDB 多租户使用 QoS(服务质量满足) 实现负载隔离,当周期资源用量超过 RU 限制时触发限流,具体限流逻辑如下:
假设业务1对应资源组 RU 为10,业务1执行查询语句 SQL1 生成执行计算之后有三次 RPC 请求 TiKV 。
第一次 RPC :假设请求 4 个 TiKV Region,参考之前 RU 计算公式,此时消耗 RU 为 4 * 0.25 = 1个 RU,这 4 个请求消耗了3ms CPU 并且读取了 64 KB 数据,TiKV 处理完这 4 个请求之后会将资源消耗信息返回给 TiDB ,TiDB 计算出此次消耗 RU 为 1 + 3*1/3 + 64*1/64 = 3 个 RU。
第二次 RPC:因为第一次 RPC 消耗了 3 个 RU 业务真实 RU 为 10,此时还有 RU 余量,可以直接继续第二次 RPC ,假设第二次 RPC 消耗了 20 个 RU ,因为 RU 是 TiKV 消耗 Response 之后 TiDB 事后统计,因此会存在突发超过 RU 限制的情况。
第三次 RPC:因为前面两次 RPC 累积消耗了 23 个 RU,已经超过业务 10 RU 资源限制,会形成负债并触发限流。第三次 RPC 会先等待 1.3 秒左右等待将 RU 负债还清再开始将 RPC 请求发送给 TiKV 。进而实现负载隔离。
Bad SQL 限流
基于 RU 和 SQL Binding 可以实现 Bad SQL 限流,假设集群忽然出现一个新的全表扫描 SQL 消耗大量资源,此时可以通过 SQL binding 将此 SQL 绑定到 RU 为 1 的 Resource Group 进而实现限流。具体操作如下:
创建 RU 为 1 Resource Group:
create resource group small_rg1 PER_RU_SEC=1;
为 Bad SQL 创建 SQL Binding :
create GLOBAL binding for select count(1) from big_table using select /*+ RESOURCE_GROUP(small_rg1) */ count(1) from big_table
观察限流效果:
可以发现此 Bad SQL 无法再次运行,实现了 SQL 禁用。
上面三次 RPC 分析时超过资源限制时可以通过等待一定时间周期来低速运行,但是为什么此时 Bad SQL 不是慢运行而是直接报错呢?因为 TiDB 多租户有负债上限,为了避免负债累计过多造成请求大量积压,当负债达到一定规模时,TiDB 就不再接收新的请求,当前版本是 30倍 RU 限额。 在这个case里,等待约 30 秒。
总结
为多个业务分别绑定不同 Resource Group,观察真实消耗情况,再基于真实消耗预留一定 Buffer ,只为重要且真实错峰的业务设置 BURSTABLE 属性,实现 TiDB 资源池化。
此时可以将 TiDB 当做一个资源池,不断将中小业务迁移到 TiDB ,资源不够时再单独添加 TiDB 或 TiKV 资源。