自动分片postgresql?

Posted

技术标签:

【中文标题】自动分片postgresql?【英文标题】:Auto sharding postgresql? 【发布时间】:2012-05-06 14:09:36 【问题描述】:

我有一个问题,我需要非常快速地将大量数据(5+ 十亿行)加载到数据库中(理想情况下少于 30 分钟,但越快越好),最近有人建议我研究 postgresql(我mysql 失败,正在查看 hbase/cassandra)。我的设置是我有一个生成大量数据的集群(目前有 8 个服务器),我正在考虑在集群中的每台机器上本地运行数据库,它在本地快速写入,然后在最后(或在整个数据生成过程中)数据是合并在一起。数据没有任何顺序,所以我不在乎它在哪个特定的服务器上(只要它最终在那里)。

我的问题是,有没有什么好的教程或地方可以学习 PostgreSQL 自动分片(我找到了像 sykpe 这样的公司做自动分片但没有教程的结果,我想自己玩这个)?我正在尝试做的事情可能吗?因为数据没有任何顺序我打算使用自增ID号,如果合并数据会导致冲突(这不再是一个大问题了)?

更新:下面 Frank 的想法消除了我所询问的自动递增冲突问题。现在的问题基本上是,我如何了解自动分片,它是否支持将数据分布式上传到多个服务器?

【问题讨论】:

我已经在 postgresql.org/docs/8.1/static/populate.html 这看起来也很有希望:pgbulkload.projects.postgresql.org I was going to use auto-incrementing ID number, will that cause a conflict if data is merged? 只需增加 10,并从不同的偏移量开始。服务器 1 使用 ids 1,11,21,31;服务器 2 使用 ids 2,12,22,32 @FrankFarmer 感谢您的链接和重新:增量的好主意。我认为这消除了一些复杂性,然后我猜这个问题只与自动分片和分布式上传有关。 请注意,增量和偏移量可以通过序列轻松完成:postgresql.org/docs/current/static/sql-createsequence.html 【参考方案1】:

以下几点可能会有所帮助:

每台服务器上的数据库都应该有一个具有该服务器独特特征的小型元数据表。比如是哪个服务器;服务器可以按顺序编号。除了该表的内容之外,尝试保持每台服务器上的架构尽可能相似可能是明智之举。

拥有数十亿行,您需要 bigint id(或 UUID 等)。使用 bigints,您可以为每个服务器分配一个大范围,并设置其顺序以使用它。例如。服务器 1 得到 1..1000000000000000,服务器 2 得到 1000000000000001 到 2000000000000000 等等。

1234563这是为了提高效率而进行的显式非规范化。 (我blogged 讲述了我自己对这个方案的体验。)

【讨论】:

【参考方案2】:

抱歉,我手头没有教程,但这里有一个可能的解决方案的概要:

将八分之一的数据加载到每台服务器上的 PG 实例中 为了获得最佳加载速度,不要使用插入,而是使用 COPY 方法 加载数据时,不要将八个数据库合二为一。相反,请使用 plProxy 启动单个语句来一次查询所有数据库(或满足您查询的正确语句)

如前所述,密钥可能是个问题。使用不重叠的序列或 uuid 或带有字符串前缀的序列号,应该不难解决。

您应该先在其中一台服务器上进行 COPY 测试,然后看看您离 30 分钟的目标有多近。如果您的数据不重要并且您有最新的 Postgresql 版本,您可以尝试使用unlogged tables,它应该会快很多(但不是崩溃安全的)。听起来是个有趣的项目,祝你好运。

【讨论】:

谢谢,我会看看 plProxy.. 看起来真的很有趣。我会尝试一下并取消记录表..【参考方案3】:

首先:您真的需要将集群中生成的数据直接插入到关系数据库中吗?无论如何,您不介意最后合并它,那么为什么还要麻烦插入数据库呢?在你的位置,我会让你的集群节点编写平面文件,可能是 gzip 的 CSV 数据。然后我会使用pg_bulkload 之类的工具批量导入和合并这些数据。

