PostgreSQL中citus节点间的网络需求有哪些

62次阅读
没有评论

共计 10106 个字符,预计需要花费 26 分钟才能阅读完成。

本篇内容介绍了“PostgreSQL 中 citus 节点间的网络需求有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让丸趣 TV 小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

背景

citus 节点间的网络需求:

1、cn 节点访问所有 worker 节点。oltp 业务的访问较频繁。

2、重分布数据时,worker 节点间相互访问。访问频度不大,OLAP 业务常见,一旦有可能数据交换吞吐较大。

citus 的 cn 节点连 worker 节点为有两种模式,

一种为事务级保持连接模式(每条 SQL 发起时建立连接,SQL 结束后释放连接 (除非在事务中,否则 SQL 结束立即释放连接)。),

另一种为会话级保持连接模式(会话发起时建立连接,会话结束后释放连接。)。

1、跑 OLAP 类的 SQL 时,使用的是第一种即时连接模式(OLAP 场景并发不高,建立连接带来的额外开销不明显)

可以在 worker 节点打开参数进行跟踪

postgres=# show log_connections ; 
 log_connections 
----------------- 
 on 
(1 row) 
 
postgres=# show log_disconnections ; 
 log_disconnections 
-------------------- 
 on 
(1 row)

例子,

以下两条 SQL 均为即时短连接模式 (Custom Scan (Citus Task-Tracker) Custom Scan (Citus Real-Time))。

postgres=# set citus.task_executor_type =task; 
ERROR: invalid value for parameter  citus.task_executor_type :  task  
HINT: Available values: real-time, task-tracker. 
 
 
postgres=# set citus.task_executor_type = task-tracker  
SET 
postgres=# explain select count(*) from pgbench_accounts ; 
 QUERY PLAN 
--------------------------------------------------------------------------------------------------------------------- 
 Aggregate (cost=0.00..0.00 rows=0 width=0) 
 -  Custom Scan (Citus Task-Tracker) (cost=0.00..0.00 rows=0 width=0) 
 Task Count: 128 
 Tasks Shown: One of 128 
 -  Task 
 Node: host=172.24.211.224 port=1921 dbname=postgres 
 -  Aggregate (cost=231.85..231.86 rows=1 width=8) 
 -  Seq Scan on pgbench_accounts_106812 pgbench_accounts (cost=0.00..212.48 rows=7748 width=0) 
(8 rows) 
 
 
postgres=# set citus.task_executor_type = real-time  
 
postgres=# explain select count(*) from pgbench_accounts ; 
 QUERY PLAN 
--------------------------------------------------------------------------------------------------------------------- 
 Aggregate (cost=0.00..0.00 rows=0 width=0) 
 -  Custom Scan (Citus Real-Time) (cost=0.00..0.00 rows=0 width=0) 
 Task Count: 128 
 Tasks Shown: One of 128 
 -  Task 
 Node: host=172.24.211.224 port=1921 dbname=postgres 
 -  Aggregate (cost=231.85..231.86 rows=1 width=8) 
 -  Seq Scan on pgbench_accounts_106812 pgbench_accounts (cost=0.00..212.48 rows=7748 width=0) 
(8 rows)

2、跑 OLTP 查询时(通常并发很高,前端有连接池(保持会话)),为会话级保持连接模式(Custom Scan (Citus Router))。

以下 SQL 为长连接模式(不会立即释放,而是等会再释放,以降低高并发时连接带来的开销)

postgres=# explain select * from pgbench_accounts where aid=5; 
 QUERY PLAN 
------------------------------------------------------------------------------------------------------------------------------------------ 
 Custom Scan (Citus Router) (cost=0.00..0.00 rows=0 width=0) 
 Task Count: 1 
 Tasks Shown: All 
 -  Task 
 Node: host=172.24.211.224 port=1921 dbname=postgres 
 -  Index Scan using pgbench_accounts_pkey_106836 on pgbench_accounts_106836 pgbench_accounts (cost=0.28..2.50 rows=1 width=97) 
 Index Cond: (aid = 5) 
(7 rows)

看以上两种场景,CITUS 应该说设计得已经很不错了。既能满足 TP 也能满足 AP。

但是前面也说了,连接保持是在事务或会话层面的,如果查询量大,或者用户使用了短连接,建立连接的开销就会很凸显。

newdb=  \c postgres postgres 
You are now connected to database  postgres  as user  postgres . 
 
postgres=# select * from pgbench_accounts where aid=1; 
 aid | bid | abalance | filler 
-----+-----+----------+-------------------------------------------------------------------------------------- 
 1 | 1 | 7214 | 
(1 row) 
 
Time: 11.264 ms --  包括新建连接的开销  
 
postgres=# select * from pgbench_accounts where aid=1; 
 aid | bid | abalance | filler 
-----+-----+----------+-------------------------------------------------------------------------------------- 
 1 | 1 | 7214 | 
