/ 云数据库 rds/ / rds for postgresql/ 使用客户端驱动程序实现故障转移和读写分离
更新时间:2024-09-26 gmt 08:00

使用客户端驱动程序实现故障转移和读写分离-九游平台

从postgresql 10(libpq.so.5.10)开始,libpq驱动层开始支持故障转移和读写分离,jdbc驱动层则支持读写分离、故障转移和负载均衡。

postgresql客户端连接程序向下兼容,对于rds for postgresql 9.5及9.6版本,使用新版本的libpq驱动程序也可以实现故障转移。

本章节中故障转移指的是读业务的故障转移。

  • libpq是postgresql的c应用程序接口,包含一组库函数,允许客户端程序将查询请求发送给postgresql后端服务器并接收这些查询的结果。
  • jdbc是java语言中用来规范客户端程序如何访问数据库的应用程序接口,在postgresql中jdbc支持故障转移和负载均衡。
表1 libpq和jdbc驱动支持的功能

驱动

读写分离

负载均衡

故障转移

libpq驱动

×

jdbc驱动

libpq实现故障转移和读写分离

通过libpq函数连接多个数据库,当出现故障时会自动切换到可用的数据库。

postgresql://[user[:password]@][netloc][:port][,...][/dbname][?param1=value1&...]

示例:连接1个rds for postgresql主实例数据库和对应的2个只读实例数据库,只要确保至少有一个数据库可用,读请求就不会失败。

postgres://:,:,:/?target_session_attrs=any

表2 参数说明

参数

说明

取值样例

数据库的主机ip。

如果通过内网连接,“instance_ip”是主机ip,即“概览”页面该实例的“内网地址”。

如果通过连接了公网的设备访问,“instance_ip”为该实例已绑定的“弹性公网ip”。

数据库端口。

默认5432,当前端口,参考“概览”页面该实例的“数据库端口”。

数据库名,即需要连接的数据库名。

默认的管理数据库是postgres,可根据业务实际情况填写数据库名。

target_session_attrs

允许连接到指定状态的数据库。

  • any:默认值,表示允许连接到任意数据库,会连接到第一个允许连接的数据库,如果连接的数据库出现故障导致连接断开,会尝试连接其他数据库,从而实现故障转移。
  • read-write:只会连接到支持读写的数据库,即从第一个数据库开始尝试连接,如果连接后发现不支持读写,则会断开连接,然后尝试连接第二个数据库,以此类推,直至连接到支持读写的数据库。
  • read-only:只会连接只读数据库,即从第一个数据库开始尝试连接,如果连接后发现支持读写,则会断开连接,然后尝试连接第二个数据库,以此类推,直至连接到只读的数据库。rds for postgresql 13(libpq.so.5.13)及以下版本,不支持该取值。

更多libpq的使用方法和参数说明请参见。

您还可以在应用程序中结合pg_is_in_recovery()函数,判断连接的数据库是主实例数据库(结果为“f”表示主数据库)还是只读实例数据库,进而实现读写分离。

使用python代码的示例如下(psycopg2使用的为libpq):

// 认证用的用户名和密码直接写到代码中有很大的安全风险,建议在配置文件或者环境变量中存放(密码应密文存放,使用时解密),确保安全。
// 本示例以用户名和密码保存在环境变量中为例,运行本示例前请先在本地环境中设置环境变量(环境变量名称请根据自身情况进行设置)example_username_env和example_password_env。
import psycopg2
import os
username = os.getenv("example_username_env")
password = os.getenv("example_password_env")
conn = psycopg2.connect(database=,host=, user=username, password=password, port=, target_session_attrs="read-write")
cur = conn.cursor()
cur.execute("select pg_is_in_recovery()")
row = cur.fetchone()
print("recovery =", row[0])

jdbc实现故障转移和读写分离

您可以在连接url中定义多个数据库(主机和端口),并用逗号分隔,驱动程序将尝试按顺序连接到它们中的每一个,直到连接成功。如果没有成功,会返回连接异常报错。

jdbc:postgresql://node1,node2,node3/${database}?targetservertype=prefersecondary&loadbalancehosts=true

示例:

jdbc:postgresql://:,:,:/?targetservertype=prefersecondary&loadbalancehosts=true

jdbc连接实例java实现代码请参考:通过jdbc连接rds for postgresql实例

表3 参数说明

参数

说明

取值样例

targetservertype

允许连接到指定状态的数据库。

  • any:任何数据库。
  • primary:主数据库(可写可读)。jdbc 42.2.0以下版本请使用参数值“master”。
  • secondary:从数据库(可读)。jdbc 42.2.0以下版本请使用参数值“slave”。
  • prefersecondary:优先从数据库,如果没有从数据库才连接到主数据库。jdbc 42.2.0以下版本请使用参数值“preferslave”。

loadbalancehosts

尝试连接数据库的顺序。

  • false:默认值,按url中的定义顺序连接数据库。
  • true:随机连接数据库。

区别数据库主从的方式是通过查询数据库是否允许写入,允许写入数据的判断为主数据库,不允许写入数据的判断为从数据库。参考libpq实现故障转移和读写分离中通过pg_is_in_recovery()函数来判断,结果为“f”表示为主数据库。

为实现读写分离,需要在配置jdbc时设置2个数据源,首先设置targetservertype=primary,用于写操作。另一个可以根据以下情况进行设置:

  • 有一个只读实例,为实现高可用设置targetservertype=prefersecondary,用于读操作。假设主实例ip为10.1.1.1,只读实例ip为10.1.1.2。

    jdbc:postgresql://10.1.1.2:5432,10.1.1.1:5432/${database}?targetservertype=prefersecondary

  • 有两个以上只读实例,可设置targetservertype=any,用于读操作。假设只读实例ip分别为10.1.1.2、10.1.1.3。

    jdbc:postgresql://10.1.1.2:5432,10.1.1.3:5432/${database}?targetservertype=any&loadbalancehosts=true

相关文档

网站地图