GaussDB(DWS)中共享消息隊列實現的三大功能


摘要:本文將詳細介紹GaussDB(DWS)中共享消息隊列的實現。

本文分享自華為雲社區《GaussDB(DWS)CBB組件之共享消息隊列介紹》,作者:瘋狂朔朔。

1)共享消息隊列是什么?

在前文中,我們講解了SysCache的實現原理,GaussDB(DWS)通過SysCache緩存表元數據,以加速查詢,然而在並發查詢過程中,不可避免地會出現需要同步元數據的情況,舉個簡單例子,假設存在以下語句執行流程:

  1. Create table abc(會話1)
  2. Select * from abc(會話1)
  3. Drop table abc(會話2)
  4. Select * from abc(會話1)

在會話1中,會連續兩次執行Select表操作(b和d),在b語句執行后,會話1將對abc的元數據進行緩存,緩存到SysCache中,以備后續使用。然而,在c語句執行后,需要對會話1中的元數據進行失效,否則,會話1將在執行d語句過程中發生錯誤,讀取已刪除的數據。

那么,會話2如何“通知”會話1失效哪些數據呢?答案是共享消息隊列。

2)共享消息隊列存儲結構

如圖所示,為共享消息隊列數據結構

圖示中主要包括兩部分,下面部分為ThreadLocal結構,主要記錄的是每個線程內部的數據,線程間數據是獨立的,無法互相訪問,上面部分為共享消息隊列中的數據,共享消息隊列存在於共享內存中,可同時被多個線程訪問,共享消息隊列的訪問場景是典型的一寫多讀場景。

在共享消息隊列中,核心變量有三個,nextMsgNum、minMsgNum、MaxMsgNum,其中nextMsgNum記錄了每個線程消息讀取到的位置,minMsgNum記錄了共享消息隊列中最早消息的位置,maxMsgNum記錄了共享消息隊列中最新消息的位置,對於每個線程而言,需要定期(在表加鎖/事務開始/收到信號時觸發)從共享消息隊列中讀取失效消息,利用失效消息(共享消息隊列中的每個消息)更新線程內部數據,同時,若線程內部產生失效消息(通常DDL語句在事務提交時產生大量失效消息),則需要向共享消息隊列中插入失效數據,供其他線程讀取。另外,還有兩個參數,hasMessages、resetState,其中hasMessages用於標記對應線程是否存在未讀取的失效消息,resetState用於標記對應線程是否需要失效全部消息。

NOTE:失效數據有哪些?失效消息一共有六類(源自PG),有興趣的同學可以研讀PG源碼,在此處我們不再展開,僅需知道線程需要從共享消息隊列中讀取/插入消息,以實現數據同步。

3)共享消息隊列接口實現

共享消息隊列本質上對於外部接口只需要提供三個功能:讀取共享消息隊列中消息、向共享消息隊列中寫入消息、清理共享消息隊列。

3.1)讀取共享消息隊列

如圖所示,為失效消息讀取過程。在線程同步失效消息過程中,有幾個關鍵點:

  • 若共享內存中線程對應的hasMessage為True,則表示有失效消息需要讀取,否則直接返回,無新的失效消息。
  • 讀取失效消息過程中,需要持有讀共享鎖,以保證讀取的消息不會被清理掉。
  • 若讀取失效消息過程中,發現resetState被置為True,說明該線程已經無法使用共享消息隊列中的消息進行追增,需要對緩存進行全失效。緩存全失效相當於追增全部數據,需要將nextMsgNum置為maxMsgNum。緩存全失效將嚴重降低SQL執行性能,盡量減少緩存全失效的發生頻率。
  • 在追增數據過程中,會推進線程自身的nextMsgNum,以標記數據追增位置。

NOTE:在讀取共享消息隊列過程中,每個線程推進自己的nextMsgNum位置,以方便記錄數據追增情況。

3.2)向共享消息隊列中寫入消息

如圖所示,為失效消息寫入過程。有以下幾個關鍵點:

  • 寫入失效消息過程,需要調用清理共享消息隊列接口,以保證有足夠多的空位寫入失效消息。
  • 在寫入失效消息過程中,會更新maxMsgNum。
  • 寫入失效消息完畢以后,需要將其他線程的hasMessage標記為True。
  • 寫入失效消息過程,需要持排他寫鎖,阻塞其他線程寫操作,但不阻塞讀。

NOTE:寫入失效消息過程實際上是推進maxMsgNum的過程,同時告知其他線程有新的失效消息需要讀取。

3.3)清理共享消息隊列

如圖所示,清理共享消息隊列過程中,有以下幾個關鍵點:

  • 清理共享消息隊列需要持有排他讀鎖和排他寫鎖,阻塞讀過程。其主要原因是,清理共享消息隊列會推進minMsgNum,若不持讀鎖,可能導致nextMsgNum讀取過期數據。
  • 清理共享消息隊列會推進minMsgNum。
  • 清理共享消息隊列過程,會將所有沒有及時追增失效消息的線程執行全失效。
  • 在清理共享消息隊列最后步驟,會對距離minMsgNum最近的線程,發送追增信號,以確保不會頻繁發生全失效。該步驟主要考慮的情況是,若線程長時間處於idle狀態,需要外部信號觸發其及時追增消息。

NOTE:清理共享消息隊列過程,實際上是推進minMsgNum的過程,同時對所有沒有及時追增失效消息的線程執行全失效。

根據以上共享消息隊列接口可知,讀取共享消息隊列主要負責推進各個線程自身的nextMsgNum;寫入失效消息主要負責推進maxMsgNum;清理共享消息隊列主要負責推進minMsgNum。通過共享消息隊列,可有效實現各個線程之間的數據同步。

 

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM