1

我有两台 PostgreSQL 服务器,一台集中式,一台外围。这个想法是让外围服务器从运行在同一台机器上的各种进程中积累数据。定期(可能每小时或大约每小时),数据从外围服务器传送到中央服务器。在确认服务器成功后,外围服务器将擦除其内容以使其实现尽可能轻量级。

虽然最初这是一个相当直接的场景,其中有许多现有的解决方案,但我敢肯定,有几个因素限制了我的选择:

  • 外围服务器和集中式服务器之间的链接可能会一次关闭数天,在这种情况下,它只会保留所有数据,然后重试下一次预定的传输,数据量是原来的两倍。

  • 没有记录被重复是至关重要的,因此被擦除的记录与传输的记录完全匹配很重要。

  • 外围服务器很可能在传输过程中积累了额外的数据,因此删除并重新创建表是不可行的,因为这会清除一些尚未传输的记录。


我从几个角度审视了这一点,我得出的结论是,我最有可能在这里重新发明轮子,因为有各种方法几乎可以满足我的需求。因此,我决定后退几步,看看会出现哪些针对这种情况的建议。那么我的问题是:

  • 当链路不可靠时,推荐的传输方法是什么?

  • 有哪些转账验证方法?

  • 当外围数据库在传输过程中仍在累积数据时,如何确保擦除日期与传输的数据完全匹配?

在 debian 上使用 postgresql 9.4.9。


一个想法的大致轮廓:

  1. 该表有一serial列跟踪记录 ID。

  2. pg_dump数据到一个文件。文件名中使用了上述序列号,基本上是“这包含所有来自X和到的记录Y

  3. 转储文件通过 rsync 等复制到集中式服务器。

  4. 集中式服务器加载数据,并以某种方式将验证发送回包含串行的外围服务器。考虑重复几次以确保以后不会传输重复项。

  5. 外围服务器核对与已验证序列有关的所有数据。

有什么想法吗?

4

1 回答 1

2

您提出的方法是一个合理的起点,但在第一点存在缺陷。您隐含地假设serial列提供了一些可靠的排序边界。它没有

  1. Txn 1 开始
  2. Txn 2 开始
  3. Txn 1 获取序列值 4
  4. Txn 2 获得序列值 5
  5. Txn 2 次提交
  6. Txn 3 开始
  7. Txn 3 复制出数据
  8. Txn 3 通知最高承诺值为 5
  9. Txn 1 次提交
  10. Txn 3 删除所有 id <= 5 的数据

哎呀。Txn 3 删除了 id=4,但它不会被复制。通过制作 txn3 可以解决这种特殊情况SERIALIZABLE,但是如果改为 Txn3 提交而其他一些 tx txn4 进行删除,问题又回来了。

为了安全起见,您必须在 5 到 7 之间的某个位置添加一个屏障,LOCK TABLE ... IN EXCLUSIVE MODE然后等待获取锁。这确保没有未完成的写入,所有内容都已提交。您现在可以相信以后不会提交低于最高读取值的值。

不同的(新开始的)xact,你然后pg_export_snapshot.

导出快照后,您可以回滚获取锁定的 xact 并让写入继续。

将导出快照的 xact 保持打开状态。将快照 ID 传递给pg_dumpwith --snapshot,因此它会准确地从您知道最高提交 ID 的虚拟时间点开始转储。您必须保持打开快照的 xact 直到转储完成,但同时可以继续写入。

你现在可以安全地DELETE FROM ... WHERE id < xx你所持有的锁查找的值。您知道,由于导出的快照,您没有转储任何具有更高 ID 的内容。而且您知道,由于锁定,您不会错过稍后以较低 ID 提交的任何内容。


看起来很复杂?

相反,我建议使用 PostgreSQL 的逻辑解码特性。使用逻辑解码的工具pglogical具有使您想做的事情相对容易的功能;它摆脱了排序问题并保证行被复制一次。将其设置为复制插入而不是删除很容易,因此您可以不时DELETE FROM mytable进行。

(当然,我是 pglogical 及其相关工具 BDR 的开发团队的一员,所以我有偏见)。

您可能面临的主要问题是您必须保留更多数据,因为您需要保留 WAL,而不仅仅是表格内容。(从技术上讲,您实际上可以DELETE在数据一经INSERT编辑就立即复制它,并且它会很好地复制,但您可能不想这样做)。因此,如果磁盘空间是一个问题,您可能希望使用转储方法。但是 pglogical3 中有一些重大改进将使这个问题消失。

于 2017-09-03T14:52:34.373 回答