帮你快速理解、总结文档立即下载

Distribution Policy

最近更新时间:2026-08-20 16:35:00
我的收藏
Distribution Policy(DP) 是 TDSQL Boundless 管理数据对象分布的规则系统,通过对数据对象显式设置规则,元数据服务(MC)可以进行相应的调度。通过设置不同的调度规则,用户可以精细化控制数据对象的分布,如副本数量,副本位置分布,Replication Group Leader 位置等。

规则介绍

Distribution Policy 通常由多条具体的规则组成。元数据服务会对用户指定的多条规则进行校验,以确保规则本身的正确性以及多条规则之间不会互相冲突,具体的校验规则可参考注意事项。DP 的单条规则的设计参考了 Kubernetes 的 LabelConstraint 的设计,通常由含有 key, op, values 字段的 JSON 组成,如下所示:
{"key": "key1", "op": "op1", "values": ["value1","value2"]}
目前 TDSQL Boundless 支持的规则如下所示:
key
op
values
region
"in", "notIn", "exists", "notExists"
地域列表,如 ["guangzhou"]
zone
"in", "notIn", "exists", "notExists"
可用区列表,如 ["guangzhou-1"]
rack
"in", "notIn", "exists", "notExists"
机架列表,如 ["rack-1","rack-2"]
host
"in", "notIn", "exists", "notExists"
主机列表,如 ["host-1","host-2","host-3"]
node
"in", "notIn"
节点列表,如 ["node-tdsql3-xxx-001"]
replica-count
"="
副本数量,如 ["3"]
follower-count
"="
RG follower 数量,如 ["2"]
learner-count
"="
RG learner 数量,如 ["1"]
witness-count
"="
RG witness 数量,如 ["1"]
leader-preferences
"="
RG leader 偏好,用法参考说明2
fault-tolerance-level
"="
容灾级别,如 ["zone"]
tdsql-storage-type
"in", "notIn", "exists", "notExists"
磁盘类型列表,如 ["CLOUD_TCS","CLOUD_BSSD"]
storage-tier
"="
存储层类型,如["OBJECT_STORAGE"]
说明:
1. 操作符含义:
in:给定 key 对应的 value 包含在给定的 values 列表中。
notIn:给定 key 对应的 value 不包含在给定的 values 列表中。
exists:包含给定 key。
notExists:不包含给定 key。
2. leader-preferences 的 values 由嵌套结构组成,例如:["{\\"key\\": \\"zone\\", \\"op\\": \\"in\\", \\"values\\": [\\"guangzhou-1\\"]}", "{\\"key\\": \\"zone\\", \\"op\\": \\"in\\", \\"values\\": [\\"guangzhou-2\\"]}"]。leader-preferences 对应的 SQL 写法请参见 创建 Distribution Policy
注意:
1. RG 副本相关的规则说明:RG leader 数量 + RG follower 数量 = replica-count - learner-count - witness-count。
当不指定 learner-count 或 witness-count 时,默认 learner 和 witness 的数量均为0。
例如指定 replica-count = 4 时表示 RG leader 数量为1,follower 数量为3。
2. 使用 node 作为 key 时的规则说明:
2.1 必须保证 values 中的节点是真实存在于实例中。
2.2 如指定副本数时,values 中的节点数量需要大于等于副本数,否则 DP 将无法调度。
3. 使用 leader-preferences 时的规则说明:RG leader 的位置应该始终是副本位置约束的子集,例如当指定副本位置位于可用区 ["zone1", "zone2", "zone3"] 时,需要保证 RG leader 的位置也指定在上述可用区中。
警告:
元数据服务在发现不合理的 DP 设置时,会拒绝进行调度,但不会影响其他功能的可用性以及数据的正确性。

使用 Distribution Policy

