PostgreSQL 同事能建表,自己报 read-only:检查 HA 写入入口
PostgreSQL HA 中一台客户端能建表、另一台却只读时,对照原连接的恢复状态与地址,核对硬编码 IP 和写入入口,区分备用节点与普通只读事务。
连接 PostgreSQL 高可用服务时,自己的 Python 或 pgAdmin 执行建表报 cannot execute CREATE TABLE in a read-only transaction,同事却能执行。如果两边的 pg_is_in_recovery() 一个为 true、一个为 false,应先比较实际连接目标。硬编码某个节点 IP,可能绕过指向可写节点的 HA 入口,直接连到了备用节点。
这只是一种可判断的场景。IP 地址本身不代表只读,域名也不保证可写;关键是这套服务为写入提供了什么入口,以及当前连接落在哪个节点。
在原连接中对照恢复状态和地址
下面是只读检查示例。通过各自真正失败或成功的连接执行,不要另外找一条正常连接来证明原连接没问题:
SELECT current_database(), current_user,
inet_server_addr(), inet_server_port(),
pg_is_in_recovery();
SHOW transaction_read_only;
SHOW default_transaction_read_only;
数据库名与用户用于排除环境或账号不同,地址和端口帮助确认连接落点。使用 Unix socket 时 inet_server_addr() 可能为空,不能据此判定故障。
pg_is_in_recovery() 为 true 表示服务器正在恢复。高可用部署中的 hot standby 通常处于持续恢复状态,允许只读查询,但不能执行建表等写操作。这也可能是备份恢复流程中的实例,不能只凭函数结果就确定其角色名称。
若失败端为 true、成功端为 false,继续核对两边配置的 host、端口和服务端提供的写入入口。不要因为账户权限看起来充足,就在备用节点重复 GRANT 或尝试关闭只读事务。
使用已确认的写入端点,更新真正失败的客户端
从高可用平台或数据库管理员处确认当前 writer/primary 入口。它可能是专用域名、代理地址或服务端点,不一定与某个固定节点 IP 相同。将需要写入的客户端改用该入口,保留原连接参数中的认证、数据库名和 TLS 要求。
不要为了让新地址连通而关闭证书校验;域名更换涉及证书名称与客户端连接配置,应同时核对。记录修改前的连接参数,但不要把密码写进排查日志或公共配置。
修改应用配置后,已有连接池中的连接不会因 DNS 或 host 配置变化自动全部迁移。按应用支持的方式更新连接并重建连接池,评估短暂断连及正在执行的事务。不要在提交结果未知时直接重放业务写入,先确认事务是否成功。
回退配置时也要重新检查原端点角色。旧 IP 此刻可能仍是只读节点,恢复旧配置不能作为继续写入的保证。
为 false 仍只读,检查事务配置
pg_is_in_recovery() 为 false,但 transaction_read_only 为 on,说明还需检查当前事务、会话默认值及驱动配置。应用可能主动启用了只读事务,或账号、数据库、连接参数设置了只读默认值。
default_transaction_read_only 决定新事务的默认状态,不等于当前事务状态。不要在已经失败或正在进行的事务里随意切换模式;先按正常流程回滚错误事务,确认应用为何设置只读,再在有写入授权的流程中建立正确事务。
hot standby 处于恢复时,不能靠 SET TRANSACTION READ WRITE 将其变成可写主库。升主、移除恢复配置和调整 HA 角色是集群管理操作,可能影响复制与故障切换,不能作为客户端报错的快捷修复。
验收应从原客户端重新建立连接:落点符合服务的写入设计,恢复状态与事务状态符合预期,受控业务写入能够提交。还应确认 HA 入口的后续切换方式,避免这次把地址改成另一个固定 IP,下一次切换后再出现同一问题。


