PostgreSQL 接入

接入(Access)解决客户端如何稳定地访问正确PostgreSQL服务的问题,Pigsty默认使用L2 VIP + HAProxy接入。

接入是为了解决生产环境中高并发,高可用,高性能的问题。个人用户可以选择无视接入机制,绕过域名、VIP、负载均衡器、连接池,直接通过IP地址访问数据库。

个人用户可直接用连接串 postgres://dbuser_dba:DBUser.DBA@10.10.10.10:5432/meta 访问默认数据库 (注意替换IP地址与密码,沙箱环境可从宿主机访问)

在Pigsty的默认配置中,每一个数据库实例/节点上都一一对应部署有一个功能完整的负载均衡器(HAProxy),因此整个数据库集群中的任意实例都可以作为整个集群的服务接入点。Pigsty数据库集群的交付边界止步于接入层负载均衡器(HAProxy);您需要自行决定接入策略:如何将业务流量分发至集群中的一台、多台、或全部负载均衡实例

Pigsty提供了丰富的接入方式,用户可以根据自己的网络基础设施情况与喜好自行选择。作为样例,Pigsty沙箱中使用了一个绑定在集群主库上的L2 VIP,一个绑定在该VIP上的域名。应用程序通过域名透过L2 VIP访问集群主库上的负载均衡实例。当该节点不可用时,VIP会随集群主库漂移,流量也随之由新主库上的负载均衡器承载,如下图所示:

另一种经典的策略是直接使用DNS轮询的方式,将DNS域名解析至所有实例,本文会给出几种常见的接入模式。

用户接口

从用户的角度来看,访问数据库只需要一个连接串;而Pigsty向最终用户交付的接口,也是一个数据库连接串。

不同的接入方式在形式上的区别是连接串中主机端口部分的不同。

端口

Pigsty使用不同的端口来区分数据库服务,提供Postgres等效服务的端口如下:

端口 服务 类型 说明
5432 postgres 数据库 直接访问当前节点数据库实例
6432 pgbouncer 连接池 通过连接池访问当前节点数据库
5433 primary 服务 负载均衡并通过连接池访问集群主库
5434 replica 服务 负载均衡并通过连接池访问集群主库
5436 default 服务 通过负载均衡直达集群主库
5438 offline 服务 通过负载均衡直达集群离线访问实例

主机

类型 样例 说明
集群域名 pg-test 直接访问当前节点数据库实例
集群VIP 10.10.10.3 通过连接池访问当前节点数据库
特定实例域名 pg-test-1 负载均衡并通过连接池访问集群主库
特定实例IP 10.10.10.11 负载均衡并通过连接池访问集群主库
所有IP地址 10.10,10.11,10.12 使用Multihost特性,需要客户端支持

根据host部分填入的内容,与可用的port值,可以排列组合出多种连接串来。

可用连接串组合

以单节点沙箱环境为例,以下连接串都可以用于数据库集群pg-test上的test数据库:

可用连接串排列组合
# 通过集群域名接入
postgres://test@pg-test:5432/test               # DNS -> L2 VIP -> 主库直连
postgres://test@pg-test:6432/test               # DNS -> L2 VIP -> 主库连接池 -> 主库
postgres://test@pg-test:5433/test               # DNS -> L2 VIP -> HAProxy -> 主库连接池 -> 主库
postgres://test@pg-test:5434/test               # DNS -> L2 VIP -> HAProxy -> 从库连接池 -> 从库
postgres://dbuser_dba@pg-test:5436/test         # DNS -> L2 VIP -> HAProxy -> 主库直连(管理用)
postgres://dbuser_stats@pg-test:5438/test       # DNS -> L2 VIP -> HAProxy -> 离线库直连(ETL/个人查询用)

# 通过集群VIP直接接入
postgres://test@10.10.10.3:5432/test            # L2 VIP -> 主库直连
postgres://test@10.10.10.3:6432/test            # L2 VIP -> 主库连接池 -> 主库
postgres://test@10.10.10.3:5433/test            # L2 VIP -> HAProxy -> 主库连接池 -> 主库
postgres://test@10.10.10.3:5434/test            # L2 VIP -> HAProxy -> 从库连接池 -> 从库
postgres://dbuser_dba@10.10.10.3:5436/test      # L2 VIP -> HAProxy -> 主库直连(管理用)
postgres://dbuser_stats@10.10.10.3::5438/test   # L2 VIP -> HAProxy -> 离线库直连(ETL/个人查询用)