自 TDSQL Boundless V21.2.3 起,您可以直接使用 SQL 语句创建、修改、删除和查询 Distribution Policy,无需借助内部运维工具。SQL 语法中的关键字与前文规则表中的 keyop 字段对应关系如下:
规则字段
对应 SQL 关键字
region
REGION
zone
ZONE
rack
RACK
host
HOST
node
NODE
replica-count
REPLICA_COUNT
follower-count
FOLLOWER_COUNT
learner-count
LEARNER_COUNT
witness-count
WITNESS_COUNT
leader-preferences
LEADER_PREFERENCES
fault-tolerance-level
FAULT_TOLERANCE_LEVEL
tdsql-storage-type
STORAGE_TYPE
storage-tier
STORAGE_TIER
in / notIn / exists / notExists
IN / NOT IN / EXISTS / NOT EXISTS
注意:
若实例内核版本低于 V21.2.3,暂不支持通过 SQL 语句管理 Distribution Policy,请联系腾讯云技术支持处理。

开启和关闭 Distribution Policy

distribution-policy-enabled 自 V18.0.0 起默认开启,一般无需手动设置。如果您需要关闭该功能,请联系腾讯云技术支持处理。

创建 Distribution Policy

使用 CREATE DISTRIBUTION POLICY 语句创建 DP,一条 DP 可包含多条规则,多条规则之间使用 AND 连接:
CREATE DISTRIBUTION POLICY "$policy_name" SET $key1 $op1 ($value1, $value2, ...) AND $key2 $op2 (...) ...;
说明:
创建 DP 需要指定 policy_name,并通过 SET 子句设置一条或多条 DP 规则,各规则对应的 SQL 关键字请参见前文关键字对照表。

修改 Distribution Policy

使用 ALTER DISTRIBUTION POLICY 语句修改 DP 的规则,使用 RENAME DISTRIBUTION POLICY 语句修改 DP 的名称:
-- 修改名称为 policy_1 的 DP 规则
ALTER DISTRIBUTION POLICY "policy_1" SET $key $op (...);

-- 将 DP old_dp_name 的名称修改为 new_dp_name
RENAME DISTRIBUTION POLICY "old_dp_name" TO "new_dp_name";
注意:
只有未绑定数据对象的 DP 规则可以被修改,如果需要修改已绑定数据对象的 DP,需要先解除数据对象与 DP 的绑定。

删除 Distribution Policy

使用 DROP DISTRIBUTION POLICY 语句删除 DP:
DROP DISTRIBUTION POLICY "$policy_name";
注意:
只有未绑定数据对象的 DP 规则可以被删除,如果需要删除已绑定数据对象的 DP,需要先解除数据对象与 DP 的绑定。

查看 Distribution Policy

通过系统视图 information_schema.META_CLUSTER_DPS 查询已创建的 DP:
-- 查看已创建的所有 DP
SELECT * FROM information_schema.META_CLUSTER_DPS;

-- 按名称查看指定 DP
SELECT * FROM information_schema.META_CLUSTER_DPS WHERE distribution_policy_name = '$policy_name';

数据对象绑定 DP

在创建 DP 完成之后,可将数据对象与 DP 绑定,从而达到对应的调度效果。

数据库绑定 DP

CREATE DATABASE db1 USING distribution policy "$policy_name";

单表绑定 DP

CREATE TABLE t1(a INT) USING distribution policy "$policy_name";

分区表绑定 DP

CREATE TABLE t1(a INT) PARTITION BY HASH(a) PARTITIONS 4 USING distribution policy "$policy_name";
说明:
DP 在数据对象中遵循继承规则。例如上述例子中,创建数据库 db1 并绑定 DP 后,在该数据库中创建的所有单表和分区表都将使用与数据库相同的 DP,但如果直接对该数据库中的一张表绑定另一种 DP,其优先级高于继承规则。

典型 DP 示例

场景1:创建一个5副本的 DP。
CREATE DISTRIBUTION POLICY "policy_1" SET REPLICA_COUNT = 5;
场景2:创建一个4副本并包含一个 learner 的 DP。
CREATE DISTRIBUTION POLICY "policy_2" SET REPLICA_COUNT = 4 AND LEARNER_COUNT = 1;
场景3:创建一个副本位于 node-001, node-002, node-003 节点,且 RG Leader 位于 node-001 节点的 DP。
CREATE DISTRIBUTION POLICY "policy_3" SET NODE IN ("node-001", "node-002", "node-003") AND
LEADER_PREFERENCES = (NODE IN ("node-001"));
场景4:创建一个副本放置于磁盘类型是 SSD 的 DP。
CREATE DISTRIBUTION POLICY "policy_4" SET STORAGE_TYPE IN ("SSD");

