准备工作

这里假设,你已经在 k8s 上部署好了基于 Citus 扩展的分布式 PostgreSQL 集群。

查看 Citus 集群(kubectl get po -n citus),1Coordinator(协调器) 节点 + 3Worker(工作器) 节点。

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存储过程分布式事务

创建引用表

当您需要不包含分布列的快速 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) 的对比。压缩了几十倍,效果非常的惊人,大大节省了存储空间。

您可以单独使用列存储,也可以在分布式表中使用,以结合压缩和分布式查询引擎的优势。

使用列式存储时,您应该只使用 COPYINSERT..SELECT 批量加载数据以实现良好的压缩。柱状表目前不支持更新、删除和外键。 但是,您可以使用分区表,其中较新的分区使用基于行的存储,而较旧的分区使用列存储进行压缩。

更多

在 Kubernetes 上快速测试 Citus 分布式 PostgreSQL 集群(分布式表,共置,引用表,列存储)的更多相关文章

  1. Citus 分布式 PostgreSQL 集群 - SQL Reference(创建和修改分布式表 DDL)

    创建和分布表 要创建分布式表,您需要首先定义表 schema. 为此,您可以使用 CREATE TABLE 语句定义一个表,就像使用常规 PostgreSQL 表一样. CREATE TABLE ht ...

  2. 分布式 PostgreSQL 集群(Citus),官方快速入门教程

    多租户应用程序 在本教程中,我们将使用示例广告分析数据集来演示如何使用 Citus 来支持您的多租户应用程序. 注意 本教程假设您已经安装并运行了 Citus. 如果您没有运行 Citus,则可以使用 ...

  3. 分布式 PostgreSQL 集群(Citus)官方教程 - 迁移现有应用程序

    将现有应用程序迁移到 Citus 有时需要调整 schema 和查询以获得最佳性能. Citus 扩展了 PostgreSQL 的分布式功能,但它不是扩展所有工作负载的直接替代品.高性能 Citus ...

  4. 分布式 PostgreSQL 集群(Citus)官方示例 - 时间序列数据

    在时间序列工作负载中,应用程序(例如一些实时应用程序查询最近的信息,同时归档旧信息. https://docs.citusdata.com/en/v10.2/sharding/data_modelin ...

  5. 分布式 PostgreSQL 集群(Citus)官方安装指南

    单节点 Citus Docker (Mac 与 Linux) Docker 镜像仅用于开发/测试目的, 并且尚未准备好用于生产用途. 您可以使用一个命令在 Docker 中启动 Citus: # st ...

  6. 分布式 PostgreSQL 集群(Citus),分布式表中的分布列选择最佳实践

    确定应用程序类型 在 Citus 集群上运行高效查询要求数据在机器之间正确分布.这因应用程序类型及其查询模式而异. 大致上有两种应用程序在 Citus 上运行良好.数据建模的第一步是确定哪些应用程序类 ...

  7. Citus 分布式 PostgreSQL 集群 - SQL Reference(摄取、修改数据 DML)

    插入数据 要将数据插入分布式表,您可以使用标准 PostgreSQL INSERT 命令.例如,我们从 Github 存档数据集中随机选择两行. INSERT http://www.postgresq ...

  8. Citus 分布式 PostgreSQL 集群 - SQL Reference(查询分布式表 SQL)

    如前几节所述,Citus 是一个扩展,它扩展了最新的 PostgreSQL 以进行分布式执行.这意味着您可以在 Citus 协调器上使用标准 PostgreSQL SELECT 查询进行查询. Cit ...

  9. 分布式 PostgreSQL 集群(Citus)官方示例 - 实时仪表盘

    Citus 提供对大型数据集的实时查询.我们在 Citus 常见的一项工作负载涉及为事件数据的实时仪表板提供支持. 例如,您可以是帮助其他企业监控其 HTTP 流量的云服务提供商.每次您的一个客户端收 ...

随机推荐

  1. python小白记录一 ——python脚本生成windows可执行exe

    1.需要安装pywin32 先查看自己有没有安装:使用如下命令查看 pip show pywin32 如果没有则用下面方式进行安装: pip install pywin32 然后等待安装完成: 2.再 ...

  2. Solution Set -「LOCAL」冲刺省选 Round XXIII

    \(\mathscr{Summary}\)   有一说一,虽然我炸了,但这场锻炼心态的效果真的好.部分分聊胜于无,区分度一题制胜,可谓针对性强的好题.   A 题,相对性签到题.这个建图确实巧妙,多见 ...

  3. 三、Mybatis多表关联查询应用

    一对一查询 实现语句:select * from neworder o, user u where o.uid = u.id 实体Order: 接口: 配置: 测试: 一对多查询 实现语句:selec ...

  4. blender导入灰度图生成地形模型

    安装软件 在此处下载blender并安装. 添加平面 1.打开blender,右键删除初始的立方体. 2.shift+a选择平面添加进场景: 3.按下s键鼠标拖动调节平面大小确定后按下鼠标左键: 4. ...

  5. Selenium自动化测试面试题合集

    1.什么是自动化测试.自动化测试的优势是什么? 通过工具或脚本代替手工测试执行过程的测试都叫自动化测试. 自动化测试的优势: 1.减少回归测试成本 2.减少兼容性测试成本 3.提高测试反馈速度 4.提 ...

  6. NSSCTF-easyupload1.0

    2.0和3.0已经说过,这个1.0上传也可以使用那两个题目的做法,就是使用htaccess的方式进行定义上传文件的类型来进行连接shell,1.0肯定是没有2.0和3.0难的,所以说,也不要将这个题目 ...

  7. 做PPT必备的大数据分析网站,好看又免费的报表工具

    小明以前是学技术,跳槽来到一家大公司,在这个公司里会经常开会,比如有月度报告.季度报告以及年度报告,在开会前小明了解到同事们都会制作精美的PPT来汇报工作计划和目标,看到同事们精美的PPT里各种好看的 ...

  8. WPF使用MVVM(三)-事件转命令

    WPF使用MVVM(三)-事件转命令 上一节介绍了WPF中的命令,可是仅仅介绍的是WPF框架给我们提供的点击命令,也就是用Command属性来绑定一个命令,用来响应按钮的点击行为!显然这是不够的,界面 ...

  9. Delegate 委托细说

    目录 委托的申明 委托的赋值 委托实例方法的使用C#Invoke\BeginInvoke\Endinoke  系统自带的委托Action.Action<T>.Func<T>.P ...

  10. ubuntu系统黑屏,只有一个光标

    使用easyBCD删除原ubuntu引导,重建 添加新条目 引导选择900M左右那个选项