(1 row) 
 
Time: 0.905 ms --  已建立连接 

使用 pgbouncer,解决建立连接的开销

在 worker 节点上,部署 pgbouncer,所有与 worker 节点建立的连接都通过 pgbouncer 连接池,以此来保持住连接,降低 worker 节点频繁新建连接的开销。

部署方法

1、所有 worker 节点

pgbouncer

yum install -y pgbouncer

配置

vi /etc/pgbouncer/pgb.ini 
 
[databases] 
newdb = host=/tmp dbname=newdb port=1921 user=digoal pool_size=128 reserve_pool=10 
[pgbouncer] 
logfile = /var/log/pgbouncer/pgbouncer.log 
pidfile = /var/run/pgbouncer/pgbouncer.pid 
listen_addr = 0.0.0.0 
listen_port = 8001 
auth_type = any 
auth_file = /etc/pgbouncer/userlist.txt 
pool_mode = session 
server_reset_query = DISCARD ALL 
max_client_conn = 5000 
default_pool_size = 128 
;  最大不要超过 4 倍 CPU 数 

启动

pgbouncer -d -u pgbouncer /etc/pgbouncer/pgb.ini

在一个 citus 集群中,可以同时存在直连 worker 或者通过 pgbouncer 连接 worker。

不同的 database 可以有不同的配置。

以下例子,新建一个 database,使用 pgbouncer 连接 worker.

2、所有节点(包括 cn, worker)

新建数据库,插件

su - postgres 
psql -c  create role digoal login;  
psql -c  create database newdb;  
psql -c  grant all on database newdb to digoal;  
psql -U postgres newdb -c  create extension citus;

cn 节点

将 worker 添加到集群配置,使用 pgbouncer 的连接端口

su - postgres -c  psql -U postgres newdb -c \ SELECT * from master_add_node(xxx.xxx.xxx.224 , 8001);\  
su - postgres -c  psql -U postgres newdb -c \ SELECT * from master_add_node(xxx.xxx.xxx.230 , 8001);\  
su - postgres -c  psql -U postgres newdb -c \ SELECT * from master_add_node(xxx.xxx.xxx.231 , 8001);\  
su - postgres -c  psql -U postgres newdb -c \ SELECT * from master_add_node(xxx.xxx.xxx.225 , 8001);\  
su - postgres -c  psql -U postgres newdb -c \ SELECT * from master_add_node(xxx.xxx.xxx.227 , 8001);\  
su - postgres -c  psql -U postgres newdb -c \ SELECT * from master_add_node(xxx.xxx.xxx.232 , 8001);\  
su - postgres -c  psql -U postgres newdb -c \ SELECT * from master_add_node(xxx.xxx.xxx.226 , 8001);\  
su - postgres -c  psql -U postgres newdb -c \ SELECT * from master_add_node(xxx.xxx.xxx.229 , 8001);\

MX 配置,同样,将 worker 节点添加到元数据同步中。

psql newdb postgres
select * from master_add_node(xxx.xxx.xxx.224 ,8001); 
select * from master_add_node(xxx.xxx.xxx.230 ,8001);

开启同步到元数据。

select start_metadata_sync_to_node(xxx.xxx.xxx.224 ,8001); 
select start_metadata_sync_to_node(xxx.xxx.xxx.230 ,8001);

测试

1、tpc-b 长连接测试

pgbench -i -s -U digoal newdb
psql -U digoal newdb 
 
