分布式分片
HDS(Halo Data Sharding)是 Halo 数据库的分布式分片组件,采用存算分离架构,专为高并发 OLTP 应用设计。它通过水平分区将数据分布到多个独立数据库(分片/数据节点)中,同时向应用程序呈现为单一逻辑数据库,应用通过 JDBC 等标准接口访问,无需修改代码。
HDS 的核心特点:
- 线性可扩展性:通过在线添加分片节点,实现性能与容量的线性增长;
- 故障隔离:单个分片故障不影响其他分片,消除单点故障;
- 透明性:应用程序只连接工作节点,数据的分片存储与路由对应用完全透明;
- 条件下推与自动剪枝:查询带分区键条件时,自动裁剪无关分片,只扫描相关数据节点。
HDS 集群由两类节点组成:
- 工作节点(Worker):接收应用的 SQL 请求,根据分区规则将请求路由到对应的数据节点;工作节点通过参数
instance_type = 'HDS'标识。 - 数据节点(Data Node):实际存储分片数据的独立 Halo 数据库实例,每个数据节点存储整个逻辑表的一个子集。
工作节点与数据节点之间通过 shard_fdw 外部数据包装器建立连接通道。
HDS 的部署
执行环境说明:以下命令与输出基于 Halo 1.0.16 实测。示例中 ${数据节点1IP} 等为占位符,部署时替换为实际 IP;密码请使用实际强密码。
部署数据节点
数据节点为普通的 Halo 单机实例。在每个数据节点上安装 Halo 数据库(安装流程参见单机安装),并创建用于存放分片数据的数据库与表。
以两个数据节点为例,在每个数据节点上执行:
halo0root=# CREATE DATABASE halo_hds;
CREATE DATABASE
halo_hds=# CREATE TABLE tbl_user (id int, info text, logdate date not null);
CREATE TABLE
说明:各数据节点上需创建结构相同的基表(本例为 tbl_user),工作节点的外部分区表将通过 shard_fdw 映射到这些基表。
部署工作节点
工作节点的安装与单机流程一致,在此基础上完成 HDS 配置。
1)设置工作节点类型
修改工作节点的 postgresql.conf,将本节点标识为 HDS 工作节点:
instance_type = 'HDS'
2)创建 shard_fdw 扩展
在工作节点用于分片的数据库(本例为 halo_hds)中创建 shard_fdw 扩展:
halo_hds=# CREATE EXTENSION shard_fdw CASCADE;
CREATE EXTENSION
3)创建外部服务器(fdw-server)
为每个数据节点创建一个外部服务器,作为工作节点访问该数据节点的通道:
halo_hds=# CREATE SERVER hds_fdw_halo_db_01
FOREIGN DATA WRAPPER shard_fdw
OPTIONS (host '${数据节点1IP}', port '1921', dbname 'halo_hds');
CREATE SERVER
halo_hds=# CREATE SERVER hds_fdw_halo_db_02
FOREIGN DATA WRAPPER shard_fdw
OPTIONS (host '${数据节点2IP}', port '1921', dbname 'halo_hds');
CREATE SERVER
4)创建用户映射(user-mapping)
为工作节点的应用用户在每个外部服务器上创建用户映射,指定连接数据节点时使用的远程用户与密码:
halo_hds=# CREATE USER MAPPING FOR halo
SERVER hds_fdw_halo_db_01
OPTIONS (user 'dbadmin', password '${实际密码}', password_required 'false');
CREATE USER MAPPING
halo_hds=# CREATE USER MAPPING FOR halo
SERVER hds_fdw_halo_db_02
OPTIONS (user 'dbadmin', password '${实际密码}', password_required 'false');
CREATE USER MAPPING
说明:需为每个外部服务器都创建对应的用户映射。dbadmin 为数据节点上的数据库用户,应用用户(本例为 halo)通过该映射以 dbadmin 身份访问对应数据节点。
创建外部分区表
在工作节点上创建分区父表,并为每个分区创建指向数据节点的外部子表,将不同分区的数据路由到不同数据节点。
1)创建分区父表
halo_hds=# CREATE TABLE tbl_user (id int, info text, logdate date not null)
PARTITION BY RANGE (logdate);
CREATE TABLE
2)创建外部分区子表
将 2019 年的数据分区映射到数据节点 1,2020 年的数据分区映射到数据节点 2:
halo_hds=# CREATE FOREIGN TABLE tbl_user_0 PARTITION OF tbl_user
FOR VALUES FROM ('2019-01-01') TO ('2020-01-01')
SERVER hds_fdw_halo_db_01
OPTIONS (schema_name 'public', table_name 'tbl_user');
CREATE FOREIGN TABLE
halo_hds=# CREATE FOREIGN TABLE tbl_user_1 PARTITION OF tbl_user
FOR VALUES FROM ('2020-01-01') TO ('2021-01-01')
SERVER hds_fdw_halo_db_02
OPTIONS (schema_name 'public', table_name 'tbl_user');
CREATE FOREIGN TABLE
3)授权(按需)
若应用用户与工作节点部署用户不同,需将外部服务器与外部表的使用权限授予应用用户(工作节点部署用户为 dba 时可跳过):
halo_hds=# GRANT USAGE ON FOREIGN SERVER hds_fdw_halo_db_01 TO halo_test;
GRANT
halo_hds=# GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO halo_test;
GRANT
至此,HDS 分片配置完成。
HDS 的验证
验证分片写入
在工作节点插入数据,数据将按分区键(logdate)自动路由到对应的数据节点:
halo_hds=# INSERT INTO tbl_user VALUES
(1,'a','2019-01-01'),
(2,'b','2020-01-01'),
(3,'c','2019-02-01'),
(4,'d','2020-02-01');
INSERT 0 4
验证分片透明性
工作节点查询时看到全部数据,分片存储对应用透明:
-- 在工作节点执行
halo_hds=# SELECT * FROM tbl_user ORDER BY id;
id | info | logdate
----+------+------------
1 | a | 2019-01-01
2 | b | 2020-01-01
3 | c | 2019-02-01
4 | d | 2020-02-01
(4 rows)
验证数据分片存储
分别登录两个数据节点查询,确认数据已按分区键分散存储:
-- 数据节点 1(存储 2019 年分区)
SELECT * FROM tbl_user ORDER BY id;
id | info | logdate
----+------+------------
1 | a | 2019-01-01
3 | c | 2019-02-01
(2 rows)
-- 数据节点 2(存储 2020 年分区)
SELECT * FROM tbl_user ORDER BY id;
id | info | logdate
----+------+------------
2 | b | 2020-01-01
4 | d | 2020-02-01
(2 rows)
说明:上述验证表明,应用只连接工作节点写入与查询,数据按分区键 logdate 自动分散到两个数据节点——2019 年的数据落在数据节点 1,2020 年的数据落在数据节点 2。分片的存储与路由对应用完全透明。
验证条件下推与分区裁剪
当查询带分区键条件时,HDS 会自动裁剪无关分片,只扫描包含目标数据的数据节点。通过 EXPLAIN 可观察到只访问了匹配的分区:
halo_hds=# EXPLAIN SELECT * FROM tbl_user
WHERE logdate >= '2019-01-01' AND logdate < '2020-01-01';
QUERY PLAN
----------------------------------------------------------------------------
Foreign Scan on tbl_user_0 tbl_user (cost=100.00..129.32 rows=6 width=40)
(1 row)
说明:查询条件限定在 2019 年,执行计划只扫描了 tbl_user_0(数据节点 1 上的分区),未扫描 tbl_user_1(2020 年分区)。这就是 HDS 的条件下推与自动剪枝——查询只下发到相关分片,避免全分片扫描,显著降低跨节点开销。