如何利用MongoDB實(shí)現(xiàn)高性能,高可用的雙活應(yīng)用架構(gòu)?
原創(chuàng)【51CTO.com原創(chuàng)稿件】投資界有一句至理名言——“不要把雞蛋放在同一個(gè)籃子里”。說(shuō)的是投資需要分解風(fēng)險(xiǎn),以免孤注一擲失敗之后造成巨大的損失。
隨著企業(yè)服務(wù)窗口的不斷增加,業(yè)務(wù)中斷對(duì)很多企業(yè)意味著毀滅性的災(zāi)難,因此,跨多個(gè)數(shù)據(jù)中心的應(yīng)用部署成為了當(dāng)下最熱門(mén)的話題之一。
如今,在跨多個(gè)數(shù)據(jù)中心的應(yīng)用部署***實(shí)踐中,數(shù)據(jù)庫(kù)通常負(fù)責(zé)處理多個(gè)地理區(qū)域的讀取和寫(xiě)入,對(duì)數(shù)據(jù)變更的復(fù)制,并提供盡可能高的可用性、一致性和持久性。
但是,并非所有的技術(shù)在選擇上都是平等的。例如,一種數(shù)據(jù)庫(kù)技術(shù)可以提供更高的可用性保證,卻同時(shí)只能提供比另一種技術(shù)更低的數(shù)據(jù)一致性和持久性保證。
本文先分析了在現(xiàn)代多數(shù)據(jù)中心中應(yīng)用對(duì)于數(shù)據(jù)庫(kù)架構(gòu)的需求。隨后探討了數(shù)據(jù)庫(kù)架構(gòu)的種類及優(yōu)缺點(diǎn),***專門(mén)研究 MongoDB 如何適用于這些類別,并最終實(shí)現(xiàn)雙活的應(yīng)用架構(gòu)。
雙活的需求
當(dāng)組織考慮在多個(gè)跨數(shù)據(jù)中心(或區(qū)域云)部署應(yīng)用時(shí),他們通常會(huì)希望使用“雙活”的架構(gòu),即所有數(shù)據(jù)中心的應(yīng)用服務(wù)器同時(shí)處理所有的請(qǐng)求。
圖 1:“雙活”應(yīng)用架構(gòu)
如圖 1 所示,該架構(gòu)可以實(shí)現(xiàn)如下目標(biāo):
- 通過(guò)提供本地處理(延遲會(huì)比較低),為來(lái)自全球的請(qǐng)求提供服務(wù)。
- 即使出現(xiàn)整個(gè)區(qū)域性的宕機(jī),也能始終保持高可用性。
- 通過(guò)對(duì)多個(gè)數(shù)據(jù)中心里服務(wù)器資源的并行使用,來(lái)處理各類應(yīng)用請(qǐng)求,并達(dá)到***的平臺(tái)資源利用率。
“雙活”架構(gòu)的替代方案是由一個(gè)主數(shù)據(jù)中心(區(qū)域)和多個(gè)災(zāi)備(DR)區(qū)域(如圖 2 所示)所組成的主-DR(也稱為主-被)架構(gòu)。
圖 2:主-DR 架構(gòu)
在正常運(yùn)行條件下,主數(shù)據(jù)中心處理請(qǐng)求,而 DR 站點(diǎn)處于空閑狀態(tài)。如果主數(shù)據(jù)中心發(fā)生故障,DR 站點(diǎn)立即開(kāi)始處理請(qǐng)求(同時(shí)變?yōu)榛顒?dòng)狀態(tài))。
一般情況下,數(shù)據(jù)會(huì)從主數(shù)據(jù)中心復(fù)制到 DR 站點(diǎn),以便在主數(shù)據(jù)中心出現(xiàn)故障時(shí),能夠迅速實(shí)施接管。
如今,對(duì)于雙活架構(gòu)的定義尚未得到業(yè)界的普遍認(rèn)同,上述主-DR 的應(yīng)用架構(gòu)有時(shí)也被算作“雙活”。
區(qū)別在于從主站到 DR 站點(diǎn)的故障轉(zhuǎn)移速度是否夠快(通常為幾秒),并且是否能夠自動(dòng)化(無(wú)需人為干預(yù))。在這樣的解釋中,雙活體系架構(gòu)意味著應(yīng)用停機(jī)時(shí)間接近于零。
有一種常見(jiàn)的誤解,認(rèn)為雙活的應(yīng)用架構(gòu)需要有多主數(shù)據(jù)庫(kù)。這樣理解是錯(cuò)誤的,因?yàn)樗饬硕鄠€(gè)主數(shù)據(jù)庫(kù)對(duì)于數(shù)據(jù)一致性和持久性的把握。
一致性確保了能讀取到先前寫(xiě)入的結(jié)果,而數(shù)據(jù)持久性則確保了提交的寫(xiě)入數(shù)據(jù)能夠被***保存,不會(huì)產(chǎn)生沖突寫(xiě)入;或是由于節(jié)點(diǎn)故障所產(chǎn)生的數(shù)據(jù)丟失。
雙活應(yīng)用的數(shù)據(jù)庫(kù)需求
在設(shè)計(jì)雙活的應(yīng)用架構(gòu)時(shí),數(shù)據(jù)庫(kù)層必須滿足如下四個(gè)方面的架構(gòu)需求(當(dāng)然,也要具備標(biāo)準(zhǔn)數(shù)據(jù)庫(kù)的功能,如具有:豐富的二級(jí)索引能力的查詢語(yǔ)言,低延遲地訪問(wèn)數(shù)據(jù),本地驅(qū)動(dòng)程序,全面的操作工具等):
- 性能,低延遲讀取和寫(xiě)入操作。這意味著:能在本地?cái)?shù)據(jù)中心應(yīng)用的節(jié)點(diǎn)上,處理讀取和寫(xiě)入操作。
- 數(shù)據(jù)持久性,通過(guò)向多個(gè)節(jié)點(diǎn)的復(fù)制寫(xiě)入來(lái)實(shí)現(xiàn),以便在發(fā)生系統(tǒng)故障時(shí),數(shù)據(jù)能保持不變。
- 一致性,確保能讀取之前寫(xiě)入的結(jié)果,而且在不同地區(qū)和不同節(jié)點(diǎn)所讀到的結(jié)果應(yīng)該相同。
- 可用性,當(dāng)某個(gè)節(jié)點(diǎn)、數(shù)據(jù)中心或網(wǎng)絡(luò)連接中斷時(shí),數(shù)據(jù)庫(kù)必須能繼續(xù)運(yùn)行。另外,從此類故障中恢復(fù)的時(shí)間應(yīng)盡可能短,一般要求是幾秒鐘。
分布式數(shù)據(jù)庫(kù)架構(gòu)
針對(duì)雙活的應(yīng)用架構(gòu),一般有三種類型的數(shù)據(jù)庫(kù)結(jié)構(gòu):
- 使用兩步式提交的分布式事務(wù)。
- 多主數(shù)據(jù)庫(kù)模式,有時(shí)也被稱為“無(wú)主庫(kù)模式”。
- 分割(分片)數(shù)據(jù)庫(kù)具有多個(gè)主分片,每個(gè)主分片負(fù)責(zé)數(shù)據(jù)的某個(gè)唯一片區(qū)。
下面讓我們來(lái)看看每一種結(jié)構(gòu)的優(yōu)缺點(diǎn)。
兩步式提交的分布式事務(wù)
分布式事務(wù)方法是在單次事務(wù)中更新所有包含某個(gè)記錄的節(jié)點(diǎn),而不是寫(xiě)完一個(gè)節(jié)點(diǎn)后,再(異步)復(fù)制到其他節(jié)點(diǎn)。
該事務(wù)保證了所有節(jié)點(diǎn)都會(huì)接收到更新,否則如果某個(gè)事務(wù)失敗,則所有節(jié)點(diǎn)都恢復(fù)到之前的狀態(tài)。
雖然兩步式提交協(xié)議可以確保持久性和多節(jié)點(diǎn)的一致性,但是它犧牲了性能。
兩步式提交協(xié)議要求在事務(wù)中所有參與的節(jié)點(diǎn)之間都要進(jìn)行兩步式的通信。即在操作的每個(gè)階段,都要發(fā)送請(qǐng)求和確認(rèn),以確保每個(gè)節(jié)點(diǎn)同時(shí)完成了相同的寫(xiě)入。
當(dāng)數(shù)據(jù)庫(kù)節(jié)點(diǎn)分布在多個(gè)數(shù)據(jù)中心時(shí),會(huì)將查詢的延遲從毫秒級(jí)別延長(zhǎng)到數(shù)秒級(jí)別。
而在大多數(shù)應(yīng)用,尤其是那些客戶端是用戶設(shè)備(移動(dòng)設(shè)備、Web 瀏覽器、客戶端應(yīng)用等)的應(yīng)用中,這種響應(yīng)級(jí)別是不可接受的。
多主數(shù)據(jù)庫(kù)
多主數(shù)據(jù)庫(kù)是一種分布式的數(shù)據(jù)庫(kù),它允許某條記錄只在多個(gè)群集節(jié)點(diǎn)中一個(gè)之上被更新。而寫(xiě)操作通常會(huì)復(fù)制該記錄到多個(gè)數(shù)據(jù)中心的多個(gè)節(jié)點(diǎn)上。
從表面上看,多主數(shù)據(jù)庫(kù)應(yīng)該是實(shí)現(xiàn)雙活架構(gòu)的理想方案。它使得每個(gè)應(yīng)用服務(wù)器都能不受限地讀取和寫(xiě)入本地?cái)?shù)據(jù)的副本。但是,它在數(shù)據(jù)一致性上卻有著嚴(yán)重的局限性。
由于同一記錄的兩個(gè)(或更多)副本可能在不同地點(diǎn)被不同的會(huì)話同時(shí)更新。這就會(huì)導(dǎo)致相同的記錄會(huì)出現(xiàn)兩個(gè)不同的版本,因此數(shù)據(jù)庫(kù)(有時(shí)是應(yīng)用本身)必須通過(guò)解決沖突來(lái)解決不一致的問(wèn)題。
常用的沖突解決策略是:最近的更新“獲勝”,或是具有更多修改次數(shù)的記錄“獲勝”。因?yàn)槿绻褂闷渌鼮閺?fù)雜的解決策略,則性能上將受到顯著的影響。
這也意味著,從進(jìn)行寫(xiě)入到完成沖突解決機(jī)制的這個(gè)時(shí)間段內(nèi),不同的數(shù)據(jù)中心會(huì)讀取到某個(gè)相同記錄的不同值和沖突值。
分區(qū)(分片)數(shù)據(jù)庫(kù)
分區(qū)數(shù)據(jù)庫(kù)將數(shù)據(jù)庫(kù)分成不同的分區(qū),或稱為分片。每個(gè)分片由一組服務(wù)器來(lái)實(shí)現(xiàn),而每個(gè)服務(wù)器都包含一份分區(qū)數(shù)據(jù)的完整副本。這里關(guān)鍵在于每個(gè)分片都保持著對(duì)數(shù)據(jù)分區(qū)的獨(dú)有控制權(quán)。
對(duì)于任何給定時(shí)間內(nèi)的每個(gè)分片來(lái)說(shuō),由一臺(tái)服務(wù)器充當(dāng)主服務(wù)器,而其他服務(wù)器則充當(dāng)其副本。數(shù)據(jù)的讀取和寫(xiě)入被發(fā)布到主數(shù)據(jù)庫(kù)上。
如果主服務(wù)器出于任何原因的(例如硬件或網(wǎng)絡(luò)故障)失敗,則某一臺(tái)備用服務(wù)器會(huì)自動(dòng)接任為主服務(wù)器的角色。
數(shù)據(jù)庫(kù)中的每條記錄都屬于某個(gè)特定的分區(qū),并由一個(gè)分片來(lái)進(jìn)行管理,以確保它只會(huì)被主分片進(jìn)行寫(xiě)入。分片內(nèi)的記錄映射到每個(gè)分片的一個(gè)主分片,以確保一致性。
由于集群內(nèi)包含多個(gè)分片,因此會(huì)有多個(gè)主分片(多個(gè)主分區(qū)),因此這些主分片可以被分配到不同的數(shù)據(jù)中心,以確保都在每個(gè)數(shù)據(jù)中心的本地都能發(fā)生寫(xiě)入操作,如圖 3 所示:
圖 3:分區(qū)數(shù)據(jù)庫(kù)
分片數(shù)據(jù)庫(kù)可用于實(shí)現(xiàn)雙活的應(yīng)用架構(gòu),其方法是:至少部署與數(shù)據(jù)中心一樣多的分片,并為分片分配主分片,以便每個(gè)數(shù)據(jù)中心至少有一個(gè)主分片,如圖 4 所示:
圖 4:具有分片數(shù)據(jù)庫(kù)的雙活架構(gòu)
另外,通過(guò)配置分片能保證每個(gè)分片在各種數(shù)據(jù)中心里至少有一個(gè)副本(數(shù)據(jù)的副本)。
例如,圖 4 中的圖表描繪了跨三個(gè)數(shù)據(jù)中心的分布式數(shù)據(jù)庫(kù)架構(gòu):
- 紐約(NYC)
- 倫敦(LON)
- 悉尼(SYD)
群集有三個(gè)分片,每個(gè)分片有三個(gè)副本:
- NYC 分片在紐約有一個(gè)主分片,在倫敦和悉尼有副本。
- LON 分片在倫敦有一個(gè)主分片,在紐約和悉尼有副本。
- SYD 分片在悉尼有一個(gè)主分片,在倫敦和紐約有副本。
通過(guò)這種方式,每個(gè)數(shù)據(jù)中心都有來(lái)自所有分片的副本,因此本地應(yīng)用服務(wù)器可以讀取整個(gè)數(shù)據(jù)集和一個(gè)分片的主分片,以便在其本地進(jìn)行寫(xiě)入操作。
分片數(shù)據(jù)庫(kù)能滿足大多數(shù)使用場(chǎng)景的一致性和性能要求。由于讀取和寫(xiě)入發(fā)生在本地服務(wù)器上,因此性能會(huì)非常好。
從主分片中讀取時(shí),由于每條記錄只能分配給一個(gè)主分片,因此保證了一致性。
例如:我們?cè)诿绹?guó)的新澤西州和俄勒岡州有兩個(gè)數(shù)據(jù)中心,那么我們可以根據(jù)地理區(qū)域(東部和西部)來(lái)分割數(shù)據(jù)集,并將東海岸用戶的流量路由到新澤西州的數(shù)據(jù)中心。
因?yàn)樵摂?shù)據(jù)中心包含的是主要用于東部的分片;并將西海岸用戶的流量路由到俄勒岡州數(shù)據(jù)中心,因?yàn)樵摂?shù)據(jù)中心包含的是主要用于西部的分片。
我們可以看到分片的數(shù)據(jù)庫(kù)為我們提供了多個(gè)主數(shù)據(jù)庫(kù)的所有好處,而且避免了數(shù)據(jù)不一致所導(dǎo)致的復(fù)雜性。
應(yīng)用服務(wù)器可以從本地主服務(wù)器上進(jìn)行讀取和寫(xiě)入,由于每個(gè)主服務(wù)器擁有各自的記錄,因此不會(huì)出現(xiàn)任何的不一致。相反,多主數(shù)據(jù)庫(kù)的解決方案則可能會(huì)造成數(shù)據(jù)丟失和讀取的不一致。
數(shù)據(jù)庫(kù)架構(gòu)比較
圖 5:數(shù)據(jù)庫(kù)架構(gòu)比較
圖 5 提供了每一種數(shù)據(jù)庫(kù)架構(gòu)在滿足雙活應(yīng)用需求時(shí)所存在的優(yōu)缺點(diǎn)。在選擇多主數(shù)據(jù)庫(kù)和分區(qū)數(shù)據(jù)庫(kù)時(shí),其決定因素在于應(yīng)用是否可以容忍可能出現(xiàn)的讀取不一致和數(shù)據(jù)的丟失問(wèn)題。
如果答案是肯定的,那么多主數(shù)據(jù)庫(kù)可能會(huì)稍微容易部署些。而如果答案是否定的,那么分片數(shù)據(jù)庫(kù)則是***的選擇。
由于不一致性和數(shù)據(jù)丟失對(duì)于大多數(shù)應(yīng)用來(lái)說(shuō)都是不可接受的,因此分片數(shù)據(jù)庫(kù)通常是***的選擇。
MongoDB 雙活應(yīng)用
MongoDB 是一個(gè)分片數(shù)據(jù)庫(kù)架構(gòu)的范例。在 MongoDB 中,主服務(wù)器和次服務(wù)器集的構(gòu)造被稱為副本集。副本集為每個(gè)分片提供了高可用性。
一種被稱為區(qū)域分片(Zone Sharding)的機(jī)制被配置為:由每個(gè)分片去管理的數(shù)據(jù)集。如前面所提到的,ZoneSharding 可以實(shí)現(xiàn)地域分區(qū)。
白皮書(shū)《MongoDB多數(shù)據(jù)中心部署》:
- https://www.mongodb.com/collateral/mongodb-multi-data-center-deployments?utm_medium=dzone-synd&utm_source=dzone&utm_content=active-application&jmp=dzone-ref
Zone Sharding 相關(guān)文檔:
- https://docs.mongodb.com/manual/tutorial/sharding-segmenting-data-by-location/的“分區(qū)(分片)數(shù)據(jù)庫(kù)”部分描述了 MongoDB 具體實(shí)現(xiàn)和運(yùn)作的細(xì)節(jié)。
其實(shí)許多組織,包括:Ebay、YouGov、Ogilvyand Maher 都正在使用 MongoDB 來(lái)實(shí)現(xiàn)雙活的應(yīng)用架構(gòu)。
除了標(biāo)準(zhǔn)的分片數(shù)據(jù)庫(kù)功能之外,MongoDB 還提供對(duì)寫(xiě)入耐久性和讀取一致性的細(xì)粒度控制,并使其成為多數(shù)據(jù)中心部署的理想選擇。對(duì)于寫(xiě)入,我們可以指定寫(xiě)入關(guān)注(write concern)來(lái)控制寫(xiě)入的持久性。
Writeconcern 使得應(yīng)用在 MongoDB 確認(rèn)寫(xiě)入之前,就能指定寫(xiě)入的副本數(shù)量,從而在一個(gè)或多個(gè)遠(yuǎn)程數(shù)據(jù)中心內(nèi)的服務(wù)器上完成寫(xiě)入操作。籍此,它保證了在節(jié)點(diǎn)或數(shù)據(jù)中心發(fā)生故障時(shí),數(shù)據(jù)庫(kù)的變更不會(huì)被丟失。
另外,MongoDB 也補(bǔ)足了分片數(shù)據(jù)庫(kù)的一個(gè)潛在缺點(diǎn):寫(xiě)入可用性無(wú)法達(dá)到 100%。
由于每條記錄只有一個(gè)主節(jié)點(diǎn),因此如果該主節(jié)點(diǎn)發(fā)生故障,則會(huì)有一段時(shí)間不能對(duì)該分區(qū)進(jìn)行寫(xiě)入。
MongoDB 通過(guò)多次嘗試寫(xiě)入,大幅縮短了故障切換的時(shí)間。通過(guò)多次嘗試的寫(xiě)入操作,MongoDB 能夠自動(dòng)應(yīng)對(duì)由于網(wǎng)絡(luò)故障等暫時(shí)性系統(tǒng)錯(cuò)誤而導(dǎo)致的寫(xiě)入失敗,因此也大幅簡(jiǎn)化了應(yīng)用的代碼量。
MongoDB 的另一個(gè)適合于多數(shù)據(jù)中心部署的顯著特征是:MongoDB 自動(dòng)故障切換的速度。
當(dāng)節(jié)點(diǎn)或數(shù)據(jù)中心出現(xiàn)故障或發(fā)生網(wǎng)絡(luò)中斷時(shí),MongoDB 能夠在 2-5 秒內(nèi)(當(dāng)然也取決于對(duì)它的配置和網(wǎng)絡(luò)本身的可靠性)進(jìn)行故障切換。
發(fā)生故障后,剩余的副本集將根據(jù)配置去選擇一個(gè)新的主切片和 MongoDB 驅(qū)動(dòng)程序,從而自動(dòng)識(shí)別出新的主切片。一旦故障切換完成,其恢復(fù)進(jìn)程將自動(dòng)履行后續(xù)的寫(xiě)入操作。
對(duì)于讀取,MongoDB 提供了兩種功能來(lái)指定所需的一致性級(jí)別。
首先,從次數(shù)據(jù)進(jìn)行讀取時(shí),應(yīng)用可以指定***時(shí)效值(maxStalenessSeconds)。
這可以確保次節(jié)點(diǎn)從主節(jié)點(diǎn)復(fù)制的滯后時(shí)間不能超過(guò)指定的時(shí)效值,從而次節(jié)點(diǎn)所返回的數(shù)據(jù)具有其時(shí)效性。
另外,讀取也可以與讀取關(guān)注(ReadConcern)相關(guān)聯(lián),來(lái)控制查詢到的返回?cái)?shù)據(jù)的一致性。
例如,ReadConcern 能通過(guò)一些返回值來(lái)告知 MongoDB,那些被復(fù)制到副本集中的多數(shù)節(jié)點(diǎn)上的數(shù)據(jù)。
這樣可以確保查詢只讀取那些沒(méi)有因?yàn)楣?jié)點(diǎn)或數(shù)據(jù)中心故障而丟失的數(shù)據(jù),并且還能為應(yīng)用提供一段時(shí)間內(nèi)數(shù)據(jù)的一致性視圖。
MongoDB 3.6 還引入了“因果一致性(causal consistency)”的概念,以保證客戶端會(huì)話中的每個(gè)讀取操作,都始終只“關(guān)注”之前的寫(xiě)入操作是否已完成,而不管具體是哪個(gè)副本正在為請(qǐng)求提供服務(wù)。
通過(guò)在會(huì)話中對(duì)操作進(jìn)行嚴(yán)格的因果排序,這種因果一致性可以確保每次讀取都始終遵循邏輯上的一致,從而實(shí)現(xiàn)分布式系統(tǒng)的單調(diào)式讀?。╩onotonic read)。而這正是各種多節(jié)點(diǎn)數(shù)據(jù)庫(kù)所無(wú)法滿足的。
因果一致性不但使開(kāi)發(fā)人員,能夠保留過(guò)去傳統(tǒng)的單節(jié)點(diǎn)式關(guān)系型數(shù)據(jù)庫(kù),在實(shí)施過(guò)程中具備的數(shù)據(jù)嚴(yán)格一致性的優(yōu)勢(shì);又能將時(shí)下流行架構(gòu)充分利用到可擴(kuò)展和具有高可用性的分布式數(shù)據(jù)平臺(tái)之上。
陳峻(Julian Chen) ,有著十多年的 IT 項(xiàng)目、企業(yè)運(yùn)維和風(fēng)險(xiǎn)管控的從業(yè)經(jīng)驗(yàn),日常工作深入系統(tǒng)安全各個(gè)環(huán)節(jié)。作為 CISSP 證書(shū)持有者,他在各專業(yè)雜志上發(fā)表了《IT運(yùn)維的“六脈神劍”》、《律師事務(wù)所IT服務(wù)管理》 和《股票交易網(wǎng)絡(luò)系統(tǒng)中的安全設(shè)計(jì)》等論文。他還持續(xù)分享并更新《廉環(huán)話》系列博文和各種外文技術(shù)翻譯,曾被(ISC)2 評(píng)為第九屆亞太區(qū)信息安全***成就表彰計(jì)劃的“信息安全踐行者”和 Future-S 中國(guó) IT 治理和管理的 2015 年度踐行人物。
【51CTO原創(chuàng)稿件,合作站點(diǎn)轉(zhuǎn)載請(qǐng)注明原文作者和出處為51CTO.com】