【摘要】從發展歷程到通訊模型設計,到你瞭解一下GaussDB通訊原理知識。
MPPDB通訊庫發展歷程1、Postgres-XC
方法:採用libpq通訊庫實現CN和DN之間的連線,CN負責計算,DN僅進行資料儲存。
缺點:隨著計算任務的不斷增大,CN計算出現瓶頸,且白白浪費DN的計算能力。
2、V1R3
方法:提出分散式執行框架,將計算下推到DN上執行,DN不僅作為儲存同時承擔計算任務。由於每個DN只儲存有一部分資料,因此DN間也需要進行通訊,採用stream執行緒TCP直連,每個連線都需要一個TCP埠。
缺點:隨著叢集規模的增加,DN之間的連線數不斷增加,在大併發場景下需要大量的TCP埠,而實際情況是由於單機TCP埠只有65535個,TCP埠數嚴重限制了資料庫的叢集規模和併發規模。
3、V1R5-V1R7C00
方法:結合SCTP協議的多流優點,DN間的通訊採用SCTP通訊庫架構,使用邏輯連線來代替物理連線,用來解決DN之間連線太多的問題。
缺點:SCTP協議本身存在的核心BUG,通訊報錯。
4、V1R7C10
方法:TCP代理通訊庫。
缺點:CN和DN之間的物理連線數也會暴漲。
5、V1R8C00
方法:CN和DN之間也採用邏輯連線實現,即CN多流。
問題1:DN間是查詢結果的通訊還是原始資料的通訊?
解:既有查詢結果,也有原始資料;DN之間的資料交流是Hash之後,各個DN根據所需獲取。
通訊模型的設計1、Pooler通訊模型
問題2:連線池上的CN、DN是否存在交集,即poolA中的DN在poolB中也存在?
解:不存在。
問題3:CN和CN的連線是做什麼的?為什麼設計連線池連線CN上的PG執行緒?CN上為什麼有多個PG執行緒,有什麼用途?
解:CN和CN之間連線是為了資料同步等,包括建表之後的資訊交匯。CN上的PG執行緒也是為了使用者查詢建立。
問題4:DN上為什麼有多個PG執行緒,有什麼用途?
解:一個查詢操作就是建立一個新的PG執行緒。
問題5:如何理解gsql客戶端退出時,只退出PG執行緒和agent代理執行緒,而取到的slot連線會還回database pool?
解:slot連線退回到pooler,下次連線可以直接獲取,若不存在,則重新建立。
問題6:DN間的TCP連線數:C = (H * D * Q * S)* D,為什麼最後乘以D,而不是(D - 1)/ 2 ? 此外,這個公式是否存在高重複,每次查詢都要建立DN間的通訊,而不考慮重複性?DN間的通訊執行緒數量是否有限制?
解:資料是雙向通訊,但執行運算元是單向的,所以不能除以2。數量有限制,但可以調整。
2、DN間stream執行緒通訊模型
執行計劃需要使用多個執行緒進行執行,包括1個CN執行緒和每個DN上3個執行緒t1-t3。每個DN節點都有3個執行緒是因為資料是分佈到每個DN上的,在執行查詢過程中,查詢的每個階段每個DN都要參與。
自下而上是資料流,自上而下是控制流。具體執行過程如下:
每個DN的t3順序掃描table表,將表資料廣播到所有DN的t2執行緒;每個DN的t2接收t3的資料,建立hash表,然後掃描store_sales資料與customer表進行hashjoin,join結果進行雜湊聚集後,重分佈傳送到對應DN的t1執行緒;每個DN的t1執行緒將收到的資料進行第二次雜湊聚集, 排序後將結果傳輸到CN;CN收集所有DN的返回資料,作為結果集返回。問題7:DN上是否執行查詢操作?DN廣播的資料是否屬於同一個資料表?每個DN都廣播資料,那最後所有DN的資料是否相同?圖中t2傳送給所有DN的t1?
解:執行,DN上存的資料是表的幾分之幾,不是整個表,也不是一個表的部分,是所有表的一部分,這樣做是為了併發。DN資料不相同,因為各取所需。
SCTP通訊庫設計1、概要
SCTP 協議:一種可靠、保序協議,支援message-based模式,單個通道支援65535個流,且多流之間互不阻塞,利用該特性,可以打破裝置物理連線數對大規模叢集節點間通訊的限制,支援更大規模的節點規模。通道共享:每兩個節點之間有一個數據傳輸單向SCTP物理通道,在這條物理通道內部有很多邏輯通道(inner Stream),每個stream流由producer傳送到consumer,利用SCTP內部支援多流的特性,不同的producer & consumer對使用通道中不同的流(SCTP流),因此每兩個點之間僅需要兩個資料連線通道。通道複用:查詢完成後,物理通道中的邏輯連線關閉,物理連線不關閉,後面的查詢繼續使用建好的物理連線。流量控制:採用pull模式,因為SCTP通道的所有流共享核心的socket buffer, 為了避免一個連線發的資料量過大,consumer端卻不接收,導致kernel的buffer被填滿,阻塞了其他流的傳送,增加了流控,給每個流設定一個quota, 由接收端分配,當有quota時,告知傳送端可傳送資料,傳送端根據發來的quota值,傳送quota大小的資料量,實現接收端與傳送端同步控制;為了保證控制資訊的可靠性,將控制資訊和資料通道分離,流控資訊走單獨的一條雙向TCP控制通道。2、架構
TCP Channels:TCP控制通道,控制流走此通道;SCTP Channels:SCTP資料通道,包含很多stream流,資料流走此通道;Send Controller傳送端流控執行緒:gs_senders_flow_controller(),收發控制訊息;Recv Controller接收端流控執行緒:gs_receivers_flow_controller(),接收端用於傳送和接收控制報文,與代理接收執行緒不同,代理接收執行緒接收的是資料,而接收流控執行緒接收的是報文;Receiver代理接收執行緒:gs_receivers_loop(),用於接收資料的執行緒,從sctp資料通道中接收資料,將資料放到不同邏輯連線的不同cmailbox報箱中,並通知執行層的consumer工作執行緒來取,取走後,有空閒的buffer時,接收端流控執行緒會透過tcp控制通道通知傳送端還有多少空閒記憶體,即還有多少quota可用於繼續接收資料;Auxiliary輔助執行緒:gs_auxiliary(),由top consumer,每個兩秒檢查一下,處理公共事務,如DFX訊息,Cancel訊號響應等;資料PULL模型:每個邏輯連線有quota大小的buffer,需要資料時將空閒buffer的大小(即quota)傳送給傳送端,傳送端即可以傳送quota大小的資料,quota不足時阻塞傳送,直到接收端的buffer被應用取走。TCP多流實現TCP代理在現有的邏輯連線、代理分發、quota流控等實現的基礎上,將資料通道從SCTP協議替換成TCP協議,TCP代理邏輯連線的實現基於head+data的資料包收發模型,在head中寫入邏輯連線id及後續data的長度。
問題8:單機TCP只有65535個埠,SCTP呢?TCP多流和TCP在埠上的區別?TCP的三次握手是否依舊?
SCTP是基於訊息流傳輸,資料收發的最小單位是訊息包(chunk),一個SCTP連線(Association)同時可以支援多個流(stream),每個流包含一系列使用者所需的訊息資料(chunk)。而TCP協議本身只能支援一個流,因此我們需要在這一個流中區分不同邏輯連線的資料,透過在TCP報文的head中寫入邏輯連線id及後續data的長度來區分,這樣雖然TCP只有一個數據包組成,但每個資料包包含多個塊,實現了TCP的多流。同時傳送時需保證整包原子傳送。
問題9:如何多流?是多個通道同時傳送head+data嗎?
解:一個流傳送完整的資料。多流是併發。
TCP代理通訊庫的傳送端實現,producerA和producerB分別給DN1傳送資料,為保證傳送端head+data傳送的完整性,producerA首先需要對單個物理連加鎖,此時producerB處於等鎖狀態,producerA將資料完整發送到本地協議棧後返回,並釋放鎖,producerB獲得鎖後傳送資料。節點數越多衝突越少。
問題10:加鎖等待是否影響效率?SCTP的實現也是如此?
解:不影響,因為有快取buffer。
問題11:資料丟失,永遠無法達到head怎麼辦?一直快取?
解:不會丟失,TCP協議有保證。
CN多流實現在V1R8C00版本中,CN和DN之間的連結使用libcomm通訊庫,即兩個節點間僅存在一條物理通道,在該物理通道上使用邏輯連線通道實現並行通訊。
1、CN端流程:
建立連線:CN呼叫Libcomm的gs_connect與DN建立連線,入參中指明建立雙向邏輯通道,使用相同的nidx,sidx同時初始化傳送和接受的mailbox,透過傳送流控執行緒通知接收端;等待DN返回結果:透過判斷髮送mailbox的狀態,確認DN端已成功建立的邏輯連線(傳送流控執行緒收到DN端的CTRL_READY報文);傳送startuppacket:透過PQbuildPGconn,初始化libpq的pg_conn結構體,生成startuppacket,隨後透過gs_send傳送startuppacket給DN端;等待DN PG執行緒初始化:透過LIBCOMMgetResult,等待DN端返回ready for query報文,之後認為連線建立成功。2、DN端流程:
初始化傳送、接收mailbox:DN端接收流控執行緒識別到連線請求來自CN後,呼叫gs_build_reply_conntion,註冊CN的資訊,初始化傳送mailbox,隨後初始化接收mailbox,最終透過流控執行緒返回CTRL_READY報文,表示邏輯通道建立成功;建立unix domain sock:DN端接收流控執行緒,建立一個unix domain sock,將生成的邏輯連線地址透過該通道發給postmaster主執行緒;fork postgres子執行緒:postmaster主執行緒的serverloop監聽到unix domain sock後,接收邏輯連線地址,儲存到port結構體中,隨後fork postgres子執行緒(沿用原有邏輯);postgres執行緒初始化完畢:在pg執行緒完成初始化後,首先給CN回覆ready for query報文,隨後進入ReadCommand函式,等待CN發來的下一個Query。