高级特性

TDSQL Boundless V21.2.3版本提供了一种高级 DP 特性,RANGE 和 RANGE COLUMNS 并以时间类型为分区键的分区表可以绑定该种高级 DP,其效果可以让分区表的部分分区在指定时间后再进行调度,一种典型的场景是自动对分区进行落冷,以下是具体介绍:
使用 SQL 创建 DP
-- 示例一:将超时的冷数据迁移到挂载了HDD的节点上,需要集群中存在挂载HDD的节点。
CREATE DISTRIBUTION POLICY "policy_x_disk" SET PARTITION_METHOD = "RANGE" AND
PARTITION_KEY_TO_TIME_TYPE = "predefined:TO_DAYS" AND
EXPIRE = "1 YEAR" AND
START_TIME = "2024-06-11 00:11:22" AND
END_TIME = "2025-06-11 00:11:22" AND
STORAGE_TYPE IN ("HDD");

-- 示例二:将超时的冷数据落冷到对象存储上,需要集群开启对象存储层,数据可读写,但存在性能回退与功能限制
CREATE DISTRIBUTION POLICY "policy_x_storage_tier" SET PARTITION_METHOD = "RANGE" AND
PARTITION_KEY_TO_TIME_TYPE = "predefined:TO_DAYS" AND
EXPIRE = "1 YEAR" AND
STORAGE_TIER = "OBJECT_STORAGE";
这条 DP 中的几个关键字解释如下:
PARTITION_METHOD:表示 DP 支持的分区表所对应的分区方式,目前仅支持 RANGERANGE COLUMNS
PARTITION_KEY_TO_TIME_TYPE:仅在 RANGE 分区方式时需要指定,用来将分区边界值转换为时间类型。该 key 对应的 values 是转换函数,有三种可选的转换方式:
1. 预定义转换函数:系统提供了三个预定义的转换函数,即 TO_DAYS, UNIX_TIMESTAMPYEAR
2. 用户自定义转换函数:自定义函数需要给出年月日时分秒的计算公式,遵从的格式为:year/month/day/hour/minute/second:(含有标识符 v 的数学公式),其中 v 是标识符,表示的是分区边界的整型值。如将 values 设置为 ["year:v/100", "month:v%100"],省略的 day/hour/minute/second 则按照对应时间单位的零值处理。
3. SQL 转换表达式:用户可在约束值中使用 sql: 前缀声明任意 SQL 表达式,表达式中通过 BOUND 占位符引用分区 bound 值,运行时由 SQLEngine 计算为 DATETIME,如"sql:STR_TO_DATA(CONCAT(BOUND, '01'), '%Y%m%d')"
BOUND 占位符:表达式中必须包含 BOUND 标识符,运行时替换为分区的实际 bound 值(整数或字符串,取决于分区键类型)。例如分区 p202006 VALUES LESS THAN (202007)BOUND 值为 202007
EXPIRE:分区过期时间,正整数 + 单位的格式,如 1 YEAR 。可用单位有:YEAR, MONTH, DAY, HOUR
START_TIME:非必选项,默认为分区的起始,如指定这一项,则表示从这个时间之后开始应用 DP 规则。
END_TIME:非必选项,默认为分区的结束,如指定这一项,则表示从这个时间之后拒绝应用 DP 规则。
常见分区键格式的 SQL 转换表达式示例
分区键格式
转换表达式
说明
yyyymm(INT,如 202007)
sql:STR_TO_DATE(CONCAT(BOUND,'01'),'%Y%m%d')
补全为 20200701 后转为日期
yyyy-mm-dd(VARCHAR)
sql:STR_TO_DATE(BOUND,'%Y-%m-%d')
直接解析日期字符串
Unix 时间戳(INT)
sql:FROM_UNIXTIME(BOUND)
时间戳转 DATETIME
注意:
1. 仅支持一级 RANGE 和 RANGE COLUMNS 分区使用相关特性,其分区键也必须是时间类型。
2. RANGE COLUMNS 分区仅支持一个分区列。
3. SQL 表达式需含 BOUND 占位符,否则 DP 创建时拒绝。
4. 表达式中不允许包含分号、SQL 注释、DML/DDL 关键词,否则 DP 创建时拒绝。
5. 表达式在 DP 创建时用测试值校验语法,绑定到表时用首个分区的真实 bound 值校验兼容性,校验失败则拒绝绑定。

