用Kong突破單一數據庫
譯文【51CTO.com快譯】您一定對RESTful API并不陌生吧。它為客戶端應用提供了一種能夠滿足業務需求的、訪問數據資源的簡單方式。事實上,Angular、React和Vue等都是依賴RESTful API的Javascript框架,它們引領著Web應用的市場。
從效果上說,此類RESTful服務類型的API和前端Javascript框架模式的配合,激發了許多組織從單一(monolithic)或過時的應用程序,遷移到新項目中的愿望。當然,凡事都有利與弊,RESTful API在助推敏捷迭代式開發的同時,也帶來了一個問題:在傳統的應用設計中,我們雖然可以使用多個RESTful API和Javascript框架的組件化客戶端,但是也使用著單一的數據庫。這種設計的結果往往會導致數據所有權的沖突、高于預期的數據庫連接數、以及對大型數據庫過高的支持與維護成本。
下圖展示了多個服務競爭來自單個數據庫資源的情況:
而且,此類現象在開發領域十分常見。大家會傾向于將單個數據庫作用并服務于整個微服務的集合。
微服務應該從數據庫開始
在大多數編程語言中,我們通常可以使用單個的文件,去創建功能齊全的應用程序。例如在Java中,一切都可以被放置在同一個類的文件中,并且由簡單的main()方法實現統領和調用:
- Java
- public class SingleClassApplication {
- public static void main(String[] args) {
- // Start doing something really cool here
- }
- }
但是,這種方法并不利于多個開發人員通過協作的方式貢獻代碼。就應用程序的各個方面而言,我們需要關注“所有權”(或系統記錄)的概念。如果不止一項服務或功能對賬戶等組件存在著交叉所有權的話,那么我們的業務規則可能會在不同的場景下出現混亂的局面。例如,在RESTful API聲明對于某個給定對象的所有權時,就可能發生類似的情況。而且,當我們采取RESTful API的設計模式時,這些概念都需要被轉化到數據庫的層面上。對此,我們需要遵從如下規則:
將單個RESTful API視為某個應用在給定方面的記錄系統(system of record),以便相應的數據層僅專注和使用應用在該方面的數據存儲。
下圖展示了遵循該規則的微服務設計:
據此,那些為了滿足客戶需求,而對給定服務采取的擴展,不會對任何其他的服務產生影響。這便是優秀的、針對微服務的數據庫設計實踐。
數據庫的各種約束
在開發過程中,我力推將給定的微服務與專用數據庫相隔離。這能夠保證相關組件的數量和大小,能夠與用戶需求相匹配,同時避免具有不同需求水平的元素產生額外的成本。
數據庫管理員往往會發現,當應用程序的所有元素都駐留在單個數據庫中時,各種約束和關系能夠很好地在單個數據庫的設計模式中發揮作用。例如,如果有與客戶相關聯的訂單在排隊等待刪除的話,那么單一數據庫的設計就會阻止刪除某個客戶的請求,畢竟該用戶的訂單尚未“結清”。
雖然這絕對是擁有單個數據庫的好處,但在選擇為所有微服務使用單個數據庫之前,您需要考慮如下幾點:
- 將使用單個數據庫可能獲得的長期價值,與擴展單個大型數據庫的相關成本進行比較,以了解未來擴展和支持單一數據庫設計的預期成本。
- 在API層強制實施各類約束的利與弊。請記住,由于單個微服務將被視為給定數據庫的所有者,因此在業務邏輯上可能會出現上述提到的,不允許刪除帶有活躍訂單的客戶的情況。
- 對于事件驅動(或基于消息)的設計而言,某個微服務如何處理請求,取決于來自另一個微服務的響應情況。雖然這與單個應用程序+單個數據庫的設計有著相似之處,但需要在隔離和控制時,具有一定的擴展和分配專用處理算力的能力。
當然,做為一種良好的開發習慣,即使是數據庫僅支持某個專用的服務實例,我們也應該實施和強制執行對應的約束關系。
公共元素應該被抽象出來
如果規劃不當,采用真正的微服務設計也可能會產生副作用。例如在微服務中,包括認證、緩存、日志記錄、監控、以及安全在內的各個公共組件元素,可能會與服務層相重復。
如上圖所示,在軟件開發的生命周期中,人們往往會用不同的語言,去重復相同的軟件模式。對此,我們需要通過在應用程序棧的公共級別、或不同級別,抽象和處理某些元素,來盡可能地避免DRY(不要重復自己)。在此,我推薦使用Kong的情況,進而提供分布式的微服務抽象層。
將Kong置于理想的設計中心
Kong Gateway(允許開發者將服務層API的復雜性,降低到專注于滿足業務需求和功能集合的各個端點(或 URI)處。由網關處理的諸如:身份驗證、日志記錄和安全性等重復性組件,可以被Kong Gateway從服務層的設計中移出。
如下圖所示,每個RESTful微服務都維護著一個專用的數據庫實例,并且抽象出了各個重復的組件。這里所展示的便是一組以目的為驅動(purpose-driven)的微服務:
開發人員可以通過使用各種常見的企業集成模式(enterprise integration patterns)的消息傳遞層來,去處理服務間的通信,其中包括:
這樣的設計會給我們的應用開發帶來如下好處:
- 如果Node.js服務的使用率高于預期的話,則可以通過擴展,來低成本地實現服務與專用數據庫的相互隔離。
- 如果任何服務發現了數據存儲模式從SQL更改為NoSQL,則可以在不更改RESTful API的URI的前提下,部署新的設計,而不會對任何其他服務產生影響。
- 任何抽象層組件的更改(例如,使用新的日志記錄方法)都可以在Kong Gateway層進行,而不會影響到底層服務。
小結
開發人員往往利用包和類,來對他們的程序代碼進行分組,以實現可支持性和可維護性。在這些類中,定義方法和函數的規則是,每個代碼塊應當小且易于理解。這也正是“微服務”的“微”字的體現。其實不只是微服務,程序員也需要讓數據庫持續以微小、高效、以及目標驅動的方式進行擴展。
通過上述討論可知,Kong真正為微服務的設計提供了可擴展、且易于采用的核心方式。而Kong Gateway則允許開發人員引入通用組件,并駐留在分布式微服務的抽象層,以實現DRY。
原文標題:Breaking Up a Monolithic Database with Kong,作者:John Vester
【51CTO譯稿,合作站點轉載請注明原文譯者和出處為51CTO.com】