2023年6月20日 星期二

PostgreSQL 資料庫執行異常緩慢兇手 LWLock : SubtransSLRU

 在前年的時候 Gitlab 發布了一篇文章分享他們如何以及為何要排除 Subtransaction。

https://about.gitlab.com/blog/2021/09/29/why-we-spent-the-last-month-eliminating-postgresql-subtransactions/

在 Postgres 一般發生交易失敗時,會整筆交易自動進行 RollBack,而如果繼續嘗試執行 SQL 會出現以下錯誤訊息。

ERROR:  current transaction is aborted, commands ignored until end of transaction block

必須要先執行 Rollback 或 Commit (實際上會 Rollback) 才能重新執行 SQL。


如果要做到發生問題時仍可以 Commit 已經執行的 SQL,則需要搭配 Savepoint、Exception 等語法,或是 EDB 企業版有的參數設定 edb_stmt_level_tx 和 transaction_rollback_scope,這些功能背後都是利用 Subtransaction 來達成,也是潛在會造成異常的兇手。


Subtransaction 的資訊一般會暫存於記憶體,但是有一個上限若超過則會開始落檔案儲存,一般來說一個 Session 最多能開啟 64 個 Subtransaction ,若超過則會開始落檔案儲存。


Postgres 的 Session 在查詢表格時,會需要去檢視目前資料在 MVCC 下的 Visibility,確保能正確地檢視資料,當有發生 Subtransaction 將資料往硬碟寫入時,在讀取這些資訊時都會需要去從硬碟 I/O 將這些資訊讀取出來,從記憶體中讀取出來相對會比較慢,而因此導致整個資料庫進行任何查詢都會有延遲卡住的狀況發生

當問題發生時,我們若檢視系統表 pg_stat_activity 可以觀察到 SubtransSLRU 這樣的 Wait Event,代表一般的 SQL 執行有被卡到。

這時候就有必要去檢視 AP 的程式碼中是否有對應使用到相關會產生 Subtransaction 的功能,主要注意盡量避免在複雜的查詢中,以及長查詢中使用到 Subtransaction 的功能,一般小量使用可能不會有什麼問題,但大量的長查詢使用就有可能導致資料庫出現效能異常。


參考資料:

https://about.gitlab.com/blog/2021/09/29/why-we-spent-the-last-month-eliminating-postgresql-subtransactions/

https://www.cybertec-postgresql.com/en/subtransactions-and-performance-in-postgresql/