select create_distributed_table( pgbench_accounts , aid  
select create_distributed_table( pgbench_branches , bid  
select create_distributed_table( pgbench_tellers , tid  
select create_distributed_table(pgbench_history , aid
pgbench -M prepared -v -r -P 1 -c 64 -j 64 -T 120 -U digoal newdb -S

性能与不使用 pgbouncer 差不多,因为使用了长连接测试简单 SQL(本身 citus 就使用了会话级连接保持,没有短连接问题)。

citus 第一次 QUERY 的隐藏耗时

在一个新建的会话中,第一次查询总是需要需要耗费更多的时间(如果没有建立连接,那么包括建立连接的时间。即使已建立连接,也需要耗费额外的一些时间)(具体原因可以跟踪分析一下 code)。

以下使用的是 pgbouncer 连接 worker,因此第一次 QUERY 不包含建立连接的时间。

newdb=  \q 
postgres@digoal-citus-gpdb-test001-  psql newdb digoal 
psql (10.5) 
Type  help  for help. 
 
\timing 
 
newdb=  select * from pgbench_accounts where aid=5; 
 aid | bid | abalance | filler 
-----+-----+----------+-------------------------------------------------------------------------------------- 
 5 | 1 | 0 | 
(1 row) 
 
Time: 6.016 ms --  不包括新建连接(已使用 pgbouncer 建立),但是也多了几毫秒  
--  但是相比未使用 pgbouncer,已经降低了 5 毫秒左右的延迟。 
newdb=  select * from pgbench_accounts where aid=5; 
 aid | bid | abalance | filler 
-----+-----+----------+-------------------------------------------------------------------------------------- 
 5 | 1 | 0 | 
(1 row) 
 
Time: 0.989 ms

多出的几毫秒,我们社区的小伙伴邓彪、王健给出了原因如下,很多地方需要检查安装的 citus 版本与 citus.control 控制文件的版本是否兼容 (比如加载分布式 TABLE 的 RELCACHE 时,第一次访问就是这个问题),不兼容报错:

详见代码

https://github.com/citusdata/citus/blob/3fa04d8f2c8f27b1377fe4c1468ee47358117e3c/src/backend/distributed/utils/metadata_cache.c

/*
 * CheckAvailableVersion compares CITUS_EXTENSIONVERSION and the currently
 * available version from the citus.control file. If they are not compatible,
 * this function logs an error with the specified elevel and returns false,
 * otherwise it returns true.
 */
CheckAvailableVersion(int elevel)
 char *availableVersion = NULL;
 if (!EnableVersionChecks)
 return true;
 availableVersion = AvailableExtensionVersion();
 if (!MajorVersionsCompatible(availableVersion, CITUS_EXTENSIONVERSION))
 ereport(elevel, (errmsg( loaded Citus library version differs from latest  
 available extension version ),
  errdetail( Loaded library requires %s, but the latest control  
   file specifies %s. , CITUS_MAJORVERSION,
  availableVersion),
  errhint( Restart the database to load the latest Citus  
   library. )));
 return false;
 return true;
 
 * AvailableExtensionVersion returns the Citus version from citus.control file. It also
 * saves the result, thus consecutive calls to CitusExtensionAvailableVersion will
 * not read the citus.control file again.
 */
static char *
AvailableExtensionVersion(void)
 ReturnSetInfo *extensionsResultSet = NULL;
 TupleTableSlot *tupleTableSlot = NULL;
 FunctionCallInfoData *fcinfo = NULL;
 FmgrInfo *flinfo = NULL;
 int argumentCount = 0;
 EState *estate = NULL;
 bool hasTuple = false;
 bool goForward = true;
 bool doCopy = false;
 char *availableExtensionVersion;
 InitializeCaches();
 estate = CreateExecutorState();
 extensionsResultSet = makeNode(ReturnSetInfo);
 extensionsResultSet- econtext = GetPerTupleExprContext(estate);
 extensionsResultSet- allowedModes = SFRM_Materialize;
 fcinfo = palloc0(sizeof(FunctionCallInfoData));
 flinfo = palloc0(sizeof(FmgrInfo));
 fmgr_info(F_PG_AVAILABLE_EXTENSIONS, flinfo);
 InitFunctionCallInfoData(*fcinfo, flinfo, argumentCount, InvalidOid, NULL,
  (Node *) extensionsResultSet);
 /* pg_available_extensions returns result set containing all available extensions */
 (*pg_available_extensions)(fcinfo);
 tupleTableSlot = MakeSingleTupleTableSlot(extensionsResultSet- setDesc);
 hasTuple = tuplestore_gettupleslot(extensionsResultSet- setResult, goForward, doCopy,
  tupleTableSlot);
 while (hasTuple)
 Datum extensionNameDatum = 0;
 char *extensionName = NULL;
 bool isNull = false;
 extensionNameDatum = slot_getattr(tupleTableSlot, 1,  isNull);
 extensionName = NameStr(*DatumGetName(extensionNameDatum));
 if (strcmp(extensionName,  citus) == 0)
 MemoryContext oldMemoryContext = NULL;
 Datum availableVersion = slot_getattr(tupleTableSlot, 2,  isNull);
 /* we will cache the result of citus version to prevent catalog access */
 oldMemoryContext = MemoryContextSwitchTo(CacheMemoryContext);
 availableExtensionVersion = text_to_cstring(DatumGetTextPP(availableVersion));
 MemoryContextSwitchTo(oldMemoryContext);
 ExecClearTuple(tupleTableSlot);
 ExecDropSingleTupleTableSlot(tupleTableSlot);
 return availableExtensionVersion;
 ExecClearTuple(tupleTableSlot);
 hasTuple = tuplestore_gettupleslot(extensionsResultSet- setResult, goForward,
  doCopy, tupleTableSlot);
 ExecDropSingleTupleTableSlot(tupleTableSlot);
 ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 errmsg(citus extension is not found)));
 return NULL;
}

pgbouncer 连接池连接 worker 的好处

1、对于业务层短连接会有比较好的效果。可以降低至少 5 毫秒左右的延迟。

2、对于大量复杂查询(需要 motion 的查询),可以减少节点间的连接数。

“PostgreSQL 中 citus 节点间的网络需求有哪些”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注丸趣 TV 网站,丸趣 TV 小编将为大家输出更多高质量的实用文章!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-20发表,共计10106字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)