在 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 流量的云服务提供商.每次您的一个客户端收 ...
随机推荐
- 今天你花里胡哨了吗 --- 定制属于自己的linux ssh迎宾信息
请开始你的表演 linux-oz6w:~ # cat << 'eof' > /etc/profile.d/ssh-login-info.sh #!/bin/sh # 输出一个图像 e ...
- JUC并发工具类之 CountDownLatch等待多线程完成
上篇JUC同步工具之Semaphore - 池塘里洗澡的鸭子 - 博客园 (cnblogs.com)示例中,资源释放一个线程就可以退出然后另一个线程可以使用了,那如果需要所有规定数量的资源同时释放了才 ...
- jenkins持续集成go应用
上文讲到使用supervisor管理我们的终端应用,这次讲一下使用jenkins持续集成 下面分别讲一下pipeline里每一个段落的含义 agent any 使用任意节点构建 parameters ...
- Windows禁用445端口
今天来公司有好多电脑感染了0day病毒, 写个脚本,一键执行禁用445,135-139端口.Windows7测试没有问题. reg add "HKEY_LOCAL_MACHINE\SYSTE ...
- (tamcat控制台乱码)在idea中运行toncat后控制台出现乱码的情况解决办法(教程附图)。
详细教程: (tamcat控制台乱码)在idea中运行toncat后控制台出现乱码的情况解决办法(教程附图)._IT打工酱的博客-CSDN博客
- 巧用阿里云同步k8s.gcr镜像
问题 谷歌云镜像仓库:k8s.gcr.io 镜像拉取不下来 阿里云操作配置 注册阿里云账号:点击注册 右上角点击"控制台" 点击左上角 选择"容器镜像服务" 第 ...
- 力扣第二题 大数相加 ,链表在python到底该怎么写?
但问题在于链表的表示 如何创建一个L3呢 如何用next将他们连接起来呢? 原来是采用 制作链表的形式 l3_pointer.next = ListNode(l1_pointer.val + l2_ ...
- Oracle RAC架构图和常用命令
转至:https://www.cnblogs.com/yaoyangding/p/15596308.html Oracle RAC(实时应用集群)是Oracle数据库完全高可用体系解决方案中的一个关键 ...
- linux中rlwrap安装
转至:https://www.cnblogs.com/hw-1015/p/6601294.html 在linux上使用sqlplus命令的时候,上下键.空格键.删除键都不能使用,非常麻烦.安装了rlw ...
- Python:Scrapy(四) 命令行相关
学习自Scrapy 2.4.1 documentation 这一部分是对官方文档的学习,主要是理解翻译,来对之前的应用部分进行详细的理论补充. 1.保存爬取到的要素的方式: ①运行scrapy指令时, ...