接到應(yīng)用側(cè)反饋GP數(shù)據(jù)庫有些表經(jīng)常出現(xiàn)突然無法查詢的情況,或者表的某些數(shù)據(jù)查詢不了了,并且報(bào)錯(cuò)信息都非常相似,報(bào)錯(cuò)信息均指向表對(duì)應(yīng)的數(shù)據(jù)文件校驗(yàn)不一致,報(bào)錯(cuò)信息如下:
運(yùn)行日志:【在Agent[1330162]執(zhí)行結(jié)果:存儲(chǔ)過程:p_dw_ulc_usr_prov_happy_ds執(zhí)行完成,返回信息:參數(shù)名稱:o_return_code參數(shù)值:XX000,參數(shù)名稱:o_return_msg參數(shù)值:SQL5:從接口取原始數(shù)據(jù)出錯(cuò)! 錯(cuò)誤信息:Block checksum does not match. Expected 0xBD17CA1E and found 0x450D9B9 (cdbappendonlystorageread.c:1210) …………………………Append-Only segment file/data1/primary/gpfs/gpseg186/33389/2435928/65966825.1537, block header offset in file = 50650432, bufferCount 2990,】 |
看到報(bào)錯(cuò)信息,立馬想到是否是磁盤問題造成文件在寫磁盤的時(shí)候出現(xiàn)了問題,按照這個(gè)思路抓緊核查磁盤。
RAID卡底層日志沒有發(fā)現(xiàn)有reset、time out等異常打印
暫時(shí)排除磁盤問題,那還有哪里出問題會(huì)導(dǎo)致數(shù)據(jù)問題?順其自然想到是否是GP數(shù)據(jù)庫在primary實(shí)例和mirror實(shí)例數(shù)據(jù)同步的時(shí)候出現(xiàn)問題?
我們先來溫故一下primary實(shí)例和mirror實(shí)例主備復(fù)制的機(jī)制。
大家都知道Greenplum 是基于PostgreSQL開發(fā),PostgreSQL的主備也是通過流復(fù)制實(shí)現(xiàn),但是Segment節(jié)點(diǎn)中的Primary和Mirror之間的數(shù)據(jù)同步是基于文件級(jí)別的同步方式實(shí)現(xiàn)的。為什么Primary和Mirror不能再使用流復(fù)制實(shí)現(xiàn)呢?
Append Only表不寫WAL日志,所以Append Only表的數(shù)據(jù)就不能通過XLOG發(fā)送到Mirror再Apply;
pg_control等文件也是不寫WAL日志,也只能通過文件方式同步到Mirror。
Primary和Mirror同步的內(nèi)容主要有兩部分,即文件和數(shù)據(jù)。之所以Primary和Mirror要同步文件,是因?yàn)镻rimary和Mirror之間可以自動(dòng)failover,只有兩者保持同步才能相互替代,如果只把數(shù)據(jù)同步過去,pg_control、pg_clog、pg_subtrans 沒有同步,那么從Primary切換到Mirror就會(huì)出現(xiàn)問題。
GP master和GP slave卻不用擔(dān)心這些問題,Append Only 表的數(shù)據(jù)只會(huì)存在 Segment,所以WAL日志足夠保持GP master和GP slave同步(只要是流復(fù)制,pg_control、pg_clog、pg_subtrans 這些文件Slave會(huì)自動(dòng)更新,無需從Master同步)。
當(dāng)GP master向Primary下發(fā)執(zhí)行計(jì)劃后,Primary開始執(zhí)行,如果是DML操作,那么Primary會(huì)產(chǎn)生XLOG及更新page。會(huì)在SlruPhysicalWritePage函數(shù)中(寫數(shù)據(jù)頁)產(chǎn)生FileRepOperationOpen、FileRepOperationWrite、FileRepOperationFlush、FileRepOperationClose等指令消息(消息中包含具體要更新的文件page及內(nèi)容),通過primary sender進(jìn)程向Mirror發(fā)送Message,然后Mirror的mirror consumer等進(jìn)程解析消息,執(zhí)行變更。XLOG通過XLogWrite函數(shù)(寫XLOG)執(zhí)行同樣的操作,把XLOG更新同步過去。
Primary的recovery進(jìn)程會(huì)循環(huán)把Primary的 pg_control、pg_clog、pg_subtrans 等文件覆蓋到Mirror。同時(shí)檢查XLOG是否一致,如果不一致以Primary為主,對(duì)Mirror進(jìn)行覆蓋。除把Primary部分文件同步到Mirror之外recovery進(jìn)程還會(huì)將Mirror上面的臨時(shí)文件刪掉。
根據(jù)以上的機(jī)制,在實(shí)驗(yàn)環(huán)境做了兩個(gè)實(shí)驗(yàn)進(jìn)行驗(yàn)證:
1. 將mirror的data目錄設(shè)置為gpadmin無權(quán)限訪問。
2. 在master上操作, 進(jìn)行數(shù)據(jù)寫入。
1. 寫入操作卡住一段時(shí)間(等待mirror寫入)。
2. primary發(fā)現(xiàn)無法與mirror同步, 因此將mirror設(shè)置為down的狀態(tài)。
3. 數(shù)據(jù)寫入繼續(xù)在primary進(jìn)行, 寫入完成。
正常情況下, 一個(gè)事務(wù)必須在primary和mirror都寫入完成的情況下才會(huì)提交, 如果primary和mirror無法同步, 那么會(huì)在超時(shí)后將mirror標(biāo)記為 down的狀態(tài)。
gpadmin=# insert into t1 select generate_series(1,100000) ; WARNING: mirror failure, could not complete mirrored request identifier pg_xlog/000000010000000000000001 ack state waiting for ack, failover requested (seg0 172.28.8.2:23168 pid=20162) HINT: run gprecoverseg to re-establish mirror connectivity CONTEXT: mirroring role primary role mirroring state sync segment state in shutdown process name(pid) filerep uninitialized process(20162) filerep state not initialized position ack begin 0x7f4a97f3e040 position ack end 0x7f4a97fbe040 position ack insert 0x7f4a97f69c58 position ack consume 0x7f4a97f69c58 position ack wraparound 0x7f4a97fbe040 insert count ack 43 consume count ack 44 WARNING: mirror failure, could not complete operation on mirror, failover requested (seg0 172.28.8.2:23168 pid=20162) DETAIL: identifier pg_xlog/000000010000000000000001 operation not specified relation type flat file message count -1 ... INSERT 0 100000 Time: 37849.733 ms |
1. 在master進(jìn)行寫入操作。
2. 在寫入的同時(shí), 破壞primary的table文件. (cat xxx >> [table file]), 模擬硬件/文件系統(tǒng)問題導(dǎo)致?lián)p壞的情況。
3. 寫入完成后, 對(duì)表執(zhí)行select操作。
1. 寫入可以正常完成, 因?yàn)閷懭氲牟僮鞯膲K文件正常完成(fsync)。
2. 由于文件被破壞, 因此在select的時(shí)候會(huì)報(bào)錯(cuò)。
3. 同時(shí), 由于復(fù)制是基于塊的同步, 因此primary的損壞操作(人為追加)不會(huì)同步到mirror上, 因此mirror上的文件沒有問題。
1.當(dāng)數(shù)據(jù)寫入時(shí), 數(shù)據(jù)塊分兩條線走, 一條發(fā)送給mirror, 一條到primary落盤。
2.GP只會(huì)檢查數(shù)據(jù)塊本身是否寫入完成(fsync), 對(duì)于落盤之后的外部操作無法感知, 即硬件/系統(tǒng)問題引起的數(shù)據(jù)文件損壞在數(shù)據(jù)塊落盤后是無法發(fā)現(xiàn)的
3.只有在之后讀取到對(duì)應(yīng)的數(shù)據(jù)文件時(shí), 才會(huì)檢查到數(shù)據(jù)塊錯(cuò)誤.
gpadmin=# insert into t1 select generate_series(1,100000000); INSERT 0 100000000 Time: 44379.438 ms gpadmin=# copy (select * from t1) to /dev/null; WARNING: page verification failed, calculated checksum 24539 but expected 27626 (seg0 slice1 172.28.8.2:23168 pid=22869) ERROR: invalid page in block 6129 of relation base/16384/16388 (seg0 slice1 172.28.8.2:23168 pid=22869) gpadmin=# packet_write_wait: Connection to 10.152.9.3 port 22: Broken pipe [gpadmin@sdw3 16384]$ md5sum 16388 83918050bc9ce93dfad130a24e105e61 16388 [gpadmin@sdw2 16384]$ md5sum 16388 48b7740a044bb3398283f4d44e01e46b 16388 ## 切換到mirror后: ## gpadmin=# copy (SELECT * from t1 ) to /dev/null; COPY 100000000 Time: 36918.063 ms gpadmin=# |
通過上面的實(shí)驗(yàn)可以了解到primary實(shí)例和mirror實(shí)例之間的同步機(jī)制:當(dāng)數(shù)據(jù)寫入時(shí)候, 數(shù)據(jù)塊分兩條線走, 一條發(fā)送給mirror, 一條到primary落盤,GP只會(huì)檢查數(shù)據(jù)塊本身是否寫入完成(fsync), 對(duì)于落盤之后的外部操作無法感知, 即硬件/系統(tǒng)問題引起的數(shù)據(jù)文件損壞在數(shù)據(jù)塊落盤后是無法發(fā)現(xiàn)的,只有在之后讀取到對(duì)應(yīng)的數(shù)據(jù)文件時(shí), 才會(huì)檢查到數(shù)據(jù)塊錯(cuò)誤。
上面實(shí)驗(yàn)報(bào)錯(cuò)明顯的指出了是primary實(shí)例下的文件有校驗(yàn)不一致的情況發(fā)生,那我們接著往下看mirror的文件是否有問題。
這個(gè)該怎么驗(yàn)證?很簡(jiǎn)單,把出現(xiàn)問題的文件和對(duì)應(yīng)mirror實(shí)例下的文件做個(gè)md5sum的校驗(yàn),看結(jié)果值是否一致,如一致則表明mirror實(shí)例下的文件肯定也損壞了,如不一致,則把兩個(gè)文件備份一份,再把mirror實(shí)例下的文件覆蓋primary實(shí)例下有問題的文件,對(duì)有問題的表再做一次查詢,看是否還報(bào)錯(cuò),通過實(shí)驗(yàn)及測(cè)試,如果AO表使用上面的方法可以解決文件壞塊的問題,則說明是文件損壞的問題,不是在primary實(shí)例和mirror實(shí)例之間同步數(shù)據(jù)造成,因?yàn)槿绻峭綌?shù)據(jù)造成的,mirror文件也會(huì)損壞。
問題分析到這里遇到了瓶頸,磁盤也沒有問題,也不是數(shù)據(jù)庫數(shù)據(jù)同步造成的,那該是什么原因造成的呢?
看來只能對(duì)損壞的文件進(jìn)行分析了,把之前報(bào)錯(cuò)的文件全部收集出來對(duì)文件塊進(jìn)行分析,
數(shù)據(jù)文件 7398846.1: Block 124473 checkusm 錯(cuò)誤
- 日志顯示損壞位置為 block header offset in file = 644305640
- 通過解析該數(shù)據(jù)文件, 對(duì)應(yīng)的block為 124473
- 數(shù)據(jù)文件顯示block 21406存在checksum錯(cuò)誤, head中的checksum與實(shí)際不符
- 同時(shí), Mirror的文件正常
***** Block 124473 Start ***( Position: 644305640) ************************* HeaderKind: 1 Header Checksum Valid (checksum -1229617606) (AoHeaderKind_SmallContent) executorBlockKind: 1 rowCount: 67 headerLen: 24 uncompressedLen: 32302 compressedLen: 4421 firstRowNumber: 8904392 Content checksum doesnt match storedChecksum: 945093312, computedChecksum: 1985286725 |
數(shù)據(jù)文件 15165123.1: Block 21406 checksum 錯(cuò)誤:
- 日志顯示損壞位置為 block header offset in file = 182856032
- 通過解析該數(shù)據(jù)文件, 對(duì)應(yīng)的block為 21406
- 數(shù)據(jù)文件顯示block 21406存在checksum錯(cuò)誤, head中的checksum與實(shí)際不符
- 同時(shí), mirror的數(shù)據(jù)文件正常。
***** Block 21406 Start ***( Position: 182856032) ************************* HeaderKind: 1 Header Checksum Valid (checksum 454188836) (AoHeaderKind_SmallContent) executorBlockKind: 1 rowCount: 270 headerLen: 24 uncompressedLen: 32716 compressedLen: 8298 firstRowNumber: 5759608 Content checksum valid (checksum: -482616586) |
目前我們可以確定, 數(shù)據(jù)文件的確存在受損的問題, 且損壞只發(fā)生在primary segment上。
下面我們對(duì)出現(xiàn)文件損壞的表在進(jìn)行分析下:
- 我們?cè)谏钊霗z查table文件之后, 發(fā)現(xiàn)primary并沒有缺損, 事實(shí)上primary從08ed2000位置開始被寫了"0"
- primary從08ed2000 到 08ee03e0 都是0, 而mirror并不是
- 同時(shí), 16進(jìn)制的08ed2000,08ee03e0分別對(duì)應(yīng)10進(jìn)制的149757952和149816288, 恰好都是是4096的整數(shù)倍(即這個(gè)位置是一個(gè)4096大小的block的開始)
2 < 08ed2000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 3 < * << 這里的星號(hào)表示都是0 4 --- 5 > 08ed2000 4c 4b d6 af 07 f2 31 74 10 4b e7 f5 8f fc 77 f9 |LK....1t.K....w.| 6 > 08ed2010 1c 7e 02 39 49 16 21 3b 70 f4 39 52 f3 e5 df 8c |.~.9I.!;p.9R....| 7 > 08ed2020 76 c4 99 ea bf af 73 8b 33 ae 76 38 d2 5f 15 a0 |v.....s.3.v8._..| |
- 同樣另外一張表, primary的01110000開始到0111ecf0變成了0, 而mirror不是:
1 1118209,1118210c1118209,1122000 2 < 01110000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 3 < * 4 --- 5 > 01110000 cf 9c 87 4d 9e 61 d7 61 97 4f b0 5f 66 ff 84 fd |...M.a.a.O._f...| 6 > 01110010 2b f6 ef d9 5f b0 b7 ed bc 6b 47 ef 84 97 ac f0 |+..._....kG.....| |
- 16進(jìn)制01110000和0111ecf0分別對(duì)應(yīng)10進(jìn)制17891328和17951984, 同樣是4096的整數(shù)倍。
綜上所述, 經(jīng)研發(fā)部門確認(rèn)該問題并非GPDB造成, 因?yàn)镚PDB從來不會(huì)對(duì)table文件寫0。所以將從軟硬件方面來繼續(xù)排查問題 (XFS? LVM? SAN? RAID card?)。
問題分析到這里基本可以得出結(jié)論,造成Block checksum does not match問題的不是磁盤,也不是數(shù)據(jù)庫軟件本身的問題,但是還需要從主機(jī)系統(tǒng)等層面進(jìn)行分析,已聯(lián)系操作系統(tǒng)等相關(guān)廠商一起進(jìn)行分析,后續(xù)有進(jìn)展將繼續(xù)分享。
這個(gè)問題目前的處理方法很簡(jiǎn)單,有兩種:
1.找到該實(shí)例對(duì)應(yīng)的mirror實(shí)例,在對(duì)應(yīng)mirror實(shí)例下找到對(duì)應(yīng)的數(shù)據(jù)文件,通過MD5SUM工具來校驗(yàn)mirror和primary實(shí)例下數(shù)據(jù)文件的值是否一致,通過mirror的文件來覆蓋primary下的文件來解決;
2. 一般這種表都為歷史時(shí)間分區(qū)表,數(shù)據(jù)可以通過hadoop集群重新寫入,所以如果出現(xiàn)問題,則可以通過把該表刪除,并重新入數(shù)來解決;
上面的講到了GP數(shù)據(jù)庫中文件的損壞,及排查思路,那怎么確定損壞的數(shù)據(jù)文件和表之間的關(guān)系,下面在一起了解下這個(gè)關(guān)系如何確定;
首先介紹下在GP數(shù)據(jù)庫中表的存儲(chǔ)格式:Heap表和AO表(AORO表,AOCO表)
Heap表:這種存儲(chǔ)格式是從PostgreSQL繼承而來的,目前是GP默認(rèn)的表存儲(chǔ)格式,只支持行存儲(chǔ)。
AO表:AO表最初設(shè)計(jì)是只支持append的(就是只能insert),因此全稱是Append-Only,在4.3之后進(jìn)行了優(yōu)化,目前已經(jīng)可以u(píng)pdate和delete了,全稱也改為Append-Optimized。AO支持行存儲(chǔ)(AORO)和列存儲(chǔ)(AOCO)。
從上面的這個(gè)錯(cuò)誤信息可以看出表在primary實(shí)例對(duì)應(yīng)的數(shù)據(jù)文件有損壞,遇到這個(gè)問題,首先想到的就是這個(gè)數(shù)據(jù)文件對(duì)應(yīng)的是那個(gè)表,但是該如何通過數(shù)據(jù)文件查到對(duì)應(yīng)的表呢?
熟悉GP數(shù)據(jù)庫的工程師立馬會(huì)想到通過pg_class 中的relfilenode 這個(gè)信息來找到對(duì)應(yīng)的表例如:
這樣就找到了對(duì)應(yīng)的表,大家肯定會(huì)說這也太簡(jiǎn)單了,這種方式一般都是用來查heap表和一些剛好是AO表的數(shù)據(jù)文件對(duì)應(yīng)的應(yīng)用數(shù)據(jù)表。
但是GP數(shù)據(jù)庫中AO表是一種比較特殊的表,每個(gè)AO表都有一個(gè)關(guān)聯(lián)的系統(tǒng)表,該系統(tǒng)表用于管理文件系統(tǒng)上的段文件,所以我們可以查到下面兩種結(jié)果,仔細(xì)看這兩種結(jié)果有什么不同:
AO表的行存和列存在數(shù)據(jù)庫中存儲(chǔ)時(shí)名稱是有區(qū)別的,區(qū)別如下:
AORO(行存)表名: [pg_aoseg.pg_aoseg_xxxxxx>]
AOCO(列存)表名: [pg_aoseg.pg_aocsseg_xxxxxx>]
這明顯不是我們想要的表,遇到這種結(jié)果我們?cè)撛趺赐ㄟ^這個(gè)系統(tǒng)表來找到對(duì)應(yīng)的表?
當(dāng)年一些有經(jīng)驗(yàn)的老鳥曾告訴過一種比較偷懶的辦法是AO表的系統(tǒng)表結(jié)構(gòu)中結(jié)尾都是數(shù)字結(jié)束的,這些數(shù)字就是該表所對(duì)應(yīng)的relfilenode,我就試了下,結(jié)果如下:
還真的查到了,快捷方便,所以在接下來的一段時(shí)間里,我一直使用這種方式也解決了很多問題。
直到一次故障,讓我意識(shí)到偷懶的辦法只能用來偷懶,在遇到更棘手的故障時(shí),這種純經(jīng)驗(yàn)式解決方法是行不通的。事情是這的,應(yīng)用側(cè)反饋又出現(xiàn)了Block checksum does not match的報(bào)錯(cuò),把對(duì)應(yīng)的數(shù)據(jù)文件號(hào)發(fā)給我后。按照老方法根據(jù)文件號(hào),通過pg_class 中的relfilenode來找對(duì)應(yīng)的表,找到后發(fā)現(xiàn)是張AO表,然后又根據(jù)AO表的系統(tǒng)表后面的數(shù)字找對(duì)應(yīng)的表,結(jié)果這次沒找,確認(rèn)了好幾次就是這個(gè)文件號(hào),但是查出來的結(jié)果卻是為空;
結(jié)果如下:
這讓我意識(shí)到該辦法不科學(xué)不嚴(yán)謹(jǐn),不能予以依賴,通過基于原理的辦法步驟來找對(duì)應(yīng)的表。
首先想到AO表所有信息會(huì)存在pg_appendonly數(shù)據(jù)字典中,然后一步步按照流程來查詢,最終找到了的對(duì)應(yīng)表;
在后續(xù)通過幾次實(shí)驗(yàn)得出了一個(gè)兩張數(shù)據(jù)字典表的關(guān)聯(lián)關(guān)系:
ao表的系統(tǒng)表 pg_class 的oid等于pg_appendonly 的segrelid;
ao表的基表中 pg_class 的oid等于pg_appendonly 的relid
今天的GP故障分享就到這里,后續(xù)會(huì)繼續(xù)帶來現(xiàn)場(chǎng)各種問題處理的案例分享和心得體會(huì),我們下次見。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/130221.html
摘要:上有主節(jié)點(diǎn)和從節(jié)點(diǎn)兩部分,兩者主要的功能是生成查詢計(jì)劃并派發(fā),以及協(xié)調(diào)并行計(jì)算,同時(shí)在上保存著,這個(gè)全局目錄存著一組數(shù)據(jù)庫系統(tǒng)本身所具有的元數(shù)據(jù)的系統(tǒng)表。 前言:近年來,互聯(lián)網(wǎng)的快速發(fā)展積累了海量大數(shù)據(jù),而在這些大數(shù)據(jù)的處理上,不同技術(shù)棧所具備的性能也有所不同,如何快速有效地處理這些龐大的數(shù)據(jù)倉,成為很多運(yùn)營(yíng)者為之苦惱的問題!隨著Greenplum的異軍突起,以往大數(shù)據(jù)倉庫所面臨的很多...
閱讀 1353·2023-01-11 13:20
閱讀 1699·2023-01-11 13:20
閱讀 1211·2023-01-11 13:20
閱讀 1902·2023-01-11 13:20
閱讀 4161·2023-01-11 13:20
閱讀 2748·2023-01-11 13:20
閱讀 1397·2023-01-11 13:20
閱讀 3664·2023-01-11 13:20