在 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 流量的云服务提供商.每次您的一个客户端收 ...
随机推荐
- P2678 [NOIP2015 提高组] 跳石头
#include<bits/stdc++.h> using namespace std; int l,n,m,a[100010];//与起点的距离 bool check(int d) { ...
- Linux 基础练习题
Linux 测试 1.找出/proc/meminfo文件中以s开头的行,至少用三种方式忽略大小写 [root@localhost proc]# grep -i '^s' /proc/meminfo [ ...
- [VSCode] Todo Tree VSCode插件 待办事项树
Todo Tree 一款待办事项插件 我们写程序的时候,难免会遇到一些情况需要标记或者搁置,在写代码的时候会用一些特殊的注释来表示不同的内容,使我们可以快速的定位我们注释的位置. 主要有以下几种: T ...
- Abp 异常处理
Abp 异常处理 最近一直在读代码整洁之道,我在读到第三章函数的3.9 使用异常替代返回错误码,其实在我的开发经历中都是使用返回错误码给到前端,之前在阅读ABP官网文档中就有看到过使用异常替代异常的做 ...
- CobaltStrike逆向学习系列(3):Beacon C2Profile 解析
这是[信安成长计划]的第 3 篇文章 关注微信公众号[信安成长计划] 0x00 目录 0x01 Controller 端分析 0x02 Beacon 端分析 0x03 展示图 在上一篇文章中完成了 S ...
- 思迈特软件Smartbi:Excel数据分析常用函数汇总!
多传统行业的数据分析师只要求掌握Excel即可,会SPSS/SAS是加分项.即使在挖掘满街走,Python不如狗的互联网数据分析界,Excel也是不可替代的. Excel是我们工作中经常使用的一种工具 ...
- NTLK情感分析安装与使用的两种方式 nltk-python
下载安装到实战详细步骤 NLTK下载安装 先使用pip install nltk 安装包 然后运行下面两行代码会弹出如图得GUI界面,注意下载位置,然后点击下载全部下载了大概3.5G. import ...
- 【C# Task】TaskCompletionSource
TaskCompletionSource具体功能 用于封装一个没有不带委托的任务实列.可以在其他线程控制该任务实列什么时候结束.取消.错误.类似于EventWaitHandle的功能. 属性 Task ...
- textbox 实现跨操作系统换行的两种写法
每个操作系统对换坏的解释都不一样.所以写代码的时候要注意这个细节: 要基于.net跨环境的基类去写,才能跨平台. Unix系统里,每行结尾只有"<换行>",即" ...
- oracle 11g rac修改监听端口(远程监听和本地监听)
转至:https://www.cnblogs.com/yj411511/p/12459533.html 目录 1.修改远程监听端口 1.1 查看远程监听状态 1.2 修改SCAN listener端口 ...