Berkeley DB -- DB Replication (HA)中部
Synchronizing with a master
當一個client探測到replication組内一個新的master後,在它能去處理新的資料庫變化之前,這個client必須去同步這個新的master。同步是一個重量及操作,它能同時給
這個client和master增加負擔。這兒有一些措施,一個應用程式可以用來減輕同步的負擔。
延遲client同步:
當組内有了一個新的master,不論是被應用程式指定的還是因為選舉的結果,所有的clients必須去同步這個新的master。這會使新的master的資源過度損耗,因為很多clients可能都試圖去和它通信和從它那兒取得記錄。clients應用程式如果想延遲client的同步,應該用DB_REP_CONF_DELAYCLIENT标志去調用DB_ENV->rep_set_config 方法。這個配置使得client總從DB_ENV->rep_process_message方法傳回DB_REP_NEWMASTER,但是這個client将不會繼續去同步這個新的master。Client端應用程式選擇延遲同步,用這種方法,那麼将來再用DB_ENV->rep_sync方法去同步将是可靠的。
client-to-client的同步:
Clients可以接受和服務其他clients的請求。Clients請求記錄調用這個Client應用程式的傳輸回調函數。可以由其他Clients滿足的請求,傳輸函數的标志被設定成DB_REP_ANYWHERE。應用程式可以選擇發送這些請求到任意client,或者忽略這個标志,而把請求發送到這個消息的環境id所指定的站點。
Client應用程式可以用不管什麼算法,它們選擇來負載均衡到其它clients的請求。
任何client接受到一個它不能滿足的請求,都将回複給請求的client,告訴它,自己不能夠提供請求的資訊,而那個最初的請求者,将重新請求這個資訊。另外,如果這個最初的請求沒有到達發要發送給的那個目标client端,這個最初的發送請求的client也将重新請求這個資訊。這這些任意一種情況下,這個重新的請求将把傳輸函數的标志設定成DB_REP_REREQUEST 。應用程式可能通過把這個請求進一步傳遞給naster來響應這個DB_REP_REREQUEST 标志(因為是被這個消息的環境id指定的),或繼續把這個請求傳送給另一個client。
這延遲的同步和client-to-client的同步特性允許應用程式在replication組内做負載均衡。例如,考慮到一個組内有5個站點, A, B, C, D 和 E,站點E剛剛倒掉了,站點A被選舉為master。站點C 和 D 被配置成延遲同步的,當B注意到站點A是一個新master,它立即進行同步。當B完成和master的同步的時候,站點C 和 D 上的應用程式調用 DB_ENV->rep_sync 方法,使它們也進行同步。站點C 和 D (和 E, 當它完成了重新開機) 可以發送他們的請求到站點 B, 而B可以負擔因為同步而産生的工作和網絡流量的沖擊, 使的master,站點A,有空去處理正常的應用程式工作量和由于選舉而暫停的寫請求。
阻塞client的操作:
Clients在處理和master的同步的時候将阻塞bdb其它的操作。預設的,許多bdb方法将阻塞,直到client同步完成,然後,這些被阻塞的方法才繼續調用。
那些不能等待的Client應用程式,将更願意立即得到一個錯誤傳回而不是阻塞,那麼就應該用DB_REP_CONF_NOWAIT 标志調用DB_ENV->rep_set_config方法。如果這個clinet現在正在同步一個master,這個配置使得bdb方法調用立即傳回一個DB_REP_LOCKOUT 錯誤,而不是阻塞。
Clients太落伍以至于不能同步:
Clients試圖去和master同步的時候可能會發現,同步是不可能的了,因為client和master 已經失去聯系很久了。預設地,client和master自動的檢測這個狀态和執行clinet内部初始化。因為内部初始化需要傳輸整個資料庫到clinet,這可能會發費一個相對較長的時間,可能需要clinet應用程式的資料庫句柄重新被打開。
那些不能等待的應用程式,更願意推後内部初始化直到一個更加便利的時間,或者更希望做一個熱備份而不是執行内部初始化,應該用REP_CONF_NOAUTOINIT 标志來調用DB_ENV->rep_set_config方法。這個配置使得bdb傳回DB_REP_JOIN_FAILURE到應用程式而不是執行内部初始化。
Client應用程式如果選擇了延遲同步,這樣就有責任在将來的時間和master進行同步。這可以通過關閉DB_REP_CONF_NOAUTOINIT标志和調用DB_ENV->rep_sync 方法來完成,或通過執行一個熱備份。
Initializing a new site
預設地,添加一個新站點到一個replication組,隻需要這個client去加入。bdb将自動從master到client給它執行内部初始化,引導這個client和master同步。盡管如此,還依賴于網絡和底層結構,在一些場合下使用“熱備份”在組内去初始化一個client還是比較有利的。Clients不想自動執行内部初始化應該用DB_REP_CONF_NOAUTOINIT标志調用DB_ENV->rep_set_config 方法。這個配置使得bdb傳回DB_REP_JOIN_FAILURE到應用程式的DB_ENV->rep_process_message方法,而不是執行内部初始化。
為了使用熱備份去初始化一個到replication組的clinet,執行下面的步驟:
做個一master環境的檔案備份,就像在“資料庫和日志檔案檔案”(Database and log file archival)中描述的那樣。這個備份可以是正常的備份或一個熱備份。
拷貝這個檔案備份到client的一個幹淨的環境目錄中。在client的新環境裡執行災難恢複,就像在恢複程式中描述的那樣。
重新配置和重新打開這個環境作為組内的一個client成員。如果拷貝這個備份到client,相對于用db_archive公用程式或用DB_ENV->log_archive方法再造日志檔案的周期來說,發費較長的時間,它可能需要抑制日志再造(reclamation),直到這個新啟動的client已經追上(caught up)和應用了所有在停工期間産生的log記錄。
就像任何bdb應用程式一樣,當應用程式啟動的時候資料庫環境必須在一個一緻的(consistent)狀态。這是可以通過在一個線程或一個程序啟動時執行恢複來最簡單的确定的。這是對clients和masters來說無害的,即使它們不是嚴格的必需的,也就是說即使他們實際上沒什麼需要恢複的。
Bulk transfer
組内的站點們可能通過用DB_REP_CONF_BULK标志調用DB_ENV->rep_set_config 方法,而把配置成使用批量傳輸的。當被配置成批量傳輸,站點們将在一個緩沖區内積聚記錄,然後在一次單一的網絡傳輸中把它們傳送給另一個站點。配置批量傳輸對master來說當然很有意義。另外,使用client-to-client同步的應用程式可能會發現,配置成批量傳輸對clients站點們來說也是很有幫助的。
當一個master正在産生新的log記錄時,或者,或請求任何master的資訊時,如果批量傳輸被配置,記錄将堆積在一個批量緩沖區中。當緩沖區被裝滿了或一個永久的記錄(例如,一個事務送出或一個檢查點記錄)被這個client排隊等待,批量緩沖區将發送給client。
當一個client在響應另一個client的請求的資訊的時候,如果批量傳輸被配置,記錄将在批量緩沖區中堆積。批量緩沖區将發送給client,當緩沖區被裝滿了或當這個client的請求已經被滿足了,再沒有特别類型的記錄将需要這緩沖區去發送了。
批量緩沖區的大小,它自己已經内定了不能被配置。盡管如此,在一次傳輸資料的總的大小可以通過使用DB_ENV->set_rep_limit方法來限制。
Transactional guarantees
在總的資料庫環境的事務保證的上下文中去考慮replication是和重要的。作為簡要的回顧,在一個非複制(non-replicated )中事務保證,是基于寫log檔案記錄到穩定的儲存設備上,通常是一個磁盤驅動器。如果應用程式回系統出了故障,bdb的日志資訊将在恢複時被回顧,而且資料庫被更新,以使已送出的事物的改變部分出現,所有未送出的而改變的部分不出現。在這種情況下,沒有資訊将會丢失。
如果一個資料庫環境不要求當事務送出的時候把log寫到穩定儲存設備上(使用DB_TXN_NOSYNC标志能以犧牲事務的經久性為代價來增加性能),bdb恢複将隻能把這個存儲系統恢複到最後一個送出了的被儲存在磁盤上了的狀态。在這種情況下,資訊可能已經丢失(例如,一些已經由事物送出了的改變可能在恢複之後不會出現在資料庫中)。
更進一步。如果這兒有資料庫或log檔案丢失或腐爛(例如,如果一個磁盤驅動器出了故障),然後災難恢複将是必要的,bdb恢複将隻能把這個系統重新存儲到最後一次歸檔log那兒。在這中情況下,資訊仍然可能被丢失。
複制(Replicating)這個資料庫環境通過添加一個新的組成到“穩定存儲”上擴充了這個模式:這個clinet的replicated資訊。如果一個資料庫環境是replicated,在資料庫或log丢失的情況下,這兒也不會有資訊丢失,因為這個複制系統可以被配置成包含資料庫和log記錄直到故障點的全部的設定。一個資料庫丢失了一個磁盤驅動器能使這個磁盤被複制,然後,它有能重新加入這個複制(replication)組。
由于這個新的穩定存儲的組成部分,指定DB_TXN_NOSYNC到一個複制組将不再犧牲耐久性了,隻要具備一個或多個clients有公認的master所發送消息的收條。因為網絡連接配接通常比本地同步磁盤寫的快,replication成為大幅度提高它們的性能和可靠性的一個方法。
應用程式發送函數的傳回狀态必須被應用程式設定成確定應用程式想要提供的事務保障。無論什麼時候,發送函數傳回失敗,本地資料庫環境的log将被重新整理(flushed),以確定任危急到到資料庫完整性的資訊不被丢失。因為這個重新整理是一個昂貴的開銷,會影響資料庫性能,如果可能的話,應用程式應該避免從發送函數那傳回一個錯誤資訊。
replication事務保障唯一感興趣的消息類型是當應用程式的發送函數指定了DB_REP_PERMANENT 标志被調用。如果發送函數曾經傳回失敗這兒将是沒有原因的,除非
DB_REP_PERMANENT 标志被指定--消息沒有DB_REP_PERMANENT被指定,不會使資料庫有明顯的改變,而且發送函數可以成功傳回到bdb,隻要這個消息被發送到client(s),或僅僅被拷貝到本地應用程式記憶體中預備發送。
當一個client收到一個DB_REP_PERMANENT 消息,這個client将在傳回前重新整理它的log到穩定儲存設備上(除非這個client環境曾經用DB_TXN_NOSYNC 選項配置過)。
如果這個client不能重新整理一個全部的事務記錄到磁盤,不管什麼原因(例如,在被标志的消息前丢失了一個log記錄),在client上調用DB_ENV->rep_process_message方法将傳回DB_REP_NOTPERM 和在ret_lsnp參數中傳回這個記錄的LSN到應用程式。
這個應用程式的client或master消息處理的循環應該适當的帶些動作以確定在這種情況下的正确的事務保障。當丢失的記錄到達,而且允許随後處理這些以前存儲的永久記錄,在clinet上調用DB_ENV->rep_process_message 方法将傳回DB_REP_ISPERM和傳回永曾經被重新整理到磁盤中的久記錄的最大的LSN。Client 應用次序可以用這些LSN決定性的知道是否某些特定的LSN被永久存儲了。
一個應用程式依賴于client的能力去成為master,而且保證沒有資料曾經被丢失,将需要編寫發送函數傳回一個錯誤,無論什麼時候它都不能保證将赢得下一次選舉的站點會有這個記錄。
應用程式不要求這個級别的事務保證将不需要讓這發送函數傳回失敗(除非master的資料庫環境用DB_TXN_NOSYNC配置過),因為任何危急到資料庫完整性的資訊在發送被調用前已經被重新整理到本地log檔案。
總的來說,發送函數要傳回失敗的唯一的原因是當master的資料庫環境被配置成當事務送出的時候不去重新整理log(也就是說,在master上DB_TXN_NOSYNC被配置了), DB_REP_PERMANENT 标志被指定給消息, 而且發送函數不能決定哪些clients收到了目前的消息(和所有在目前消息之前的消息)。多少clients在發送函數成功傳回之前需要接收這個消息那是應用程式的選擇(可能不是過多的依賴于特定數目的cleints報告成功作為一個或多個實體上分布式的 clients)。
如果,盡管如此,master上的應用程式确實需要在磁盤上的耐久性,那麼這個應用程式應該被配置成當事務送出的時候同步的重新整理記錄。如果一個client沒被配置成同步重新整理log,也就是說,一個client運作的時候DB_TXN_NOSYNC是被被配置的,當它變成master的時候,那麼它将取決于應用程式去适當地重新配置那個client。也就是說,這個應用程式必須明确的調用DB_ENV->set_flags去重新配置這個新成為master的client,使異步log重新整理無效。
當然,確定replicated master和client環境确實是互相獨立的很重要。例如,如果master和clients在同一個能源供給上(on the same power supply),一個client承認收到一個消息對事情是沒什麼幫助的,因為能源供給的失敗仍然潛在地會使資訊丢失。
配置的你基于replication的應用程式,能事務和性能上找到最佳結合點,是很複雜的。簡言之,這兒有一些應用程式可以設定的地方以調節:為master環境指定DB_TXN_NOSYNC;為client環境指定DB_TXN_NOSYNC;不同的站點一起參加選舉的那個優先權;應用程式發送函數的行為。
首先,在一個replication client中當一個事物送出的時候,寫和同步重新整理log幾乎沒什麼用處。如果這些系統共享一個資源或多個系統同時出故障也許寫和同步重新整理log還有點用。預設地,所有的bdb環境,不管是master還是client,當事務送出的時候或預先地,都同步地重新整理log。
考慮兩個有網絡連接配接的的系統。一個作為master,一個作為隻讀的client。如果master倒掉了client取代之,在這次故障後,master又重新加入到replication組。master 和client都被配置成當事務送出的時候不同步重新整理日志(也就是說DB_TXN_NOSYNC 在兩個系統上都被配置)。這個應用程式的發送函數從不傳回失敗到bdb庫,隻個簡單的傳遞消息到這個client(或許基于一個廣播機制),而且總是傳回成功。在client上,由client的DB_ENV->rep_process_message方法傳回的DB_REP_NOTPERM也将被忽略。這個系統配置有優秀的性能,但在某些失敗的模式下有可能丢失資料。
如果這個master和client都一下子到掉了,就有可能丢失已經送出了的事務,也就是說,事務的耐久性沒有被維持。有責任去提高系統的能源供給的獨立性和把他們放在實體上隔離的地方。
如果這兩個系統間的連接配接出了故障(或者僅僅是一些消息丢失了),并且随後這個master倒掉了,也有可能失去已送出的事務。又是因為事務的耐久性沒有被維護。下面的一些方法中可以提高可靠性:
使用可靠的網絡協定(例如,tcp而不是udp)。
增加clients和網絡路徑的數目,以使消息不太可能被丢失。在這種情況下,確定 client确實收到了這消息以赢得任何随後的選舉也是很重要的。 如果一個client沒有受到這個消息而赢得了随後的選舉,那麼資料仍然可能被丢失。
進一步的,系統可能想保證消息傳遞給了client(s)(例如,去阻止網絡連接配接簡單的丢棄消息)。一些系統可能想確定clients從來不傳回已過期的資訊,也就是說,一旦事務送出後在master上傳回成功,将沒有client在響應隻讀請求時傳回舊的資訊。下面的改變可能會用來闡述這些觀點:
編寫應用程式的發送函數,使它們直到一個或多個client承認收到了這個消息時才傳回到bdb。這個clients的數目的選擇是由應用程式決定的:你将很可能會想網絡隔離(確定每個實體站點的client收到這個消息)和地理上多樣性(確定一個client在每條線路“each coast ”上都收到這個消息)。
編寫client的消息處理循環,使直到DB_ENV->rep_process_message傳回成功的時候才承認收到這條資訊。當DB_ENV->rep_process_message 方法傳回DB_REP_NOTPERM 時意味着這個消息不能被重新整理到client的磁盤。如果這個client不向master承認收到這個消息直到随後調用的DB_ENV->rep_process_message方法傳回DB_REP_ISPERM而且這個傳回的LSN至少和這個消息的LSN一樣大,然後這個master的發送函數将不會傳回success到bdb庫。這意味着,直到那些經由挑選的clients已經收到了這個消息而且認為完成了,mastet上正在送出事務的這個線程将才被允許繼續下去。
作為選擇,client的消息處理循環可以向master承認收到了這個消息,但是用一個錯誤代碼指明那個應用程式的發送函數不要傳回到bdb庫,直到一個随後的來自同一個client的确認成功。
應用程式的發送回調函數被bdb調用包括一個記錄的LSN被發送(如果對那個記錄來說是适當的)。當DB_ENV->rep_process_message 傳回訓示一個永久的記錄已經被寫入,然後它也回傳回這個被寫入的永久記錄的最大LSN 。
這兒最後的兩關需要考慮。首先,當應用程式的發送函數被調用的後,事務是不可被中途中斷的,因為這個 master可能已經把事物送出日志記錄寫入磁盤,是以中途中斷将不再是一個可選擇項。第二,一個相近的問題是,如果發送函數傳回失敗,盡管這個master将試圖去重新整理本地log,這個重新整理操作将可能失敗(例如,當本地磁盤是滿的)。此外,事務不能被中途中斷,因為一個或多個clients可能已經送出了這個事務即使發送函數傳回失敗。傑出的應用程式可能也忍受不了這些不太可能的失敗方式。在那中情況下應用程式可能想:
1,配置這master總去同步本地送出的事務(關閉DB_TXN_NOSYNC 配置項)。這樣将對性能有很大的影響,當然(使用replication的其中的一個原因是避免本地磁盤的寫操作),在這種配置下,不管什麼情況,寫本地日志失敗将使事務中途中斷。
2,在任何情況下都不要從應用程式的發送函數中傳回,除非挑選的那些client已經承認了收到那個消息。直到這個發送函數傳回到這個bdb庫,master上這個正在送出事務的線程都将等待,是以沒有應用程式能表現出承認事務已經被送出了。
最後可供牽扯到這些類型的失敗的應用程式選擇的是使用分布式事務,保證完全的一緻性實作全局的事務管理和垮過多bdb環境履行兩階段送出。更多的了解這個可以參見分“the Distributed Transactions”那一章。