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

作者: 数据源的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 -i
Starting 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,host
Success!
» 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 个节点的机器类型,那么便可以画出以下表格。

IP STORE ID 机器类型
xx.xx.x.151 3 物理机
xx.xx.x.152 2 虚拟机
xx.xx.x.153 1 虚拟机

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

» store label 1 region=virtual
pd/api/v1/store/1/label
Success!
» store label 2 region=virtual
pd/api/v1/store/2/label
Success!
» store label 3 region=physical
pd/api/v1/store/3/label
Success!» 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 命令,如下表格所示。

级别 SQL 命令 描述
集群 alter range [global|meta] placement policy xx 为集群配置全局放置策略,v7.5 版本开始支持
数据库 alter database xx placement policy xx 为指定的 Database 配置放置策略
alter table xx placement policy xx 为指定的 Table 配置放置策略
分区 alter table xx partition xx placement policy xx 为表中不同的 Row 创建分区,并单独对分区配置放置策略

假设此处我们期望对集群内某个数据库级别绑定以上放置策略,应该使用命令 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/437384.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

uniapp踩坑 tabbar页面数据刷新了但视图没有更新

问题描述: 有个uni-data-checkbox组件,两个选项:选项1和选项2(对应的value值分别为1和2),v-model绑定属性名为value 两个tabbar页面:tab1,tab2。 tab1页面有个逻辑是在onShow中刷新v…

IDEA 设置自动定位文件

一、场景分析 IDEA 在使用的过程中,发现有时候,打开一个类,它并不能自动帮我们在左侧 Project 树中定位出文件,需要自己手动点击 瞄准 图标。很不方便。 二、解决方法 1、点击 瞄准 图标旁边的 竖三点 2、将 Alwasy Select Opene…

Kubernetes云原生存储解决方案之 Rook Ceph实践探究

Kubernetes云原生存储解决方案之 Rook Ceph实践探究 除了手动部署独立的 Ceph 集群并配置与Kubernetes进行对接外,Rook Ceph 支持直接在 Kubernetes 集群上部署 Ceph 集群。 通过Rook Ceph云原生存储编排平台,使得 Kubernetes 集群中启用高可用的 Ceph…

text2sql方法:NatSQL和DIN-SQL

NatSQL NatSQL出自2021年9月的论文《Natural SQL: Making SQL Easier to Infer from Natural Language Specifications》(github),它是一种SQL 中间表征(SQL intermediate representation(IR))方法。 NatSQL作者认为Text2SQL的关键挑战是自然语言描述和其对应的SQ…

数据结构——“AVL树”的四种数据旋转的方法

因为上次普通的二叉搜索树在极端情况下极容易造成我们的链式结构(这会导致我们查询的时间复杂度变为O(n)),然而AVL树就很好的解决了这一问题(归功于四种旋转的方法),它让我们的树的查询的时间复杂度变得接近…

Dapper 如何确保数据的安全性和防止 SQL 注入攻击?

一、什么是SQL注入攻击 SQL注入攻击是一种常见的网络攻击手段,它利用了应用程序中安全措施不足的问题,允许攻击者插入或“注入”一个或多个SQL语句到原本的查询中。这种攻击可以用于获取、篡改或删除数据库中的数据,甚至可以执行一些数据库管…

【web安全】——sql注入

1.MySQL基础 1.1information_schema数据库详解 简介: 在mysql5版本以后,为了方便管理,默认定义了information_schema数据库,用来存储数据库元数据信息。schemata(数据库名)、tables(表名tableschema)、columns(列名或字段名)。…

字节豆包C++一面-面经总结

