GaussDB(DWS) 集群通信:详解 pooler 连接池
本文分享自华为云社区《GaussDB(DWS) 集群通信系列一:pooler连接池》,作者:半岛里有个小铁盒。
1.前言
适用版本:【8.1.0(及以上)】
GaussDB(DWS) 为 MPP 型分布式数据库,使用 Share Nothing 架构,数据分散存储在各个 DN 节点,而 CN 不存储数据,作为接收查询的入口,生成的计划会尽量下推到 DN 并行执行以提升性能,此过程中会产生大量的建连操作,使得通信开销变得很大。因此在大数据时代,集群规模越来越大,业务并发越来越高,数据库集群各节点间的通信压力也越来越大。GaussDB(DWS)集群通信技术,在大规模集群中可以承载高并发业务,能够实现高性能分布式通信系统。
2.背景
GaussDB(DWS) 中客户端执行查询流程如上图所示,其中具体的如下:
客户端向 CN 的监听端口发起连接;
CN postmaster 主线程 accept 连接,创建 postgres 线程并将连接交给此线程处理;
客户端下发 query 到 CN;
CN 的 postgres 线程将查询计划下发给其他 CN/DN,查询结果沿原路径返回到客户端;
客户端查询结束,关闭连接;
CN 上对应的 postgres 线程销毁退出;
CN 与 DN 建连立流程,和客户端与 CN 建连立流 程基本相同。因此为了减少 CN 与 DN 建立连接,以及 DN 进程中 postgres 线程创建、销毁的开销,CN 端实现了 Pooler 连接池。
3.Pooler 连接池
如上图所示,CN 的 pooler 连接池中会保存与其他 CN/DN 的连接,每一个连接在对端会对应一个 postgres 工作线程。
postgres 工作线程是带状态属性的,如 database,所以可以认为 pooler 连接池中的连接也是带属性的。不同属性间的连接是不能复用的,如上图所示,按不同属性切分为 pool A/B/C 等连接池。每个连接池中会存有连接往不同节点的空闲连接的数组,提供接口给外部使用或放入连接。
CN 上的 postgres 工作线程在需要连接其他节点时,会创建一个本地 agent,尝试从 pooler 连接池取跟本线程相同属性的空闲连接,pooler 如果没有空闲连接,就会新建一个连接。连接交给 agent 后,可以视为线程私有。在线程退出时,agent 才会将连接还给 pooler。
接下来,我们从数据结构上来看看 Pooler 连接池实现原理:
空闲连接池
DatabasePool
进程级别数据结构
DatabasePool 用于存储空闲连接,根据 database,user_name,pgoptions 三者来确定如果通过三者查找到了,那么就取其中对应的 nodePools,找不到则新加
nodePools 中对应的数据结构为 PGXCNodePool,用于存储本节点与其他每个 cn/dn 的连接,具体的保存如下
cn1[0,1,2,3,4,…]
dn1[0,1,2,3,4,…]
NodePool
进程级别数据结构
连接到某一节点的空闲连接的集合,通过无锁队列(数组)实现从这里拿到对应的连接,直接复用
正在使用连接池
AgentPool
进程级别的数据结构
存放一个进程中的所有的连接
其中 slots 为一个数组,表明一个槽位,与 pool 为一一对应的状态用于保存所有线程持有的连接,即 poolAgent 数据结构
AgentSlot
进程级别数据结构
存放进程中的某一个连接
index 与 AgentPool->pool 相关联
status 状态为,标识该连接是否正在使用/空闲/持有
agent 中为某个线程的信息(也就是每个 session),都是在全局数组 poolAgents 中保存的
PoolAgent
对于每起一个线程 session(即连接),都会有一个 PoolAgent 与之对应,即从 DatabasePool->NodePool->pool 取出来的连接
cnDef、dnDef:初始化时从 pgxc_node 中拿到,即 cn 定义、端口、ip
(session 级别)dnConn、cnConn:从 databasePools->nodePools-> pool 拿真正对应的连接
(query 级别)dnHandles、cnHandles:从 dnConn、cnConn 里边 dop 出来使用,确保两者是一一对应的状态,当 query 结束时,只需要 close handles 就行,cnConn 不需要 close
Pooler 连接池具体的复用流程如下:
session 需要连接时,通过 DB+USER 为 key 找到正确的 pooler 连接池,优先从中取走现有连接,如果连接池中没有连接的话,则新建连接;
query 结束后,CN 的 postgres 线程并不会归还连接,连接可以用于当前 session 的下一个查询;
session 结束后,CN 的 postgres 线程会将连接还到对应的 pooler,连接对应的 DN 上的 postgres 线程并不会退出,处于 ReadCommand 中,等待复用后 CN 新的 postgres 线程发起任务;
4.Pooler 连接池相关的视图
pg_pooler_status 视图
pg_pooler_status 视图记录了 pooler 连接池中的所有连接信息,每一行表示本 CN 发起的一个连接,对应对端进程的一个 postgres 线程
in_use 为‘t’表示这个连接正在某线程使用,为‘f’表示空闲连接等待复用
tid 列为本 CN 的持有此连接的线程号
node_name 列为对端进程号,remote_pid 列为对端线线程号
在 query_id 为 0 或 CN/DN 不一致时,通过 pooler 视图查找 CN 与 DN 连接关系
一般 pooler 连接池中的连接会非常多,可以按不同字段 group by 查看某个 db pool 池中的连接情况,或连往某个 node 的连接情况,如:
5.Pooler 连接清理
清理 Session 持有的连接
cache_connection,是否使用 pooler 连接池缓存连接,默认开
session_timeout,客户端连接空闲超时后报错退出归还连接
enable_force_reuse_connections,事务结束后强制归还连接
conn_recycle_timeout(8.2.1),CN 空闲 session 超时后归还连接
Pooler 空闲连接池中的连接
pg_clean_free_conn 视图/函数,清理 1/4 的空闲连接池连接,CM 定期调用
CLEAN CONNECTION 语法,清理对应 DB 或 user 的所有空闲连接 clean connection to all for database postgres to USER user1;
6.总结
本文详细介绍了 Libcomm 通信库及其原理,让我们更好的理解 GaussDB(DWS)集群通信中的具体逻辑,对于 GaussDB 通信运维也具备一定的参考意义。
版权声明: 本文为 InfoQ 作者【华为云开发者联盟】的原创文章。
原文链接:【http://xie.infoq.cn/article/f7917a86bf3796035d927a669】。文章转载请联系作者。
评论