共計(jì) 10106 個(gè)字符,預(yù)計(jì)需要花費(fèi) 26 分鐘才能閱讀完成。
本篇內(nèi)容介紹了“PostgreSQL 中 citus 節(jié)點(diǎn)間的網(wǎng)絡(luò)需求有哪些”的有關(guān)知識(shí),在實(shí)際案例的操作過程中,不少人都會(huì)遇到這樣的困境,接下來就讓丸趣 TV 小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
背景
citus 節(jié)點(diǎn)間的網(wǎng)絡(luò)需求:
1、cn 節(jié)點(diǎn)訪問所有 worker 節(jié)點(diǎn)。oltp 業(yè)務(wù)的訪問較頻繁。
2、重分布數(shù)據(jù)時(shí),worker 節(jié)點(diǎn)間相互訪問。訪問頻度不大,OLAP 業(yè)務(wù)常見,一旦有可能數(shù)據(jù)交換吞吐較大。
citus 的 cn 節(jié)點(diǎn)連 worker 節(jié)點(diǎn)為有兩種模式,
一種為事務(wù)級(jí)保持連接模式(每條 SQL 發(fā)起時(shí)建立連接,SQL 結(jié)束后釋放連接 (除非在事務(wù)中,否則 SQL 結(jié)束立即釋放連接)。),
另一種為會(huì)話級(jí)保持連接模式(會(huì)話發(fā)起時(shí)建立連接,會(huì)話結(jié)束后釋放連接。)。
1、跑 OLAP 類的 SQL 時(shí),使用的是第一種即時(shí)連接模式(OLAP 場(chǎng)景并發(fā)不高,建立連接帶來的額外開銷不明顯)
可以在 worker 節(jié)點(diǎn)打開參數(shù)進(jìn)行跟蹤
postgres=# show log_connections ;
log_connections
-----------------
on
(1 row)
postgres=# show log_disconnections ;
log_disconnections
--------------------
on
(1 row)
例子,
以下兩條 SQL 均為即時(shí)短連接模式 (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 查詢時(shí)(通常并發(fā)很高,前端有連接池(保持會(huì)話)),為會(huì)話級(jí)保持連接模式(Custom Scan (Citus Router))。
以下 SQL 為長連接模式(不會(huì)立即釋放,而是等會(huì)再釋放,以降低高并發(fā)時(shí)連接帶來的開銷)
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)
看以上兩種場(chǎng)景,CITUS 應(yīng)該說設(shè)計(jì)得已經(jīng)很不錯(cuò)了。既能滿足 TP 也能滿足 AP。
但是前面也說了,連接保持是在事務(wù)或會(huì)話層面的,如果查詢量大,或者用戶使用了短連接,建立連接的開銷就會(huì)很凸顯。
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 節(jié)點(diǎn)上,部署 pgbouncer,所有與 worker 節(jié)點(diǎn)建立的連接都通過 pgbouncer 連接池,以此來保持住連接,降低 worker 節(jié)點(diǎn)頻繁新建連接的開銷。
部署方法
1、所有 worker 節(jié)點(diǎn)
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 數(shù)
啟動(dòng)
pgbouncer -d -u pgbouncer /etc/pgbouncer/pgb.ini
在一個(gè) citus 集群中,可以同時(shí)存在直連 worker 或者通過 pgbouncer 連接 worker。
不同的 database 可以有不同的配置。
以下例子,新建一個(gè) database,使用 pgbouncer 連接 worker.
2、所有節(jié)點(diǎn)(包括 cn, worker)
新建數(shù)據(jù)庫,插件
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 節(jié)點(diǎn)
將 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 節(jié)點(diǎn)添加到元數(shù)據(jù)同步中。
psql newdb postgres
select * from master_add_node(xxx.xxx.xxx.224 ,8001);
select * from master_add_node(xxx.xxx.xxx.230 ,8001);
開啟同步到元數(shù)據(jù)。
select start_metadata_sync_to_node(xxx.xxx.xxx.224 ,8001);
select start_metadata_sync_to_node(xxx.xxx.xxx.230 ,8001);
測(cè)試
1、tpc-b 長連接測(cè)試
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 差不多,因?yàn)槭褂昧碎L連接測(cè)試簡(jiǎn)單 SQL(本身 citus 就使用了會(huì)話級(jí)連接保持,沒有短連接問題)。
citus 第一次 QUERY 的隱藏耗時(shí)
在一個(gè)新建的會(huì)話中,第一次查詢總是需要需要耗費(fèi)更多的時(shí)間(如果沒有建立連接,那么包括建立連接的時(shí)間。即使已建立連接,也需要耗費(fèi)額外的一些時(shí)間)(具體原因可以跟蹤分析一下 code)。
以下使用的是 pgbouncer 連接 worker,因此第一次 QUERY 不包含建立連接的時(shí)間。
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,已經(jīng)降低了 5 毫秒左右的延遲。
newdb= select * from pgbench_accounts where aid=5;
aid | bid | abalance | filler
-----+-----+----------+--------------------------------------------------------------------------------------
5 | 1 | 0 |
(1 row)
Time: 0.989 ms
多出的幾毫秒,我們社區(qū)的小伙伴鄧彪、王健給出了原因如下,很多地方需要檢查安裝的 citus 版本與 citus.control 控制文件的版本是否兼容 (比如加載分布式 TABLE 的 RELCACHE 時(shí),第一次訪問就是這個(gè)問題),不兼容報(bào)錯(cuò):
詳見代碼
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、對(duì)于業(yè)務(wù)層短連接會(huì)有比較好的效果。可以降低至少 5 毫秒左右的延遲。
2、對(duì)于大量復(fù)雜查詢(需要 motion 的查詢),可以減少節(jié)點(diǎn)間的連接數(shù)。
“PostgreSQL 中 citus 節(jié)點(diǎn)間的網(wǎng)絡(luò)需求有哪些”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注丸趣 TV 網(wǎng)站,丸趣 TV 小編將為大家輸出更多高質(zhì)量的實(shí)用文章!