GPDB-疑難雜症-使用資源組入庫OOM

yzs87發表於2023-03-12

GPDB-疑難雜症-使用資源組入庫OOM

1、問題

GPDB6資源組可以使業務在事務級別控制資源的使用,業務側啟用資源組後,入庫時檢視資料庫日誌發現大量OOM報錯:

ERROR...Out of memory...Resource group memory limit reached...INSERT INTO ... SELECT...

業務連線使用者具備 superuser許可權,使用admin_group資源組。對memory_limit等資源組屬性配置進行調整,仍持續報錯。

gp_resgroup_memory_policy為eager_free,gp_ressource_group_memory_limit為0.7,statement_mem為200MB,gp_resource_group_bypass為off。

memory_limit調整後,檢視gp_toolkit.gp_resgroup_status_per_segment檢視,發現全域性可用記憶體memory_available還剩餘很多,高達46GB,slot配額剩餘36GB,資源組共享區沒有使用。

2、分析

檢視中可以看到資源組可用記憶體還剩餘很多,為什麼還會報錯 OOM呢?前文我們分析過,bypass模式下,QE上限制僅10MB,若INSERT資料量特別大並且複雜時,倒是有可能超過10MB。但是,透過對資源組機制進行分析,僅SET、RESET、SHOW語句才會bypass模式,透過日誌可以看到時INSERT語句OOM。所以又是什麼原因呢?

我們找到 OOM報錯日誌的位置:

gp_failed_to_alloc函式中:

 

也就是錯誤碼是 MemoryFailure_SystemMemoryExhausted 。根據該錯誤碼向上回溯:該錯誤碼由 gp_malloc_internal函式呼叫VmemTracker_ReserveVmem時的返回值。進一步看程式碼,可知是VmemTracker_ReserveVmemChunks的返回值。VmemTracker_ReserveVmemChunks函式中返回該錯誤碼的分支為:

 

也就是 ResGroupReserveMemory函式返回false時才會報該錯誤。

前文已分析,返回 false的場景也就兩種,一種是bypass模式下的10MB限制,另一種是資源組定義的記憶體。

我們分別在這兩個分支處新增列印日誌,看下到底是哪個場景導致 OOM的。

經測試復現, 確實是 INSERT語句,走bypass模式分支報的錯

Bypass模式只能是SET、RESET、SHOW語句才會用,前文我們也分析了,同一個事務內的SQL語句都使用同一個資源組,業務會不會將INSERT語句和SET/RESET/SHOW放在一起了?

返回來,檢視業務的 SQL,發現執行INSERT前確實有個SET statement_mem語句。詢問業務側,是否將這兩個語句放到一個事務裡了,但人家回應兩個在單獨事務裡。有時候不能太相信業務端,還真得深究他們的程式碼: 他們透過 JDBC連線GPDB,預設情況下為自動提交,也就是說這兩個是獨立的兩個事務

始終懷疑,這兩個語句在同一個事務中,好了,繼續驗證:修改程式碼,讓 jdbc連線服務後執行SET語句前sleep 30秒,這段時間足夠我們ps看到服務端的程式ID,gdb跟蹤該PID,在QD端StartTransaction和CommitTransaction處都打上斷點,以及QE端資源組分配函式 SwitchResGroupOnSegment 上打斷點。

業務 JDBC執行後,StartTransaction僅執行了一次,QE端先執行SET語句,確實走的bypass模式,然後再執行INSERT,它確實在SET事務內,同樣走bypass模式。

到此,十分清楚了, SET和INSERT在同一個事務內,而SET語句在前,它的事務分配資源組bypass模式,後續的INSERT命令繼續使用該資源組,同樣繼續走bypass模式,所以限制仍舊是10MB

那出問題的就是 JDBC了,使用預設自動提交情況下,將SET命令和INSERT語句一起傳送時,成為了一個事務。有可能是JDBC的bug。

怎麼解決?將 SET命令單獨放在顯式事務中:BEGIN;SET...;COMMIT;然後再執行INSERT,這樣將其分開,INSERT獨立一個事務,讓其走資源組屬性的限制。Ok,問題解決!


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31493717/viewspace-2939230/,如需轉載,請註明出處,否則將追究法律責任。

相關文章