每個人都知道,微服務架構具有許多優(yōu)勢,如可擴展性,易于維護和頻繁的部署。但實施這些模式很棘手。您可能遇到的挑戰(zhàn)之一是管理微服務數(shù)據(jù)庫。服務如何存儲數(shù)據(jù)而不會失去獨立性?哪些微服務數(shù)據(jù)庫模型選擇基于云的應用程序?
在今天的博客中,我希望回答這些問題,我將向您解釋我們如何管理微服務中的數(shù)據(jù)。大多數(shù)人正在從單體架構轉移到微服務到分布式架構樣式。大多數(shù)系統(tǒng)都使用單片架構風格。這很簡單,你知道它很容易掌握,或多或少,他們正在使用一個數(shù)據(jù)庫,因此大多數(shù)時候,這個數(shù)據(jù)庫是一個RDMS(關系數(shù)據(jù)庫管理系統(tǒng))。
談到關系數(shù)據(jù)庫管理系統(tǒng),我們有一個重要特征,是ACID。當您使用具有ACID屬性的數(shù)據(jù)庫時,您不需要擔心數(shù)據(jù),因為它使用ACID屬性如此,數(shù)據(jù)庫管理系統(tǒng)本身負責數(shù)據(jù)的一致性和合法性。
ACID代表,原子性,一致性,隔離和持續(xù)時間;
原子性:所有對數(shù)據(jù)的更改都是如同單次操作執(zhí)行
一致性:當事務開始以及結束時,數(shù)據(jù)處于一致狀態(tài)
隔離:交易的中間狀態(tài)對其他交易是不可見的
耐用性:在事務成功完成后,即使在系統(tǒng)故障的情況下,數(shù)據(jù)持續(xù)更改并未撤消
當我們進入分布式架構或分布式數(shù)據(jù)庫管理系統(tǒng)時,我們需要遵循的一個主要原則是CAP定理?,F(xiàn)在在CAP定理有三個主要方面;
●一致性
●可用性
●分區(qū)容忍性
最重要的是,您可以在任何給定數(shù)據(jù)庫中擁有這些方面中的兩個。今天市場上沒有數(shù)據(jù)庫系統(tǒng),可以滿足單個數(shù)據(jù)庫中的所有這三個方面。例如,當您關注傳統(tǒng)的關系數(shù)據(jù)庫時,您可以進行一致性和可用性。盡管如此,如果您正在使用一致性和分區(qū)容忍,MongoDB和Redis是您需要使用的數(shù)據(jù)庫。同時,如果您正在使用可用性和分區(qū)容忍,您必須使用CouchDB或Cassandra。因此,您可以看到,您如何完全選擇此數(shù)據(jù)庫取決于您的業(yè)務需求或您正在嘗試在您的分布式架構中實現(xiàn)的內容。
現(xiàn)在讓我們進入微服務的世界。我已經看到,大多數(shù)微服務架構都使用反向代理或API網關來處理所有客戶端請求。有一個獨立的部署(Micro)服務集,但不幸的是,所有這些獨立的微服務都連接到一個數(shù)據(jù)庫。這是一個很好的做法嗎?當然不是。
使用共享數(shù)據(jù)庫具有微服務的問題:
●單點失敗
●性能瓶頸
●服務依賴項
●不自主
因此,無論我們在此架構中的服務數(shù)量如何,我們只有單點故障:數(shù)據(jù)庫,我們有許多性能瓶頸。每當他們想要進行數(shù)據(jù)查詢或數(shù)據(jù)更新或與數(shù)據(jù)相關的任何相關的數(shù)據(jù)時,所有內容都會被瓶頸瓶頸,因此在此體系結構和服務依賴項中創(chuàng)建性能瓶頸。與此同時,由于我們在數(shù)據(jù)庫上擁有的高依賴性,服務部署和更新不是自主。
自主權是微服務中的主要原則之一。您可以使用此類架構使用CICD Pipelines執(zhí)行自主服務部署。它有挑戰(zhàn)性,因為如果更改任何數(shù)據(jù)方面,它可能會影響許多其他微服務。由于數(shù)據(jù)庫依賴項,您將無法獨立部署到生產環(huán)境的情況下,而不會影響他人。
我們該怎么辦?
我們可以做的最簡單的事情是每個服務的單個數(shù)據(jù)庫,或者只有少數(shù)依賴于特定數(shù)據(jù)庫。
首先,我們可以擁有一個數(shù)據(jù)庫服務器和邏輯分隔的數(shù)據(jù)庫。
這個比我們所擁有的以前的架構風格更好,但仍然存在一些問題。它仍然有一個失敗的點;因為我們在一個物理數(shù)據(jù)庫中托管了邏輯分隔的數(shù)據(jù)庫。它有一個嘈雜的鄰居問題。例如,此紅色微序具有在此特定數(shù)據(jù)庫中運行的昂貴查詢,因為它托管在一個數(shù)據(jù)庫服務器中;此查詢的性能影響可能會影響其他邏輯分隔的數(shù)據(jù)庫。但這種架構風格中的一個加點之一是具有成本效益,因為我們不必支付不同的數(shù)據(jù)庫實例。每當您嘗試在基礎架構(內部部署)上部署您的體系結構或數(shù)據(jù)庫平臺時,這種類型的模型是合適的。有了這個,您可以密切監(jiān)視并繼續(xù)無論存在問題所需的更改,這對微服務部署的內部內部有利。
要解決我們在上述架構中的問題,我們可以具有物理分離的數(shù)據(jù)庫。由于所有這些數(shù)據(jù)庫都有物理分離,因此一個特定數(shù)據(jù)庫或任何其他故障的性能不會影響其他數(shù)據(jù)庫。因此,每當您嘗試實現(xiàn)這些服務之間的數(shù)據(jù)獨立時,這種特定的架構都非常好。但是,這種模型的成本超過了單個數(shù)據(jù)庫模型。
例如,假設您想要采取數(shù)據(jù)庫許可證。在這種情況下,您必須購買所有這些數(shù)據(jù)庫服務或服務器的許可證。每當您嘗試在云上進行數(shù)據(jù)部署時,這是良好的,因為您不必在這種情況下維護昂貴的數(shù)據(jù)庫服務器。這種架構的主要優(yōu)點是數(shù)據(jù)獨立性。
下一步
為了進一步分析這種微服務架構中的問題,讓我們探索一個例子。讓我們說有兩種服務;
●訂購的服務
●客戶服務
因此,有一個查詢進入訂單服務,詢問上周已在上周進行的頂級購買的名稱。如果您認為以傳統(tǒng)的數(shù)據(jù)庫架構方式,我們可以在客戶表和訂單表之間加入。然而,在兩個數(shù)據(jù)庫分離的微服務體系結構中,我們無法在表之間加入。
解決此問題的另一種方式是通過獲取客戶ID,并將客戶表單獨查詢來檢索客戶名稱。但是,由于訂單服務也取決于客戶表,這是一個很大的不符合MicroService架構。因此,在任何微服務體系結構中都不建議這種交叉服務數(shù)據(jù)庫調用。另一個解決方案是通過直接調用客戶服務并說“嘿給我客戶名稱ID的名稱或ID的客戶名稱”。然后我們可以檢索此客戶名稱,這使得這是在兩個微服務之間檢索數(shù)據(jù)的最合適方式。
然而,這里還有另一個問題-延遲。一個解決方案是維護服務器端緩存。我們可以從服務器端緩存中的客戶服務中擺脫數(shù)據(jù)庫調用,但網絡調用仍在存在。如果對客戶表進行了任何更改,則更容易更新現(xiàn)金。此外,這有助于有效的內存管理,因為它位于服務器端。但是,網絡電話仍在存在。
我們可以擁有的另一個解決方案是維護客戶端緩存。在設計階段,我們可以確定我們在客戶服務訂單服務中經常需要哪些數(shù)據(jù)元素,我們可以將它們上傳或將這些數(shù)據(jù)視為客戶端的緩存服務。
這種方法的優(yōu)勢在于沒有網絡呼叫。因此,在性能和彈性方面也存在明確的增益。例如,如果客戶服務下跌,我們仍然可以在緩存中檢索此數(shù)據(jù),因此它不再依賴于客戶服務。對于這種經常訪問的數(shù)據(jù),我們在這種方法中擁有的一個缺點是失效和更新問題。如果,已經在此客戶表中進行了更改,更新此特定客戶端緩存并不是簡單的,這也不簡單。
我們可以用于此數(shù)據(jù)分離的技術是什么?
執(zhí)行此操作的最有效方法是使用CDC(更改數(shù)據(jù)捕獲)工具。一個這樣的例子是debezium。Debezium是我們可以使用的優(yōu)秀CDC工具,它支持許多數(shù)據(jù)庫平臺。此工具允許我們?yōu)g覽每項事務的數(shù)據(jù)庫日志并觸發(fā)事件。捕獲數(shù)據(jù)更改后,您可以將該事件提升到消息代理或簡單的隊列中。訂單服務中的此高速緩存服務可以訂閱此事件流并相應更新緩存。
然而,這里有一個輕微的問題。在這里,我們必須考慮最終的一致性。我們不能認為,只要客戶服務更新客戶數(shù)據(jù)庫中的任何內容,它就不會直接反映緩存。緩存需要一些時間來獲得更新。這被稱為最終的一致性,這是分布式數(shù)據(jù)管理的最重要方面之一。
數(shù)據(jù)報告方案
假設存在需要來自這兩個服務的數(shù)據(jù)的報告服務。
讓我們認為這項特定的報告查詢需要1億條記錄。當此特定報告服務從主機服務本身檢索數(shù)據(jù)時,它可能會影響主要的MicroService或訂單服務的性能。因為上述報告服務正在要求100萬條記錄,因為其他要求也進入訂單服務。因此它也影響了其他功能。
此方案有哪些可用的解決方案。以下是我們的問題;
高延遲
可能會影響其他事務處理器
需要在每份報告請求上獲取數(shù)據(jù)
假設十個經理請求此報告十個不同的時間,我們需要執(zhí)行此操作10次以生成報告。那么我們如何通過使用CDC工具更新諸如Kafka以通知所有更改和報告的消息代理來提供解決方案?報告服務可以緩存或保留在事件流中更新的數(shù)據(jù)。在此事件流中,您可以在報告服務需要時查詢此數(shù)據(jù)。
您可以用于此事件流查詢的一種這樣的技術是ksqldb。因此,這一個與諸如Kafka流等事件流配對,并且您可以使用ksqdb查詢所有這些事件流甚至事件源。它與其他常規(guī)SQL查詢非常類似,但唯一的區(qū)別是而不是表,它是查詢流處理。
單體到微服務數(shù)據(jù)遷移
大多數(shù)系統(tǒng)都是從巨石開始的,然后最終,當用戶數(shù)量增加時,他們決定進入微服務。因此,我們可以在此處執(zhí)行最簡單的事情是為客戶服務構建單獨的微服務,并將所有數(shù)據(jù)元素或數(shù)據(jù)庫移動到單獨的數(shù)據(jù)庫中,例如在客戶數(shù)據(jù)庫中。
但是,可能有含義。正如馬丁福勒曾經說過的那樣,“如果你做一個大爆炸重寫,那么你保證的唯一是一個大爆炸”。我們不能在一夜之間進行這一點,因為移動數(shù)據(jù)比將代碼邏輯移動到單獨的微服務中更復雜。數(shù)據(jù)具有很高的依賴性,如果在移動后數(shù)據(jù)損壞,很難回去。因此,我們需要逐步規(guī)劃這一行動。
>Image 9:Data and code migration using strangler-fig pattern
首先,我們需要創(chuàng)建一個API,在那里從中央數(shù)據(jù)庫公開此客戶數(shù)據(jù),然后我們可以創(chuàng)建我們的客戶服務以從此自定義API檢索此數(shù)據(jù)。請記住,我們在中央數(shù)據(jù)庫中擁有一切,我們可以創(chuàng)建客戶數(shù)據(jù)庫,然后我們可以使用CDC工具或任何其他ETL技術將此數(shù)據(jù)移動到客戶數(shù)據(jù)庫中。我們可以看到自定義API仍在那里,并且客戶服務仍然獲取用于數(shù)據(jù)檢索的客戶API。在這里,我們可以在這兩個數(shù)據(jù)源之間具有一些臨時灰度期或測試時段-來自API的數(shù)據(jù),以及客戶數(shù)據(jù)庫中的數(shù)據(jù)是什么數(shù)據(jù)。因此,在運行這些測試后幾周或幾個月后,我們可以確保存在數(shù)據(jù)一致性。之后,我們最終可以擺脫此API和中央數(shù)據(jù)庫。然后我們可以使用獨立數(shù)據(jù)源具有獨立的微服務。這是將數(shù)據(jù)移動到單獨的微服務中的最佳方法。這也被稱為陌生人適合模式,而在微服務遷移方面也是如此。
(本文由聞數(shù)起舞翻譯自Using Travis CI Efficiently的文章《Managing Data in Microservices Architecture》,轉載請注明出處,原文鏈接:
https://medium.com/geekculture/managing-data-in-microservices-architecture-fb459bdbf71f)