GitLab在去年6月的時候,發現GitLab.com出現不尋常的停頓,經過調查才知道,在資料庫PostgreSQL中,透過SAVEPOINT SQL查詢起始子交易,則正在進行中的長交易(Long Transaction),有可能會對資料庫的副本產生嚴重效能衝擊。

之所以會發現這個問題,是GitLab觀察到CI/CD Runner服務偶而會出現高錯誤率,用來檢索CI/CD建置資料的資料庫查詢發生超時的狀況,並且未處理的建置積壓迅速成長。

而這個問題難以調查的程度,官方將其稱之為Nessie,意思是這個問題就像是尼斯湖水怪一樣,無法預測出現的時機。官方提到,資料庫查詢停滯的情況隨機出現,而且停頓可能持續15分鐘後就消失,幾天後才會再出現。

資料庫停頓伴隨一些模式,GitLab發現只有資料庫副本會受到影響,主要資料庫運作正常,在發生停頓期間,通常有一個長時間執行的交易正在進行,通常和PostgreSQL自動清理有關,只要長交易結束,停頓也會迅速停止。經過了長時間的調查,以及諸多假設與驗證,GitLab終於發現並且能夠重現這個問題。

官方稱這個問題為Subtrans SLRU溢位,肇因是忙碌的資料庫,可能使子交易日誌的大小,龐大到工作集無法存在記憶體中,這將導致大量快取未命中,進而造成大量磁碟I/O和CPU負載,因為PostgreSQL會瘋狂地嘗試從磁碟中載入資料,以符合查詢使用。官方提到,只要在長交易間,有一個SAVEPOINT出現,就會造成這個問題。

在PostgreSQL中,交易從 BEGIN語句啟動,而SAVEPOINT則是開始子交易,官方舉例解釋需要使用SAVEPOINT的理由,當消費者在線上商店下訂單,意外地同時有兩筆訂單抵達資料庫,要讓資料庫不因為重複建立帳戶,導致其中一筆訂單失敗,而是希望可以在訂單直接使用該帳戶,開發者便能以SAVEPOINT來進行子交易,先進行查詢,使用剛剛建立的帳戶並且完成訂單。

要解決Nessie資料庫停頓問題有三個選擇,完全消除SAVEPOINT的呼叫、消除所有長時間執行的交易,或是在PostgreSQL加入應急修補程式。GitLab先選擇方案一,消除SAVEPOINT的呼叫來解決這個問題。官方提到,消除資料庫的長交易不切實際,而且許多長交易是資料庫的自動清理,要從這方面下手,需要花費過多的時間精力。

而官方同時也在考慮對PostgreSQL安裝修補程式,但是安裝修補程式有許多需要考量的點。修補程式雖然能夠藉由增加快取到100 MB,來解決SAVEPOINT的問題,但是快取達100 MB,會讓搜尋成本變高。

問題不只如此,當使用了應急修補程式,便會使得GitLab所使用的PostgreSQL成為非官方版本,這會大幅增加基礎設施團隊的維護成本,而且自我託管的用戶也必須安裝修復程式,才能解決問題。

官方目前選擇成本最低的方案,消除SAVEPOINT的呼叫,來避免Nessie問題,而GitLab在刪除SAVEPOINT之後,也就沒有再遭遇到資料庫停頓的狀況,GitLab提到,他們建議所有PostgreSQL的使用者,要執行唯讀副本的PostgreSQL,也應該刪除所有子交易,避免遇到Nessie問題。


熱門新聞

Advertisement