Libcomm通訊庫:GaussDB(DWS) 為解決建聯過多的小妙招

华为云开发者联盟發表於2024-03-12

本文分享自華為雲社群《GaussDB(DWS) 叢集通訊系列三:Libcomm通訊庫》,作者: 半島裡有個小鐵盒。

1.前言

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

在大規模叢集、高併發業務下,如果有1000DN叢集,每個stream執行緒需要建立1000個連線。如果1000 stream併發,DN總共需要建立100萬個連線,會消耗大量的連線、記憶體、fd資源。為了解決這個問題,我們引入了Libcomm通訊庫,在一個物理長連線上模擬n個邏輯連線,使得所有併發的資料跑在一個物理連線上,極大的解決了物理連線數過多和建連耗時的問題。

2.基本原理

GaussDB(DWS)為解決建聯過多的問題,實現了Libcomm通訊庫(即邏輯連線通訊庫),在一個物理長連線上模擬n個邏輯連線,使得所有併發的資料跑在一個物理連線上。比如DN1需要給DN2傳送資料,併發數1000,在原有邏輯下,DN1需要建立與DN2連線的1000個執行緒與之進行互動,消耗了大量的連線、記憶體、fd資源,而改造Libcomm通訊庫之後,DN1與DN2僅需建立一個真正的物理連線,在這個物理連線上可以建立很多個邏輯連結,這樣可以使得1000個併發就可以用同一個物理連線進行資料互動。

那麼GaussDB(DWS)的邏輯連線是怎麼實現的呢?首先我們從連線資料流入手,挖掘其實現邏輯。

物理連線支援TCP、RDMA等協議連線,以TCP為例,其物理連線資料流可以分為兩部分,即資料包頭+資料。資料包頭為固定長度,其中包含邏輯連線號和資料塊長度,用來區別邏輯連線,並接收每個連線各自對應的資料。

瞭解了物理連線傳送的資料流,那具體的傳送邏輯是什麼樣的呢?其具體的流程如下圖所示:

上圖中producer執行緒為傳送執行緒,consumer執行緒為接收執行緒,傳送端邏輯如下:

  1. send queue:producer傳送執行緒將要傳送的資料先push到一個無鎖佇列中,push完成之後,producer執行緒就可以繼續做自己的事情了
  2. send proxy thread:通訊存在一個傳送端代理執行緒,會統一將無鎖佇列中的資料,透過物理連線傳送到對端

接收端邏輯如下:

  1. receive proxy thread:通訊存在一個接收端代理執行緒,會統一將無鎖佇列中的資料,透過物理連線接收回來,解析資料包頭之後,放到對應執行緒的buffer池中
  2. buffer1:consumer接收執行緒會從自己對應的buffer池中取出資料,執行自己的資料加工邏輯。

上述這個方法可能會存在一些問題,併發比較高時producer執行緒會一直往佇列裡push,如果此時對端cunsumer1執行緒正在處理別的資料導致接收buffer1滿了的話,producer2和producer3無法往網路上填充更多的資料,傳送階段就會阻塞,而此時可能consumer2和consumer3正在空閒狀態,等待這個接收資料,但是因為傳送端阻塞而接收不到,這種場景會嚴重影響效能。這個模型我們稱之為push模型。因此我們需要透過另外一種流控機制來解決這個問題,我們稱之為pull模型。

  • push模型:傳送端不感知接收端狀態。一直往無鎖佇列中push,直到push阻塞。
  • poll模型:傳送端感知接收端狀態。傳送端一開始不會傳送資料,當接收端裡的buffer池記憶體滿足一定條件時,通知對應的傳送端,並告知可以接收的資料量,傳送端可以按照對端可以接收的資料量進行傳送。

透過poll模型的實現,在本執行緒阻塞的情況下,其他的執行緒不會阻塞,以確保物理連線中資料永遠不會阻塞,保證連線的通暢性。

3.相關檢視

3.1.pgxc_comm_delay

該檢視展示所有DN的通訊庫時延狀態。

該檢視中的欄位包括節點名稱、連線對端節點的節點名稱、連線對端IP的對端地址、當前物理連線使用的stream邏輯連線數量、當前物理連線一分鐘內探測到的最小時延、當前物理連線一分鐘內探測道德平均值和當前物理連線一分鐘內探測到的最大時延。

img

3.2.pgxc_comm_recv_stream

該檢視展示所有DN上的通訊庫接收流狀態。其中欄位包括節點名稱、使用此通訊流的執行緒ID、連線對端節點名稱、連線對端節點ID、通訊對端DN在本DN內的標識編號、通訊流在物理連線中的標識編號、通訊流所使用的tpc通訊socket、通訊流當前的狀態、通訊流對應的debug_query_id編號、通訊流所執行查詢的plan_node_id編號、通訊流所執行查詢send端的smpid編號、通訊流所執行查詢recv端的smpid編號、通訊流接收的資料總量、通訊流當前生命週期使用時長、通訊流的平均接收速率、通訊流當前的通訊配額值、通訊流當前快取的資料大小。

img

3.3.pgxc_comm_send_stream

該檢視展示所有DN上的通訊庫傳送流狀態。其中欄位包括節點名稱、使用此通訊流的執行緒ID、連線對端節點名稱、連線對端節點ID、通訊對端DN在本DN內的標識編號、通訊流在物理連線中的標識編號、通訊流所使用的tpc通訊socket、通訊流當前的狀態、通訊流對應的debug_query_id編號、通訊流所執行查詢的plan_node_id編號、通訊流所執行查詢send端的smpid編號、通訊流所執行查詢recv端的smpid編號、通訊流接收的資料總量、通訊流當前生命週期使用時長、通訊流的平均接收速率、通訊流當前的通訊配額值和通訊流等待quota值產生的額外時間開銷。

