{
    "componentChunkName": "component---src-templates-blog-blog-detail-tsx",
    "path": "/blog/six-things-to-know-about-resource-control",
    "result": {"pageContext":{"blog":{"id":"Blogs_515","title":"TiDB 7.1.0 LTS 特性解读丨关于资源管控 (Resource Control) 应该知道的 6 件事","tags":["资源管控"],"category":{"name":"案例实践"},"summary":"面对 TiDB 7.1 若干重要特性，新 GA 的资源管控 (Resource Control) 是必须要充分理解、测试的一个重量级特性。本文将围绕“资源管控”主题，详细说说关于 “资源管控” 您应该知道的 6 件事。","body":"TiDB 7.1.0 LTS 在前段时间发布，相信很多同学都已经抢先使用了起来，甚至都已然经过一系列验证推向了生产环境。面对 TiDB 7.1 若干重要特性，新 GA 的资源管控 (Resource Control) 是必须要充分理解、测试的一个重量级特性。对于常年奋斗在一线 DBA 岗位的我来说，学术方面的精进已经力不从心，大部分的时间都在强化“术”的方面，所以 TiDB 每更（新）必追，每个新 GA 的特性都要熟悉，这样当生产环境 TiDB 升级到目标版本后，才不至于手忙脚乱，新建 TiDB 集群后才能对新特性驾轻就熟。相信本文会给读者朋友们带来一些实质性的收获。言归正传，本文将围绕“资源管控”主题，详细说说关于 “资源管控” 您应该知道的 6 件事。\n\n## 从用户场景出发，看特性如何使用\n\n从 200+ 的国产数据库中脱颖而出，其有效、完备的文档当属“功不可没”。在 TiDB 7.1 的文档中是这样描述使用场景的：\n\n资源管控特性的引入对 TiDB 具有里程碑的意义。它能够将一个分布式数据库集群划分成多个逻辑单元，即使个别单元对资源过度使用，也不会挤占其他单元所需的资源。利用该特性：\n\n- 你可以将多个来自不同系统的中小型应用合入一个 TiDB 集群中，个别应用的负载升高，不会影响其他业务的正常运行。而在系统负载较低的时候，繁忙的应用即使超过设定的读写配额，也仍然可以被分配到所需的系统资源，达到资源的最大化利用。\n- 你可以选择将所有测试环境合入一个集群，或者将消耗较大的批量任务编入一个单独的资源组，在保证重要应用获得必要资源的同时，提升硬件利用率，降低运行成本。\n- 当系统中存在多种业务负载时，可以将不同的负载分别放入各自的资源组。利用资源管控技术，确保交易类业务的响应时间不受数据分析或批量业务的影响。\n- 当集群遇到突发的 SQL 性能问题，可以结合 SQL Binding 和资源组，临时限制某个 SQL 的资源消耗。\n\n那么，从务实的 DBA 角度来看这段话，可能会是下面这个样子：\n\n资源管控，这一新特性，将数据库中的用户、会话、SQL 等日常行为的性能指标做了更加细致的量化处理。引入了 “Request Unit (RU)” 这一量化概念，目前包括了 CPU, IOPS, IO 带宽 三个重要指标，未来还会增加内存、网络等指标。\n\n- 可以将若干 MySQL 数据库合并进一个 TiDB 集群，比如读写峰值常出现于日间的 OA 系统，读写峰值常出现于夜间的 Batch 系统，以及 24 小时运行但负载持续稳定的数据采集系统，这种“三合一”的方式，使得各系统“错峰出行”，借助资源管控的能力“按需分配”，以此达到降低综合成本的目标。\n\n![三合一.png](https://img1.www.pingcap.com/prod/_da5cfc79ec.png)\n\n- 在一个 TiDB 集群，为不同测试环境 (Env) 创建不同测试用户 (User)，然后依据测试所需资源规格创建不同资源组 (Resource Group)，并将用户与对应的资源组做绑定。如此做到了不同用户的资源隔离，由于是测试环境，可将资源组设置为**超限** ( BURSTABLE ) ，或者理解为“超卖”，某个或某几个用户使用的资源超过了资源组规定的限制，依旧可以正常使用，而不影响测试，可以最大化利用硬件资源。不过，这里的测试应该理解为业务测试，而非标准的性能测试，不然需要更加严谨的考虑资源分配以及**超限** ( BURSTABLE ) 的使用。\n- 类似于第一节中的描述，三个系统分别对应三个资源组，且 BURSTABLE 的设定为 NO，那么三个系统使用的资源将是隔离的，不受彼此影响。也就是说，在当前 TiDB 集群中，即使 TP、AP 业务同时运行，由于使用了资源控制特性，此时 TP 业务并不会受到 AP 业务的干扰。\n- 业务是不断变化的，“Bad SQL” 问题随时可能发生，如果某条 SQL 占用资源 (RU) 过高，影响该用户的其他 SQL 性能。此时，可以新建一个资源组，并可以使用 执行计划绑定(SQL Binding)功能，将该 SQL 语句绑定到新建的资源组上，以起到限制 SQL 资源消耗，甚至拒绝 SQL 执行的目的。测试 SQL 如下：\n\n```\nCREATE RESOURCE GROUP rg1 RU_per_SEC=1;\n\nCREATE GLOBAL BINDING FOR\n  SELECT COUNT(*) FROM t1 t JOIN t1 t2 USING (uid) \nUSING\n  SELECT /*+ resource_group(rg1) */ COUNT(*) FROM t1 t JOIN t1 t2 USING (uid);\n\nEXPLAIN ANALYZE FORMAT = 'verbose' SELECT COUNT(*) FROM t t1 JOIN t1 t2 USING (uid);\n```\n\n为了实现上述场景，TiDB 实现了若干 SQL 语法，接下来看看如何具体操作。\n\n## “资源控制”相关 SQL，用这些就够了\n\n研究 TiDB 的人还有不知道 [AskTUG](https://asktug.com/)[1] 的么？半年前，@社区小助手整理了一篇极具实用价值的帖子 -- 【社区智慧合集】[TiDB 相关 SQL 脚本大全](https://asktug.com/t/topic/999618)[2]， 内含 38 条实用 SQL，是 TiDBer 们必收藏的帖子之一。  \n\n彼时“资源控制”功能尚未“问世”，所以帖子里并不包含该特性相关 SQL，下面我将“资源控制”相关的精华 SQL 贴出，以供参考。  \n\n**1)增删改查 -- 资源组 (Resource Group)**\n\n- 增：\n\n```\n-- 创建 `rg1` 资源组，限额是每秒 `500 RU`，优先级为 `HIGH`，允许这个资源组的超额 (`BURSTABLE`) 占用资源。\nCREATE RESOURCE GROUP IF NOT EXISTS rg1 \n  RU_PER_SEC = 100\n  PRIORITY = HIGH\n  BURSTABLE;\n\n-- 创建 `rg2` 资源组，限额是每秒 `500 RU`，其他选项为默认值。\nCREATE RESOURCE GROUP rg2 RU_PER_SEC = 200;\n```\n\n- 删：\n\n```\n-- 删除资源组\nDROP RESOURCE GROUP rg2;\n```\n\n- 改：\n\n```\n-- 修改资源组资源配置\nALTER RESOURCE GROUP rg2 ru_per_sec = 2000;\n```\n\n- 查：\n\n```\n-- 通过 I_S 表查看\nSELECT * FROM INFORMATION_SCHEMA.RESOURCE_GROUPS;\n```\n\n需要注意的是，创建、修改、删除资源组，需要拥有 `SUPER` 或者 `RESOURCE_GROUP_ADMIN` 权限，否则会遇到报错：\n\n```\nERROR 1227 (42000): Access denied; you need (at least one of) the SUPER or RESOURCE_GROUP_ADMIN privilege(s) for this operation\n```\n\n**2)绑定用户到 Resource Group**  \n\n- 将某个用户绑定到资源组\n\n将用户和资源组绑定很简单，其实就是修改用户的属性。如果是已创建的用户，可以用 `ALTER USER`，如果是新建用户，则可用 `CREATE USER`。\n\n```\n-- CREATE\nCREATE USER u3 RESOURCE GROUP rg3;\n-- ALTER\nALTER USER u2 RESOURCE GROUP rg2;\n```\n\n- 查看某个用户绑定到资源组  \n\n这里有两种方法和二个问题，两种方法是分别通过 `mysql` 库和 `INFORMATION_SCHEMA` 库进行查询。\n\n```\nmysql> SELECT User, JSON_EXTRACT(User_attributes, \"$.resource_group\") AS RG FROM mysql.user ;\n+------+-----------+\n| User | RG        |\n+------+-----------+\n| root | NULL      |\n| u1   | \"default\" |\n| u2   | \"rg2\"     |\n| u3   | \"\"        |\n+------+-----------+\n4 rows in set (0.00 sec)\n```\n\n**问题一：Resource Group 的 `` 和 `default` 等同**  \n\n从上面的查询结果来看，除了普通用户 `u2` 绑定的资源组 `rg2` 之外，其余三个用户其实都使用的是默认资源组，即 `default`。只是这里出现了空 (``)，可能会造成稍许疑虑，经与官方同学确认， “**空和 default 在行为上面是一样的**” 。交流帖子参见：resource control，default resource group [文档勘误](https://asktug.com/t/topic/1008372/6?u=shawnyan)[3]\n\n**问题二：通过 `INFORMATION_SCHEMA.USER_ATTRIBUTES` 暂无法查询用户绑定的资源组**  \n\n普通用户是无权通过 `mysql` 库查询哪些用户绑定了哪些资源组的，包括当前用户，但是每个用户都可以通过 I_S 库查询自己应该可以获取的信息。所以方法二，是指普通用户通过查询 I_S 库来获取相关信息，SQL 如下：\n\n```\nSELECT * FROM INFORMATION_SCHEMA.USER_ATTRIBUTES;\n```\n\n只是目前效果不如意，期待下个版本会得到改进。相关帖子参见：resource control 相关，INFORMATION_SCHEMA.USER_ATTRIBUTES [表取值问题](https://asktug.com/t/topic/1008437)[4]\n\n**3)绑定会话到 Resource Group**  \n\n前面提到了绑定用户到 RG，其实 TiDB 提供了更加灵活的方式，可以绑定会话 (Session) 到 RG，以及绑定 SQL 语句到 RG。  \n\n将当前会话绑定到资源组\n\n```\nSET RESOURCE GROUP rg1;\n```\n\n查看当前会话所使用的资源组\n\n```\nSELECT CURRENT_RESOURCE_GROUP();\n```\n\n重置当前会话绑定资源组\n\n```\nSET RESOURCE GROUP `default`;\nSET RESOURCE GROUP ``;\n```\n\n注：两条 SQL 的功能等价，但建议使用第一条，原因参见【问题一】。  \n\n**4)绑定语句到 Resource Group**  \n\n可以使用 Hint 来控制具体某条 SQL 语句占用的 RU 资源，举例如下：\n\n```\nSELECT /*+ RESOURCE_GROUP(rg1) */ * FROM t1 limit 10;\n```\n\n如何查看某条语句消耗的 RU 呢？可以通过实际执行计划来获取，举例如下：\n\n```\nEXPLAIN ANALYZE SELECT /*+ RESOURCE_GROUP(rg1) */ * FROM t1 limit 10;\n```\n\n![查看某条语句消耗的 RU.png](https://img1.www.pingcap.com/prod/RU_9663c44d79.png)\n\n**5)不可或缺的 `PROCESSLIST`**  \n\n`INFORMATION_SCHEMA` 是 ANSI 标准中定义的一组只读视图，提供数据库中所有表、视图、列和过程的信息。多个关系型数据库中都有各自的实现，在 TiDB 的 `INFORMATION_SCHEMA.PROCESSLIST` 表中，增加了字段 `RESOURCE_GROUP varchar(32)` ，以此来显示当前活跃会话使用的是哪个资源组。  \n\n案例如下，分别开三个窗口，启动三个会话，分别使用默认资源组，会话级资源组，和语句级资源组：  \n\n```\nmysql -h 192.168.195.128 -P 4000 -c -u u1 -e 'select sleep(1000)'\nmysql -h 192.168.195.128 -P 4000 -c -u u2 -e 'SET RESOURCE GROUP `rg1`; select sleep(1000)'\nmysql -h 192.168.195.128 -P 4000 -c -u u3 -e 'SELECT /*+ RESOURCE_GROUP(rg1) */ * sleep(1000)'\n```\n\n此时用 root 用户查看 `INFORMATION_SCHEMA.PROCESSLIST` 表：  \n\n```\nmysql> SELECT USER, RESOURCE_GROUP, INFO from INFORMATION_SCHEMA.PROCESSLIST ORDER BY USER;\n+------+----------------+-------------------------------------------------------------------------------------+\n| USER | RESOURCE_GROUP | INFO                                                                                |\n+------+----------------+-------------------------------------------------------------------------------------+\n| root | default        | SELECT USER, RESOURCE_GROUP, INFO from INFORMATION_SCHEMA.PROCESSLIST ORDER BY USER |\n| u1   | default        | select sleep(1000)                                                                  |\n| u2   | rg1            | select sleep(1000)                                                                  |\n| u3   | rg1            | SELECT /*+ RESOURCE_GROUP(rg1) */ sleep(1000)                                       |\n+------+----------------+-------------------------------------------------------------------------------------+\n4 rows in set (0.00 sec)\n```\n\n\n![resource group.png](https://img1.www.pingcap.com/prod/resource_group_77168ce4b8.png)\n\n相关讨论见此（感谢 @db_user 的提示）：[resource control, 如何查看 session 级别变量](https://asktug.com/t/topic/1008357)[5]  \n\n**问题三：I_S.USER_ATTRIBUTES / I_S.RESOURCE_GROUPS 权限控制**  \n\n接上例，如果使用普通用户，如 u2 用户查看 `INFORMATION_SCHEMA.PROCESSLIST` 表，则只会显示当前用户，或者说是权限范围内能看到的信息：\n\n```\nmysql> SELECT USER, RESOURCE_GROUP, INFO from INFORMATION_SCHEMA.PROCESSLIST ORDER BY USER;\n+------+----------------+-------------------------------------------------------------------------------------+\n| USER | RESOURCE_GROUP | INFO                                                                                |\n+------+----------------+-------------------------------------------------------------------------------------+\n| u2   | rg2            | SELECT USER, RESOURCE_GROUP, INFO from INFORMATION_SCHEMA.PROCESSLIST ORDER BY USER |\n| u2   | rg1            | select sleep(1000)                                                                  |\n+------+----------------+-------------------------------------------------------------------------------------+\n2 rows in set (0.00 sec)\n```\n\n![resource group-2.png](https://img1.www.pingcap.com/prod/resource_group_2_7fe19eeda8.png)\n\n这里的推断是，`PROCESSLIST` 作为既存表，权限设定都是延用之前的逻辑，这里只是增加了字段，所以很好的继承了权限隔离，即普通用户无权、无法看到其他用户，如用户 u1 正在使用的资源组。  \n\n但是，对于新增的表 `INFORMATION_SCHEMA.USER_ATTRIBUTES` 和 `INFORMATION_SCHEMA.RESOURCE_GROUPS` 并没有做到如此细粒度的权限控制。  \n\n- 对于表 `USER_ATTRIBUTES`，普通用户可以查看所有用户的属性，如果【问题二】的功能实现，那么普通用户就可以查看到所有用户绑定的资源组。\n- 对于表 `RESOURCE_GROUPS` ，普通用户可以查看所有资源组。那么，关于 Bad SQL 问题，其实就有另外一种处理方式，开发者可以在 SQL 里写入 Hint，使得 Bad SQL 可以“越权”调用 default 资源组，轻则打破平衡，影响其他业务性能，重则打穿资源规划，再现 “一条 SQL 炮轰整个 TiDB 集群” 的威力。\n\n从权限角度来看，资源管控所控制的不同资源组虽然做到了资源隔离，但是普通用户可以在 Session 级别随意切换资源组，比如说管理员将普通用户 u2 绑定资源组 rg1，但是 u2 登陆 TiDB 后，可以再切换到 rg2，以获取被分配更多资源的资源组的使用权。  \n\n相关交流贴链接：[resource control, I_S 权限控制问题](https://asktug.com/t/topic/1008596)[6]  \n\n正如我在帖子里提到的，对于 TiDB，高效、保质地实现功能是第一位的，权限 (Privileges) 实现次之，这是可以接受、理解的。毕竟，在如此内卷，国产数据库竞争如此激烈的市场环境下，“活下去”才是第一要务。但 Rule is Rule，权限（可以引申为“安全”）也是一个很重要、且绕不开的课题。  \n\n**6)Resource Control 相关配置项**  \n\n参见[官方文档](https://docs.pingcap.com/zh/tidb/stable/tidb-resource-control#%E7%9B%B8%E5%85%B3%E5%8F%82%E6%95%B0)[7]，资源管控引入的两个新变量，  \nTiDB：通过配置全局变量 `tidb_enable_resource_control` 控制是否打开资源组流控。\n\nTiKV：通过配置参数 `resource-control.enabled` 控制是否使用基于资源组配额的请求调度。\n\n查看方法如下：\n\n```\n-- tidb\nSHOW VARIABLES LIKE \"tidb_enable_resource_control\";\n-- tikv\nSHOW CONFIG WHERE NAME LIKE \"resource-control.enabled\";\n```\n\n**7)Calibrate 资源估算**  \n\n据文档[预估集群容量](https://docs.pingcap.com/zh/tidb/stable/tidb-resource-control#%E9%A2%84%E4%BC%B0%E9%9B%86%E7%BE%A4%E5%AE%B9%E9%87%8F)[8]介绍，目前有根据实际负载估算容量，基于硬件部署估算容量，两种估算方式，而比较直观的方法是基于硬件部署估算容量方式，具体命名如下：    \n\n```\n-- 默认 TPC-C 模型预测，等同于下一条命令\nCALIBRATE RESOURCE;\n-- 根据类似 TPC-C 的负载模型预测\nCALIBRATE RESOURCE WORKLOAD TPCC;\n-- 根据类似 sysbench oltp_write_only 的负载模型预测\nCALIBRATE RESOURCE WORKLOAD OLTP_WRITE_ONLY;\n-- 根据类似 sysbench oltp_read_write 的负载模型预测\nCALIBRATE RESOURCE WORKLOAD OLTP_READ_WRITE;\n-- 根据类似 sysbench oltp_read_only 的负载模型预测\nCALIBRATE RESOURCE WORKLOAD OLTP_READ_ONLY;\n```\n\n在 TiDB Dashboard v7.1.0 面板上，我们可以看到新增了【资源管控】菜单，如图，\n\n![资源管控面板.png](https://img1.www.pingcap.com/prod/_d5631bf67f.png)\n\n这里也可以查看资源预估情况，但实际上，Dashboard 也是调用上面的 SQL 进行预测，可以从 TiDB-Server 的日志中进行确认。\n\n```\n...[INFO] [session.go:3878] ... [sql=\"calibrate resource workload tpcc\"]\n...[INFO] [session.go:3878] ... [sql=\"calibrate resource workload oltp_read_write\"]\n...[INFO] [session.go:3878] ... [sql=\"calibrate resource workload oltp_read_write\"]\n...[INFO] [session.go:3878] ... [sql=\"calibrate resource workload oltp_read_only\"]\n...[INFO] [session.go:3878] ... [sql=\"calibrate resource workload oltp_write_only\"]\n```\n\n此外，这款估算模型是基于 TiDB 的多年经验积累，在基准测试的基础上实现的算法，适用于多种环境。引申一步，对于目前没有升级到 TiDB v7.1.0 版本的集群，或者需要对将要同步到 TiDB 集群的数据库进行容量估算，如何来处理呢？计算过程略微复杂，如果有兴趣可以参考相关源码 [calibrate_resource](https://github.com/pingcap/tidb/blob/v7.1.0/executor/calibrate_resource.go#L295)[9]。\n\n## “资源管控”也需要监控  \n\n**1)TiDB Dashboard**  \n\n上文提到，TiDB Dashboard 增加了[【资源管控】](https://docs.pingcap.com/zh/tidb/stable/dashboard-resource-manager)[10] 菜单，在页面下半部分，展示了 RU 相关图表，可以一目了解查看 TiDB 集群的 RU 负载情况，也可以选中图表的某个时间段，来使用 “[根据实际负载估算容量](https://docs.pingcap.com/zh/tidb/stable/sql-statement-calibrate-resource#%E6%A0%B9%E6%8D%AE%E5%AE%9E%E9%99%85%E8%B4%9F%E8%BD%BD%E4%BC%B0%E7%AE%97%E5%AE%B9%E9%87%8F)”[11]功能。  \n![TiDB Dashboard.png](https://img1.www.pingcap.com/prod/Ti_DB_Dashboard_d966f2daaf.png)\n\n**2)Grafana**  \n\n相对于 TiDB Dashboad，Grafana 提供了更全面的监控数据，甚至在面板上分别展示了 读 RU (RRU) 和 写 RU (WRU)。关于 RRU/WRU 的概念性描述较少，只是在[设计文档](https://github.com/pingcap/tidb/blob/master/docs/design/2022-11-25-global-resource-control.md#distributed-token-buckets)[12] 的令牌桶 (Token Buckets) 章节和 Grafana 的参数介绍页面有所体现。  \n\n**问题四：RRU/WRU 的表述问题**  \n\n关于 RRU/WRU 的表述问题，其实只要关注 RU 就好，这是经过基准测试后的预测值，具有统一的观测价值，只是在监控面板上加以区分，以观测 TiDB 集群的读写情况，在代码提交的记录里，也有研发同学的批注，“面向用户是 RU，监控项里面区分是有更多细节”。相关交流贴参见：  \n\n- resource control, [Grafana 面板默认配置](https://asktug.com/t/topic/1008464)[13]\n- resource control, [Grafana 文档内容不完整](https://asktug.com/t/topic/1008693)[14]\n\n**3)RU 余量问题**  \n\n对于日常运维，至少有两个监控指标需要考虑：  \n\n- 日常 RU 余量监控\n- 异常 RU 突增监控\n\n其中，对于 RU 余量监控，TiDB 7.1 只能从 Grafana 面板上看到 RU 使用量，没有直观展示 RU 余量情况，所以在 TiDB 7.2 中得到了增强，具体实现可参考PR：[resource_manager: add metrics for avaiable RU #6523](https://github.com/tikv/pd/pull/6523)[15]。  \n\n![TiDB 7.1 的 Grafana 面板.png](https://img1.www.pingcap.com/prod/Ti_DB_7_1_Grafana_c0fac9c1bf.png)\n图 -- TiDB 7.1 的 Grafana 面板  \n\n![TiDB 7.2 的 Grafana 面板.png](https://img1.www.pingcap.com/prod/Ti_DB_7_2_Grafana_f9a9ea3a2c.png)\n图 -- TiDB 7.2 的 Grafana 面板  \n\n**4)Log**  \n\n从日志中可以看出什么时候真的开始调用了资源管控，但是无法通过日志或者面板看出有哪些用户使用过资源组。  \n  \n```\n[2023/06/29 11:27:50.069 +09:00] [INFO] [session.go:3878] [GENERAL_LOG] [conn=7398943596793037429] [user=u2@192.168.195.128] [schemaVersion=53] [txnStartTS=0] [forUpdateTS=0] [isReadConsistency=false] [currentDB=] [isPessimistic=false] [sessionTxnMode=PESSIMISTIC] [sql=\"select @@version_comment limit 1\"]\n[2023/06/29 11:27:58.973 +09:00] [INFO] [session.go:3878] [GENERAL_LOG] [conn=7398943596793037429] [user=u2@192.168.195.128] [schemaVersion=53] [txnStartTS=0] [forUpdateTS=0] [isReadConsistency=false] [currentDB=] [isPessimistic=false] [sessionTxnMode=PESSIMISTIC] [sql=\"select current_resource_group()\"]\n[2023/06/29 11:28:09.557 +09:00] [INFO] [session.go:3878] [GENERAL_LOG] [conn=7398943596793037429] [user=u2@192.168.195.128] [schemaVersion=53] [txnStartTS=0] [forUpdateTS=0] [isReadConsistency=false] [currentDB=] [isPessimistic=false] [sessionTxnMode=PESSIMISTIC] [sql=\"set resource group rg1\"]\n[2023/06/29 11:28:19.532 +09:00] [INFO] [session.go:3878] [GENERAL_LOG] [conn=7398943596793037429] [user=u2@192.168.195.128] [schemaVersion=53] [txnStartTS=0] [forUpdateTS=0] [isReadConsistency=false] [currentDB=] [isPessimistic=false] [sessionTxnMode=PESSIMISTIC] [sql=\"select * from test.t1 limit 1\"]\n[2023/06/29 11:28:19.534 +09:00] [INFO] [controller.go:287] [\"[resource group controller] create resource group cost controller\"] [name=rg1]\n```\n\n如果真的出现【问题三】中描述的，存在 Bad SQL “越权” 运行的情况，可以从日志中查找线索。\n\n## TiFlash 或将在未来版本中支持 Resource Control\n\n在当前版本 (TiDB 7.1.0 LTS) 中，TiFlash 暂不支持资源管控功能，预计将在未来版本中得到支持。下面从两个实验来观察 TiFlash 组件对资源管控的调度情况，结果肯定是未使用的，不过这个实验可以等未来版本发布之后再做一次，相信会得到不同的结果。\n\n**实验一：指定 SQL 从 TiFlash 读取数据，观察执行计划中的 RU 值**  \n\n对实验表 `t` 创建 TiFlash 副本，分别从 TiKV / TiFlash 读取数据，并查看实际执行计划中的 RU 值。  \n\n```\n-- tiflash replica\nALTER TABLE t SET TIFLASH REPLICA 1;\n\n-- read from tiflash\nEXPLAIN ANALYZE FORMAT = 'verbose'\nSELECT /*+ read_from_storage(tiflash[t]) */ COUNT(*)\nFROM t;\n\n-- read from tikv\nEXPLAIN ANALYZE FORMAT = 'verbose'\nSELECT /*+ read_from_storage(tikv[t]) */ COUNT(*)\nFROM t;\n```\n\nSQL 执行结果如图所示，从 TiKV 读取数据的 SQL， RU 值约 40， 而 TiFlash 的 RU 值则为 0，说明当前版本的 TiFlash 并不支持 RU 的计算。  \n\n![TiFlash 显示 RU.png](https://img1.www.pingcap.com/prod/Ti_Flash_RU_c9285223fb.png)\n\n**实验二：从日志中观测是否调用资源组控制器**  \n\n当某个用户连接到 TiDB 后，并向 TiDB 发出 SQL 语句，TiDB Server 向 PD 发起请求，PD 会创建（分配）一个资源组控制器 (resource group controller)，TiDB Server 会将相关信息打印到日志中，如：  \n\n```\n... [INFO] [controller.go:287] [\"[resource group controller] create resource group cost controller\"] [name=rg1]\n```\n\n我们可以通过分析 TiDB Server 的日志，来观测发送到 TiFlash 的查询是否调用资源组控制器，并以此来判断 TiFlash 是否实现 RU 计算。对照试验如下：  \n\n```\nEXPLAIN ANALYZE FORMAT = 'verbose' SELECT /*+ RESOURCE_GROUP(rg2), read_from_storage(tikv[t]) */ COUNT(*) FROM t;\nEXPLAIN ANALYZE FORMAT = 'verbose' SELECT /*+ RESOURCE_GROUP(rg3), read_from_storage(tiflash[t]) */ COUNT(*) FROM t;\n```\n\n![TiDB Server 日志-1.png](https://img1.www.pingcap.com/prod/Ti_DB_Server_1_30757c8045.png)\n\n![TiDB Server 日志-2.png](https://img1.www.pingcap.com/prod/Ti_DB_Server_2_bebfbf1ec9.png)\n\n从截图中可以直观的看到，资源控制器为上面的 SQL 创建了一个资源组消费控制器 (resource group cost controller)，资源组名称为 rg2 。而下面的 SQL 由于从 TiFlash 读取数据，所以并不会调用资源控制器创建新的资源组消费控制器。  \n\n需要注意的是，这个实验连续触发可能并不会得到想要的结果，因为源码里实现了资源组控制器实例化判重逻辑，即在本实验中，如果资源控制器已经为用户 u2 创建了 rg2 资源组，那么连续的会话将持续延用已经创建好的控制器，只有当超过 GC 时间 （默认 10 分钟），再次发起新会话，才会再次创建新的资源组消费控制器。  \n\n## 与 MySQL 的兼容性\n\n本文已经详细列举了 TiDB 中资源控制的语法，在 MySQL 8.0 中也有[资源组 (Resource Groups)](https://dev.mysql.com/doc/refman/8.0/en/resource-groups.html)[16]特性，具体可参考 [WL#9467: Resource Groups](https://dev.mysql.com/worklog/task/?id=9467)[17]，但 TiDB 与之的实现不同，两者并不兼容。  \n\n如果同时管理 TiDB 和 MySQL，具体使用时，需要多加区分以免混淆。  \n\n**相似之处**  \n\n- TiDB, MySQL 中的资源组相关命令，“增 ( `CREATE RESOURCE GROUP` ) 删 ( `DROP RESOURCE GROUP` ) 改 ( `ALTER RESOURCE GROUP` ) 查 ( `SELECT * FROM INFORMATION_SCHEMA.RESOURCE_GROUPS` )” 语法相近，但命令后跟接参数不同，`I_S.RESOURCE_GROUPS` 表结构亦不同。\n- TiDB, MySQL 均支持 Hint，可以实现语句级资源组调用。\n\n```\nINSERT /*+ RESOURCE_GROUP(rg1) */ into t1 values (1);\n```\n\n**不同之处**  \n\n1.MySQL 中资源组的线程优先级 (`THREAD_PRIORITY`) 设定，需要开启 Linux 中的 `CAP_SYS_NICE`。而 TiDB 不需要。\n\n```\n[Service]\nAmbientCapabilities=CAP_SYS_NICE\n```\n\n2.TiDB 中资源组设定的 RU 是定值，而在 MySQL 中可以指定 vCPU 为范围值，这个范围值对应所有可用的 CPU。\n\n```\nmysql> select version()\\G\n*************************** 1. row ***************************\nversion(): 8.0.28\n1 row in set (0.00 sec)\n\nmysql> ALTER RESOURCE GROUP rg1 VCPU = 0-1;\nQuery OK, 0 rows affected (0.01 sec)\n```\n\n3.TiDB 中的一些 SQL 语法或函数 (Functions) 是特有的，与 MySQL 不兼容，如 `CURRENT_RESOURCE_GROUP()`。\n\n## 回归本源，再看 cgroup\n\n前文提到了 MySQL 需要借助 Nice 来控制线程优先级，其实熟悉 Linux 系统的朋友都知道 Nice 成名已久，而 cgroup 这位后来者近年逐渐走入人们的视野，尤其是虚拟化、云化技术（如 Docker, Kubernetes）成熟后，cgroup 技术更是不可或缺。比如，从 RHEL 7 之后，可以直接为某个服务在 systemd 文件中设置 `CPUAccounting` 和 `CPUShares` 来控制进程对 CPU 的占用率。从 RHEL 8 开始引入了 cgroup v2，以完善功能，简化配置，CPU 控制参数也做了调整，变为 `cpu.weight`。\n\n于 TiDB 而言，cgroup 也早有[使用案例](https://asktug.com/t/topic/37127/2?u=shawnyan)[18]，比如在 TiDB Server 的 systemd 文件中管控服务的内存配额，来控制 OOM 触发条件。另外，在 TiDB v5.0 版本，对 TiDB Server 的参数 `performance.max-procs`实现逻辑做了修改，变更为“默认情况下为当前机器或者 cgroups 的 CPU 数量”，相关内容可参考 [PR #17706](https://github.com/pingcap/tidb/pull/17706)[19]。\n\n## 总结\n\n由于时间关系，关于 “资源控制 (Resource Control)” 的内容暂且就分享到这里，内容颇多，相信能读到这里的 “Ti 友” 都是真正喜爱 TiDB 的。文本分享了若干具体的使用方式，也提出了若干问题，力争做到求真务实，相信对 TiDBer 有所提示和帮助。最后，关于 Resource Control 的探索才刚刚开始，期待后续版本中的功能增强（比如，对超时 SQL 进行降级或中止（TiDB 7.2 中已实现），将内存等更多资源纳入 RU，用户支持绑定多资源组等），也期待更多关于此特性的生产案例分享。\n\n参考资料  \n\n[1] AskTUG: https://asktug.com/\n\n[2]【社区智慧合集】TiDB 相关 SQL 脚本大全: https://asktug.com/t/topic/999618\n\n[3] resource control，default resource group 文档勘误: https://asktug.com/t/topic/1008372/6?u=shawnyan\n\n[4] resource control 相关，INFORMATION_SCHEMA.USER_ATTRIBUTES 表取值问题: https://asktug.com/t/topic/1008437\n\n[5] resource control, 如何查看session级别变量: https://asktug.com/t/topic/1008357\n\n[6] resource control, I_S 权限控制问题: https://asktug.com/t/topic/1008596\n\n[7] 官方文档: https://docs.pingcap.com/zh/tidb/stable/tidb-resource-control#%E7%9B%B8%E5%85%B3%E5%8F%82%E6%95%B0\n\n[8] 预估集群容量: https://docs.pingcap.com/zh/tidb/stable/tidb-resource-control#%E9%A2%84%E4%BC%B0%E9%9B%86%E7%BE%A4%E5%AE%B9%E9%87%8F\n\n[9] calibrate_resource: https://github.com/pingcap/tidb/blob/v7.1.0/executor/calibrate_resource.go#L295\n\n[10]【资源管控】: https://docs.pingcap.com/zh/tidb/stable/dashboard-resource-manager\n\n[11] “根据实际负载估算容量”: https://docs.pingcap.com/zh/tidb/stable/sql-statement-calibrate-resource#%E6%A0%B9%E6%8D%AE%E5%AE%9E%E9%99%85%E8%B4%9F%E8%BD%BD%E4%BC%B0%E7%AE%97%E5%AE%B9%E9%87%8F\n\n[12] 设计文档: https://github.com/pingcap/tidb/blob/master/docs/design/2022-11-25-global-resource-control.md#distributed-token-buckets\n\n[13] resource control, Grafana 面板默认配置: https://asktug.com/t/topic/1008464\n\n[14] resource control, Grafana 文档内容不完整: https://asktug.com/t/topic/1008693\n\n[15] resource_manager: add metrics for avaiable RU #6523: https://github.com/tikv/pd/pull/6523\n\n[16] 资源组 (Resource Groups): https://dev.mysql.com/doc/refman/8.0/en/resource-groups.html\n\n[17] WL#9467: Resource Groups: https://dev.mysql.com/worklog/task/?id=9467\n\n[18] 使用案例: https://asktug.com/t/topic/37127/2?u=shawnyan\n\n[19] #17706: https://github.com/pingcap/tidb/pull/17706\n","date":"2023-09-19","author":"严少安","fillInMethod":"writeDirectly","customUrl":"six-things-to-know-about-resource-control","file":null,"relatedBlogs":[{"relatedBlog":{"body":"## 导读\n\n资源管控技术（Resource Control）是 TiDB 7.0 版本中优化提升的重要能力之一，不仅可以在负载剧烈变化时，保证服务质量，同时提供了数据库的多租户隔离能力，能够有效地降低数据库运行成本，帮助企业节省信息化管理开支，提升企业的竞争力。  \n\n本文从将技术优势、配置方式、场景实践等角度详细解析 TiDB 7.0 版本中的资源管控技术。  \n\n作为可透明扩展的分布式数据库，TiDB 一直致力于满足企业对大型数据库集群的管理需要，集群内资源管控和资源隔离是企业客户长久以来的诉求之一。资源管控的主要目的在于解决数据库管理中常见的一些问题：  \n\n- 当多个业务共享同一数据库集群时，某个业务的非预期负载变化会影响其他业务的正常运行\n- 当集群中存在混合负载时，对资源需求较高的数据分析或批量作业会影响在线交易类业务的响应时间\n- 在需要 7x24 高可用性的业务系统中，数据备份、统计信息收集等后台任务可能会影响服务质量\n- 应用灰度上线时，小流量引发的性能问题仍可能“击穿”整个生产数据库\n\n为了解决上述场景中的问题，TiDB 开发了资源管控技术，于 TiDB 6.6 首次引入，并在 TiDB 7.0 进行了优化和增强。该技术利用资源组 (Resource Group) 将一个庞大的数据库集群划分为多个逻辑单元，每个资源组都能限制其所需的计算和 I/O 资源。通过特定设置，当集群有空闲资源时，允许一部分资源组超越其限制，以实现资源的充分利用。\n\n## 核心优势\n\n- TiDB 采用了业界领先的双层资源管控机制来实现更精确的管控。“流量控制”模块控制资源限额，确保仅在限额内的操作才能得以执行；“调度控制”模块则对队列中的任务设置不同的优先级，以确保在负载剧烈变化或超负荷运行时，高优先级的任务能够得到快速反馈。与同类产品通常只提供其中一层管控能力不同，TiDB 同时具备流控和调度控制能力，能够精确定义出更符合用户场景的配置。\n- 基于存储计算分离的架构，TiDB 的资源管控对最重要的 I/O 资源进行了限制。I/O 吞吐通常是数据库系统最常见的资源瓶颈，也是资源管控的难点，多数数据库产品并不支持对 I/O 进行控制。只有控制住主要瓶颈，才能保证在资源阻塞时有疏通调控的手段。\n- 把所有资源抽象成统一的单位来进行分配和限制。太过细粒度的设置通常难以衡量，也容易失去灵活性。TiDB 希望通过尽量少的指标来识别用户的意图，自适应地完成最佳的调度方案，提升易用性。\n- 除了隔离性，提升资源利用率也是 TiDB 资源管控的重要目标。在整体资源尚有空闲的情况下，允许部分业务超过资源组定义的限制。 \n- 提供用量统计的精确反馈， 通过监控面板获取实际用量的使用情况，协助用户合理改进配置。同时，配合企业管理目标，TiDB 能够协助企业精确统计各部门数据库资源的使用情况，进而完成合理的成本分摊。\n- 提供灵活的资源绑定手段。支持在用户级，会话级，和语句级指定资源的绑定方式，满足不同场景的资源控制需要。\n\n## 管理方式\n\n资源管控引入了“资源组(Resource Group)”的概念，通过设置“用户”和“资源组” 的对应关系，把会话与用户组进行绑定，利用“用量 (RU)”对资源限额进行定义。结构如下：\n\n![资源组结构.png](https://img1.www.pingcap.com/prod/_d377c2529e.png)\n\n### 资源组 (Resource Group)  \n\n资源组是资源管理的逻辑单元。任意一个会话属于唯一的资源组，而同一资源组的所有会话共享同一组资源限额。TiDB 支持数据库用户与资源组的映射关系，通过设置数据库用户的默认资源组，用户会话可以分属于不同的资源组。未指定默认资源组的用户，与系统内置的 default 资源组相关联。\n\n### 资源限额\n\nTiDB 首先支持为资源组配置用量 (RU)。RU (Request Unit) 是 TiDB 对 CPU、IO 等系统资源的统一抽象的单位，目前会考虑 CPU、IOPS 和 IO 带宽三个指标，按照一定的比例统一到 [RU 单位上](https://docs.pingcap.com/zh/tidb/v6.6/tidb-resource-control#什么是-request-unit-ru)。TiDB 支持设置资源组为 BURSTABLE 模式，BURSTABLE 模式允许资源组超额使用到集群的空闲资源。\n用户可以查看面板数据的反馈，以获取真实的用量请求和分配情况。通过对数据进行分析，来优化资源组的限额配置。配合真实负载的压力测试，用户还可以通过数据反馈得出整个系统的用量上限。\n\n### 调度优先级\n\n默认情况下，所有资源组的优先级 (PRIORITY)均为“中等(medium)”。当资源组在同一优先级下，调度优先级按照资源配额的比例分配，这已经能够满足绝大多数场景的需要。用户仍旧可以显式地指定资源组优先级为“高(high)”或者“低(low)”，从而完成更复杂的设定。比如，为一个算力需求不大，但优先级很高的应用配置资源组。\n\n### 资源组设定\n\n在 TiDB v7.0，用户能够通过以下方式指定资源组：\n- 用户级别。通过 `CREATE USER` 或 `ALTER USER` 语句将用户绑定到特定的资源组。绑定后，对应的用户新创建的会话会自动绑定对应的资源组。\n- 会话级别。通过 `SET RESOURCE GROUP` 设置当前会话的资源组。\n- 语句级别。通过优化器 hint `RESOURCE_GROUP()` 设置当前语句的资源组。\n\n### 配置步骤\n\n- 启用资源管控\n\n手工开启资源管控分两步进行（资源管控在 TiDB 7.0 中默认开启）：  \n\n1)设置 TiDB 全局变量启用“流量控制”：  \n```\nSET GLOBAL tidb_enable_resource_control = 'ON';\n```  \n\n2)在 TiKV 配置中将 `resource-control.enabled` 设为 `true` 启用“调度控制”  \n\n- 估算集群容量\n\n在资源规划之前，TiDB 提供了集群总用量(RU)的估算。需要注意的是，这个值是基于当前硬件配置结合平均负载经验得出的参考值，在运行用户实际应用时可能会有偏差。用户可以以此作为资源组起始规划的参考，后续再根据实际运行数据进行微调。  \n\n```\nCALIBRATE RESOURCE;\n```\n\n- 有了总容量的估算，此时我们可以根据实际业务目标规划和创建资源组。例如创建一个名为 rg1 的资源组，分配每秒 500 RU 的流量，并允许资源组在有空闲资源的情况下超限额分配。  \n\n```\nCREATE RESOURCE GROUP IF NOT EXISTS rg1 RU_PER_SEC = 500 BURSTABLE;\n```\n\n- 将用户 `usr1` 的资源组设置为 `rg1`\n\n```\nALTER USER usr1 RESOURCE GROUP rg1;\n```\n\n完成上述配置后，当系统繁忙时，用户 `usr1` 的所有会话使用的资源上限为 500 RU/秒；非繁忙时间段， `usr1` 则能够使用空闲集群资源。\n\n## 场景演示\n\n我们来看一个配置的示例。假定我们有三个租户分别运行三种不同的业务形态，每类业务有不同的管控目标：\n\n![三租户配置示例.png](https://img1.www.pingcap.com/prod/_963a4a6f64.png)\n\n对于以上这个需求，如果选择严格的多租户物理隔离，就不得不为每一个租户分配足够的资源，同时会造成 oltp 谷值负载时的资源浪费比较严重；而放入一套集群又无法消除租户 batch 对租户 oltp 的影响。利用 TiDB 既“隔离”又“融合”的资源管控技术，我们可以为这几类用户分别创建资源组：\n\n- 为租户 oltp 分配一个较高的用量，租户 batch 和 租户 hr 则相对低，这样在系统资源紧张的情况下，保证租户 oltp 的服务质量。\n- 租户 oltp 和 batch 的资源组设置为 burstable， 这样租户 oltp 发生超预期的负载，仍旧可能会保证质量；而当整个集群负载有空余时， 租户 batch 可以利用空闲资源加速其工作。\n\n![三租户配置示例-2.png](https://img1.www.pingcap.com/prod/2_79a66c4018.png)\n\n- 创建资源组\n\n```\nCREATE RESOURCE GROUP oltp  RU_PER_SEC=4000 BURSTABLE;\nCREATE RESOURCE GROUP batch RU_PER_SEC=400 BURSTABLE;\nCREATE RESOURCE GROUP hr    RU_PER_SEC=400;\n```\n\n- 创建租户对应租户，并设置其所属的资源组\n\n```\nCREATE USER 'oltp' RESOURCE GROUP oltp;\nGRANT ALL PRIVILEGES ON oltp.* TO 'oltp'@'%';\n\nCREATE USER 'batch' RESOURCE GROUP batch;\nGRANT ALL PRIVILEGES ON batch.* TO 'batch'@'%';\n\nCREATE USER 'hr' RESOURCE GROUP hr;\nGRANT ALL PRIVILEGES ON hr.* TO 'hr'@'%';\n```\n\n在完成以上简单的设置之后，我们来模拟几个租户不同的负载，观测吞吐量 (QPS) 和服务质量 (P99 响应时间）。整个场景模拟分为三个阶段：  \n\n1. 首先三类负载同时运行， 租户 oltp 设置为峰值负载。\n2. 切换租户 oltp 的负载到谷值，其他不变。\n3. 再次切换租户 oltp 的负载回到峰值。\n\n![三租户配置示例-3.png](https://img1.www.pingcap.com/prod/3_ec8c33d535.png)\n\n从实际数据来看，TiDB 资源管控技术在负载变化时的反馈非常及时。租户 oltp 的响应时间始终维持在较低的水平，租户 hr 的吞吐被限制在较低的范围内：\n\n1. 当租户 oltp 维持在峰值负载时， 它保持高吞吐和较低的响应时间；租户 batch 和 租户 hr 维持在低吞吐，由于租户 batch 可以使用空闲资源，因此吞吐要略高于租户 hr。\n2. 当租户 oltp 进入谷值负载，吞吐下降，其响应时间仍旧很低。这时由于租户 batch 的资源需求很大，因此它的吞吐迅速提升，响应时间下降， 租户 hr 仍旧被限制在其限额内。\n3. 当租户 oltp 重新回到峰值负载，租户 batch 则立即让出资源，使得租户 oltp 的吞吐再次回到之前的水平，响应时间维持不变。\n\n由此得出， 利用 TiDB 提供的资源管控和调度能力，多个不同诉求的租户能够共存在一套系统中，在保证各自服务目标的基础上，提升资源使用效率。\n\n## 资源管控技术协助企业兼顾质量与成本\n\n从上面的例子我们看到， 资源管控技术能够有效地解决在负载剧烈变化时，服务质量无法保证的问题。我们也可以利用这项技术防止未经验证的应用出现资源过载，比如新业务上线前的灰度测试，为资源组为灰度流量定义上限，避免局部性能问题引发大范围影响。  \n\n资源管控技术同时提供了数据库的多租户隔离能力，支持企业将中小型的系统进行合并，降低数据库运行成本。成本的节约主要来自几个方面：  \n\n- **节省预留资源**：一般来说，我们在规划单系统容量的时候，平均负载一般占到规划容量的 50% 甚至更低，留下足够的空间应对突发的性能抖动，以及未来可能的业务增长。而多个不相关的业务系统很少在同一时间出现负载波动，结合 TiDB 可透明扩展的特性，将这些系统合并到同一集群中，就不必预留相同比例的空间了。\n![节省预留资源.png](https://img1.www.pingcap.com/prod/_01adb7ab23.png)\n\n\n- **缓解峰值谷值波动**：如果将负载峰值与谷值不同的系统整合在一起，整合后的系统可以减少负载波动的幅度。在“削峰填谷”的作用下，资源利用率得到提升，低负载时段的硬件浪费也得到了减少。\n\n![缓解峰值谷值波动.png](https://img1.www.pingcap.com/prod/_9712ec1ec2.png)\n\n\n- **快速扩展与收缩**：企业经常需要为定期的业务活动增加临时的计算资源，以确保系统的稳定性。在多个业务系统合并的情况下，可以借助合理的业务规划，共享预留资源，轮流进行促销活动，而不必反复部署，节约重复的人力投入。\n\n- **提升运维效率**：将多个业务系统整合成一个系统，可以显著降低运维人员的投入。因为管理实体变少了，系统数量也减少到以前的几十分之一，运维难度和需要的人工成本都随之大大降低。\n\n这要求产品需要有很强的负载隔离能力，同时又能够将资源融合，正是 TiDB 资源管控技术想要达成的目标。\n\n## 未来展望\n\nTiDB 发布的资源管控能力是一个很好的开始，我们将沿着这个方向从多角度持续深耕这项技术，通过细粒度资源管控技术为客户创造更多的价值：  \n\n- **更多样的管控方式**： 根据场景的不同，为客户提供百分比，权重，用量等多种资源限额定义方式，并把 TiDB Cloud 中 Serverless 模式的计量方式和经验注入产品，协助客户运行自己的私有云服务，轻松完成成本分摊。扩展资源组的映射方式，支持除用户以外其他会话属性向资源组的映射。\n\n- **更多维的管控范围**： 除了最重要的 CPU 与 I/O 资源，持续延伸管控的范围和粒度，如分析型负载，内存使用，并行度等等。另外， 还将支持把运维操作和系统内部任务编入资源组， 协助客户做更精细的场景定义。\n\n- **更智能的管控手段**：通过分析历史运行数据，提供资源管理的建议，协助客户发现资源配置的潜在问题和风险，结合 TiDB Cloud 的部署运行经验，为客户提供更经济更合理的资源配置建议，协助企业的成本控制。\n\nTiDB 的弹性扩展特性和资源管控能力可以有效提高 IT 系统的效率，并协助企业降低 IT 运营的成本，同时确保系统的稳定性和安全性。随着资源管控技术的不断增强， TiDB 一定能够协助企业在数字化的道路上更加扎实地前进。","author":"宋日杰","category":1,"customUrl":"tidb-resource-control","fillInMethod":"writeDirectly","id":486,"summary":"资源管控技术是 TiDB 7.0 版本中优化提升的重要能力之一，不仅可以在负载剧烈变化时，保证服务质量，同时提供了数据库的多租户隔离能力，能够有效地降低数据库运行成本，帮助企业节省信息化管理开支，提升企业的竞争力。","tags":["Resource Control"],"title":"新特性解析丨TiDB 资源管控的设计思路与场景解析"}}]}}},
    "staticQueryHashes": ["1327623483","1820662718","3081853212","3430003955","3649515864","4265596160","63159454"]}