在 Kubernetes 上快速测试 Citus 分布式 PostgreSQL 集群(分布式表,共置,引用表,列存储)

准备工作
这里假设,你已经在 k8s 上部署好了基于 Citus 扩展的分布式 PostgreSQL 集群。
查看 Citus 集群(kubectl get po -n citus),1 个 Coordinator(协调器) 节点 + 3 个 Worker(工作器) 节点。
NAME READY STATUS RESTARTS AGE
citus-coordinator-0 2/2 Running 0 3h55m
citus-worker-0 2/2 Running 0 22m
citus-worker-1 2/2 Running 0 21m
citus-worker-2 2/2 Running 0 21m
进入 coordinator 节点(kubectl -n citus exec -it citus-coordinator-0 -- bash),查看活动的 worker 节点(psql 'host=citus-coordinator user=postgres' -c "SELECT * FROM citus_get_active_worker_nodes();")。
node_name | node_port
-----------------------------------------------------+-----------
citus-worker-1.citus-worker.citus.svc.cluster.local | 6432
citus-worker-2.citus-worker.citus.svc.cluster.local | 6432
citus-worker-0.citus-worker.citus.svc.cluster.local | 6432
(3 rows)
一旦拥有 Citus 集群,就可以开始创建分布式表、引用表和使用列存储。
创建分布式表
create_distributed_table 将在本地或工作节点之间透明地切分您的表。
进入命令行工具:psql 'host=citus-coordinator user=postgres'
建表
CREATE TABLE events (
device_id bigint,
event_id bigserial,
event_time timestamptz default now(),
data jsonb not null,
PRIMARY KEY (device_id, event_id)
);
-- 将事件表分布在本地或工作节点上的分片上
SELECT create_distributed_table('events', 'device_id');
执行此操作后,对特定设备 ID 的查询将有效地路由到单个工作节点,而跨设备 ID 的查询将在集群中并行化。
插入一些事件
INSERT INTO events (device_id, data)
SELECT s % 100, ('{"measurement":'||random()||'}')::jsonb FROM generate_series(1,1000000) s;
-- INSERT 0 1000000
获取设备 1 的最后 3 个事件,路由到单个节点
命令行开启计时:postgres=# \timing
SELECT * FROM events WHERE device_id = 1 ORDER BY event_time DESC, event_id DESC LIMIT 3;
device_id | event_id | event_time | data
-----------+----------+-------------------------------+-------------------------------------
1 | 999901 | 2022-03-24 02:30:50.205478+00 | {"measurement": 0.8822990134507691}
1 | 999801 | 2022-03-24 02:30:50.205478+00 | {"measurement": 0.5239176115816448}
1 | 999701 | 2022-03-24 02:30:50.205478+00 | {"measurement": 0.9900647926398349}
(3 rows)
Time: 4.779 ms
解释跨分片并行化的查询的计划,以下显示了查询其中一个分片的计划以及如何完成跨分片的聚合
执行 sql 语句:
EXPLAIN (VERBOSE ON) SELECT count(*) FROM events;
QUERY PLAN
---------------------------------------------------------------------------------------------------------
Aggregate (cost=250.00..250.02 rows=1 width=8)
Output: COALESCE((pg_catalog.sum(remote_scan.count))::bigint, '0'::bigint)
-> Custom Scan (Citus Adaptive) (cost=0.00..0.00 rows=100000 width=8)
Output: remote_scan.count
Task Count: 32
Tasks Shown: One of 32
-> Task
Query: SELECT count(*) AS count FROM public.events_102008 events WHERE true
Node: host=citus-worker-0.citus-worker.citus.svc.cluster.local port=6432 dbname=postgres
-> Aggregate (cost=725.00..725.01 rows=1 width=8)
Output: count(*)
-> Seq Scan on public.events_102008 events (cost=0.00..650.00 rows=30000 width=0)
Output: device_id, event_id, event_time, data
(13 rows)
Time: 5.427 ms
使用共置(Co-location)创建分布式表
具有相同分布列的分布式表可以位于同一位置,以实现分布式表之间的高性能分布式连接(join)和外键。 默认情况下,分布式表将根据分布列的类型位于同一位置,但您可以使用 create_distributed_table 中的 colocate_with 参数显式定义同一位置。
建表
CREATE TABLE devices (
device_id bigint primary key,
device_name text,
device_type_id int
);
CREATE INDEX ON devices (device_type_id);
-- 将设备表与事件表放在一起
SELECT create_distributed_table('devices', 'device_id', colocate_with := 'events');
插入设备元数据
INSERT INTO devices (device_id, device_name, device_type_id)
SELECT s, 'device-'||s, 55 FROM generate_series(0, 99) s;
可选:确保应用程序只能插入已知设备的事件
ALTER TABLE events ADD CONSTRAINT device_id_fk
FOREIGN KEY (device_id) REFERENCES devices (device_id);
获得跨分片并行的所有类型 55 设备的平均测量值
SELECT avg((data->>'measurement')::double precision)
FROM events JOIN devices USING (device_id)
WHERE device_type_id = 55;
avg
--------------------
0.4997412230952178
(1 row)
Time: 122.548 ms
Co-location 还可以帮助您扩展 INSERT..SELECT、存储过程和分布式事务。
- INSERT..SELECT
- 存储过程
- 分布式事务
创建引用表
当您需要不包含分布列的快速 join 或外键时,您可以使用 create_reference_table 在集群中的所有节点之间复制表。
建表
CREATE TABLE device_types (
device_type_id int primary key,
device_type_name text not null unique
);
跨所有节点复制表以在任何列上启用外键和 join
SELECT create_reference_table('device_types');
插入设备类型
INSERT INTO device_types (device_type_id, device_type_name) VALUES (55, 'laptop');
可选:确保应用程序只能插入已知类型的设备
ALTER TABLE devices ADD CONSTRAINT device_type_fk
FOREIGN KEY (device_type_id) REFERENCES device_types (device_type_id);
获取类型名称以笔记本电脑开头的设备的最后 3 个事件,跨分片并行
SELECT device_id, event_time, data->>'measurement' AS value, device_name, device_type_name
FROM events JOIN devices USING (device_id) JOIN device_types USING (device_type_id)
WHERE device_type_name LIKE 'laptop%' ORDER BY event_time DESC LIMIT 3;
device_id | event_time | value | device_name | device_type_name
-----------+-------------------------------+---------------------+-------------+------------------
31 | 2022-03-24 02:30:50.205478+00 | 0.9994211581289107 | device-31 | laptop
31 | 2022-03-24 02:30:50.205478+00 | 0.13771543211483106 | device-31 | laptop
88 | 2022-03-24 02:30:50.205478+00 | 0.5585740912470349 | device-88 | laptop
(3 rows)
Time: 96.537 ms
引用表使您能够扩展复杂的数据模型并充分利用关系数据库的功能。
使用列式存储创建表
要在 PostgreSQL 数据库中使用列式存储,您只需将 USING columnar 添加到 CREATE TABLE 语句中,您的数据将使用列式访问方法自动压缩。
建表
CREATE TABLE events_columnar (
device_id bigint,
event_id bigserial,
event_time timestamptz default now(),
data jsonb not null
)
USING columnar;
插入一些数据
INSERT INTO events_columnar (device_id, data)
SELECT d, '{"hello":"columnar"}' FROM generate_series(1,10000000) d;
创建一个基于行的表进行比较
CREATE TABLE events_row AS SELECT * FROM events_columnar;
查看表大小
postgres=# \d+
List of relations
Schema | Name | Type | Owner | Persistence | Access method | Size | Description
--------+------------------------------+----------+----------+-------------+---------------+------------+-------------
public | citus_tables | view | postgres | permanent | | 0 bytes |
public | device_types | table | postgres | permanent | heap | 8192 bytes |
public | devices | table | postgres | permanent | heap | 8192 bytes |
public | events | table | postgres | permanent | heap | 8192 bytes |
public | events_columnar | table | postgres | permanent | columnar | 25 MB |
public | events_columnar_event_id_seq | sequence | postgres | permanent | | 8192 bytes |
public | events_event_id_seq | sequence | postgres | permanent | | 8192 bytes |
public | events_row | table | postgres | permanent | heap | 806 MB |
(8 rows)
注意 events_row(806 MB) 与 events_columnar(25 MB) 的对比。压缩了几十倍,效果非常的惊人,大大节省了存储空间。
您可以单独使用列存储,也可以在分布式表中使用,以结合压缩和分布式查询引擎的优势。
使用列式存储时,您应该只使用 COPY 或 INSERT..SELECT 批量加载数据以实现良好的压缩。柱状表目前不支持更新、删除和外键。 但是,您可以使用分区表,其中较新的分区使用基于行的存储,而较旧的分区使用列存储进行压缩。
更多
- Citus 集群 - 官方快速入门教程
- Citus 集群 - 官方安装指南
- Citus 简介 - 将 Postgres 转换为分布式数据库
- Citus 架构及概念
- Citus 集群官方示例 - 多租户应用程序实战
- Citus 集群官方教程 - 迁移现有应用程序
- Citus 集群)官方示例 - 实时仪表盘
- Citus 集群)官方示例 - 时间序列数据
- 多租户数据库项目实战(Python/Django+Postgres+Citus)
- Citus 集群 - 分布式表中的分布列选择最佳实践
- 扩展分析处理服务(Smartly.io) - 使用 Citus 对 PostgreSQL 数据库进行分片
在 Kubernetes 上快速测试 Citus 分布式 PostgreSQL 集群(分布式表,共置,引用表,列存储)的更多相关文章
- Citus 分布式 PostgreSQL 集群 - SQL Reference(创建和修改分布式表 DDL)
创建和分布表 要创建分布式表,您需要首先定义表 schema. 为此,您可以使用 CREATE TABLE 语句定义一个表,就像使用常规 PostgreSQL 表一样. CREATE TABLE ht ...
- 分布式 PostgreSQL 集群(Citus),官方快速入门教程
多租户应用程序 在本教程中,我们将使用示例广告分析数据集来演示如何使用 Citus 来支持您的多租户应用程序. 注意 本教程假设您已经安装并运行了 Citus. 如果您没有运行 Citus,则可以使用 ...
- 分布式 PostgreSQL 集群(Citus)官方教程 - 迁移现有应用程序
将现有应用程序迁移到 Citus 有时需要调整 schema 和查询以获得最佳性能. Citus 扩展了 PostgreSQL 的分布式功能,但它不是扩展所有工作负载的直接替代品.高性能 Citus ...
- 分布式 PostgreSQL 集群(Citus)官方示例 - 时间序列数据
在时间序列工作负载中,应用程序(例如一些实时应用程序查询最近的信息,同时归档旧信息. https://docs.citusdata.com/en/v10.2/sharding/data_modelin ...
- 分布式 PostgreSQL 集群(Citus)官方安装指南
单节点 Citus Docker (Mac 与 Linux) Docker 镜像仅用于开发/测试目的, 并且尚未准备好用于生产用途. 您可以使用一个命令在 Docker 中启动 Citus: # st ...
- 分布式 PostgreSQL 集群(Citus),分布式表中的分布列选择最佳实践
确定应用程序类型 在 Citus 集群上运行高效查询要求数据在机器之间正确分布.这因应用程序类型及其查询模式而异. 大致上有两种应用程序在 Citus 上运行良好.数据建模的第一步是确定哪些应用程序类 ...
- Citus 分布式 PostgreSQL 集群 - SQL Reference(摄取、修改数据 DML)
插入数据 要将数据插入分布式表,您可以使用标准 PostgreSQL INSERT 命令.例如,我们从 Github 存档数据集中随机选择两行. INSERT http://www.postgresq ...
- Citus 分布式 PostgreSQL 集群 - SQL Reference(查询分布式表 SQL)
如前几节所述,Citus 是一个扩展,它扩展了最新的 PostgreSQL 以进行分布式执行.这意味着您可以在 Citus 协调器上使用标准 PostgreSQL SELECT 查询进行查询. Cit ...
- 分布式 PostgreSQL 集群(Citus)官方示例 - 实时仪表盘
Citus 提供对大型数据集的实时查询.我们在 Citus 常见的一项工作负载涉及为事件数据的实时仪表板提供支持. 例如,您可以是帮助其他企业监控其 HTTP 流量的云服务提供商.每次您的一个客户端收 ...
随机推荐
- Solution -「多校联训」轮回
\(\mathcal{Description}\) 有 \(n\) 个黑盒,第 \(i\) 个黑盒可以让输入变量以 \(p_i\) 的概率保持不变,以 \(\frac{1-p_i}2\) 的概率加 ...
- Dubbo的前世今生
搜索关注微信公众号"捉虫大师",后端技术分享,架构设计.性能优化.源码阅读.问题排查.踩坑实践. 本文已收录 https://github.com/lkxiaolou/lkxiao ...
- Linux性能优化之磁盘I/O调优
I/O指标已介绍,那么如何查看系统的这些指标呢? 一.根据工具查性能 二.根据性能找工具 三.磁盘I/O观察实例 iostat 是最常用的磁盘 I/O 性能观测工具,它提供了每个磁盘的 使用率 . I ...
- Golang Sync.WaitGroup 使用及原理
Golang Sync.WaitGroup 使用及原理 使用 func main() { var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.A ...
- IDEA中快速排除maven中的依赖
选中该模块 点击show dependenties 切换试图 选中要排除的依赖,右击 选择Execlude,然后选择需要在哪个模块添加排除依赖 完成
- 私有化轻量级持续集成部署方案--07-私有NPM仓库-Verdaccio
提示:本系列笔记全部存在于 Github, 可以直接在 Github 查看全部笔记 对于个人来说,私有NPM仓库 作用性基本很小,但是对于企业,私有NPM仓库 可以保护代码暴露,具有很大的意义. 也是 ...
- 『无为则无心』Python面向对象 — 59、魔法方法
目录 1.魔法方法__new__() 2.魔法方法__init__() 3.魔法方法__del__() 4.魔法方法__str__()和__repr__() 5.魔法方法__call__() 6.魔法 ...
- Docker从入门到精通
1 容器简介1.1 什么是 Linux 容器1.2 容器不就是虚拟化吗1.3 容器发展简史2 什么是 Docker?2.1 Docker 如何工作?2.2 Docker 技术是否与传统的 Linux ...
- Map<String, String> map按key值排序
private static String buildMd5Params(Map<String, String> map) { StringBuilder result = new Str ...
- Hive常用函数大全-数值计算
1 1.取整函数:round(X)(遵循四舍五入) 2 select round(3.1415926) from table --3 3 select round(3.5) from table -- ...