写点什么

GaussDB(DWS) 集群通信:详解 pooler 连接池

  • 2024-03-11
    广东
  • 本文字数:3658 字

    阅读完需:约 12 分钟

GaussDB(DWS)集群通信:详解pooler连接池

本文分享自华为云社区《GaussDB(DWS) 集群通信系列一:pooler连接池》,作者:半岛里有个小铁盒。

1.前言


适用版本:【8.1.0(及以上)】


GaussDB(DWS) 为 MPP 型分布式数据库,使用 Share Nothing 架构,数据分散存储在各个 DN 节点,而 CN 不存储数据,作为接收查询的入口,生成的计划会尽量下推到 DN 并行执行以提升性能,此过程中会产生大量的建连操作,使得通信开销变得很大。因此在大数据时代,集群规模越来越大,业务并发越来越高,数据库集群各节点间的通信压力也越来越大。GaussDB(DWS)集群通信技术,在大规模集群中可以承载高并发业务,能够实现高性能分布式通信系统。

2.背景



GaussDB(DWS) 中客户端执行查询流程如上图所示,其中具体的如下:


  1. 客户端向 CN 的监听端口发起连接;

  2. CN postmaster 主线程 accept 连接,创建 postgres 线程并将连接交给此线程处理;

  3. 客户端下发 query 到 CN;

  4. CN 的 postgres 线程将查询计划下发给其他 CN/DN,查询结果沿原路径返回到客户端;

  5. 客户端查询结束,关闭连接;

  6. 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


/* All pools for specified database */typedef struct databasepool{    char    *database;    char    *user_name;    char    *pgoptions; /* Connection options */    HTAB    *nodePools; /* Hashtable of PGXCNodePool, one entry for each node */    MemoryContext mcxt;    struct databasepool *next; /* Reference to next to organize linked list */} DatabasePool;
DatabasePool *databasePools = NULL;
复制代码


进程级别数据结构


DatabasePool 用于存储空闲连接,根据 database,user_name,pgoptions 三者来确定如果通过三者查找到了,那么就取其中对应的 nodePools,找不到则新加


nodePools 中对应的数据结构为 PGXCNodePool,用于存储本节点与其他每个 cn/dn 的连接,具体的保存如下


cn1[0,1,2,3,4,…]

dn1[0,1,2,3,4,…]


NodePool


typedef struct NodePool{    Oid nodeoid; /* Hash key (must be first!) */    bool valid;    ArrayLockFreeQueue pool;} PGXCNodePool;
复制代码


进程级别数据结构


连接到某一节点的空闲连接的集合,通过无锁队列(数组)实现从这里拿到对应的连接,直接复用

正在使用连接池


AgentPool


typedef struct{    ArrayLockFreeQueue pool;    AgentSlot* slots;}AgentPool;
复制代码


进程级别的数据结构


存放一个进程中的所有的连接


其中 slots 为一个数组,表明一个槽位,与 pool 为一一对应的状态用于保存所有线程持有的连接,即 poolAgent 数据结构


AgentSlot


typedef struct{    int index;    volatile AgentStatus status;    PoolAgent* agent;}AgentSlot;
复制代码


进程级别数据结构


存放进程中的某一个连接


index 与 AgentPool->pool 相关联


status 状态为,标识该连接是否正在使用/空闲/持有


agent 中为某个线程的信息(也就是每个 session),都是在全局数组 poolAgents 中保存的


PoolAgent


typedef struct{    /* Agent members */    ThreadId        pid;    DatabasePool*   pool;    int             index;
/* param members */ char* user_name; char* pgoptions; char* paramsStr; char* localParams; /* params temporarily saved before commit */ char* tempNamespace; /* temp namespace name of session */ List* paramsList; /* save session params, for build paramsStr */ int paramsReady; /* param is set, need rebuild paramsStr */
/* Connection members */ int dnNum; int cnNum; PoolSlot** dnConn; PoolSlot** cnConn; NodeConnDef* cnDef; NodeConnDef* dnDef;
/* handles members */ NodeHandle** dnHandles; NodeHandle** cnHandles; int dnUsed; int cnUsed;} 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 连接池具体的复用流程如下:


  1. session 需要连接时,通过 DB+USER 为 key 找到正确的 pooler 连接池,优先从中取走现有连接,如果连接池中没有连接的话,则新建连接;

  2. query 结束后,CN 的 postgres 线程并不会归还连接,连接可以用于当前 session 的下一个查询;

  3. session 结束后,CN 的 postgres 线程会将连接还到对应的 pooler,连接对应的 DN 上的 postgres 线程并不会退出,处于 ReadCommand 中,等待复用后 CN 新的 postgres 线程发起任务;

4.Pooler 连接池相关的视图

pg_pooler_status 视图


pg_pooler_status 视图记录了 pooler 连接池中的所有连接信息,每一行表示本 CN 发起的一个连接,对应对端进程的一个 postgres 线程


postgres=# select * from pg_pooler_status; database | user_name | tid |  node_oid  |  node_name   | in_use | node_port | fdsock |   remote_pid    | session_params----------+-----------+-----+------------+--------------+--------+-----------+--------+-----------------+---------------- postgres |   user1   |     | 2147483650 | datanode1    | f      |     37110 |     94 | 140259241618584 | none postgres |   user1   |     | 2147483650 | datanode1    | f      |     37110 |    101 | 140259241619432 | none postgres |   user1   |     | 2147483650 | datanode1    | f      |     37110 |     91 | 140259241618160 | none postgres |   user1   |     | 2147483650 | datanode1    | f      |     37110 |     95 | 140259241619008 | none postgres |   user1   |     | 2147483650 | datanode1    | f      |     37110 |     59 | 140259241562192 | none postgres |   user1   |     | 2147483650 | datanode1    | f      |     37110 |    106 | 140259241619856 | none postgres |   user1   |     | 2147483650 | datanode1    | f      |     37110 |    108 | 140259241620280 | none postgres |   user1   |     | 2147483650 | datanode1    | f      |     37110 |    117 | 140259241621128 | none postgres |   user1   |     | 2147483650 | datanode1    | f      |     37110 |    114 | 140259241620704 | none
复制代码


  • in_use 为‘t’表示这个连接正在某线程使用,为‘f’表示空闲连接等待复用

  • tid 列为本 CN 的持有此连接的线程号

  • node_name 列为对端进程号,remote_pid 列为对端线线程号

  • 在 query_id 为 0 或 CN/DN 不一致时,通过 pooler 视图查找 CN 与 DN 连接关系


一般 pooler 连接池中的连接会非常多,可以按不同字段 group by 查看某个 db pool 池中的连接情况,或连往某个 node 的连接情况,如:


select database,user_name,node_name,in_use,count(*) from pg_pooler_status group by 1, 2, 3 ,4 order by 5 desc limit 50;
复制代码

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 通信运维也具备一定的参考意义。


点击关注,第一时间了解华为云新鲜技术~

发布于: 刚刚阅读数: 4
用户头像

提供全面深入的云计算技术干货 2020-07-14 加入

生于云,长于云,让开发者成为决定性力量

评论

发布
暂无评论
GaussDB(DWS)集群通信:详解pooler连接池_数据库_华为云开发者联盟_InfoQ写作社区