# 直接指定任意集群实例名
postgres://test@pg-test-1:5432/test             # DNS -> 数据库实例直连 (单实例接入)
postgres://test@pg-test-1:6432/test             # DNS -> 连接池 -> 数据库
postgres://test@pg-test-1:5433/test             # DNS -> HAProxy -> 连接池 -> 数据库读写
postgres://test@pg-test-1:5434/test             # DNS -> HAProxy -> 连接池 -> 数据库只读
postgres://dbuser_dba@pg-test-1:5436/test       # DNS -> HAProxy -> 数据库直连
postgres://dbuser_stats@pg-test-1:5438/test     # DNS -> HAProxy -> 数据库离线读写

# 直接指定任意集群实例IP接入
postgres://test@10.10.10.11:5432/test           # 数据库实例直连 (直接指定实例,无自动流量分发)
postgres://test@10.10.10.11:6432/test           # 连接池 -> 数据库
postgres://test@10.10.10.11:5433/test           # HAProxy -> 连接池 -> 数据库读写
postgres://test@10.10.10.11:5434/test           # HAProxy -> 连接池 -> 数据库只读
postgres://dbuser_dba@10.10.10.11:5436/test     # HAProxy -> 数据库直连
postgres://dbuser_stats@10.10.10.11:5438/test   # HAProxy -> 数据库离线读写

# 直接指定任意集群实例IP接入
postgres://test@10.10.10.11:5432/test           # 数据库实例直连 (直接指定实例,无自动流量分发)
postgres://test@10.10.10.11:6432/test           # 连接池 -> 数据库
postgres://test@10.10.10.11:5433/test           # HAProxy -> 连接池 -> 数据库读写
postgres://test@10.10.10.11:5434/test           # HAProxy -> 连接池 -> 数据库只读
postgres://dbuser_dba@10.10.10.11:5436/test     # HAProxy -> 数据库直连
postgres://dbuser_stats@10.10.10.11:5438/test   # HAProxy -> 数据库离线读写

# 智能客户端自动读写分离(连接池)
postgres://test@10.10.10.11:6432,10.10.10.12:6432,10.10.10.13:6432/test?target_session_attrs=primary
postgres://test@10.10.10.11:6432,10.10.10.12:6432,10.10.10.13:6432/test?target_session_attrs=prefer-standby

# 智能客户端自动读写分离(数据库)
postgres://test@10.10.10.11:5432,10.10.10.12:5432,10.10.10.13:5432/test?target_session_attrs=primary
postgres://test@10.10.10.11:5432,10.10.10.12:5432,10.10.10.13:5432/test?target_session_attrs=prefer-standby

在集群层次,用户可以通过集群域名+服务端口的方式访问集群提供的 四种默认服务,Pigsty强烈建议使用这种方式。当然用户也可以绕开域名,直接使用集群的VIP(L2 or L4)访问数据库集群。

在实例层次,用户可以通过节点IP/域名 + 5432端口直连Postgres数据库,也可以用6432端口经由Pgbouncer访问数据库。还可以通过Haproxy经由5433~543x访问实例所属集群提供的服务。

典型接入方案

Pigsty推荐使用基于Haproxy的接入方案(1/2),在生产环境中如果有基础设施支持,也可以使用基于L4VIP(或与之等效的负载均衡服务)的接入方案(3)。

序号 方案 说明
1 L2VIP + Haproxy Pigsty沙箱使用的标准接入架构,使用L2 VIP确保Haproxy高可用
2 DNS + Haproxy 标准高可用接入方案,系统无单点。
3 L4VIP + Haproxy 方案2的变体,使用L4 VIP确保Haprxoy高可用。
4 L4 VIP 大规模高性能生产环境建议使用DPVS L4 VIP直接接入
5 Consul DNS 使用Consul DNS进行服务发现,绕开VIP与Haproxy
6 Static DNS 传统静态DNS接入方式
7 IP 采用智能客户端接入

L2 VIP + Haproxy

方案简介

Pigsty沙箱使用的标准接入方案,采用单个域名绑定至单个L2 VIP,VIP指向集群中的HAProxy。

集群中的Haproxy采用Node Port的方式统一对外暴露 服务。每个Haproxy都是幂等的实例,提供完整的负载均衡与服务分发功能。Haproxy部署于每一个数据库节点上,因此整个集群的每一个成员在使用效果上都是幂等的。(例如访问任何一个成员的5433端口都会连接至主库连接池,访问任意成员的5434端口都会连接至某个从库的连接池)

Haproxy本身的可用性通过幂等副本实现,每一个Haproxy都可以作为访问入口,用户可以使用一个、两个、多个,所有Haproxy实例,每一个Haproxy提供的功能都是完全相同的。

