一、背景
常見的高可用架構中,如果master掛了且有數據沒有同步到備,高可用系統會提升備爲主對外服務。對於老主有可能再以備的身份加入集羣時,可能搭建流複製關係失敗。可以用pg_rewind工具使主備的數據一致。
二、pg_rewind原理
三、相關代碼
1、每個文件(目錄)的差異被記錄在結構體 file_entry_t 中,其定義如下
typedef struct file_entry_t
{
char *path;
file_type_t type;
file_action_t action;
/* for a regular file */
size_t oldsize;
size_t newsize;
Bool isrelfile;
/* is it a relation data file? */
datapagemap_t pagemap;
/* for a symlink */
char *link_target;
struct file_entry_t *next;
} file_entry_t;
2、文件類型
typedef enum
{
FILE_TYPE_REGULAR,//常規文件
FILE_TYPE_DIRECTORY,//目錄
FILE_TYPE_SYMLINK//軟連接
} file_type_t;
3、對應文件的操作action
typedef enum
{
FILE_ACTION_CREATE, /* 創建目錄或者軟鏈接: create_target(entry)*/
FILE_ACTION_COPY, /* 複製整個文件或者重寫已存在的文件: fetch_file_range(entry->path, 0, entry->newsize);*/
FILE_ACTION_COPY_TAIL, /* 從source中拷貝從oldsize到newsize的部分 fetch_file_range(entry->path, entry->oldsize, entry->newsize)*/
FILE_ACTION_NONE, /* 無操作 */
FILE_ACTION_TRUNCATE, /* 裁剪target集羣文件到'newsize'大小: truncate_target_file(entry->path, entry->newsize)*/
FILE_ACTION_REMOVE /* 刪除本地文件/目錄/軟鏈接: remove_target(entry)*/
} file_action_t;
4、其他變量解讀
isrefile 表示該文件是否是一個表數據文件,表數據文件的路徑要滿足以下幾個條件:
isRelDataFile(path):
global/ 目錄下的文件,即數據庫共享的表文件目錄下的文件
base/ 目錄下的文件,即默認tablespace的表文件目錄下的文件
pg_tblspc/&rnode.spcNode/TABLESPACE_VERSION_DIRECTORY/目錄下的文件,即其他tablespace 的表文件目錄下的文件,其中PG_9.4_201403261 與版本相關
文件名符合的格式
pagemap (怎麼用?extractPageInfo)存儲了一個bitmap,每一位存儲了對應的目的集羣文件中的每個page 從兩個集羣的分叉點之後是否發生了變化,1代表發生變化,0代表未變化。
oldsize 代表目的集羣該文件的大小,newsize 代表源集羣該文件的大小。pg_rewind 中通過源集羣和目的集羣的對應文件大小比較或者文件(目錄)是否存在,指定文件的處理action,例如:
oldsize > newsize: action=FILE_ACTION_TRUNCATE
oldsize < newsize: action=FILE_ACTION_COPY_TAIL
如果文件不存在,則action=FILE_ACTION_COPY,PG_VERSION文件除外
如果目錄不存在,則action=FILE_ACTION_CREATE
如果文件多餘,則action=FILE_ACTION_REMOVE
以上動作由函數process_target_file和process_source_file一起處理。只在process_target_file設置FILE_ACTION_REMOVE
5、提取wal日誌獲取更改頁的步驟:
extractPageInfo:
for (block_id = 0; block_id <= record->max_block_id; block_id++){
if (!XLogRecGetBlockTag(record, block_id, &rnode, &forknum, &blkno))
continue;
/* We only care about the main fork; others are copied in toto */
if (forknum != MAIN_FORKNUM)//MAIN_FORKNUM是什麼意思?
continue;
process_block_change(forknum, rnode, blkno);
}
6、pagemap中的bitmap
pg_rewind 工具執行需要打開full_page_writes,而打開了full_page_writes 之後,checkpoint 後每個數據頁的第一次修改對應的數據頁的全部內容都會寫在WAL日誌記錄中,所以pg_rewind 可以根據WAL 日誌的組織結構很容易的找到對應已經修改的數據頁信息,並把對應的file_entry_t 的bitmap 置爲1。
XLogRecGetBlockTag:XLogReaderState.blocks[XLR_MAX_BLOCK_ID + 1]