天天看點

Greenplum報“could not open relation XXX”

作者:中啟乘數科技

一天下午某個greenplum叢集發生了某個資料節點報“could not open relation 1663/16384/32749972: 無此檔案或目錄”,然後這個節點就再也無法啟動了,然後導緻了整個叢集無法啟動。雖然可以通過從備節點拷貝整個資料庫恢複了這個節點上,來恢複此資料庫,但由于資料庫的資料大小有500G-600G,資料量比較大,是以恢複時間比較長,對業務有很大的影響。這個故障在幾周前也出現過一次,本周四早上又出現過一次,是以是一個急需要解決的問題。是以想能否有一種方法能讓資料庫正常啟動,這樣就不需要從備節點拷貝資料了。

通過對此問題進行了詳細分析:發現當資料庫在啟動過程中,在通過應用WAL日志(類似oracle的redo日志)做執行個體恢複時,需要檔案“32749972”,而我們檢查其它好的節點,卻沒有發現這個檔案,是以基本認為,這個檔案隻是恢複過程中需要的一個檔案,最終實際上并不需要這個檔案。

可能的場景是:一個表先insert了一些資料,然後又被truncate掉了,這時開始這個檔案存在,且被insert了一些資料,最後中由于truncate,這個檔案被删除,然後又為這個表建了一個新的檔案。我們想,如果先touch一個空的檔案,然後再啟動資料庫,看資料庫能否正常啟動,這樣做後,發現恢複過程中會自動把我們建立的這個檔案删除掉,然後再報同樣的錯誤。從這個現象看,可能是資料庫在記WAL日志時出現了某種錯誤、或軟體bug。于是想,如果恢複過程中讓資料庫先删除不掉這個檔案,後面它再需要這個檔案時,就不會發生找不到此檔案的錯誤了。

那如何讓系統無法删除這個檔案呢?

可以這樣做,寫一個動态庫,動态庫中寫一個删除函數unlink,然後設定環境變量LD_PRELOAD_64等指向這個動态庫,然後再啟動資料庫,這樣資料庫調用删除函數unlink删除檔案時,就會調用到這個動态庫中的unlink函數。然後我寫的這個unlink函數中判斷如果要删除的檔案是32749972時,就不删除這個檔案,直接返加0,這樣讓資料庫認為成功删除了這個檔案,實際上這個檔案沒有被删除 。

此函數為:

int unlink(const char *path)
{
 static int (*real_unlink)(const char * path) = NULL;
 char * hookenv=getenv("FILEHOOK");
 char * filename;
 int len;
 len = strlen(path);

 filename = (char *)malloc(len+2);
 strcpy(filename,path);
 strcat(filename,",");

 if(strstr(hookenv,filename)!=NULL)
 {
 free(filename);
 return 0;
 }

 free(filename);

 if (!real_unlink)
 {
 real_unlink = dlsym(RTLD_NEXT, "unlink");
 if (!real_unlink)
 {
 exit(20);
 }

 }
 return real_unlink(path);
}
           

注意,我這個函數讀環境變量FILEHOOK,我們把環境變量FILEHOOK設定為:

export FILEHOOK=base/16384/32749972,base/16384/32749972.1,base/16384/32749972.2,           

這樣,當恢複過程中删除檔案32749972和32749972.1時,這兩個檔案實際并不會删除 。

下面開始我們的恢複過程:

export LD_PRELOAD_64='/export/home/gpadmin/filehook/filehook.so'
export FILEHOOK=base/16384/32749972,           

啟動資料庫:

postgres -D /storagepool/gpdatap4_bak/aligp71/ -i -p 50004           

發現資料庫還是啟動不起來,日志中報如下錯誤:

2011-03-04 10:57:12.568698 CST,,,p12300,th1,,,,0,,,seg-1,,,,,"WARNING","01000","page 33141 of relation 1663/16384/32749972 did not exist",,,,,,,0,,"xlogu

tils.c",186,

2011-03-04 10:57:12.569183 CST,,,p12300,th1,,,,0,,,seg-1,,,,,"PANIC","XX000","WAL contains references to invalid pages (xlogutils.c:193)",,,,,,,0,,"xlogu

tils.c",193,"Traceback 0: a11dc6: /opt/greenplum/greenplum-db-3.3.6.1/bin/postgres errstart+0x3e6           

日志的意思是資料塊“33141”不存在,由于greenplum中資料檔案最大是1G,33141塊的位置大約是1035M,超過了1G的大小,這樣資料庫就會把資料放到32749972.1的檔案中。

而我們沒有建立32749972.1的檔案,看樣子,我們還需要再建一個32749972.1的空檔案。

建了再試:

touch /storagepool/gpdatap4_bak/aligp71/base/16384/32749972
touch /storagepool/gpdatap4_bak/aligp71/base/16384/32749972.1
export LD_PRELOAD_64='/export/home/gpadmin/filehook/filehook.so'
export FILEHOOK=base/16384/32749972,base/16384/32749972.1           

資料庫仍然報:

2011-03-04 13:35:09.988426 CST,,,p12748,th1,,,,0,,,seg-1,,,,,"WARNING","01000","page 33141 of relation 1663/16384/32749972 was uninitialized",,,,,,,0,,"xlogutils.c",182,
2011-03-04 13:35:09.988915 CST,,,p12748,th1,,,,0,,,seg-1,,,,,"PANIC","XX000","WAL contains references to invalid pages (xlogutils.c:193)",,,,,,,0,,"xlogutils.c",193,"Traceback 0: a11dc6: /opt/greenplum/greenplum-db-3.3.6.1/bin/postgres errstart+0x3e6           

報33141塊是一個未初使用化的資料塊,把這個資料塊讀出來。

以前寫過一個blkcpy(https://gitee.com/osdba/blkcpy)的工具,使用這個工具讀這個資料塊。

33141塊超過了1G大小,33141塊應該在32749972.1的檔案中,前1G大小的塊是32768塊(32768*32K=1G),那麼這個塊就是32749972.1中的第373個塊,也就是在檔案32749972.1的11936k的偏移量處,讀這個塊:

blkcpy /storagepool/gpdatap4_bak/aligp71/base/16384/32749972 11936k 32k tang1.dat 0           

檢視内容:

od -t x1 tang1.dat |more           

發現原來全是0,怪不得報“was uninitialize”,于是我想拷貝一個正确的塊,把這個塊覆寫掉,能否就可以了呢?

先把下一個塊拷貝出來:

blockcopy /storagepool/gpdatap4_bak/aligp71/base/16384/32749972.1 11968k 32k tang2.dat 0           

檢視内容:

od -t x1 tang2.dat |more           

發現不是全零,可以使用。

把塊覆寫回去:

blkcpy tang2.dat 0 32k /storagepool/gpdatap4_bak/aligp71/base/16384/32749972.1 11936k           

然後再啟動資料庫,日志中出現“database system is ready”,資料庫終于啟動起來了。

2011-03-04 15:29:24.254245 CST,,,p13035,th1,,,,0,,,seg-1,,,,,"LOG","00000","next MultiXactId: 1; next MultiXactOffset: 0",,,,,,,0,,"xlog.c",5746,
2011-03-04 15:29:24.254403 CST,,,p13035,th1,,,,0,,,seg-1,,,,,"LOG","00000","database system was not properly shut down; automatic recovery in progress",,,,,,,0,,"xlog.c",5829,
2011-03-04 15:29:24.264931 CST,,,p13035,th1,,,,0,,,seg1,,,,,"LOG","00000","redo starts at 3C4/F85DB258",,,,,,,0,,"xlog.c",5893,
2011-03-04 15:29:25.417542 CST,,,p13035,th1,,,,0,,,seg1,,,,,"LOG","00000","recovery restart point at 3C4/F85DB258",,,,,"xlog redo checkpoint: redo 3C4/F85DB258; undo 0/0; tli 1; xid 0/16208151; oid 32752070; multi 1; offset 0; online",,0,,"xlog.c",7283,
2011-03-04 15:31:33.492538 CST,,,p13035,th1,,,,0,,,seg1,,,,,"LOG","00000","record with zero length at 3C5/31EB7BF8",,,,,,,0,,"xlog.c",3725,
2011-03-04 15:31:33.492623 CST,,,p13035,th1,,,,0,,,seg1,,,,,"LOG","00000","redo done at 3C5/31EB7BC0",,,,,,,0,,"xlog.c",5979,
2011-03-04 15:31:33.492814 CST,,,p13035,th1,,,,0,,,seg1,,,,,"LOG","00000","end of transaction log location is 3C5/31EB7BF8",,,,,,,0,,"xlog.c",5998,
2011-03-04 15:31:35.816999 CST,,,p13035,th1,,,,0,,,seg1,,,,,"LOG","00000","database system is ready",,,,,,,0,,"xlog.c",6189,
2011-03-04 15:31:35.817076 CST,,,p13035,th1,,,,0,,,seg-1,,,,,"LOG","00000","PostgreSQL 8.2.13 (Greenplum Database 3.3.6.1 build           

中啟乘數官網:中啟乘數科技(杭州)有限公司 - 首頁

原文連結:文章: Greenplum報“could not open relation XXX“

繼續閱讀