如果您确实需要直接插入关系数据库:这就是PgPool-II 和(特别是)PgBouncer 的(部分)用途。将 PgBouncer 配置为在不同节点之间进行负载平衡,您应该会得到很好的排序。

请注意,PostgreSQL 是一个事务性数据库,具有强大的数据持久性保证。这也意味着,如果您以简单的方式使用它,执行大量小型写入可能会很慢。您必须考虑您愿意在数据持久性、速度和硬件成本之间做出哪些权衡。

在一个极端情况下,每个INSERT 都可以是自己的事务,在返回成功之前同步提交到磁盘。这将每秒事务的数量限制为磁盘子系统可以执行的 fsync() 数量,这通常只有每秒几十或几百次(没有电池备份 RAID 控制器)。如果你没有做任何特别的事情并且你没有将你的 INSERTs 包装在 BEGINCOMMIT 中,这是默认设置。

在另一个极端,您说“我真的不在乎我是否会丢失所有这些数据”并使用unlogged tables 进行插入。这基本上授予数据库在无法保证数据正常时丢弃您的数据的权限 - 例如,在操作系统崩溃、数据库崩溃、断电等之后。

中间地带是您可能想成为的地方。这涉及到asynchronous commit、group commits(commit_delay 和 commit_siblings)的某种组合,将插入批量插入以显式 BEGINEND 包装的组中,等等。代替 INSERT 批量,您可以执行 COPY 加载一次有几千条记录。所有这些都以数据持久性与速度为代价。

对于快速批量插入,您还应该考虑插入到除了主键之外没有任何索引的表中。也许甚至不是。完成批量插入后创建索引。这会快很多。

【讨论】:

哇..感谢您的出色回答。你的权利我根本不需要数据库,但我正在尝试使用它与其他工作节点共享最终数据。因此,我的第一个过程生成了大量数据,但第二个过程使用集群来针对先前的数据集分析数据(仅在不同的日子以相同的方式生成)。我不确定我是否需要中间立场或更极端的未记录表,因为如果我只在数据库死亡时使用数据,那么我会知道它何时死亡并且可以再次重新开始我的处理,但如果它没有死亡并且进展缓慢,我会错过最后期限。 您认为在我的情况下将数据保存为文件然后简单地上传是否更有意义?我想既然我要把它放在数据库中进行分析,我不妨在我的程序中创建线程,在我处理时发送它,但如果它更快地只是在本地写入然后批量上传,我可能只是这样做..另外,我的表上没有任何索引(我的列是我作为字符串加载的字符串/整数字典,另一个是我认为将是 Long int 的 ID 列。 )。所有其他决策考虑都只是为了速度。 将数据插入分片数据库的关键在于,它只有在您可以以分片形式查询时才有用。有一些工具(例如,请参阅 PL/Proxy),但它们比单个数据库实例更复杂且难以使用。 OTOH,它们可以快得多。如果您不打算查询分片,而是想在分析数据之前合并数据,您不妨将其编写为平面文件,然后将其插入到最终数据库中。【参考方案4】:

您可以使用 mySQL - 它支持跨集群的自动分片。

【讨论】:

相信你会想到 MySQL Cluster,它是独立于 MySQL 本身的付费产品。【参考方案5】:

使用 citus 进行 PostgreSQL 自动分片。 this link 也很有帮助。

【讨论】:

以上是关于自动分片postgresql?的主要内容,如果未能解决你的问题,请参考以下文章

PgSQL主要贡献者对PostgreSQL内置分片功能的看法

Postgres-XL 向后兼容 PostgreSQL?

CitusDB —— 基于最新 PostgreSQL 构建的分布式数据库

连接多台服务器 PostgreSQL R

PostgreSQL版本快速升级

PostgreSQL:自动删除旧分区