大數據“復活”記
707
2025-04-02
GaussDB(DWS)在并發執行DDL過程中,會涉及元數據失效的問題,那么語句執行線程如何及時通知其他線程元數據失效呢?答案是共享消息隊列。
共享消息隊列主要用于存儲失效消息,當線程執行DDL后,會將本地的失效消息提交到到共享消息隊列中,并通知其他線程處理元數據失效。在本文中,將詳細說明共享消息隊列實現機制。在后續講解過程中,如果各位看官有任何問題或者編寫不正確的地方,歡迎留言討論!
1)共享消息隊列是什么?
在前文中,我們講解了SysCache的實現原理,GaussDB(DWS)通過SysCache緩存表元數據,以加速查詢,然而在并發查詢過程中,不可避免地會出現需要同步元數據的情況,舉個簡單例子,假設存在以下語句執行流程:
Create table abc(會話1)
Select * from abc(會話1)
Drop table abc(會話2)
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。通過共享消息隊列,可有效實現各個線程之間的數據同步。
EI企業智能 Gauss AP 數據倉庫服務 GaussDB(DWS)
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。