写点什么

TiDB 在线打标签实现副本调度应用实践

  • 2024-09-27
    北京
  • 本文字数:7242 字

    阅读完需:约 24 分钟

作者: 数据源的 TiDB 学习之路原文来源:https://tidb.net/blog/4e14596a

案例背景

某原有系统为虚拟机环境部署,整体性能不满足预期。为提升集群整体性能,计划分阶段采购物理机,并以扩缩容的方式逐渐把物理机添加到现有集群中,逐渐淘汰虚拟机节点。


原始部署拓扑中,每个虚拟机节点只部署一个 TiKV 实例,且未设置标签。扩容物理机时,为了简便起见,每个物理机暂时也只部署了一个 TiKV 实例,同样未设置任何标签。


集群当前处于物理机与虚拟机混合部署的中间态,由于下一批次物理机将在数月后就绪,这意味着物理机与虚拟机混合架构将持续几个月时间。在这个阶段,为了能够充分发挥物理机性能,期望能有一个方案将重要业务数据的 leader 副本尽量分布在物理机上。

解决思路

首先需要能够识别出哪些实例在物理机哪些在虚拟机,通过 TiDB 在线打标签的方式,将物理机和虚拟机上的实例划分到 2 个标签组。然后,结合 Placements Rules 功能将重要业务数据的 leader 副本固定在物理机所属的组。以下通过实际测试环境验证此方法的有效性,供大家参考。

测试步骤

环境准备

首先,需要准备一个 TiDB 测试环境,且当前所有节点上均未设置标签(本示例中使用 3 节点混合部署的 TiDB 集群)。使用 config show 命令查看集群当前的 label 情况,确认没有打任何标签。


tiup ctl-ee:v7.1.1-3 pd -u http://xx.xx.x.151:12379 -iStarting component `ctl-ee`: /home/tidb/.tiup/components/ctl-ee/v7.1.1-3/ctl pd -u http://xx.xx.x.151:12379 -i» config show{  "replication": {    "enable-placement-rules": "true",    "enable-placement-rules-cache": "false",    "isolation-level": "",    "location-labels": "",    "max-replicas": 3,    "strictly-match-label": "false"  },
复制代码


从 Grafana 中查看 Region 及 Leader 的分布情况,可以发现 3 个节点上的 leader 和 region 副本个数完全均衡。由于此时所有节点均未设置标签且未设置任何 Placement Rules 策略,根据 PD 自动调度均衡的原则,符合预期。


在线打标签

如果使用 TiUP 部署集群,可以在初始化配置文件中统一进行 location 相关配置。然而,如果是一个生产运行中的集群,我们需要通过在线的方式添加标签从而不影响业务的正常运行。


在不考虑 TiFlash 组件的前提下,在线打标签需要同时配置 PD 的 location-labels 和 TiKV 的 labels 参数。PD 的 location-labels 是一个字符串数组,该配置的每一项与 TiKV labels 的 key 是对应的,而且其中每个 key 的顺序代表不同标签的级别关系。

PD 配置 location-labels

在线给 PD 配置 location-labels 需要使用 pd-ctl 工具进行更改,使用 config set location-labels 命令。下面示例输出中显示设置的 location-lables 为 region,zone,host


[tidb@host-xx-xx-x-151 ~]$ tiup ctl-ee:v7.1.1-3 pd -u http://xx.xx.x.151:12379 -i» config set location-labels region,zone,hostSuccess!» config show{  "replication": {    "enable-placement-rules": "true",    "enable-placement-rules-cache": "false",    "isolation-level": "",    "location-labels": "region,zone,host",    "max-replicas": 3,    "strictly-match-label": "false"  },...
复制代码

TiKV 配置 labels

配置好 PD 的 location-labels 之后,我们还需要给每个 TiKV 打上标签,这仍然通过 pd-ctl 在线更改,使用 store label 命令。由于 store label 命令需要指定具体的 store id,因此我们首先需要执行 store 命令来查看并确定每个 store id 与具体物理节点的映射关系,也可以直接从 information_schema.tikv_store_status 表中获取。


