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
/* 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连接池具体的复用流程如下:
- 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线程
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通信运维也具备一定的参考意义。
GaussDB(DWS)集群通信:详解pooler连接池的更多相关文章
- Apache + Tomcat集群配置详解 (1)
一.软件准备 Apache 2.2 : http://httpd.apache.org/download.cgi,下载msi安装程序,选择no ssl版本 Tomcat 6.0 : http://to ...
- [转帖]Application Request Route实现IIS Server Farms集群负载详解
Application Request Route实现IIS Server Farms集群负载详解 https://www.cnblogs.com/knowledgesea/p/5099893.ht ...
- Solr系列二:solr-部署详解(solr两种部署模式介绍、独立服务器模式详解、SolrCloud分布式集群模式详解)
一.solr两种部署模式介绍 Standalone Server 独立服务器模式:适用于数据规模不大的场景 SolrCloud 分布式集群模式:适用于数据规模大,高可靠.高可用.高并发的场景 二.独 ...
- MySQL集群搭建详解
概述 MySQL Cluster 是MySQL 适合于分布式计算环境的高实用.可拓展.高性能.高冗余版本,其研发设计的初衷就是要满足许多行业里的最严酷应用要求,这些应用中经常要求数据库运行的可靠性要达 ...
- Clickhouse单机及集群部署详解
一.ClickHouse简介 ClickHouse是近年来备受关注的开源列式数据库,主要用于数据分析(OLAP)领域.目前国内社区火热,各个大厂纷纷跟进大规模使用: 今日头条 内部用ClickHous ...
- kafka的原理及集群部署详解
kafka原理详解 消息队列概述 消息队列分类 点对点 组成:消息队列(Queue).发送者(Sender).接收者(Receiver) 特点:一个生产者生产的消息只能被一个接受者接收,消息一旦被消费 ...
- Centos7 zookeeper单机/集群安装详解和开机自启
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件.它是一个为分布式应用提供一致性服务的软件,提供的功 ...
- 【线上测试之后的应用】基于MySQL+MHA+Haproxy构建高可用负载均衡数据库集群(详解)
这里我们先介绍一下MHA是什么,其次就是它的应用与测试,同时为了大家呈现了数据备份案例,最后总结了使用情况以及注意事项和解决办法 一.MHA 概述 MHA(Master High Availabili ...
- Storm集群安装详解
storm有两种操作模式: 本地模式和远程模式. 本地模式:你可以在你的本地机器上开发测试你的topology, 一切都在你的本地机器上模拟出来; 远端模式:你提交的topology会在一个集群的机器 ...
- Hadoop生态集群YARN详解
一,前言 Hadoop 2.0由三个子系统组成,分别是HDFS.YARN和MapReduce,其中,YARN是一个崭新的资源管理系统,而MapReduce则只是运行在YARN上的一个应用,如果把YAR ...
随机推荐
- 【JVM】运行时内存分配
程序计数器 用于标识线程执行到了字节码文件(class文件)的哪一行,当执行native方法时,值为undefined,各个线程私有 Java虚拟机栈 每个线程独有,每个方法执行时会创建一个栈帧,用于 ...
- C/C++ Crypto密码库调用方法
Crypto 库是C/C++的加密算法库,这个加密库很流行,基本上涵盖了市面上的各类加密解密算法,以下代码是我在学习是总结的,放到这里用于后期需要时能够快速解决问题. 项目地址:https://www ...
- 深入浅出Java多线程(三):线程与线程组
「引言」 大家好,我是你们的老伙计秀才!今天带来的是[深入浅出Java多线程]系列的第三篇内容:线程与线程组.大家觉得有用请点赞,喜欢请关注!秀才在此谢过大家了!!! 在现代软件开发中,多线程编程已成 ...
- 我管你什么okr还是kpi,PPT轻松交给你
word一键转ppt 通过[文件]→[选项]→[快速访问工具栏],选择[不在功能区中的命令],找到[发送到Microsoft PowerPoint ],单击[添加]后再[确定] 调出功能按钮后,就可以 ...
- 设计模式-2 简单工厂模式Factory Method
设计模式-2 简单工厂模式 1 意图: 定义一个用户创建对象的接口,让子类决定实例化那个类.Factory Method使一个类的实例化延迟到其子类 使用场景:将一个类的实例化延迟到其子类结构: 优缺 ...
- Java开发学习(四十七)----MyBatisPlus删除语句之多记录操作
1.多记录操作 先来看下问题: 之前添加了很多商品到购物车,过了几天发现这些东西又不想要了,该怎么办呢? 很简单删除掉,但是一个个删除的话还是比较慢和费事的,所以一般会给用户一个批量操作,也就是前面有 ...
- HttpClientTemplate JDK11以上的版本,可以用,我写的。
package com.diandaxia.common.template; import com.fasterxml.jackson.databind.ObjectMapper; import or ...
- 《ASP.NET Core 微服务实战》-- 读书笔记(第7章)
第 7 章 开发 ASP.NET Core Web 应用 ASP.NET Core 基础 在本章,我们将从一个命令行应用开始,并且在不借助任何模板,脚手架和向导的情况下,最终得到一个功能完整的 Web ...
- Postgresql-数据库无法停止,报错:pg_ctl server does not shut down
根据您的查询,pg_ctl server does not shut down(pg_ctl服务无法关闭)的原因可能有很多.以下是一些可能的解决方案和代码示例: (1)杀死所有与PostgreSQL相 ...
- JS 保姆级贴心,从零教你手写实现一个防抖debounce方法
壹 ❀ 引 防抖在前端开发中算一个基础但很实用的开发技巧,在对于一些高频操作例如监听输入框值变化触发更新之类,会有奇效.除了实际开发,在面试中我们也可能偶遇手写防抖节流的问题,鉴于不同公司考核要求不一 ...