【GaussDB】排查應(yīng)用高可用切換出現(xiàn)數(shù)據(jù)庫整體卡頓及報(bào)錯(cuò)自治事務(wù)無法創(chuàng)建的問題
背景
某客戶在做應(yīng)用程序的高可用切換測(cè)試,在應(yīng)用程序中,收到了來自數(shù)據(jù)庫的報(bào)錯(cuò),不能創(chuàng)建自治事務(wù)
ERROR: autonomous transaction failed to create autonomous session
DETAIL: wait /data/gaussdb506/tmp:7456 timeout expired
數(shù)據(jù)庫是GaussDB 506.0 SPC0100.0.0集中式單機(jī),應(yīng)用軟件是兩個(gè)節(jié)點(diǎn),同一時(shí)刻只有一個(gè)應(yīng)用節(jié)點(diǎn)會(huì)發(fā)生業(yè)務(wù),當(dāng)主應(yīng)用節(jié)點(diǎn)故障時(shí),另外一個(gè)應(yīng)用節(jié)點(diǎn)會(huì)接管業(yè)務(wù)。
測(cè)試時(shí),先讓兩個(gè)應(yīng)用都開啟,讓主應(yīng)用節(jié)點(diǎn)正常開始業(yè)務(wù),然后斷掉主應(yīng)用節(jié)點(diǎn)的網(wǎng)卡,讓備應(yīng)用節(jié)點(diǎn)接管,頓時(shí)出現(xiàn)數(shù)據(jù)庫卡頓,新建連接要很長(zhǎng)時(shí)間,已經(jīng)建立上的連接執(zhí)行任何SQL都很卡。并且大約在25秒后,日志中出現(xiàn)了上面提到的自治事務(wù)創(chuàng)建報(bào)錯(cuò)。
GaussDB的自治事務(wù)是服務(wù)端自行使用libpq建立了一個(gè)本地連接。
分析
該應(yīng)用開始執(zhí)行業(yè)務(wù)時(shí),會(huì)根據(jù)配置的并發(fā)任務(wù)數(shù),創(chuàng)建對(duì)應(yīng)個(gè)數(shù)的數(shù)據(jù)庫連接,本次測(cè)試時(shí)的并發(fā)數(shù)配置為200。另外根據(jù)測(cè)試人員反饋,當(dāng)并發(fā)為100時(shí),就不會(huì)出現(xiàn)這個(gè)問題。
檢查數(shù)據(jù)庫最大連接數(shù)和最大自治事務(wù)連接數(shù),遠(yuǎn)超測(cè)試并發(fā)度:
gaussdb=# show max_connections;
max_connections
-----------------
3000
(1 row)
gaussdb=# show max_concurrent_autonomous_transactions;
max_concurrent_autonomous_transactions
----------------------------------------
1000
(1 row)
該應(yīng)用執(zhí)行的每個(gè)業(yè)務(wù),都會(huì)調(diào)用一個(gè)自治事務(wù)的存儲(chǔ)過程用于記錄日志,因此當(dāng)業(yè)務(wù)并發(fā)數(shù)為200時(shí),也會(huì)同時(shí)創(chuàng)建200個(gè)自治事務(wù)的連接,也就是說最大也才400個(gè)連接。
嘗試編寫簡(jiǎn)單用例進(jìn)行復(fù)現(xiàn),寫一個(gè)shell文件,循環(huán)后臺(tái)使用gsql調(diào)用自治事務(wù)的匿名塊,模擬應(yīng)用行為。
#!/bin/bash
rm -rf lll.log
for i in {1..200}
do
gsql -t <<'SQL_CMD' >>lll.log 2>&1 &
select 1;
declare
PRAGMA AUTONOMOUS_TRANSACTION;
begin
pg_sleep(30);
end;
/
select pg_sleep(200);
SQL_CMD
echo "Launched $i at $(date)" >> lll.log
done
由于是后臺(tái)異步的,所以這個(gè)sh執(zhí)行很快,top觀察此時(shí)cpu和內(nèi)存占用都不高,
ps -ef |grep gsql也可以觀察到還有200個(gè)gsql進(jìn)程。
然后另開一個(gè)gsql連接,發(fā)現(xiàn)連接時(shí)間比之前長(zhǎng)了很多。
連接上之后,執(zhí)行以下SQL觀察,此時(shí)任意SQL執(zhí)行都會(huì)非常耗時(shí)
gaussdb=# select application_name,count(1) from pg_stat_activity where application_name in ('gsql','autonomoustransaction') and pid<>pg_backend_pid() group by application_name;
application_name | count
-----------------------+-------
autonomoustransaction | 54
gsql | 200
(2 rows)
發(fā)現(xiàn)gsql的主事務(wù)已經(jīng)有200個(gè)了,但是自治事務(wù)卻還只有54個(gè),說明有大量的自治事務(wù)還沒有創(chuàng)建,也就是說,并發(fā)創(chuàng)建自治事務(wù)的確會(huì)由于某種原因產(chǎn)生阻塞。
檢查lll.log文件,的確也出現(xiàn)了創(chuàng)建自治事務(wù)超時(shí)的報(bào)錯(cuò)。
從官方文檔中看有沒有什么線索
《自治事務(wù)-規(guī)格約束》-https://doc.hcs.huawei.com/db/zh-cn/gaussdbqlh/25.1.30/devg-cent/gaussdb-42-0970.html
自治事務(wù)執(zhí)行時(shí),將會(huì)在后臺(tái)啟動(dòng)自治事務(wù)session,可以通過max_concurrent_autonomous_transactions設(shè)置自治事務(wù)執(zhí)行的最大并行數(shù)量,該參數(shù)取值范圍為0~10000,默認(rèn)值為10。
當(dāng)max_concurrent_autonomous_transactions參數(shù)設(shè)置為0時(shí),自治事務(wù)將無法執(zhí)行。
自治事務(wù)新啟session后,將使用默認(rèn)session參數(shù),不共享主session下對(duì)象(包括session級(jí)別變量,本地臨時(shí)變量,全局臨時(shí)表的數(shù)據(jù)等)。
自治事務(wù)理論上限為10000,實(shí)際上限為動(dòng)態(tài)值,參考GUC參數(shù)max_concurrent_autonomous_transactions描述。
自治事務(wù)受通信緩沖區(qū)影響,返回給客戶端的信息大小受限于通信緩沖區(qū)長(zhǎng)度,超過通信緩沖區(qū)長(zhǎng)度時(shí)報(bào)錯(cuò)。
自治事務(wù)的鎖不受lock timeout影響,鎖超時(shí)時(shí)間為2147483s,自治事務(wù)執(zhí)行超過此時(shí)間會(huì)報(bào)錯(cuò)鎖超時(shí)。
自治事務(wù)設(shè)置建立連接超時(shí)時(shí)間5s,建立連接嘗試5次。建立連接期間不立即響應(yīng)信號(hào),每次建立連接前檢查信號(hào)。高并發(fā)、高CPU、高內(nèi)存,以及線程池?cái)U(kuò)容場(chǎng)景下可能存在超時(shí)報(bào)錯(cuò)現(xiàn)象。
在PACKAGE SPECIFICATION或PACKAGE BODY SPECIFICATION中聲明自治事務(wù)PRAGMA AUTONOMOUS_TRANSACTION語法,可成功創(chuàng)建PACKAGE,但自治事務(wù)不生效。
其中有一條注意事項(xiàng)和當(dāng)前現(xiàn)象有點(diǎn)像,超時(shí)5秒嘗試5次,一共就是25秒。
于是觀察故障時(shí)間點(diǎn)的CPU/內(nèi)存/磁盤IO的情況,但是發(fā)現(xiàn)故障時(shí)間點(diǎn),這些指標(biāo)反而比平時(shí)更低,可以說服務(wù)器幾乎沒有干活了。那么有可能的就是"線程池?cái)U(kuò)容場(chǎng)景"了。
為了驗(yàn)證是不是與線程池特性有關(guān),嘗試關(guān)閉線程池再執(zhí)行上面的shell測(cè)試。
發(fā)現(xiàn)自治事務(wù)創(chuàng)建非常順利,也沒有出現(xiàn)報(bào)錯(cuò)。
gaussdb=# select application_name,count(1) from pg_stat_activity where application_name in ('gsql','autonomoustransaction') and pid<>pg_backend_pid() group by application_name;
application_name | count
-----------------------+-------
autonomoustransaction | 200
gsql | 200
(2 rows)
似乎是與線程池功能有關(guān),但是我在開啟線程池后,改成400個(gè)并發(fā),不使用自治事務(wù),并沒有出現(xiàn)阻塞的情況,400個(gè)gsql連接是瞬間就連接成功了。
直覺告訴我這里的設(shè)計(jì)應(yīng)該有問題,從線程池里獲取線程用于普通連接和用于自治事務(wù)連接,似乎走了兩個(gè)不同的邏輯,自治事務(wù)連接會(huì)需要阻塞度更大的鎖,但是沒有源碼沒法分析。
大概看了一眼openGauss這里的自治事務(wù)超時(shí),從3.1版本開始就改成了固定的10min,之前版本是沒有額外的超時(shí)設(shè)置的,和libpq共用,也就是說自治事務(wù)的代碼在openGauss和GaussDB已經(jīng)有所區(qū)別了。不過我也測(cè)了下openGauss,在線程池模式下,的確也會(huì)出現(xiàn)并發(fā)創(chuàng)建自治事務(wù)導(dǎo)致數(shù)據(jù)庫整體卡頓的現(xiàn)象,只是由于超時(shí)需要10min,所以沒有出現(xiàn)報(bào)錯(cuò),自治事務(wù)的連接數(shù)會(huì)慢慢增加。但并發(fā)度如果更高,還是可能會(huì)出現(xiàn)自治事務(wù)連接超過10min而報(bào)錯(cuò)的現(xiàn)象。
這個(gè)測(cè)試已經(jīng)充分說明在GaussDB里,線程池開啟時(shí),并發(fā)創(chuàng)建自治事務(wù)會(huì)導(dǎo)致數(shù)據(jù)庫出現(xiàn)整體卡頓、新連接建立緩慢、舊連接執(zhí)行SQL緩慢、還有自治事務(wù)執(zhí)行會(huì)出現(xiàn)超時(shí)報(bào)錯(cuò)的情況。但應(yīng)用需求擺在這,如何解決這個(gè)問題呢?
回到GaussDB文檔 ,“線程池?cái)U(kuò)容場(chǎng)景下可能存在超時(shí)報(bào)錯(cuò)現(xiàn)象” ,既然擴(kuò)容就會(huì)超時(shí)報(bào)錯(cuò),那么不讓它擴(kuò)容,一開始線程數(shù)就是夠的,是不是就不會(huì)超時(shí)了?
在GaussDB中有一個(gè)這樣的參數(shù)
thread_pool_attr
參數(shù)說明:用于控制線程池功能的詳細(xì)屬性,該參數(shù)僅在enable_thread_pool打開后生效,僅sysadmin用戶可以訪問。
參數(shù)類型:字符串
參數(shù)單位:無
取值范圍:
該參數(shù)分為三個(gè)部分,‘thread_num, group_num, cpubind_info’,這三個(gè)部分的具體含義如下:
- thread_num:線程池中的初始線程總數(shù),可以動(dòng)態(tài)擴(kuò)充,取值范圍是0~4096。其中0的含義是數(shù)據(jù)庫根據(jù)系統(tǒng)CPU core的數(shù)量來自動(dòng)配置線程池的線程數(shù),如果參數(shù)值大于0,線程池中的線程數(shù)等于thread_num。線程池大小建議根據(jù)硬件配置進(jìn)行設(shè)置,計(jì)算公式如下:thread_num = CPU核數(shù)*(3~5),thread_num最大值為4096。
- group_num:線程池中的線程分組個(gè)數(shù),取值范圍是0~64。其中0的含義是數(shù)據(jù)庫根據(jù)系統(tǒng)NUMA組的個(gè)數(shù)來自動(dòng)配置線程池的線程分組個(gè)數(shù),如果參數(shù)值大于0,線程池中的線程組個(gè)數(shù)等于group_num。
- cpubind_info:線程池是否綁核的配置參數(shù)。可選擇的配置方式有:1. ‘(nobind)’ ,線程不做綁核;2. ‘(allbind)’,利用當(dāng)前系統(tǒng)所有能查詢到的CPU core做線程綁核;3. ‘(nodebind: 1, 2)’,利用NUMA組1、2中的CPU core進(jìn)行綁核;4. ‘(cpubind: 0-30)’,利用0-30號(hào)CPU core進(jìn)行綁核;5. ‘(numabind: 0-30)’,在NUMA組內(nèi)利用0-30號(hào)CPU core進(jìn)行綁核。該參數(shù)不區(qū)分大小寫。當(dāng)開啟資源多租模式時(shí),該參數(shù)不生效。
默認(rèn)值:‘4096,2,(nobind)’(196核CPU/1536G內(nèi)存,128核CPU/1024G內(nèi)存,104核CPU/1024G內(nèi)存,96核CPU/1024G內(nèi)存);‘2048,2,(nobind)’(96核CPU/768G內(nèi)存,80核CPU/640G內(nèi)存);‘1024,2,(nobind)’(64核CPU/512G內(nèi)存,60核CPU/480G內(nèi)存,32核CPU/256G內(nèi)存);‘512,2,(nobind)’(16核CPU/128G內(nèi)存);‘256,2,(nobind)’(8核CPU/64G內(nèi)存)
設(shè)置方式:該參數(shù)屬于POSTMASTER類型參數(shù),請(qǐng)參考表1中對(duì)應(yīng)設(shè)置方法進(jìn)行設(shè)置。
設(shè)置建議:內(nèi)存充足且CPU性能好的情況,當(dāng)業(yè)務(wù)需要更多連接時(shí)可以增加該參數(shù)值。
設(shè)置不當(dāng)?shù)娘L(fēng)險(xiǎn)與影響:若thread_pool_attr設(shè)置值大于等于max_connections,會(huì)導(dǎo)致proc資源全部被線程池占用,出現(xiàn)proc資源不足的問題。默認(rèn)值即推薦值,不建議修改。修改必須詳細(xì)確認(rèn)參數(shù)的規(guī)格限制,并考慮硬件資源是否足夠,否則可能導(dǎo)致數(shù)據(jù)庫異常。
當(dāng)前環(huán)境配置的是 256,2,(nobind) ,也就是說,數(shù)據(jù)庫啟動(dòng)的時(shí)候就會(huì)同時(shí)啟動(dòng)256個(gè)worker線程,可以動(dòng)態(tài)擴(kuò)充意味著并不是只允許256個(gè)worker同時(shí)干活,它應(yīng)該會(huì)根據(jù)實(shí)際需要自動(dòng)增加。但是自治事務(wù)這里似乎有些差異,結(jié)合上面查詢的會(huì)話數(shù),主事務(wù)200個(gè),自治事務(wù)54個(gè),接近256個(gè)了,所以理論上把256調(diào)大,改成超過400,那么并發(fā)200個(gè)連接套自治事務(wù),就不會(huì)報(bào)錯(cuò)了。
實(shí)測(cè)也的確如此,所以我們調(diào)整了安裝的初始化參數(shù)配置,直接把thread_pool_attr改成了4096,2,(nobind) ,這樣啟動(dòng)的時(shí)候就會(huì)有四千多個(gè)空閑的worker線程,在目前應(yīng)用場(chǎng)景下絕對(duì)是夠用的。
由于這個(gè)主事務(wù)加自治事務(wù)會(huì)話數(shù)需要低于啟動(dòng)時(shí)的線程池個(gè)數(shù)的表現(xiàn),在openGauss中似乎并不存在,因此再看openGauss的源碼分析,意義也不大了。
不過,這也意味著,在當(dāng)前GaussDB數(shù)據(jù)庫版本中,由于默認(rèn)是開啟了線程池的,所以如果業(yè)務(wù)代碼經(jīng)常使用自治事務(wù),無論機(jī)器硬件配置有多高,最大支持的并發(fā)業(yè)務(wù)數(shù)其實(shí)只有2048個(gè)了,超過就可能導(dǎo)致數(shù)據(jù)庫整體變慢,甚至還會(huì)出現(xiàn)報(bào)錯(cuò)。
結(jié)論
在GaussDB中,如果頻繁使用自治事務(wù),當(dāng)thread_pool_attr的第一個(gè)值小于應(yīng)用的并發(fā)連接數(shù)乘2時(shí),數(shù)據(jù)庫可能會(huì)出現(xiàn)嚴(yán)重的卡頓以及報(bào)錯(cuò)的現(xiàn)象,因此在硬件資源足夠的情況下,建議把thread_pool_attr的第一個(gè)值配置成實(shí)際上最大客戶端連接數(shù)的兩倍。
- 本文作者: DarkAthena
- 本文鏈接: https://www.darkathena.top/archives/gaussdb-autonomoustransaction-create-timeout-hang
- 版權(quán)聲明: 本博客所有文章除特別聲明外,均采用CC BY-NC-SA 3.0 許可協(xié)議。轉(zhuǎn)載請(qǐng)注明出處




