接到應(yīng)用側(cè)反饋GP數(shù)據(jù)庫有些表經(jīng)常出現(xiàn)突然無法查詢的情況,或者表的某些數(shù)據(jù)查詢不了了,并且報錯信息都非常相似,報錯信息均指向表對應(yīng)的數(shù)據(jù)文件校驗不一致,報錯信息如下:
運行日志:【在Agent[1330162]執(zhí)行結(jié)果:存儲過程:p_dw_ulc_usr_prov_happy_ds執(zhí)行完成,返回信息:參數(shù)名稱:o_return_code參數(shù)值:XX000,參數(shù)名稱:o_return_msg參數(shù)值:SQL5:從接口取原始數(shù)據(jù)出錯! 錯誤信息: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,】 |
看到報錯信息,立馬想到是否是磁盤問題造成文件在寫磁盤的時候出現(xiàn)了問題,按照這個思路抓緊核查磁盤。
RAID卡底層日志沒有發(fā)現(xiàn)有reset、time out等異常打印
暫時排除磁盤問題,那還有哪里出問題會導(dǎo)致數(shù)據(jù)問題?順其自然想到是否是GP數(shù)據(jù)庫在primary實例和mirror實例數(shù)據(jù)同步的時候出現(xiàn)問題?
我們先來溫故一下primary實例和mirror實例主備復(fù)制的機制。
大家都知道Greenplum 是基于PostgreSQL開發(fā),PostgreSQL的主備也是通過流復(fù)制實現(xiàn),但是Segment節(jié)點中的Primary和Mirror之間的數(shù)據(jù)同步是基于文件級別的同步方式實現(xiàn)的。為什么Primary和Mirror不能再使用流復(fù)制實現(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要同步文件,是因為Primary和Mirror之間可以自動failover,只有兩者保持同步才能相互替代,如果只把數(shù)據(jù)同步過去,pg_control、pg_clog、pg_subtrans 沒有同步,那么從Primary切換到Mirror就會出現(xiàn)問題。
GP master和GP slave卻不用擔(dān)心這些問題,Append Only 表的數(shù)據(jù)只會存在 Segment,所以WAL日志足夠保持GP master和GP slave同步(只要是流復(fù)制,pg_control、pg_clog、pg_subtrans 這些文件Slave會自動更新,無需從Master同步)。
當GP master向Primary下發(fā)執(zhí)行計劃后,Primary開始執(zhí)行,如果是DML操作,那么Primary會產(chǎn)生XLOG及更新page。會在SlruPhysicalWritePage函數(shù)中(寫數(shù)據(jù)頁)產(chǎn)生FileRepOperationOpen、FileRepOperationWrite、FileRepOperationFlush、FileRepOperationClose等指令消息(消息中包含具體要更新的文件page及內(nèi)容),通過primary sender進程向Mirror發(fā)送Message,然后Mirror的mirror consumer等進程解析消息,執(zhí)行變更。XLOG通過XLogWrite函數(shù)(寫XLOG)執(zhí)行同樣的操作,把XLOG更新同步過去。
Primary的recovery進程會循環(huán)把Primary的 pg_control、pg_clog、pg_subtrans 等文件覆蓋到Mirror。同時檢查XLOG是否一致,如果不一致以Primary為主,對Mirror進行覆蓋。除把Primary部分文件同步到Mirror之外recovery進程還會將Mirror上面的臨時文件刪掉。
根據(jù)以上的機制,在實驗環(huán)境做了兩個實驗進行驗證:
1. 將mirror的data目錄設(shè)置為gpadmin無權(quán)限訪問。
2. 在master上操作, 進行數(shù)據(jù)寫入。
1. 寫入操作卡住一段時間(等待mirror寫入)。
2. primary發(fā)現(xiàn)無法與mirror同步, 因此將mirror設(shè)置為down的狀態(tài)。
3. 數(shù)據(jù)寫入繼續(xù)在primary進行, 寫入完成。
正常情況下, 一個事務(wù)必須在primary和mirror都寫入完成的情況下才會提交, 如果primary和mirror無法同步, 那么會在超時后將mirror標記為 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進行寫入操作。
2. 在寫入的同時, 破壞primary的table文件. (cat xxx >> [table file]), 模擬硬件/文件系統(tǒng)問題導(dǎo)致?lián)p壞的情況。
3. 寫入完成后, 對表執(zhí)行select操作。
1. 寫入可以正常完成, 因為寫入的操作的塊文件正常完成(fsync)。
2. 由于文件被破壞, 因此在select的時候會報錯。
3. 同時, 由于復(fù)制是基于塊的同步, 因此primary的損壞操作(人為追加)不會同步到mirror上, 因此mirror上的文件沒有問題。
1.當數(shù)據(jù)寫入時, 數(shù)據(jù)塊分兩條線走, 一條發(fā)送給mirror, 一條到primary落盤。
2.GP只會檢查數(shù)據(jù)塊本身是否寫入完成(fsync), 對于落盤之后的外部操作無法感知, 即硬件/系統(tǒng)問題引起的數(shù)據(jù)文件損壞在數(shù)據(jù)塊落盤后是無法發(fā)現(xiàn)的
3.只有在之后讀取到對應(yīng)的數(shù)據(jù)文件時, 才會檢查到數(shù)據(jù)塊錯誤.
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=# |
通過上面的實驗可以了解到primary實例和mirror實例之間的同步機制:當數(shù)據(jù)寫入時候, 數(shù)據(jù)塊分兩條線走, 一條發(fā)送給mirror, 一條到primary落盤,GP只會檢查數(shù)據(jù)塊本身是否寫入完成(fsync), 對于落盤之后的外部操作無法感知, 即硬件/系統(tǒng)問題引起的數(shù)據(jù)文件損壞在數(shù)據(jù)塊落盤后是無法發(fā)現(xiàn)的,只有在之后讀取到對應(yīng)的數(shù)據(jù)文件時, 才會檢查到數(shù)據(jù)塊錯誤。
上面實驗報錯明顯的指出了是primary實例下的文件有校驗不一致的情況發(fā)生,那我們接著往下看mirror的文件是否有問題。
這個該怎么驗證?很簡單,把出現(xiàn)問題的文件和對應(yīng)mirror實例下的文件做個md5sum的校驗,看結(jié)果值是否一致,如一致則表明mirror實例下的文件肯定也損壞了,如不一致,則把兩個文件備份一份,再把mirror實例下的文件覆蓋primary實例下有問題的文件,對有問題的表再做一次查詢,看是否還報錯,通過實驗及測試,如果AO表使用上面的方法可以解決文件壞塊的問題,則說明是文件損壞的問題,不是在primary實例和mirror實例之間同步數(shù)據(jù)造成,因為如果是同步數(shù)據(jù)造成的,mirror文件也會損壞。
問題分析到這里遇到了瓶頸,磁盤也沒有問題,也不是數(shù)據(jù)庫數(shù)據(jù)同步造成的,那該是什么原因造成的呢?
看來只能對損壞的文件進行分析了,把之前報錯的文件全部收集出來對文件塊進行分析,
數(shù)據(jù)文件 7398846.1: Block 124473 checkusm 錯誤
- 日志顯示損壞位置為 block header offset in file = 644305640
- 通過解析該數(shù)據(jù)文件, 對應(yīng)的block為 124473
- 數(shù)據(jù)文件顯示block 21406存在checksum錯誤, head中的checksum與實際不符
- 同時, 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 錯誤:
- 日志顯示損壞位置為 block header offset in file = 182856032
- 通過解析該數(shù)據(jù)文件, 對應(yīng)的block為 21406
- 數(shù)據(jù)文件顯示block 21406存在checksum錯誤, head中的checksum與實際不符
- 同時, 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上。
下面我們對出現(xiàn)文件損壞的表在進行分析下:
- 我們在深入檢查table文件之后, 發(fā)現(xiàn)primary并沒有缺損, 事實上primary從08ed2000位置開始被寫了"0"
- primary從08ed2000 到 08ee03e0 都是0, 而mirror并不是
- 同時, 16進制的08ed2000,08ee03e0分別對應(yīng)10進制的149757952和149816288, 恰好都是是4096的整數(shù)倍(即這個位置是一個4096大小的block的開始)
2 < 08ed2000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 3 < * << 這里的星號表示都是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進制01110000和0111ecf0分別對應(yīng)10進制17891328和17951984, 同樣是4096的整數(shù)倍。
綜上所述, 經(jīng)研發(fā)部門確認該問題并非GPDB造成, 因為GPDB從來不會對table文件寫0。所以將從軟硬件方面來繼續(xù)排查問題 (XFS? LVM? SAN? RAID card?)。
問題分析到這里基本可以得出結(jié)論,造成Block checksum does not match問題的不是磁盤,也不是數(shù)據(jù)庫軟件本身的問題,但是還需要從主機系統(tǒng)等層面進行分析,已聯(lián)系操作系統(tǒng)等相關(guān)廠商一起進行分析,后續(xù)有進展將繼續(xù)分享。
這個問題目前的處理方法很簡單,有兩種:
1.找到該實例對應(yīng)的mirror實例,在對應(yīng)mirror實例下找到對應(yīng)的數(shù)據(jù)文件,通過MD5SUM工具來校驗mirror和primary實例下數(shù)據(jù)文件的值是否一致,通過mirror的文件來覆蓋primary下的文件來解決;
2. 一般這種表都為歷史時間分區(qū)表,數(shù)據(jù)可以通過hadoop集群重新寫入,所以如果出現(xiàn)問題,則可以通過把該表刪除,并重新入數(shù)來解決;
上面的講到了GP數(shù)據(jù)庫中文件的損壞,及排查思路,那怎么確定損壞的數(shù)據(jù)文件和表之間的關(guān)系,下面在一起了解下這個關(guān)系如何確定;
首先介紹下在GP數(shù)據(jù)庫中表的存儲格式:Heap表和AO表(AORO表,AOCO表)
Heap表:這種存儲格式是從PostgreSQL繼承而來的,目前是GP默認的表存儲格式,只支持行存儲。
AO表:AO表最初設(shè)計是只支持append的(就是只能insert),因此全稱是Append-Only,在4.3之后進行了優(yōu)化,目前已經(jīng)可以update和delete了,全稱也改為Append-Optimized。AO支持行存儲(AORO)和列存儲(AOCO)。
從上面的這個錯誤信息可以看出表在primary實例對應(yīng)的數(shù)據(jù)文件有損壞,遇到這個問題,首先想到的就是這個數(shù)據(jù)文件對應(yīng)的是那個表,但是該如何通過數(shù)據(jù)文件查到對應(yīng)的表呢?
熟悉GP數(shù)據(jù)庫的工程師立馬會想到通過pg_class 中的relfilenode 這個信息來找到對應(yīng)的表例如:
這樣就找到了對應(yīng)的表,大家肯定會說這也太簡單了,這種方式一般都是用來查heap表和一些剛好是AO表的數(shù)據(jù)文件對應(yīng)的應(yīng)用數(shù)據(jù)表。
但是GP數(shù)據(jù)庫中AO表是一種比較特殊的表,每個AO表都有一個關(guān)聯(lián)的系統(tǒng)表,該系統(tǒng)表用于管理文件系統(tǒng)上的段文件,所以我們可以查到下面兩種結(jié)果,仔細看這兩種結(jié)果有什么不同:
AO表的行存和列存在數(shù)據(jù)庫中存儲時名稱是有區(qū)別的,區(qū)別如下:
AORO(行存)表名: [pg_aoseg.pg_aoseg_xxxxxx>]
AOCO(列存)表名: [pg_aoseg.pg_aocsseg_xxxxxx>]
這明顯不是我們想要的表,遇到這種結(jié)果我們該怎么通過這個系統(tǒng)表來找到對應(yīng)的表?
當年一些有經(jīng)驗的老鳥曾告訴過一種比較偷懶的辦法是AO表的系統(tǒng)表結(jié)構(gòu)中結(jié)尾都是數(shù)字結(jié)束的,這些數(shù)字就是該表所對應(yīng)的relfilenode,我就試了下,結(jié)果如下:
還真的查到了,快捷方便,所以在接下來的一段時間里,我一直使用這種方式也解決了很多問題。
直到一次故障,讓我意識到偷懶的辦法只能用來偷懶,在遇到更棘手的故障時,這種純經(jīng)驗式解決方法是行不通的。事情是這的,應(yīng)用側(cè)反饋又出現(xiàn)了Block checksum does not match的報錯,把對應(yīng)的數(shù)據(jù)文件號發(fā)給我后。按照老方法根據(jù)文件號,通過pg_class 中的relfilenode來找對應(yīng)的表,找到后發(fā)現(xiàn)是張AO表,然后又根據(jù)AO表的系統(tǒng)表后面的數(shù)字找對應(yīng)的表,結(jié)果這次沒找,確認了好幾次就是這個文件號,但是查出來的結(jié)果卻是為空;
結(jié)果如下:
這讓我意識到該辦法不科學(xué)不嚴謹,不能予以依賴,通過基于原理的辦法步驟來找對應(yīng)的表。
首先想到AO表所有信息會存在pg_appendonly數(shù)據(jù)字典中,然后一步步按照流程來查詢,最終找到了的對應(yīng)表;
在后續(xù)通過幾次實驗得出了一個兩張數(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ù)會繼續(xù)帶來現(xiàn)場各種問題處理的案例分享和心得體會,我們下次見。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/130221.html
摘要:上有主節(jié)點和從節(jié)點兩部分,兩者主要的功能是生成查詢計劃并派發(fā),以及協(xié)調(diào)并行計算,同時在上保存著,這個全局目錄存著一組數(shù)據(jù)庫系統(tǒng)本身所具有的元數(shù)據(jù)的系統(tǒng)表。 前言:近年來,互聯(lián)網(wǎng)的快速發(fā)展積累了海量大數(shù)據(jù),而在這些大數(shù)據(jù)的處理上,不同技術(shù)棧所具備的性能也有所不同,如何快速有效地處理這些龐大的數(shù)據(jù)倉,成為很多運營者為之苦惱的問題!隨著Greenplum的異軍突起,以往大數(shù)據(jù)倉庫所面臨的很多...
閱讀 1356·2023-01-11 13:20
閱讀 1707·2023-01-11 13:20
閱讀 1215·2023-01-11 13:20
閱讀 1906·2023-01-11 13:20
閱讀 4165·2023-01-11 13:20
閱讀 2757·2023-01-11 13:20
閱讀 1402·2023-01-11 13:20
閱讀 3671·2023-01-11 13:20