» store{  "count": 3,  "stores": [    {      "store": {        "id": 2,        "address": "xx.xx.x.152:30160",        ...      },...{      "store": {        "id": 3,        "address": "xx.xx.x.151:30160",        ...      },...{      "store": {        "id": 1,        "address": "xx.xx.x.153:30160",        ...      },    
复制代码


从上面输出中我们已经能够找到节点 IP 与 store id 的映射关系,假设我们知道这 3 个节点的机器类型,那么便可以画出以下表格。



下一步,我们便可以基于上述的 store id 来给物理机和虚拟机上的实例添加不同的标签从而分成不同的组。打完标签后,再次使用 store 命令查看每个 store,发现 store id 为 3 的被打上了 physical 标签而 store id 为 2 和 3 的被打上了 virtual 标签。


» store label 1 region=virtualpd/api/v1/store/1/labelSuccess!» store label 2 region=virtualpd/api/v1/store/2/labelSuccess!» store label 3 region=physicalpd/api/v1/store/3/labelSuccess!
» store{ "count": 3, "stores": [ { "store": { "id": 3, "address": "xx.xx.x.151:30160", "labels": [ { "key": "region", "value": "physical" } ], ... { "store": { "id": 1, "address": "xx.xx.x.153:30160", "labels": [ { "key": "region", "value": "virtual" } ], ...{ "store": { "id": 2, "address": "xx.xx.x.152:30160", "labels": [ { "key": "region", "value": "virtual" } ], ...
复制代码

配置 Placement Rules

节点打了标签之后,我们便可以配置 Placement Rules 来规划副本的放置策略。TiDB v5.3 版本中引入了 Placement Rules in SQL,可以采用 SQL 的方式更方便的配置数据的副本策略,本文我们使用这种方式来进行配置。


首先,我们可以使用 SQL 命令 show placement labels 来查看当前集群中有哪些 labels。


mysql> show placement labels;+--------+-------------------------+| Key    | Values                  |+--------+-------------------------+| region | ["physical", "virtual"] |+--------+-------------------------+
复制代码

创建放置策略 (placement policy)

上述输出证明之前在线打标签操作的正确性。在此基础上,我们便可以通过 create placement policy 的方式创建放置策略。下述示例意味着我们将创建一个放置策略 mypolicy,并指定 leader 放置在标签为 physical 的实例上,followers 被放置在标签为 physical 和 virtual 的实例上。


mysql> create placement policy mypolicy primary_region="physical" regions="physical,virtual" ;Query OK, 0 rows affected (0.54 sec)
mysql> show create placement policy mypolicy;+----------+-----------------------------------------------------------------------------------------+| Policy | Create Policy |+----------+-----------------------------------------------------------------------------------------+| mypolicy | CREATE PLACEMENT POLICY `mypolicy` PRIMARY_REGION="physical" REGIONS="physical,virtual" |+----------+-----------------------------------------------------------------------------------------+1 row in set (0.00 sec)
mysql> select * from information_schema.placement_policies;+-----------+--------------+-------------+----------------+------------------+-------------+--------------------+----------------------+---------------------+----------+-----------+----------+| POLICY_ID | CATALOG_NAME | POLICY_NAME | PRIMARY_REGION | REGIONS | CONSTRAINTS | LEADER_CONSTRAINTS | FOLLOWER_CONSTRAINTS | LEARNER_CONSTRAINTS | SCHEDULE | FOLLOWERS | LEARNERS |+-----------+--------------+-------------+----------------+------------------+-------------+--------------------+----------------------+---------------------+----------+-----------+----------+| 1 | def | mypolicy | physical | physical,virtual | | | | | | 2 | 0 |+-----------+--------------+-------------+----------------+------------------+-------------+--------------------+----------------------+---------------------+----------+-----------+----------+1 row in set (0.00 sec)
复制代码

绑定放置策略

创建了 placement policy 之后,需要告诉数据库指定哪些数据绑定这个放置策略。placement policy 对应的数据范围可以基于集群级、数据库级、表级和分区级进行配置。不同的级别使用不同的 SQL 命令,如下表格所示。



假设此处我们期望对集群内某个数据库级别绑定以上放置策略,应该使用命令 alter database placement policy 实现。绑定完成后可以使用 show create database 查看到 database 已经被添加的策略,也可以通过 show placement 来查看策略的调度进度,SCHEDULED 表示 PD 调度完成。


mysql> alter database test_dbsuat placement policy=mypolicy;Query OK, 0 rows affected (0.53 sec)
mysql> show create database test_dbsuat;+-------------+------------------------------------------------------------------------------------------------------------------------+| Database | Create Database |+-------------+------------------------------------------------------------------------------------------------------------------------+| test_dbsuat | CREATE DATABASE `test_dbsuat` /*!40100 DEFAULT CHARACTER SET utf8mb4 */ /*T![placement] PLACEMENT POLICY=`mypolicy` */ |+-------------+------------------------------------------------------------------------------------------------------------------------+1 row in set (0.01 sec)
mysql> show placement;+----------------------+------------------------------------------------------+------------------+| Target | Placement | Scheduling_State |+----------------------+------------------------------------------------------+------------------+| POLICY mypolicy | PRIMARY_REGION="physical" REGIONS="physical,virtual" | NULL || DATABASE test_dbsuat | PRIMARY_REGION="physical" REGIONS="physical,virtual" | SCHEDULED |+----------------------+------------------------------------------------------+------------------+2 rows in set (0.06 sec)
复制代码


需要注意的是,alter database placement policy 是修改数据库默认的放置策略,它只对之后新建的表生效,对于已有的表需要逐个使用命令 alter table placement policy 使之生效。因此,如果想对此数据库下属所有表应用放置策略,我们需要执行以下步骤来完成。


mysql> SELECT * FROM information_schema.tables WHERE tidb_placement_policy_name IS NOT NULL;Empty set (0.04 sec)
use test_dbsuat;alter table table1 placement policy=mypolicy;alter table table2 placement policy=mypolicy;alter table table3 placement policy=mypolicy;...
//验证有多少个表绑定了放置策略mysql> SELECT count(*) FROM information_schema.tables WHERE tidb_placement_policy_name IS NOT NULL;+----------+| count(*) |+----------+| 40 |+----------+1 row in set (0.04 sec)
//查看哪些对象配置了放置策略及状态mysql> show placement;+--------------------------+------------------------------------------------------+------------------+| Target | Placement | Scheduling_State |+--------------------------+------------------------------------------------------+------------------+| POLICY mypolicy | PRIMARY_REGION="physical" REGIONS="physical,virtual" | NULL || DATABASE test_dbsuat | PRIMARY_REGION="physical" REGIONS="physical,virtual" | SCHEDULED || TABLE test_dbsuat.table1 | PRIMARY_REGION="physical" REGIONS="physical,virtual" | SCHEDULED || TABLE test_dbsuat.table2 | PRIMARY_REGION="physical" REGIONS="physical,virtual" | SCHEDULED || TABLE test_dbsuat.table3 | PRIMARY_REGION="physical" REGIONS="physical,virtual" | SCHEDULED |...
复制代码


上述步骤完成后,我们可以通过 SQL 语句检查此数据库下面表的 leader 及所有副本分布情况。


select distinct t2.db_name,t2.table_name,t2.region_id,t3.peer_id,t3.is_leader,t1.address,replace(replace(t1.label,', "value"',''),'"key": ','') as label from information_schema.tikv_store_status t1,information_schema.tikv_region_status t2,information_schema.tikv_region_peers t3 where t2.db_name='dbname' and t2.region_id=t3.region_id and t3.store_id=t1.store_id order by 1,2,3,4;
复制代码


如若输出结果显示所有的 leader 均在标签为 physical 的 Region,说明 leader 副本已经按照我们配置的策略完成了调度。以下是一个被正确调度后的输出示例。


+-------------+------------+-----------+----------+-----------+-------------------+--------------------------+| db_name     | table_name | region_id | peer_id  | is_leader | address           | label                    |+-------------+------------+-----------+----------+-----------+-------------------+--------------------------+| test_dbsuat | table1     |  57954143 | 57954144 |         1 | xx.xx.x.151:30160 | [{"region": "physical"}] || test_dbsuat | table1     |  57954143 | 57954145 |         0 | xx.xx.x.153:30160 | [{"region": "virtual"}]  || test_dbsuat | table1     |  57954143 | 57954146 |         0 | xx.xx.x.152:30160 | [{"region": "virtual"}]  || test_dbsuat | table2     |  57954499 | 57954500 |         0 | xx.xx.x.152:30160 | [{"region": "virtual"}]  || test_dbsuat | table2     |  57954499 | 57954501 |         1 | xx.xx.x.151:30160 | [{"region": "physical"}] || test_dbsuat | table2     |  57954499 | 57954502 |         0 | xx.xx.x.153:30160 | [{"region": "virtual"}]  || test_dbsuat | table3     |  57954507 | 57954508 |         0 | xx.xx.x.152:30160 | [{"region": "virtual"}]  || test_dbsuat | table3     |  57954507 | 57954509 |         1 | xx.xx.x.151:30160 | [{"region": "physical"}] || test_dbsuat | table3     |  57954507 | 57954510 |         0 | xx.xx.x.153:30160 | [{"region": "virtual"}]  |...
复制代码


通过上述步骤,我们成功的实现了 test_dbsuat 数据库下面所有表的 leader 固定在物理机节点、follower 分散在所有节点上面的要求。

在集群拓扑配置中持久化标签

使用 pd-ctl 在线配置的标签虽然会持久化,但是却并不会同步到集群拓扑配置当中。当我们使用 tiup cluster show-config 查看时并不会显示这些标签,容易造成不一致的错觉。


要解决此问题,我们可以使用 tiup cluster edit-config 在拓扑配置文件中将标签维护到配置文件中,并使用 tiup cluster reload xx –skip-restart 将配置重载。这样无论之后集群怎么重启,始终可以保持一致性。


...server_configs:  pd:     replication.location-labels: ["region", "zone", "host"]...tikv_servers:- host: xx.xx.x.151  ...  config:    server.labels:      region: physical ... - host: xx.xx.x.152  ...  config:    server.labels:      region: virtual ... - host: xx.xx.x.153  ...  config:    server.labels:      region: virtual...  

//reload 集群,--skip-restart 表示不重启tiup cluster reload tidb-ee -R pd,tikv --skip-restart
复制代码


Reload 也将拓扑配置文件中的标签持久化到 PD 和 TiKV 各自的配置文件中,我们可以进一步查看相应的配置文件以确保 reload 生效。


[tidb@host-xx-xx-x-151 conf]$ cat tikv.toml...[server][server.labels]region = "physical"...
[tidb@host-xx-xx-x-151 conf]$ cat pd.toml...[replication]location-labels = ["region", "zone", "host"]...
复制代码

总结

在线打标签及配置 Placement Rules 是 TiDB 数据库中在不影响生产运行的同时实现数据副本按需调度的一种有效手段。本文结合一个实际应用场景,通过测试环境模拟的方式验证方案的有效性。为了突出重点内容,本文未考虑有 TiFlash 副本的情况,也没有考虑配置 PD 的 isolation-level。TiFlash 添加标签的步骤与 TiKV 几乎相同,isolation-level 主要用于节点上部署多个 TiKV 实例的场景,两者在官网文档 “ 通过拓扑 label 进行副本调度 ” 一文中均有描述,本文不再赘述。

参考链接

通过拓扑 label 进行副本调度


PD Control 使用说明


Placement Rules in SQL


CREATE PLACEMENT POLICY


ALTER RANGE


SHOW PLACEMENT


发布于: 刚刚阅读数: 4
用户头像

TiDB 社区官网:https://tidb.net/ 2021-12-15 加入

TiDB 社区干货传送门是由 TiDB 社区中布道师组委会自发组织的 TiDB 社区优质内容对外宣布的栏目,旨在加深 TiDBer 之间的交流和学习。一起构建有爱、互助、共创共建的 TiDB 社区 https://tidb.net/

评论

发布
暂无评论
TiDB 在线打标签实现副本调度应用实践_实践案例_TiDB 社区干货传送门_InfoQ写作社区