大數(shù)據(jù)“復(fù)活”記
1592
2025-03-31
1????????? 問題背景
在使用客戶端連接GaussDB時,可能會出現(xiàn)連接失敗或者連接慢的問題,如果不能及時解決恢復(fù)很容易影響使用體驗甚至業(yè)務(wù)運(yùn)行。本文針對幾種常見場景,結(jié)合原理快速分析定位,也可幫助客戶進(jìn)行合理的使用配置,從而在根源上減少問題的發(fā)生。文中涉及的參數(shù)、視圖詳情可參考產(chǎn)品文檔。
2????????? 場景一:too many clients already, active/non_active: xxxx/xxxx.
2.1???????? 問題描述
客戶端連接數(shù)據(jù)庫、查詢語句等,報錯連接已滿:too many clients already, active/non_active: xxxx/xxxx.
圖1. dn上連接滿
2.2???????? 原理分析
max_connections決定了進(jìn)程內(nèi)的線程數(shù)量上限。
2.2.1??????? DN上連接滿
DN上連接滿通常是由于CN與此DN的連接數(shù)(一條連接即在DN上開啟一個線程)和此DN上啟動的Stream線程數(shù)量之和達(dá)到max_connections所致,報錯信息一般會指明具體DN,如圖1。當(dāng)客戶端與CN建連后,CN會根據(jù)連接的database、username和options匹配到pooler中對應(yīng)的pool,pool中會保留與其他DN的連接。當(dāng)需要執(zhí)行query時,pool會根據(jù)執(zhí)行計劃選擇與對應(yīng)DN的保留的連接,若沒有,則進(jìn)行建連。當(dāng)query執(zhí)行結(jié)束或客戶端斷開與CN連接后,CN與DN間連接直接歸還給相應(yīng)的pool,便于其他query直接使用,節(jié)省建連所需的時間、資源成本。
然而,如果user1訪問database1執(zhí)行了100條并發(fā)語句后全部退出,那么相應(yīng)的pool1中就會保留與其他每個DN的100條連接,user2訪問database1執(zhí)行100條并發(fā)語句后,又會在pool2中保留100條連接,隨著不同pool保留的累積,最后在DN上的連接數(shù)達(dá)到了max_connections,連接報錯。
圖2. pooler通信框架
為此,數(shù)據(jù)庫設(shè)計了pooler復(fù)用技術(shù),即客戶端連接數(shù)據(jù)庫只根據(jù)database進(jìn)行匹配pool,不同的user可以訪問同一個pool,從而減少pool的數(shù)量,進(jìn)而減少了保留的連接。然而,隨著database數(shù)量的增加,相應(yīng)的pool數(shù)量同樣也會增加,保留的連接數(shù)依然可能達(dá)到max_connections。8.0版本增加自動clean connection功能,當(dāng)CN與DN建連時發(fā)現(xiàn)DN連接已滿,會清理所有pool中四分之一的空閑連接,不足四個則清理一個,從而保證空閑連接不會產(chǎn)生影響。
影響DN上此參數(shù)的另一方面是Stream線程數(shù)量,其與相應(yīng)業(yè)務(wù)的執(zhí)行計劃相關(guān),在定位該問題時,優(yōu)先排查CN與DN間的連接數(shù)量,若數(shù)量偏差較大,再進(jìn)一步考慮業(yè)務(wù)Stream情況。
2.2.2??????? CN上連接滿
CN上連接滿與DN上有著較大差別,是指CN與CN之間(同DN,也是和pooler相關(guān))和客戶端與CN的連接數(shù)之和達(dá)到max_connections,通常此報錯與業(yè)務(wù)側(cè)相關(guān)。對于CN與CN之間的連接,如果更多的是active狀態(tài),可能是業(yè)務(wù)中包含很多DDL操作;如果更多的是idle狀態(tài),那么則為pooler中保留的連接,可使用clean connection清理。對于客戶端的連接,active狀態(tài)表示正有業(yè)務(wù)運(yùn)行,如果大部分連接都是此狀態(tài),那么很有可能是業(yè)務(wù)并發(fā)太高(存在特殊情況),需要降低并發(fā)。如果更多的是idle狀態(tài)的話,則很有可能是對于idle狀態(tài)連接管控的問題(詳見2.3.2)。
2.3???????? 定位方法
2.3.1??????? DN上連接滿
1. clean connection to [node (dn_xxxx_xxxx/cn_xxxx)] [all] for database dbname;
CN上提供了pg_pooler_status視圖可以看到當(dāng)前CN與所有DN的連接情況,對于某個報錯的DN,需要分別在所有CN上執(zhí)行:
1.??????? select?in_use,?count(*)?from?pg_pooler_status?where?node_name?=?'dn_xxxx_xxxx'?group?by?1;
可查看此DN的連接情況,其中in_use為f表示此連接沒有被占用,即保留在pool中,為t即為正在使用。
使用clean connection操作可清理in_use為f的連接,指定node (dn_xxxx_xxxx)即清理指定DN的連接,指定node (cn_xxxx)即清理指定CN與所有DN的連接,指定all則清理集群所有的in_use為f的連接。當(dāng)指定all的時候可添加關(guān)鍵字force,這樣in_use為t的連接也同樣會進(jìn)行清理,詳見產(chǎn)品文檔。
2. 如果開啟了persistent_datanode_connections,釋放掉CN上的idle連接或關(guān)閉此參數(shù);
當(dāng)無可執(zhí)行的query時,CN和DN的連接將歸還pool,即in_use由t變?yōu)閒,但是若此參數(shù)開啟,則會一直保留連接。關(guān)閉此參數(shù)或清理CN上idle狀態(tài)的連接(詳見2.3.2)是一種有效的手段。
3. GUC參數(shù)max_connections;
CN和DN上的max_connections設(shè)置是有依據(jù)的,理論上,DN上應(yīng)設(shè)置為CN上的值 * CN的個數(shù)。這是由于不同的CN都會與同一個DN進(jìn)行建連,DN的連接上限要滿足大于所有CN連接上限之和。核查一下,說不定真的是DN上不夠了!
4. 神級視圖:pgxc_thread_wait_status;
1.? 查詢當(dāng)前DN上所有線程數(shù)量:select?count(*)?from?pgxc_thread_wait_status?where?thread_name?like?'cn%'?and?node_name?=?'dn_xxxx_xxxx';
2.? 查詢當(dāng)前DN上所有Stream線程數(shù)量:select?count(*)?from?pgxc_thread_wait_status?where?thread_name?like?'cn%'?and?tlevel?<>?0?and?node_name?=?'dn_xxxx_xxxx';
3.? 查詢所有DN上的線程數(shù)量:select?node_name,?count(*)?from?pgxc_thread_wait_status?where?thread_name?like?'cn%'?and?node_name?like?'dn%'?group?by?1?order?by?2?desc;
4.? 查詢所有DN與CN的連接和Stream線程數(shù)量:select?node_name,?sum(level0)?cnt0,?sum(level1)?cnt1,?cnt0?+?cnt1?sum?from?(select?node_name,?case?tlevel?when?0?then?1?else?0?end?as?level0,?case?tlevel?when?0?then?0?else?1?end?as?level1?from?pgxc_thread_wait_status?where?thread_name?like?'cn%'?and?node_name?like?'dn%')?group?by?1?order?by?1,?2,?3?desc;
5.? 查詢所有query在每個DN上的Stream線程數(shù)量:select?query_id,?node_name,?count(*)?from?pgxc_thread_wait_status?where?query_id?<>?0?and?tlevel?<>?0?and?thread_name?like?'cn%'?and?node_name?like?'dn%'?group?by?1,?2?order?by?1,?3?desc;
6.? ...
使用-rm工程模式登錄數(shù)據(jù)庫,根據(jù)pgxc_thread_wait_status視圖查看所需信息。然而,存在一些情況是場景丟失、連接數(shù)已恢復(fù)正常,此時可以部署腳本等待問題再次復(fù)現(xiàn)。
圖3. general腳本用法
5. gstack打堆棧;
若前幾種方案均無法排查出問題,可以使用gstack收集堆棧信息,逐一線程分析為何沒有正常退出(線程數(shù)量可能很龐大,建議打印的堆棧重定向至文件中)。
6. kill dn_xxxx_xxxx;(應(yīng)急)
1.??????? 找DN目錄:cm_ctl?query?-Cvd?|?grep?dn_xxxx_xxxx
2.??????? 找DN進(jìn)程:ps?ux?|?grep?上一步找到的目錄
3.??????? 統(tǒng)計連接數(shù)量:netstat?-anpt?|?grep?pid?|?wc?-l
4.??????? Kill DN進(jìn)程:kill?-9?pid
kill連接數(shù)滿的DN進(jìn)程是一種快速、有效的規(guī)避手段,然而此方法會對正在執(zhí)行的業(yè)務(wù)有短暫影響,且不利于定位根因,使用時需慎重考慮。
7. cm_ctl switchover –n 備機(jī)序號 –D 備機(jī)目錄;(應(yīng)急)
對于一些特殊情況,例如僅在個別節(jié)點應(yīng)急后連接數(shù)仍頻繁漲滿、其他節(jié)點均正常且暫時無法定位根因,使用主備切換方法可進(jìn)行應(yīng)急。
2.3.2??????? CN上連接滿
1. 設(shè)置session_timeout;
當(dāng)業(yè)務(wù)側(cè)未配備連接池管控idle連接時,需要數(shù)據(jù)庫進(jìn)行管控,否則idle連接一直不釋放,很容易造成連接滿的問題。對此,設(shè)置session_timeout不為0,當(dāng)達(dá)到此時間沒有任何操作,則數(shù)據(jù)庫會自動斷開連接。值得注意的是,若業(yè)務(wù)側(cè)有進(jìn)行對idle的管控,數(shù)據(jù)庫同時設(shè)置session_timeout,當(dāng)超時后數(shù)據(jù)庫自動斷開連接,業(yè)務(wù)側(cè)再獲取idle狀態(tài)的連接,此時連接已斷開,會報錯:An I/O error occurred while sending to the backend.
2. 排查業(yè)務(wù)側(cè)哪些連接沒有釋放;
1.??????? select?usename,?application_name,?client_addr,?count(*)?from?pgxc_stat_activity?where?state?=?'idle'?and?coorname?=?'cn_xxxx'?group?by?1,?2,?3?order?by?4?desc;
2.??????? select?usename,?application_name,?query_start?from?pgxc_stat_activity?where?state?=?'idle'?and?coorname?=?'cn_xxxx'?group?by?1,?2,?3?order?by?3?desc;
3.??????? ...
根據(jù)pgxc_stat_activity視圖可以看到報錯CN上的所有連接情況,按照相應(yīng)的客戶端IP地址、用戶名、應(yīng)用名稱等信息可定位到連接來源,從而分析根因。此視圖可在任意CN上查詢,根據(jù)需求選擇字段查詢,詳見產(chǎn)品文檔。
3. 神級視圖:pgxc_thread_wait_status;
1.? select?*?from?pgxc_thread_wait_status?where?node_name?=?'cn_xxxx';
同DN連接滿,此視圖可查每個連接對應(yīng)的線程狀態(tài),進(jìn)而分析根因。
4. gstack打堆棧;
若所有CN均出現(xiàn)此報錯、無法正常登錄數(shù)據(jù)庫或前幾種方案均無法排查出問題,可以使用gstack收集堆棧信息,逐一線程分析為何沒有正常退出(線程數(shù)量可能很龐大,建議打印的堆棧重定向至文件中)。
5. kill連接線程;(應(yīng)急)
1.??????? select?pid,?state?from?pgxc_stat_activity;
2.??????? select?pg_terminate_backend(pid);
對于CN上的每一條連接,都有一個線程相對應(yīng),將對應(yīng)線程kill則會將連接斷開。然而此方法同樣不利于分析根因,日后還是容易復(fù)發(fā)。不過嘗試kill少量空閑連接對定位影響較小,且也有助于業(yè)務(wù)恢復(fù)。
6. kill cn_xxxx;(應(yīng)急)
同樣,kill CN進(jìn)程應(yīng)急快、效果好,但是難以分析根因,且執(zhí)行中的業(yè)務(wù)會受到影響。
3????????? 場景二:An I/O error occurred while sending to the backend.
3.1???????? 問題描述
客戶端使用與數(shù)據(jù)庫建好的連接報錯:An I/O error occurred while sending to the backend.
圖4. 場景二報錯截圖
3.2???????? 原理分析
正如2.3.2中所說,當(dāng)數(shù)據(jù)庫側(cè)由于某種原因?qū)⑦B接斷開,應(yīng)用側(cè)再次使用此連接就會產(chǎn)生這個報錯。而數(shù)據(jù)庫側(cè)連接異常斷開主要有四種原因:1. CN進(jìn)程異常重啟;2. session超時;3. 人為kill session;4. LVS中virtual router id沖突。
3.3???????? 定位方法
1. 查看CN進(jìn)程是否異常重啟
1.? ps?-eo?pid,lstart,etime,cmd?|?grep?coo
如果連接在CN進(jìn)程啟動之前就存在,那么CN進(jìn)程重啟之后,連接就會斷開,業(yè)務(wù)側(cè)繼續(xù)使用則會報錯。
2.? 未達(dá)到session_timeout時間就報錯
如果不存在CN重啟,且時間未到設(shè)置的session_timeout,或者業(yè)務(wù)正在運(yùn)行中就產(chǎn)生此報錯,可排查LVS中的virtual router id是否沖突。
查看OS日志,搜索Keepalive字段,若存在如下圖字樣,即為沖突,可修改主備LVS配置文件后,重啟LVS即可:.
/etc/keepalived/keepalived.conf:文件中virtual_router_id字段,同一子網(wǎng)下不可沖突
/etc/init.d/gs_keepalived restart:重啟LVS
3. 排查CN日志是否含有due to
非常清晰的兩種情況,根據(jù)日志中相應(yīng)時間分析;
調(diào)用select pg_terminate_backend(pid); 終止了會話,多數(shù)是用戶操作產(chǎn)生,個別情況是由于cm_agent在檢測磁盤超過閾值(默認(rèn)90%)場景下,會調(diào)用此方法終止當(dāng)前CN上所有非omm用戶的SQL,同時會打印調(diào)用日志“cancel session ok”,可排查cm_agent日志。
會話設(shè)置了session_timeout時間,當(dāng)超過此時間,數(shù)據(jù)庫會自動清理連接。對于需要保持長連接的場景。可通過客戶端對此session設(shè)置session_timeout為0或預(yù)期時長。
4????????? 場景三:客戶端連接數(shù)據(jù)庫很慢.
4.1???????? 問題描述
客戶端可以連接數(shù)據(jù)庫,但是耗時長。(可能連接個別CN出現(xiàn)此現(xiàn)象)
4.2???????? 原理分析
已知的問題是GaussDB提供GUC參數(shù)log_hostname,此參數(shù)默認(rèn)開啟。當(dāng)客戶端來連接數(shù)據(jù)庫時,會根據(jù)log_hostname來選擇調(diào)用操作系統(tǒng)函數(shù)getnameinfo()時是否進(jìn)行DNS解析域名,即根據(jù)客戶端ip獲取主機(jī)名。由于DNS的配置問題,解析可能耗時較長甚至失敗,因此對于客戶端來說,連接數(shù)據(jù)庫很慢。
4.3???????? 定位方法
1. show log_hostname;
登錄連接慢的CN,查看log_hostname的值,若為on,可根據(jù)線程號打印堆棧;
1.? select?application_name,?lwtid?from?pg_stat_activity?a,?pg_thread_wait_status?b?where?a.pid?=?b.tid?and?client_addr?=?'xxxx'?and?datname?=?'xxxx'?and?usename?=?'xxxx'?and?backend_start?between?'xxxx'?and?'xxxx';
2.? gstack?lwtid
圖5. getnameinfo()堆棧信息
若堆棧中存在明顯的getnameinfo(),則關(guān)閉此參數(shù)即可;沒有打印堆棧的工具也可嘗試關(guān)閉。
2. log_hostname = on?
若log_hostname為on,可使用ping命令排查網(wǎng)絡(luò)時延等問題;如果網(wǎng)絡(luò)正常,那么還是根據(jù)線程號打堆棧進(jìn)一步分析。
EI企業(yè)智能 Gauss AP 數(shù)據(jù)倉庫服務(wù) GaussDB(DWS)
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。