如何在 JavaEE 应用程序中为 PostgreSQL 热备设置配置连接故障转移?
Posted
技术标签:
【中文标题】如何在 JavaEE 应用程序中为 PostgreSQL 热备设置配置连接故障转移?【英文标题】:How to configure connection failover for a PostgreSQL Hot Standby setup in a JavaEE application? 【发布时间】:2017-04-15 04:07:04 【问题描述】:我有两台安装了 PostgreSQL 9.5
数据库的 Linux 服务器(A
和 B
)。我按照documentation 中的说明配置了热备用 模式。在此设置中,A
配置为主,B
处于热备模式。这运行良好并且行为符合预期。
现在,我想通过Hibernate
/ JDBC
通过TomEE
数据源将独立的Java EE
应用程序(在另一台机器上运行)连接到此数据库设置。
PostgreSQL driver 文档指出,可以在 jdbc 连接 url 中指定多个主机:
jdbc:postgresql://host1:port1,host2:port2/database
所以我的问题是:
-
如果
A
关闭并且B
手动切换到正常操作模式,我的应用程序是否仍然能够使用上述jdbc 连接url 继续数据库操作?
是否必须配置其他参数/库?
注意:从我了解到的各种来源,PostgreSQL
不支持自动故障转移(除非该过程涉及第三方软件 - 请参阅下面的 cmets)。出于这个原因,故障转移需要手动执行,这对于这个特定的用例来说是可以的。
EDIT-1:
我决定测试pgBouncer
(如 cmets 中的建议)以寻求解决方法。它适用于我的用例。我写了一个看门狗脚本,它可以自动执行手动步骤:
-
不断检查
A
是否仍然存在并侦听传入连接。
如果发生故障转移,将B
切换到正常运行模式,让它成为新的master并重启服务。
将pgBouncer
设置更改为指向B
而不是A
,然后重新启动服务。
但是,如果有人有没有使用第三方软件的经验,我仍然很感兴趣?
【问题讨论】:
最简单的设置是在两台服务器前放置 pgBouncer 或 pgPool 之类的东西,让您的应用程序通过它们连接。 @a_horse_with_no_name 感谢您的提示。您现在有任何有用的设置 pgPool 指南(来自 Ubuntu 存储库),您会推荐吗? 我有一个类似的设置,一个主服务器和一个只读热备用 postgresql 9.6 服务器。有一个 pgbouncer 跑在他们面前。通过更改一行 pgbouncer 配置文件,我可以轻松切换到新的 master。我已经阅读了有关自动故障转移集群(使用 corosync 和起搏器)的论文,但它们对我来说太复杂了。如果您有高级 Linux 系统管理方面的经验,您应该尝试一下。 clusterlabs.org @KenanKocaerkek 感谢您的回答。看来,设置 pgBouncer 非常简单。如果我理解正确,如果发生故障转移,您可以切换服务器配置并重新启动 pgBouncer 服务。听起来很简单 - 我会测试一下! 【参考方案1】:在这种情况下,最好进行测试和测量。
我没有 PostrgeSQL 热备用模式的“实践”经验,但我已经为 Java 应用程序完成了数据库故障转移。
首先,测试PostgreSQL driver 文档页面上的声明
关于?targetServerType=master
参数(在页面底部提到)。
使用通过DriverManager.getConnection
使用PostgreSQL JDBC 驱动程序并运行简单更新查询的主方法编写一个小型Java“PgHsm”类。
它应该使用服务器 A 来进行更新查询。在服务器 A 上停止 PostgreSQL,运行 PgHsm:它应该无法连接,因为服务器 B 不是主服务器。
让服务器 B 成为主服务器,运行 PgHsm:它应该运行正常。
数据源由 TomEE 中的数据库连接池提供支持。 This page 列出了 TomEE 中可用的那些。 但并非所有数据库连接池都是平等的,我现在更喜欢 HikariCP,因为根据我的经验,它可以更可预测地处理“数据库关闭”场景。 另请参阅 HikariCP 的 handling database down 页面上的测试结果。
不幸的是,HikariCP 使用 JDBC 的 get/setNetworkTimeout
来实现可预测的行为
和 PostgreSQL JDBC 驱动程序does not implement this (*)。
因此,为了确保(JavaEE)应用程序线程不会在数据库操作上永远挂起,您需要设置connectTimeout
和socketTimeout
JDBC 驱动程序选项。设置socketTimeout
是不稳定的,因为它会自动设置对数据库的所有查询的时间限制。
(*) 更新:由于版本42.2.x
网络超时为implemented。
要执行的第二个测试涉及更新 Java“PgHsm”类以使用您选择的数据库连接池实现 并启动(至少)两个在循环中连续运行简单更新查询的线程(在循环中,从池中获取数据库连接并在提交/回滚后返回到池中)。 当您关闭服务器 A 并将服务器 B 切换到“主”模式时,请监视“PgHsm”记录的异常以及线程在执行数据库操作时等待/挂起的时间。 测试结果可用于更新 JDBC 驱动程序选项和池设置。关注结果:
尽快从池中删除无效连接,以便应用程序从池中获取大部分有效连接 当数据库出现故障时,尽可能少的应用程序线程挂起(在最短的时间内)第二个测试依赖于服务器 A 不可用,因此连接测试查询(由数据库连接池执行)失败。
在两台服务器保持可用,但主从切换的情况下,连接测试查询将无济于事
并且数据库连接池将为应用程序提供错误的(现在是只读的)数据库连接。
在这种情况下,需要人工干预。描述了 HikariCP 的“故障转移模式”here
(仅适用于configuration 页面上描述的选项allowPoolSuspension
):
第三个测试将是 JavaEE 应用程序,到现在为止,您应该很清楚会出现什么问题。 在这些测试之后更新应用程序以改进处理“数据库关闭”场景的情况并不少见 (例如设置(默认)query-timeouts)。 在您的情况下,在手动故障转移期间使用“挂起、刷新和恢复数据库连接池”功能(上述模式)也是可取的。
【讨论】:
感谢您在回答中的详细解释。这听起来是一个很好的开始,以便在我的设置中测试行为。 自 2017 年 1 月起,PostgreSQL JDBC 驱动程序支持 get/setNetworkTimeout,请参阅 github.com/pgjdbc/pgjdbc/pull/849以上是关于如何在 JavaEE 应用程序中为 PostgreSQL 热备设置配置连接故障转移?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Tomcat 6 中为 Hibernate 使用 JTA 支持?
postgre数据如何实现Oracle数据库中decode函数