img

3.4.pgxc_comm_status

該檢視展示所有DN的通訊庫狀態。其中欄位包括節點名稱、節點通訊庫接收速率,單位為byte/s、節點通訊庫傳送速率,單位為byte/s、節點通訊庫接收速率,單位為Kbyte/s、節點通訊庫傳送速率,單位為Kbyte/s、cmailbox的buffer大小、libcomm程序通訊記憶體的大小、libpq程序通訊記憶體的大小、postmaster執行緒實時使用率、gs_sender_flow_controller執行緒實時使用率、gs_receiver_flow_controller執行緒實時使用率、多個gs_receivers_loop執行緒中最高的實時使用率、當前使用的邏輯連線總數。

img

4.相關GUC引數

4.1 comm_max_datanode

表示TCP代理通訊庫支援的最大DN數,最小值為1,最大值為8192。當DN數小於256時,預設值為256;否則,為大於等於DN數的2的N次方。在叢集擴容、縮容場景下,要注意此引數的變更。

4.2 comm_max_stream

表示TCP代理通訊庫支援的最大併發stream數量,預設值為1024,最大為60000,此引數要保證大於併發數

每併發平均stream運算元數

(smp的平方),否則會報錯Cannot get stream index, maybe comm_max_stream is not enough。此外,在設定此引數時需要考慮佔用記憶體問題,其大小為256byte * comm_max_stream * comm_max_datanode,可見在記憶體、comm_max_datanode和comm_max_stream三者之間需要一個動態的規劃。

針對comm_max_stream不足問題,可以考慮三種解決方案:

新版本直接使用pgxc_comm_status檢視檢視DN的stream使用情況:select node_name, stream from pgxc_comm_status order by 2 desc;

img

在CN上查詢當前任意兩個DN之間的stream情況:select node_name, remote_name, count(*) as stream from pgxc_comm_send_stream group by 1, 2 order by 3 desc limit 30;

img

若當前業務恢復, 可使用指令碼對stream進行監控;

然而,還有情況是個別的SQL語句嚴重消耗stream,此時可以使用實時topsql或歷史topsql找到對應的語句,修改以解決問題。

4.3 comm_max_receiver

表示TCP代理通訊庫接收端接收執行緒的數量,最大值為50,預設值為4。在大叢集、大併發場景下,適當的調大該引數有利於提升查詢的效能;但如果通訊層可用記憶體不足,執行緒間有競爭會對接收效能有負面影響。

注:SMP是指對稱多處理技術,資料庫領域的SMP並行技術一般指利用多執行緒技術實現查詢的並行執行,以充分利用CPU資源,從而提升查詢效能。SMP特性透過運算元並行來提升效能,同時會佔用更多的系統資源,在使用時,需要根據使用場景與限制進行合理的配置。在GaussDB中,SMP功能由query_dop引數決定,預設值為1。

4.4 comm_cn_dn_logic_conn

對於256節點的叢集來說,併發場景導致CN和DN之間存在大量連線,每個連線佔用一個埠,則CN的埠號很容易受限。為解決此問題,設計了CN多流,即CN與DN之間採用邏輯連線。comm_cn_dn_logic_conn引數預設值是off,在叢集規模或併發達到一定程度時,需要將其開啟為on,避免CN與DN之間由於埠號受限而無法建連。

4.5 comm_quota_size

TCP代理通訊庫採用pull模式進行流量控制,避免訊息堵塞。兩個DN分別有一個buffer,當一條通道傳送端資料量過大時,很容易造成buffer填滿,阻塞了其他通道的傳送。此時,對於每條通道設定一個quota,接收端根據buffer剩餘空間的大小傳送給傳送端一個合理quota值,傳送端根據quota大小傳送資料。

comm_quota_size表示每個通道單次不間斷髮送資料量配額,預設值1MB。當通道傳送資料量達到配額時,傳送端等待接收端重新傳送配額,進而繼續傳送資料,從而實現流控功能。其取值為0時,表示不使用quota,在一些大流量等場景中,查詢之間可能會有影響。在1GE網路卡環境中,受網路卡能力限制,應該調小該引數,推薦20KB~40KB。如果環境記憶體充足,引數comm_usable_memory設定較大,可以適當調大,從而提升效能。

4.6 comm_usable_memory

commusable_memory表示的是TCP代理通訊庫可使用的最大記憶體大小,預設值4000MB。此引數需要根據環境記憶體及部署方式具體配置,保證了系統不會因為通訊層接收快取造成程序記憶體膨脹。在單臺機器上,通訊佔用記憶體最壞情況=部署節點個數* comm_usable_memory。考慮環境記憶體情況,此引數配置過小,會影響通訊效能,過大則可能造成系統記憶體不足等問題。與comm_quota_size結合,進行合理的配置至關重要。

5.總結

本文詳細介紹了Libcomm通訊庫及其原理,讓我們更好的理解GaussDB(DWS)叢集通訊中的具體邏輯,對於GaussDB(DWS)通訊運維也具備一定的參考意義。

6.參考連線

  1. GaussDB重要通訊引數彙總:https://bbs.huaweicloud.com/blogs/239863
  2. 【帶你走進DWS大叢集內幕】大叢集通訊:作業hang、殘留問題定位:https://bbs.huaweicloud.com/blogs/407719
  3. GaussDB(DWS) 叢集通訊系列三:叢集通訊常用檢視:https://bbs.huaweicloud.com/blogs/209112
  4. GaussDB(DWS)通訊庫libpq重構介紹(一):https://bbs.huaweicloud.com/blogs/289336
  5. GaussDB(DWS)通訊庫libpq重構介紹(二):https://bbs.huaweicloud.com/blogs/297955

點選關注,第一時間瞭解華為雲新鮮技術~

相關文章