暂无图片
暂无图片
4
暂无图片
暂无图片
暂无图片

PostgreSQL运行时角色连接及角色查询问题

原创 多米爸比 2022-03-22
2471

本文讨论两个问题,在HA场景如何连接指定角色的节点以及如何识别连接的主库。

如何只连接主库

我们可能会有疑问:直接使用主库的IP地址进行连接会有什么问题呢?但如果我们没有使用统一的公有IP呢,PG里一些HA方案没有提供公有IP方案,不过我们也可以使用多IP+PORT的方式来进行连接,这种方案架构也更轻便。

目前可以通过以下两种协议来访问主库或者指定角色的节点:

  • jdbc协议
  • libpq协议

jdbc协议的targetServerType连接参数

关于targetServerType连接参数

targetServerType指定Connection连接特定状态的数据库实例,可选状态值包括any, primary, master, slave, secondary, preferSlave and preferSecondary

详细测试请参考文章:<<PostgreSQL数据库高可用及负载均衡JDBC参数测试>>

libpq协议的target_session_attrs属性

通过java语言使用jdbc的targetServerType进行连接的方式比较熟知,毕竟使用java语言开发应用程序更为广泛。

基于C语言编程的odbc接口或者基于Python语言的psycopg2接口可以使用libpq协议像jdbc一样通过连接串指定多个host+port,建立连接时可以轮流尝试直至成功。

最早在PostgreSQL 13里,target_session_attrs属性引入了两个值:

  • any(默认值) 表示可以允许连接到任意数据库,它会从所有配置的连接中轮流尝试,直至连接建立成功,从而实现故障转移。
  • read-write 在连接的时候,只接受可以读写的数据库。当它建立连接后,会发送SHOW transaction_read_only,如果是on,就代表是只读库,它会把连接关闭,然后测试第二个数据库,以此类推,直至连接到支持读写的数据库为止。

我们可以看出target_session_attrs属性参照了PostgreSQL JDBC连接参数targetServerType的功能,并且在PostgreSQL 14里,这两个参数的选项值保持了对齐

  • any(默认值) 可以允许连接到任意数据库。
  • read-write 只接收连接到default_transaction_read_only=off,并且非standby模式的数据库。
  • read-only 与read-write相反。
  • primary 只接收连接非standby模式的数据库。
  • standby 只接收连接standby模式的数据库。
  • prefer-standby 首先尝试连接standby模式的数据库,如果失败则尝试any模式。

target_session_attrs测试

测试连接本地的单机版本13(端口1306)和版本14(端口1402),我们要连接只读实例

[postgres@pg ~]$ psql "host=localhost,localhost port=1306,1402 dbname=postgres target_session_attrs=read-only"
psql: error: connection to server at "localhost" (127.0.0.1), port 1306 failed: session is not read-only
connection to server at "localhost" (127.0.0.1), port 1402 failed: session is not read-only

可以看到提示,没能连接成功,因为默认default_transaction_read_only是off。

下面我们修改版本13(端口1306)的default_transaction_read_only,设置为on,重启服务再测试连接只读实例

[postgres@pg ~]$ psql "host=localhost,localhost port=1306,1402 dbname=postgres target_session_attrs=read-only"
psql (14.2, server 13.6)
Type "help" for help.

postgres=# show port;
 port 
------
 1306
(1 row)

可以看到连接到了版本13(端口1306)

再测试连接standby节点

[postgres@pg ~]$ psql "host=localhost,localhost port=1306,1402 dbname=postgres target_session_attrs=standby"
psql: error: connection to server at "localhost" (127.0.0.1), port 1306 failed: server is not in hot standby mode
connection to server at "localhost" (127.0.0.1), port 1402 failed: server is not in hot standby mode

两个实例都是单机,非standby模式,不能连接。

接着连接主库(非standby模式)

[postgres@pg ~]$ psql "host=localhost,localhost port=1306,1402 dbname=postgres target_session_attrs=primary"
psql (14.2, server 13.6)
Type "help" for help.

postgres=# 

[postgres@pg ~]$ psql "host=localhost,localhost port=1402,1306 dbname=postgres target_session_attrs=primary"
psql (14.2)
Type "help" for help.

postgres=# 

可以看到依次连接到版本13及版本14

首选standby测试

[postgres@pg ~]$ psql "host=localhost,localhost port=1306,1402 dbname=postgres target_session_attrs=prefer-standby"
psql (14.2, server 13.6)
Type "help" for help.

postgres=# 

由于没有standby节点,安装默认any模式进行连接

target_session_attrs测试总结

目前target_session_attrs参数可以按照我们期望的角色进行连接,也方便我们动态扩展多个节点。比如后台的报表汇总统计为了减轻主库压力,可以只连接standby节点。

不过还有一个问题,并不是所有的图形化界面工具都支持多节点配置targetServerType或者target_session_attrs参数来连接指定角色节点,一些支持配置jdbc url参数的工具可以做到这一点。

如何查询连接的实际主库

如果使用了公有IP方案,有时客户端想在SQL层查询当前服务节点,我们想了解实际提供服务的私有IP,此时通过inet_server_addr可能会起作用(IP通过中间层代理)。

如果公有IP是实际绑定在数据库服务器,那inet_server_addr并不能查到,测试如下:
绑定一个共有IP:192.168.137.150

$ sudo ip addr add 192.168.137.150/24 dev enp0s3

数据库私有IP:192.168.137.251

[postgres@pg ~]$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 08:00:27:76:8f:09 brd ff:ff:ff:ff:ff:ff
    inet 192.168.137.251/24 brd 192.168.137.255 scope global enp0s3
       valid_lft forever preferred_lft forever
    inet 192.168.137.150/24 scope global secondary enp0s3
       valid_lft forever preferred_lft forever

下面通过共有IP 192.168.137.150进行连接

[postgres@pg ~]$ psql -h 192.168.137.150 -W
Password: 
psql (14.2)
Type "help" for help.

postgres=# select inet_server_addr(),inet_server_port();
 inet_server_addr | inet_server_port 
------------------+------------------
 192.168.137.150   |             1402
(1 row)

因为该连接是通过共有IP实际建立的,所以连接的服务IP地址也就是192.168.137.150。

还有一种识别节点的方式,通过服务端配置参数cluster_name,比如postgresql.conf文件设置

cluster_name='node1:192.168.137.251'

然后可以通过show命令或者current_setting函数来查询

postgres=# select current_setting('cluster_name');
    current_setting    
-----------------------
 node1:192.168.137.251
(1 row)

注意:最好把有差异的配置参数(cluster_name)以include方式进行配置,避免HA恢复或者重建之后覆盖了参数值。

保持联系

从2019年12月开始写第一篇文章,分享的初心一直在坚持,本人现在组建了一个PG乐知乐享交流群,欢迎关注我文章的小伙伴进群吹牛唠嗑,交流技术,互赞文章。

456.png

最后修改时间:2022-12-05 09:15:52
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

文章被以下合辑收录

评论