本文介绍了PolarDB PostgreSQL版(兼容Oracle)的Shared Server功能。
前提条件
支持的PolarDB PostgreSQL版(兼容Oracle)版本如下:
Oracle 2.0(内核小版本2.0.14.6.0及以上)
您可通过如下语句查看PolarDB PostgreSQL版(兼容Oracle)的内核小版本的版本号:
show polar_version;
背景信息
原生PostgreSQL的连接调度方式是每一个进程对应一个连接 (One-Process-Per-Connection),这种调度方式适合低并发、长连接的业务场景。而在高并发或大量短连接的业务场景中,进程的大量创建、销毁以及上下文切换,会严重影响性能。同时,在业务容器化部署后,每个容器通过连接池向数据库发起连接,业务在高峰期会弹性扩展出很多容器,后端数据库的连接数会瞬间增高,影响数据库稳定性,导致OOM频发。
为了解决上述问题,在使用PostgreSQL时通常会配置连接池组件。例如,部署在数据库侧的后置连接池PgBouncer,部署在应用侧的前置连接池Druid。但后置连接池无法保留用户连接私有信息(例如,GUC参数、Prepared Statement)的相关功能,在面临进程被污染的情况(例如,加载动态链接库、修改role
参数)时也无法及时清理。前置连接池不仅无法解决后置连接池的缺陷,还无法根据应用规模扩展而实时调整配置,仍然会面临连接数膨胀的问题。
PolarDB PostgreSQL版(兼容Oracle)针对上述问题,从数据库内部提供了Shared Server(本文简称SS)内置连接池功能,采用共享内存+Session Context+Dispatcher转发+Backend Pool的架构,实现了用户连接与后端进程的解绑。后端进程具备了Native、Shared、Dedicated三种执行模式,并且在运行时可以根据实时负载和进程污染情况进行动态转换。负载调度算法充分吸收AliSQL对社区版MySQL线程池的缺陷改进,使用Stall机制弹性控制Worker数量,同时避免用户连接等待时间过长。从根本上解决了高并发或者大量短连接带来的性能、稳定性问题。
原理介绍
在PostgreSQL原生的One-Process-Per-Connection连接调度策略中,用户发起的连接与后端进程一一绑定:这里不仅是生命周期的绑定,同时还是服务与被服务关系的绑定。
在Shared Server内置连接池中,通过提取出会话相关上下文Session Context,将用户连接和后端进程进行了解绑,并且引入Dispatcher来进行代理转发:
Session Context保存Session相关数据,存放于共享内存中,跨进程共享。存放数据包括:Prepared Statement、连接私有参数、临时表元数据等,后续还可以不断扩展。
Dispatcher进程承载代理转发工作,用户连接通过Dispatcher分发调度到不同的后端进程上,后端进程通过Dispatcher被多个用户连接共享使用。Dispatcher进程可以配置多个。
每个Dispatcher管理的后端进程按
<user, database, GUCs>
为key,划分成不同的后端进程池。每个后端进程池都有自己独占的后端进程组,单个后端进程池内的后端进程数量随着负载增高而增多,随着负载降低而减少。用户连接中的一个事务会始终被同一个后端进程服务,不同事务可能会被不同的后端进程服务。
在Shared Server中,后端进程有三种执行模式。进程执行模式在运行时会根据实时负载和进程污染情况进行动态转换:
Native模式(原生模式):一个后端进程只服务一个用户连接,不存在Dispatcher转发数据。
SS关闭后,所有后端进程都处于Native模式。
SS开启后,对于以下场景,后端进程也会在用户连接的登录阶段回退为Native模式:
WAL Sender进程。
MPP进程。
SS共享内存耗尽。
在参数
polar_ss_dedicated_dbuser_names
黑名单范围内的数据库或用户。
Shared模式(共享模式):后端进程作为可共享的工作进程提供给各个用户连接使用。Shared模式是标准的、期望的连接池状态,表示后端进程是可复用的。SS开启后,后端进程会优先使用Shared模式,同时会在触发兜底机制时转换为Dedicated模式。
Dedicated模式(兜底模式):由于各种原因导致后端进程被污染,退化为当前后端进程只能服务当前用户连接,用户连接退出后,后端进程也退出。
用户连接不再使用新的SS共享内存,而是使用本地进程内存。
用户连接与后端进程之间的数据传输依旧经过Dispatcher转发。
以下场景中会触发兜底机制,执行模式会由Shared转变为Dedicated:
更新了SS黑名单内的GUC参数。
使用了SS黑名单内的插件。
执行了
DECLARE CURSOR
命令。对ONCOMMIT DELETE ROWS属性的表进行操作。
执行
CURSOR WITH HOLD
操作。使用自定义GUC参数。
加载动态链接库。
性能对比
Shared Server主要应用于高并发或大量短连接的业务场景,因此这里使用TPC-C进行测试。
TPC-C高并发
使用104核512 GB的物理机单机部署,测试TPC-C 1000仓下,并发数从300增大到5000时,不同配置下的分数对比。如下图所示:
old:不使用任何连接池,使用PostgreSQL的原生执行模式(即Native模式)。
ss off:使用Shared Server内置连接池,启动前关闭SS开关,退化为Native模式。
ss native:使用Shared Server内置连接池,启动后关闭SS开关,退化为Native模式。
ss didicated:使用Shared Server内置连接池,启动后开启SS开关,但强制使用Dedicated模式。
ss shared:使用Shared Server内置连接池,启动后开启SS开关,使用标准的Shared模式。
从图中可以看出:
原生PostgreSQL场景、Shared Server关闭的场景、Shared Server兜底场景中,均无法稳定进行TPC-C高并发测试。性能从并发数为1500时开始下跌,在并发数为5000时已经不能提供服务。
Shared Server开启并进入Shared 模式后,TPC-C性能不受高并发数影响,始终保持在稳定状态,很好地支持了高并发场景。
PgBench短连接
使用104核512 GB的物理机单机部署,利用pgbench
分别测试以下配置中,并发短连接数从1到128的场景下的性能表现:
pgbouncer session:使用PgBouncer后置连接池, 配置为Session Pooling模式。
pgbouncer transaction:使用PgBouncer后置连接池, 配置为Transaction Pooling模式。
old:不使用任何连接池,使用PostgreSQL的原生执行模式。
ss dedicated:使用Shared Server内置连接池,但强制设置为Dedicated模式。
ss shared:使用Shared Server内置连接池,配置为标准的Shared模式。
从图中可以看出,使用连接池后,对于短连接,PgBouncer和Shared Server的性能均有所提升。但PgBouncer最高只能提升14倍性能,Shared Server最高可以提升42倍性能。
功能特性
PgBouncer对比
业界典型的后置连接池PgBouncer具有多种模式。其中Session Pooling模式仅对短连接友好,一般不使用;Transaction Pooling模式对短连接、长连接都友好,是默认推荐的模式。与PgBouncer相比,Shared Server的差异化功能特点如下所示:
功能 | PgBouncer Session Pooling | PgBouncer Transaction Pooling | Shared Server |
Startup parameters | 受限 | 受限 | 支持 |
SSL | 支持 | 支持 | 暂不支持 |
LISTEN/NOTIFY | 支持 | 不支持 | 支持 触发兜底 |
LOAD statement | 支持 | 不支持 | 支持 触发兜底 |
Session-level advisory locks | 支持 | 不支持 | 支持 触发兜底 |
SET/RESET GUC | 支持 | 不支持 | 支持 |
Protocol-level prepared plans | 支持 | 暂不支持 | 支持 |
PREPARE / DEALLOCATE | 支持 | 不支持 | 支持 |
Cached Plan Reset | 支持 | 支持 | 支持 |
WITHOUT HOLD CURSOR | 支持 | 支持 | 支持 |
WITH HOLD CURSOR | 支持 | 不支持 | 暂不支持 |
PRESERVE/DELETE ROWS temp | 支持 | 不支持 | 暂不支持 |
ON COMMIT DROP temp | 支持 | 支持 | 支持 |
PgBouncer的Startup参数仅包括:
client_encoding
datestyle
timezone
standard_conforming_strings
触发进入Dedicated兜底模式,用户连接断开后,后端进程也会释放,避免污染后的进程被其他用户连接使用。
自定义配置
为了适应不同的环境,Shared Server支持丰富的参数配置:
支持配置Dispatcher进程和后端进程的最大数量,可以实时调整出最佳性能模式。
支持总连接数超过阈值后才启用SS的Shared模式,避免连接数较少时SS性能不显著。
支持配置强制启用Dedicated模式,避免后端进程被污染后持续影响其他用户连接。
支持配置指定的数据库/用户不使用Shared Server,给专用账户和管理员预留应急通道。
支持配置指定插件不使用Shared Server,避免外部插件异常导致Shared Server不稳定。
支持配置指定GUC参数不使用Shared Server,避免GUC功能复杂导致Shared Server不稳定。
支持Dispatcher阻塞连接数量超过阈值后回退到Native模式,避免Dispatcher缺陷导致不可用。
支持配置用户连接的超时等待时间,避免用户连接长时间等待后端进程。
支持配置后端进程空闲时间阈值,避免后端进程长时间空闲,占用系统资源。
支持配置后端进程活跃时间阈值, 避免后端进程长时间活跃,占用系统资源。
支持配置每个后端进程池中保留后端进程的最小个数,保持连接池热度,避免进程被全部释放。
支持配置Shared Server调试日志,方便排查后端进程调度相关的任何问题。
参数说明
Shared Server的典型配置参数说明如下:
参数 | 说明 |
polar_enable_shm_aset | 是否开启全局共享内存。默认关闭,重启生效。取值如下:
|
polar_ss_shared_memory_size | Shared Server全局共享内存的使用上限。单位为KB,取值为0时表示关闭,默认为1024 KB。重启生效。 |
polar_ss_dispatcher_count | Dispatcher进程的最大个数。默认为2,最大为CPU核数,建议配置与CPU核心数相同。重启生效。 |
polar_enable_shared_server | 是否开启Shared Server功能,默认关闭。取值如下:
|
polar_ss_backend_max_count | 后端进程的最大数量,默认为-5,表示为 |
polar_ss_backend_idle_timeout | 后端进程的空闲退出时间,默认为3分钟。 |
polar_ss_session_wait_timeout | 后端进程被用满时,用户连接等待被服务的最大时间,默认为60秒。 |
polar_ss_dedicated_dbuser_names | 记录指定数据库/用户使用时进入Native模式。默认为空,取值如下:
|
- 本页导读