自动分片的PostgreSQL?

20
我有一个问题,需要非常快速地将大量数据(超过50亿行)加载到数据库中(最好少于30分钟,但速度越快越好),我最近被建议尝试使用PostgreSQL(我之前使用MySQL未成功,曾考虑HBase /Cassandra)。我的设想是在群集中的每台机器上本地运行数据库,使其在本地快速写入数据,然后在最终结束时(或在数据生成过程中)合并数据。数据没有任何顺序,所以我不关心特定服务器在哪里(只要最终到达即可)。
我的问题是,是否有任何好的教程或地方可以学习PostgreSQL自动分片功能(我发现像Sykpe这样的公司正在使用自动分片,但没有教程,我想自己尝试解决这个问题)?我所尝试的是否可行?因为数据没有任何顺序,我打算使用自增ID号码,如果数据被合并,那会不会造成冲突(这已经不是一个大问题了)?
更新:Frank在下面提出的想法消除了我所问的自增冲突问题。问题基本上是,我如何了解自动分片,并且它是否支持将数据分布式上传到多个服务器?

1
我已经在不到5分钟的时间内将约1000万行数据加载到了Postgres数据库中,因此我可以自信地告诉您,当将数据加载到单个分片时,这是一个非常重要的资源:http://www.postgresql.org/docs/8.1/static/populate.html。这也看起来很有前途:http://pgbulkload.projects.postgresql.org/。 - Frank Farmer
9
我打算使用自动递增的ID编号,如果数据合并会不会引起冲突?只需每次递增10,并从不同的偏移开始。服务器1使用IDs 1、11、21、31;服务器2使用IDs 2、12、22、32。 - Frank Farmer
@FrankFarmer 感谢您提供的链接和关于递增的好主意。我认为这可以减少一些复杂性,那么问题只与自动分片和分布式上传有关。 - Lostsoul
2
请注意,使用序列可以轻松地进行增量和偏移量操作:http://www.postgresql.org/docs/current/static/sql-createsequence.html - Craig Ringer
5个回答

14
首先:您真的需要将集群生成的数据直接插入关系型数据库吗?反正最终都要合并,为什么不直接写入平面文件中,可能是gzip'd CSV数据。然后使用pg_bulkload这样的工具批量导入和合并数据。
如果确实需要直接插入关系型数据库:这就是PgPool-II和(特别是)PgBouncer所用的地方。配置PgBouncer以在不同节点之间进行负载均衡,您应该基本上解决了问题。
请注意,PostgreSQL是一种具有强数据耐久性保证的事务性数据库。这也意味着,如果您以简单的方式使用它,进行大量小写操作可能会很慢。您必须考虑在数据耐久性、速度和硬件成本之间做出何种权衡。
在极端情况下,每个INSERT可以成为自己的事务,在返回成功之前同步提交到磁盘。这将限制每秒事务数为磁盘子系统可以执行的fsync()数,通常只有每秒几十个或几百个(没有电池备份RAID控制器)。如果您不采取任何特殊措施并且不将INSERT包装在BEGINCOMMIT中,则默认情况下会使用此选项。
另一方面,您可以说“我真的不在乎失去所有这些数据”,并对您的插入使用未记录表。这基本上允许数据库在无法保证其安全性后丢弃您的数据-例如在操作系统崩溃、数据库崩溃、断电等情况下。
中间地带可能是你想要的地方。这涉及到异步提交组提交commit_delaycommit_siblings),将插入分批包装在明确的BEGINEND组中等的组合。除了INSERT批处理之外,您还可以每次加载几千条记录进行COPY批量加载。所有这些都会以数据耐久性为代价来换取速度。
对于快速批量插入,您还应考虑将数据插入到没有任何索引(仅有主键)的表中。也许甚至不需要主键。完成批量插入后再创建索引,这样会快得多。

哇..感谢您的好答案。 您是对的,我根本不需要数据库,但我正在尝试使用它来与其他工作节点共享最终数据。 因此,我的第一个进程生成了大量数据,但第二个进程使用集群针对先前数据集(以相同方式生成,只是在不同的日期)进行数据分析。 我不确定我需要中间地带还是更极端的非记录表,因为如果我只在数据库死亡时使用数据,那么当它死亡并且我可以重新启动处理时,我会知道,但如果它不死亡并且变慢,那么我将错过我的截止日期。 - Lostsoul
你认为在我的情况下将数据保存为文件然后简单地上传更有意义吗?我想,既然最终要在数据库中分析它,我可能会在程序中创建线程来发送它,而我正在处理它,但如果本地写入然后批量上传更快,我可能会这样做。此外,我没有在表上建立任何索引(我的列是一个字符串/整数字典,我将其作为字符串加载,另一个是ID列,我认为将是Long int..)。所有其他决策考虑都只是为了速度。 - Lostsoul
将数据插入分片数据库的好处在于,只有在其分片形式下才能查询到它。虽然有相应的工具(例如PL/Proxy),但它们比单个DB实例更复杂和难以使用。另一方面,它们可以更快速。如果您不打算查询分片,而是想在分析之前合并数据,则可以将其编写为平面文件,然后将其插入最终的DB中。 - Craig Ringer

2
以下是可能有所帮助的几点:
  • 每个服务器上的数据库应该有一个小的元数据表,记录该服务器的唯一特征,例如服务器编号等。除了该表的内容外,尽可能使每个服务器上的模式保持相似可能是明智的选择。

  • 对于数十亿行数据,您需要使用bigint ids(或UUID或类似的东西)。使用bigints,您可以为每个服务器分配一个宽裕的范围,并设置其序列以使用它。例如,服务器1获得1..1000000000000000,服务器2获得1000000000000001至2000000000000000等。

  • 如果数据是简单的数据点(例如每秒钟从10个仪器中读取的温度),则将其存储在具有列(时间戳,值double precision[])而不是更正确的(时间戳,仪器ID int,值double precision)的表中,可能会提高效率。这是一种显式的去规范化以提高效率。(我在博客中分享了自己使用此方案的经验。)


2

1

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

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

正如已经注意到的,键可能会是一个问题。使用不重叠的序列或uuids或带有字符串前缀的序列号,应该不难解决。

你应该从其中一台服务器开始进行COPY测试,看看你能否接近30分钟的目标。如果你的数据不重要,并且你有最新的Postgresql版本,你可以尝试使用未记录表,这应该会更快(但不是崩溃安全的)。听起来像是一个有趣的项目,祝你好运。


谢谢,我会看一下plProxy..听起来非常有趣。我会尝试它和未登录的表格。 - Lostsoul

-1
您可以使用支持跨集群自动分片的MySQL数据库。

2
我相信你在想MySQL Cluster,它是一个独立于MySQL本身的付费产品。 - Peeja

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接