每个集群都分配有一个L2 VIP,固定绑定至集群主库。当主库发生切换时,该L2 VIP也会随之漂移至新的主库上。这是通过vip-manager实现的:vip-manager会查询Consul获取集群当前主库信息,然后在主库上监听VIP地址。

集群的L2 VIP有与之对应的域名。域名固定解析至该L2 VIP,在生命周期中不发生变化。

方案优越性

  • 无单点,高可用
  • VIP固定绑定至主库,可以灵活访问

方案局限性

  • 多一跳
  • Client IP地址丢失,部分HBA策略无法正常生效
  • 所有候选主库必须位于同一二层网络
    • 作为备选,用户也可以通过使用L4 VIP绕开此限制,但相比L2 VIP会额外多一跳。
    • 作为备选,用户也可以选择不用L2 VIP,而用DNS直接指向HAProxy,但可能会受到客户端DNS缓存的影响。

方案示意

DNS + Haproxy

方案简介

标准高可用接入方案,系统无单点。灵活性,适用性,性能达到一个较好的平衡。

集群中的Haproxy采用Node Port的方式统一对外暴露 服务。每个Haproxy都是幂等的实例,提供完整的负载均衡与服务分发功能。Haproxy部署于每一个数据库节点上,因此整个集群的每一个成员在使用效果上都是幂等的。(例如访问任何一个成员的5433端口都会连接至主库连接池,访问任意成员的5434端口都会连接至某个从库的连接池)

Haproxy本身的可用性通过幂等副本实现,每一个Haproxy都可以作为访问入口,用户可以使用一个、两个、多个,所有Haproxy实例,每一个Haproxy提供的功能都是完全相同的。

用户需要自行确保应用能够访问到任意一个健康的Haproxy实例。作为最朴素的一种实现,用户可以将数据库集群的DNS域名解析至若干Haproxy实例,并启用DNS轮询响应。而客户端可以选择完全不缓存DNS,或者使用长连接并实现建立连接失败后重试的机制。又或者参考方案2,在架构侧通过额外的L2/L4 VIP确保Haproxy本身的高可用。

方案优越性

  • 无单点,高可用
  • VIP固定绑定至主库,可以灵活访问

方案局限性

  • 多一跳

  • Client IP地址丢失,部分HBA策略无法正常生效

  • Haproxy本身的高可用通过幂等副本,DNS轮询与客户端重连实现

    DNS应有轮询机制,客户端应当使用长连接,并有建连失败重试机制。以便单Haproxy故障时可以自动漂移至集群中的其他Haproxy实例。如果无法做到这一点,可以考虑使用接入方案2,使用L2/L4 VIP确保Haproxy高可用。

方案示意

L4 VIP + Haproxy

四层负载均衡 + HAProxy接入

方案简介

接入方案1/2的另一种变体,通过L4 VIP确保Haproxy的高可用

方案优越性

  • 无单点,高可用
  • 可以同时使用所有的Haproxy实例,均匀承载流量。
  • 所有候选主库不需要位于同一二层网络。
  • 可以操作单一VIP完成流量切换(如果同时使用了多个Haproxy,不需要逐个调整)

方案局限性

  • 多两跳,较为浪费,如果有条件可以直接使用方案4: L4 VIP直接接入。
  • Client IP地址丢失,部分HBA策略无法正常生效

L4 VIP

四层负载均衡接入

方案简介

大规模高性能生产环境建议使用 L4 VIP接入(FullNAT,DPVS)

方案优越性

  • 性能好,吞吐量大
  • 可以通过toa模块获取正确的客户端IP地址,HBA可以完整生效。

方案局限性

  • 仍然多一条。
  • 需要依赖外部基础设施,部署复杂。
  • 未启用toa内核模块时,仍然会丢失客户端IP地址。
  • 没有Haproxy屏蔽主从差异,集群中的每个节点不再“幂等”。

Consul DNS

Consul DNS接入

方案简介

L2 VIP并非总是可用,特别是所有候选主库必须位于同一二层网络的要求可能不一定能满足。

在这种情况下,可以使用DNS解析代替L2 VIP

方案优越性

  • 少一跳

方案局限性

  • 依赖Consul DNS
  • 用户需要合理配置DNS缓存策略

Static DNS

静态DNS接入

方案简介

传统静态DNS接入方式

方案优越性

  • 少一跳
  • 实施简单

方案局限性

  • 没有灵活性
  • 主从切换时容易导致流量损失

IP

IP直连接入

方案简介

采用智能客户端直连数据库IP接入

方案优越性

  • 直连数据库/连接池,少一条
  • 不依赖额外组件进行主从区分,降低系统复杂性。

方案局限性

  • 灵活性太差,集群扩缩容繁琐。

最后修改 2022-05-18