案例说明

案例1:基于 UNIX_TIMESTAMP 规则的冷数据归档

-- 使用预定义函数 UNIX_TIMESTAMP 创建 policy_x1
CREATE DISTRIBUTION POLICY "policy_x1" SET PARTITION_METHOD = "RANGE" AND
PARTITION_KEY_TO_TIME_TYPE = ("predefined:UNIX_TIMESTAMP") AND
EXPIRE = "1 MONTH" AND
STORAGE_TYPE IN ("HDD");

-- 创建 RANGE 分区表并绑定 policy_x1
CREATE TABLE t_order_1(
id bigint NOT NULL,
gmt_modified timestamp NOT NULL)
PARTITION BY RANGE(unix_timestamp(gmt_modified))(
PARTITION p1 VALUES LESS THAN(unix_timestamp('2025-11-11')),
PARTITION p2 VALUES LESS THAN(unix_timestamp('2025-12-11'))
) USING DISTRIBUTION POLICY policy_x1;
调度行为说明
p1 分区调度
分区边界时间:2025-11-11
过期时间偏移:1个月
调度触发时间:2025-11-11 + 1个月 = 2025-12-11
调度动作:将 p1 分区的数据副本迁移到 HDD 存储
p2 分区调度
分区边界时间:2025-12-11
过期时间偏移:1个月
调度触发时间:2025-12-11 + 1个月 = 2026-01-11
调度动作:将 p2 分区的数据副本迁移到 HDD 存储

案例2:自定义时间转换函数的精确调度控制

-- 使用自定义函数创建 policy_x2
CREATE DISTRIBUTION POLICY "policy_x2" SET PARTITION_METHOD = "RANGE" AND
PARTITION_KEY_TO_TIME_TYPE = ("year:v/100", "month:v%100") AND
EXPIRE = "1 MONTH" AND
LEADER_PREFERENCES = (ZONE in ("zone1")) AND
START_TIME = "2025-12-10 00:00:00";

-- 创建 RANGE 分区表并绑定 policy_x2
CREATE TABLE t_order_2(
id bigint NOT NULL,
gmt_modified datetime NOT NULL)
PARTITION BY RANGE(YEAR(gmt_modified) * 100 + MONTH(gmt_modified))(
PARTITION p1 VALUES LESS THAN(202511),
PARTITION p2 VALUES LESS THAN(202512),
PARTITION p3 VALUES LESS THAN(202601)
) USING DISTRIBUTION POLICY policy_x2;
转换函数解析
自定义函数: year:v/100, month:v%100

分区边界值 v = YEAR(gmt_modified) * 100 + MONTH(gmt_modified)

示例计算:
- p1: v=202511 → year=202511/100=2025, month=202511%100=11
- p2: v=202512 → year=202512/100=2025, month=202512%100=12
- p3: v=202601 → year=202601/100=2026, month=202601%100=1
分区时间边界计算
分区
边界值
转换后时间
调度触发时间
是否受约束
p1
202511
2025-11-01 00:00:00
2025-12-01 00:00:00
不受约束
p2
202512
2025-12-01 00:00:00
2026-01-01 00:00:00
不受约束
p3
202601
2026-01-01 00:00:00
2026-02-01 00:00:00
受约束
START_TIME 影响分析
START_TIME = "2025-12-10 00:00:00"
只有分区边界时间 ≥ START_TIME 的分区才会应用 DP 约束
p1(2025-11-01) 和 p2(2025-12-01) < START_TIME(2025-12-10) → 不受约束
p3(2026-01-01) > START_TIME(2025-12-10) → 受约束

案例3:RANGE COLUMNS 分区的时间窗口调度