talk is cheap show me the code lc206:链表反转:给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 class Solution { public:ListNode* reverseList(ListNode* head) {if(headnullptr||!head->next)return head…

sentinel原理源码分析系列(二)-动态规则和transport

本文是sentinel原理源码分析系列第二篇,分析两个组件,动态配置和transport 动态规则 Sentinel提供动态规则机制,依赖配置中心,如nacos,zookeeper,组件支持动态配置,模板类型为规则,支…

Qt开发技巧(九)去掉切换按钮,直接传样式文件,字体设置,QImage超强,巧用Qt的全局对象,信号槽断连,低量数据就用sqlite

继续讲一些Qt开发中的技巧操作: 1.去掉切换按钮 QTabWidget选项卡有个自动生成按钮切换选项卡的机制,有时候不想看到这个烦人的切换按钮,可以设置usesScrollButtons为假,其实QTabWidget的usesScrollButtons属性最终是应用到QTabWi…

python调用opencv报错“module ‘cv2‘ has no attribute ‘namedWindow‘”

之前电脑上使用pip install安装过opencv相关的python模块,不过后续学习opencv时主要使用OpenCVSharp在VS2022中创建项目测试。今天学习过程中突然想用python试试,不过运行下面代码时报错“module ‘cv2’ has no attribute namedWindow”。 import cv2c…

巡检机器人室内配电室应用

智能巡检系统实施背景 电力系统发展已进入电气化、自动化、智能化建设加速推进的新阶段,设备规模大幅增长,新设备、新技术加快应用,装备水平取得长足发展,与此同时设备规模大幅增长,新设备、新技术加快应用&#xff0…

神经网络介绍及其在Python中的应用(一)

作者简介:热爱数据分析,学习Python、Stata、SPSS等统计语言的小高同学~ 个人主页:小高要坚强的博客 当前专栏:Python之机器学习 本文内容:神经网络介绍及其在Python中的线性回归应用 作者“三要”格言:要坚…

STM32(四)LED闪烁、流水灯及蜂鸣器操作

小节任务:在对GPIO函数初始化操作及配置好输入或输出模式后,使用GPIO的输入输出函数控制LED闪烁、流水灯及蜂鸣器操作,本小节先使用GPIO的四个输出函数 SetBits函数将指定端口设置为高电平 ResetBits函数将指定端口设置为低电平 WriteBit根据…

c++进阶之多态讲解

这篇文章和大家一起学习一下c中的多态 多态的概念 多态的概念:通俗来讲,就是多种形态。多态分为编译时多态(静态多态)和运⾏时多态(动态多态)。 什么是静态多态 前⾯讲的函数重载和函数模板,它们传不同类型的参数就可以调用不同的函数&…

Linux中的软硬链接和动静态库

硬链接 ln myfile.txt hard_file.link 264962 -rw-rw-r-- 2 zhangsan zhangsan 0 Sep 30 03:16 hard_file.link 264962 -rw-rw-r-- 2 zhangsan zhangsan 0 Sep 30 03:16 myfile.txt 273922 lrwxrwxrwx 1 zhangsan zhangsan 10 Sep 30 03:17 soft_file.link -> …

Activiti7 工作流引擎学习

目录 一. 什么是 Activiti 工作流引擎 二. Activiti 流程创建步骤 三. Activiti 数据库表含义 四. BPMN 建模语言 五. Activiti 使用步骤 六. 流程定义与流程实例 一. 什么是 Activiti 工作流引擎 Activiti 是一个开源的工作流引擎,用于业务流程管理&#xf…

将给定的表达式树(二叉树)转换为等价的中缀表达式(通过括号反映操作符的计算次序)并输出

请设计一个算法,将给定的表达式树(二叉树)转换为等价的中缀表达式(通过括号反映操作符的计算次序)并输出。例如,当下列两棵表达式树作为算法输入时: 输出的中缀表达式分别为 (ab)∗(c∗(−d)) 和…

推送k8s镜像到阿里云服务器

1、服务打包 2、打包后进入Dockerfile的同级目录 运行 docker build -t 镜像名:镜像版本 . (这个点是当前目录的意思,不能忽略)例如 docker build -t trac:v1.0.4 .3、上传镜像到阿里云镜像服务 注意选择区域 例如: docker tag 70743d9bdba3 registr…

[C++] 剖析AVL树功能的实现原理

文章目录 引言AVL树的关键性质为什么选择AVL树? AVL树的结构节点对象的类 AVL树的插入检查是否为空树并处理根节点查询插入位置(非递归)插入节点并连接父节点更新平衡因子(在失去平衡的条件下进行旋转) 旋转旋转的原则…