【问题标题】:Transferring data between two PostgreSQL servers在两个 PostgreSQL 服务器之间传输数据
【发布时间】:2018-02-11 21:11:12
【问题描述】:

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

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

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

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

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


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

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

  • 转账验证有哪些方法?

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

在 debian 上使用 postgresql 9.4.9。


一个想法的大致轮廓:

  1. 该表有一个 serial 列,用于跟踪记录 ID。

  2. pg_dump 将数据写入文件。文件名中使用了上述序列号,基本上是“这包含从XY的所有记录”

  3. dumpfile 通过 rsync 等方式复制到集中式服务器。

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

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

有什么想法吗?

【问题讨论】:

    标签: postgresql networking data-replicator


    【解决方案1】:

    您提出的方法是一个合理的起点,但在第一点存在缺陷。您隐含地假设 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

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

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

    从一个不同的(新开始的)xact,然后你pg_export_snapshot

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

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

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


    看起来很复杂?

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

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

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

    【讨论】:

    • 我突然意识到我有一个时间戳列,它表示添加行的时间。应该可以使用它来提取和删除两个特定时间戳之间的部分。
    • 同样的问题也适用。较晚的时间戳可能比较早的时间戳更早提交,因为时间戳是在创建行时设置的,而不是在事务提交时设置的。 PostgreSQL 具有提交时间戳,可用于获得可靠的提交顺序,但它们不能解决可见性问题。
    猜你喜欢
    • 2022-01-13
    • 1970-01-01
    • 1970-01-01
    • 2012-08-06
    • 2014-04-12
    • 2022-01-05
    • 2013-10-13
    • 2014-03-18
    • 1970-01-01
    相关资源
    最近更新 更多