-- 创建 policy_x3
CREATE DISTRIBUTION POLICY "policy_x3" SET PARTITION_METHOD = "RANGE COLUMNS" AND
EXPIRE = "1 YEAR" AND
NODE NOT IN ("node-tdsql3-x-001") AND
START_TIME = "2025-12-10 00:00:00" AND
END_TIME = "2026-12-10 00:00:00";

-- 创建 RANGE COLUMNS 分区表并绑定 policy_x3
CREATE TABLE t_order_3(
id bigint NOT NULL,
gmt_modified datetime NOT NULL)
PARTITION BY RANGE COLUMNS(gmt_modified) (
PARTITION p1 VALUES LESS THAN("2024-12-10 00:00:00"),
PARTITION p2 VALUES LESS THAN("2025-12-10 00:00:00"),
PARTITION p3 VALUES LESS THAN("2026-12-10 00:00:00"),
PARTITION p4 VALUES LESS THAN("2027-12-10 00:00:00")
) USING DISTRIBUTION POLICY policy_x3;
由于是 RANGE COLUMNS 时间分区绑定的 DP,因此不需要使用 PARTITION_KEY_TO_TIME_TYPE 字段给出转换函数,因为此时分区边界已经是时间类型的值了。同时由于指定了 START_TIME 和 END_TIME,因此只有 p2 和 p3 分区会在到达分区边界时间的一年(EXPIRE = "1 YEAR")后发起调度。
分区
边界时间
调度触发时间
是否在时间窗口内
p1
2024-12-10
2025-12-10
早于 START_TIME
p2
2025-12-10
2026-12-10
在 [START_TIME, END_TIME] 内
p3
2026-12-10
2027-12-10
在 [START_TIME, END_TIME] 内
p4
2027-12-10
2028-12-10
晚于 END_TIME

案例4:基于 SQL 表达式将时间分区落冷到对象存储

-- 创建 policy_x4,对满足SQL规则命名的分区进行向对象存储的落冷
CREATE DISTRIBUTION POLICY 'policy_x4' SET
PARTITION_METHOD = 'RANGE' AND
PARTITION_KEY_TO_TIME_TYPE = ('sql:STR_TO_DATE(CONCAT(BOUND,''01''),''%Y%m%d'')') AND
EXPIRE = '6 MONTH' AND
STORAGE_TIER = OBJECT_STORAGE;
-- 示例1:创建分区表并绑定 policy_x4
CREATE TABLE t_order_4 (
id BIGINT NOT NULL AUTO_INCREMENT,
yyyymm INT NOT NULL,
data VARCHAR(255) DEFAULT '',
PRIMARY KEY (id, yyyymm)
) PARTITION BY RANGE (yyyymm) (
PARTITION p202006 VALUES LESS THAN (202007),
PARTITION p202106 VALUES LESS THAN (202107),
PARTITION p209906 VALUES LESS THAN (209907),
PARTITION p299912 VALUES LESS THAN (299912)
) USING DISTRIBUTION POLICY policy_x4;

-- 示例2:创建子分区表并绑定 policy_x4
CREATE TABLE t_order_4_sub (
id BIGINT NOT NULL,
yyyymm INT NOT NULL,
data VARCHAR(255) DEFAULT '',
PRIMARY KEY (id, yyyymm)
) PARTITION BY RANGE (yyyymm)
SUBPARTITION BY HASH(id)
SUBPARTITIONS 2
(
PARTITION p202006 VALUES LESS THAN (202007),
PARTITION p202106 VALUES LESS THAN (202107),
PARTITION p209906 VALUES LESS THAN (209907),
PARTITION p299912 VALUES LESS THAN (299912)
) USING DISTRIBUTION POLICY policy_x4;
示例1的行为方式与案例1中相似,区别在于调度动作为将超时的分区(p202006、p202106)落冷到对象存储层,其中数据全程可读写,但会存在较大性能回退,并且部分高级功能不支持。
示例2中子分区将随父时间分区一起调度,以示例2中的表为例,p202006、p202106两个超时分区对应的4个子分区都会被落冷到对象存储上。