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

2023-10-11 10:10

本文主要是介绍分布式 PostgreSQL 集群(Citus)官方示例 - 时间序列数据,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在时间序列工作负载中,应用程序(例如一些实时应用程序查询最近的信息,同时归档旧信息。

  • https://docs.citusdata.com/en/v10.2/sharding/data_modeling.html#distributing-by-entity-id

为了处理这种工作负载,单节点 PostgreSQL 数据库通常会使用表分区将一个按时间排序的大数据表分解为多个继承表,每个表包含不同的时间范围。

  • https://www.postgresql.org/docs/current/static/ddl-partitioning.html

将数据存储在多个物理表中会加速数据过期。 在单个大表中,删除行会产生扫描以查找要删除的行,然后清理清空空间的成本。 另一方面,删除分区是一种与数据大小无关的快速操作。 这相当于简单地删除磁盘上包含数据的文件。

将数据存储在多个物理表中会加快数据过期的速度。在一个大表中,删除行需要扫描以找到要删除的行,然后清空空的空间。另一方面,删除分区是一种与数据大小无关的快速操作。这相当于简单地删除磁盘上包含数据的文件。

  • https://www.postgresql.org/docs/current/static/routine-vacuuming.html

对表进行分区还可以使每个日期范围内的索引更小更快。 对最近数据进行的查询很可能对适合内存的 hot 索引进行操作。这加快了读取速度。

插入也有更小的索引要更新,所以它们也更快。

在以下情况下,基于时间的分区最有意义:

  1. 大多数查询只访问最近数据的一个非常小的子集
  2. 旧数据定期过期(删除/丢弃)

请记住,在错误的情况下,读取所有这些分区对开销的伤害大于帮助。 但是,在正确的情况下,它非常有帮助。 例如,保留一年的时间序列数据并定期仅查询最近一周。

扩展 Citus 上的时间序列数据

我们可以将单节点表分区技术与 Citus 的分布式分片相结合,形成一个可扩展的时间序列数据库。这是两全其美的。它在 Postgres 的声明性表分区之上特别优雅。

例如,让我们 distributepartition 一个包含历史 GitHub 事件数据的表。

  • GitHub 事件数据
    • https://examples.citusdata.com/events.csv

GitHub 数据集中的每条记录代表在 GitHub 中创建的事件,以及有关事件的关键信息,例如事件类型、创建日期和创建事件的用户。

第一步是按时间创建和分区(partition)表,就像我们在单节点 PostgreSQL 数据库中一样:

-- declaratively partitioned table
CREATE TABLE github_events (event_id bigint,event_type text,event_public boolean,repo_id bigint,payload jsonb,repo jsonb,actor jsonb,org jsonb,created_at timestamp
) PARTITION BY RANGE (created_at);

注意 PARTITION BY RANGE (created_at)。这告诉 Postgres 该表将由 created_at 列在有序范围内进行分区。不过,我们还没有为特定范围创建任何分区。

在创建特定分区之前,让我们在 Citus 中分布表。我们将按 repo_id 进行分片,这意味着事件将被聚集到每个存储库的分片中。

SELECT create_distributed_table('github_events', 'repo_id');

此时 Citus 已跨工作节点为该表创建分片。在内部,每个分片是一个表,每个分片标识符 N 的名称为 github_events_N。此外,Citus 传播了分区信息,每个分片都声明了 Partition key: RANGE (created_at)

分区表不能直接包含数据,它更像是跨分区的视图。因此,分片还没有准备好保存数据。 我们需要创建分区并指定它们的时间范围,之后我们可以插入与范围匹配的数据。

自动创建分区

Citus 为分区管理提供了辅助函数。我们可以使用 create_time_partitions() 创建一批每月分区:

SELECT create_time_partitions(table_name         := 'github_events',partition_interval := '1 month',end_at             := now() + '12 months'
);

Citus 还包括一个视图 time_partitions,以方便地调查它创建的分区。

随着时间的推移,您将需要进行一些维护以创建新分区并删除旧分区。最好设置一个定期 job 来运行带有 pg_cron 之类的扩展的维护功能:

  • pg_cron
    • https://github.com/citusdata/pg_cron
-- set two monthly cron jobs:-- 1. ensure we have partitions for the next 12 monthsSELECT cron.schedule('create-partitions', '0 0 1 * *', $$SELECT create_time_partitions(table_name         := 'github_events',partition_interval := '1 month',end_at             := now() + '12 months')
$$);-- 2. (optional) ensure we never have more than one year of dataSELECT cron.schedule('drop-partitions', '0 0 1 * *', $$CALL drop_old_time_partitions('github_events',now() - interval '12 months' /* older_than */);
$$);

一旦设置了定期维护,您就不必再考虑分区了,它们可以正常工作。

请注意,Postgres 中的原生分区仍然很新,并且有一些怪癖。 对分区表的维护操作将获取可能会短暂停止查询的激进锁。目前在 postgres 社区中正在进行大量工作来解决这些问题,因此预计 Postgres 中的 time 分区只会变得更好。

使用列式存储归档

一些应用程序的数据在逻辑上分为可更新的小部分和“冻结(frozen)”的较大部分。 示例包括日志、点击流或销售记录。 在这种情况下,我们可以将分区与列式表存储(在 Citus 10 中引入)结合起来压缩磁盘上的历史分区。Citus 柱状表目前是仅追加的,这意味着它们不支持更新或删除,但我们可以将它们用于不可变的历史分区。

  • 列式表存储
    • https://docs.citusdata.com/en/v10.2/admin_guide/table_management.html#columnar

分区表可以由行分区列分区的任意组合组成。在 timestamp key 上使用范围分区时,我们可以将最新的分区制作成行表,并定期将最新的分区滚动到另一个历史列式分区中。

让我们看一个例子,再次使用 GitHub 事件。我们将创建一个名为 github_columnar_events 的新表,以消除前面示例中的歧义。 为了完全专注于列式存储方面,我们不会分布此表。

接下来,下载示例数据:

wget http://examples.citusdata.com/github_archive/github_events-2015-01-01-{0..5}.csv.gz
gzip -c -d github_events-2015-01-01-*.gz >> github_events.csv
-- our new table, same structure as the example in
-- the previous sectionCREATE TABLE github_columnar_events ( LIKE github_events )
PARTITION BY RANGE (created_at);-- create partitions to hold two hours of data eachSELECT create_time_partitions(table_name         := 'github_columnar_events',partition_interval := '2 hours',start_from         := '2015-01-01 00:00:00',end_at             := '2015-01-01 08:00:00'
);-- fill with sample data
-- (note that this data requires the database to have UTF8 encoding)\COPY github_columnar_events FROM 'github_events.csv' WITH (format CSV)-- list the partitions, and confirm they're
-- using row-based storage (heap access method)SELECT partition, access_methodFROM time_partitionsWHERE parent_table = 'github_columnar_events'::regclass;

-- convert older partitions to use columnar storageCALL alter_old_partitions_set_access_method('github_columnar_events','2015-01-01 06:00:00' /* older_than */,'columnar'
);-- the old partitions are now columnar, while the
-- latest uses row storage and can be updatedSELECT partition, access_methodFROM time_partitionsWHERE parent_table = 'github_columnar_events'::regclass;

要查看柱状表的压缩率,请使用 VACUUM VERBOSE。我们三个柱状分区的压缩比相当不错:

VACUUM VERBOSE github_columnar_events;
INFO:  statistics for "github_columnar_events_p2015_01_01_0000":
storage id: 10000000003
total file size: 4481024, total data size: 4444425
compression rate: 8.31x
total row count: 15129, stripe count: 1, average rows per stripe: 15129
chunk count: 18, containing data for dropped columns: 0, zstd compressed: 18INFO:  statistics for "github_columnar_events_p2015_01_01_0200":
storage id: 10000000004
total file size: 3579904, total data size: 3548221
compression rate: 8.26x
total row count: 12714, stripe count: 1, average rows per stripe: 12714
chunk count: 18, containing data for dropped columns: 0, zstd compressed: 18INFO:  statistics for "github_columnar_events_p2015_01_01_0400":
storage id: 10000000005
total file size: 2949120, total data size: 2917407
compression rate: 8.51x
total row count: 11756, stripe count: 1, average rows per stripe: 11756
chunk count: 18, containing data for dropped columns: 0, zstd compressed: 18

分区表 github_columnar_events 的一个强大之处在于它可以像普通表一样被完整地查询。

SELECT COUNT(DISTINCT repo_id)FROM github_columnar_events;

只要分区键上有一个 WHERE 子句,它可以完全过滤到行表分区中,条目就可以被更新或删除。

将行分区归档到列式存储

当行分区已填满其范围时,您可以将其归档到压缩的列式存储中。我们可以使用 pg_cron 自动执行此操作,如下所示:

-- a monthly cron jobSELECT cron.schedule('compress-partitions', '0 0 1 * *', $$CALL alter_old_partitions_set_access_method('github_columnar_events',now() - interval '6 months' /* older_than */,'columnar');
$$);

有关详细信息,请参阅列式存储。

  • 列式存储
    • https://docs.citusdata.com/en/v10.2/admin_guide/table_management.html#columnar

更多

  • 分布式 PostgreSQL 集群(Citus)官方示例 - 多租户应用程序实战
  • 分布式 PostgreSQL 集群(Citus)官方示例 - 实时仪表盘

这篇关于分布式 PostgreSQL 集群(Citus)官方示例 - 时间序列数据的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/187309

相关文章

Java中注解与元数据示例详解

《Java中注解与元数据示例详解》Java注解和元数据是编程中重要的概念,用于描述程序元素的属性和用途,:本文主要介绍Java中注解与元数据的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参... 目录一、引言二、元数据的概念2.1 定义2.2 作用三、Java 注解的基础3.1 注解的定义3.2 内

将sqlserver数据迁移到mysql的详细步骤记录

《将sqlserver数据迁移到mysql的详细步骤记录》:本文主要介绍将SQLServer数据迁移到MySQL的步骤,包括导出数据、转换数据格式和导入数据,通过示例和工具说明,帮助大家顺利完成... 目录前言一、导出SQL Server 数据二、转换数据格式为mysql兼容格式三、导入数据到MySQL数据

Java中使用Java Mail实现邮件服务功能示例

《Java中使用JavaMail实现邮件服务功能示例》:本文主要介绍Java中使用JavaMail实现邮件服务功能的相关资料,文章还提供了一个发送邮件的示例代码,包括创建参数类、邮件类和执行结... 目录前言一、历史背景二编程、pom依赖三、API说明(一)Session (会话)(二)Message编程客

C++中使用vector存储并遍历数据的基本步骤

《C++中使用vector存储并遍历数据的基本步骤》C++标准模板库(STL)提供了多种容器类型,包括顺序容器、关联容器、无序关联容器和容器适配器,每种容器都有其特定的用途和特性,:本文主要介绍C... 目录(1)容器及简要描述‌php顺序容器‌‌关联容器‌‌无序关联容器‌(基于哈希表):‌容器适配器‌:(

C#提取PDF表单数据的实现流程

《C#提取PDF表单数据的实现流程》PDF表单是一种常见的数据收集工具,广泛应用于调查问卷、业务合同等场景,凭借出色的跨平台兼容性和标准化特点,PDF表单在各行各业中得到了广泛应用,本文将探讨如何使用... 目录引言使用工具C# 提取多个PDF表单域的数据C# 提取特定PDF表单域的数据引言PDF表单是一

SQL Server使用SELECT INTO实现表备份的代码示例

《SQLServer使用SELECTINTO实现表备份的代码示例》在数据库管理过程中,有时我们需要对表进行备份,以防数据丢失或修改错误,在SQLServer中,可以使用SELECTINT... 在数据库管理过程中,有时我们需要对表进行备份,以防数据丢失或修改错误。在 SQL Server 中,可以使用 SE

一文详解Python中数据清洗与处理的常用方法

《一文详解Python中数据清洗与处理的常用方法》在数据处理与分析过程中,缺失值、重复值、异常值等问题是常见的挑战,本文总结了多种数据清洗与处理方法,文中的示例代码简洁易懂,有需要的小伙伴可以参考下... 目录缺失值处理重复值处理异常值处理数据类型转换文本清洗数据分组统计数据分箱数据标准化在数据处理与分析过

大数据小内存排序问题如何巧妙解决

《大数据小内存排序问题如何巧妙解决》文章介绍了大数据小内存排序的三种方法:数据库排序、分治法和位图法,数据库排序简单但速度慢,对设备要求高;分治法高效但实现复杂;位图法可读性差,但存储空间受限... 目录三种方法:方法概要数据库排序(http://www.chinasem.cn对数据库设备要求较高)分治法(常

Python将大量遥感数据的值缩放指定倍数的方法(推荐)

《Python将大量遥感数据的值缩放指定倍数的方法(推荐)》本文介绍基于Python中的gdal模块,批量读取大量多波段遥感影像文件,分别对各波段数据加以数值处理,并将所得处理后数据保存为新的遥感影像... 本文介绍基于python中的gdal模块,批量读取大量多波段遥感影像文件,分别对各波段数据加以数值处

使用MongoDB进行数据存储的操作流程

《使用MongoDB进行数据存储的操作流程》在现代应用开发中,数据存储是一个至关重要的部分,随着数据量的增大和复杂性的增加,传统的关系型数据库有时难以应对高并发和大数据量的处理需求,MongoDB作为... 目录什么是MongoDB?MongoDB的优势使用MongoDB进行数据存储1. 安装MongoDB