微服務(wù)中如何設(shè)計(jì)高擴(kuò)展、易維護(hù)的“數(shù)據(jù)網(wǎng)格”?
原創(chuàng)【51CTO.com原創(chuàng)稿件】在本文中,我們先介紹數(shù)據(jù)網(wǎng)格的基本概念、屬性、以及能夠提供的服務(wù),然后討論了如何設(shè)計(jì)可擴(kuò)展的數(shù)據(jù)網(wǎng)格,以滿足實(shí)際場(chǎng)景的業(yè)務(wù)需求。
圖片來(lái)自 Pexels
在本文中,我們將先介紹數(shù)據(jù)網(wǎng)格(Data Grid)的基本概念、屬性、以及能夠提供的服務(wù),然后討論如何設(shè)計(jì)可擴(kuò)展的數(shù)據(jù)網(wǎng)格,以滿足實(shí)際場(chǎng)景的業(yè)務(wù)需求。
什么是數(shù)據(jù)網(wǎng)格?
數(shù)據(jù)網(wǎng)格是一組能夠提供共享數(shù)據(jù)管理的服務(wù),它可以通過(guò)網(wǎng)格狀的結(jié)構(gòu),去訪問(wèn)源自各種應(yīng)用程序與服務(wù)的異構(gòu)數(shù)據(jù)。
在技術(shù)實(shí)現(xiàn)上,我們通??梢圆捎霉δ軓?qiáng)大的中間件應(yīng)用程序和服務(wù),實(shí)現(xiàn)對(duì)于源于各種應(yīng)用請(qǐng)求的數(shù)據(jù)輸入與查詢。
網(wǎng)格中的數(shù)據(jù)往往可以通過(guò)諸如 REST、以及 JSON 格式的 API 被訪問(wèn)到。這些數(shù)據(jù)既可以被保存到磁盤(pán)上,也能夠備份到另一個(gè)數(shù)據(jù)庫(kù)里。
不同的服務(wù)可以將 JSON 格式的數(shù)據(jù)保存到網(wǎng)格之中,并在不到一毫秒的時(shí)間內(nèi)實(shí)現(xiàn)數(shù)據(jù)查詢(類似于緩存)。
以下便是數(shù)據(jù)網(wǎng)格的基本屬性:
- 使用 API(基于 REST 的 JSON 格式)從網(wǎng)格進(jìn)行數(shù)據(jù)訪問(wèn)。
- 其本質(zhì)上具有真正的彈性,即:可以水平縮放而沒(méi)有上限。
- 能夠支持任何體量的數(shù)據(jù)。
- 具有耐用性,可應(yīng)對(duì)各種宕機(jī)和系統(tǒng)故障。
- 提供低延遲的響應(yīng)。
它的選配屬性則包括:
- 可以利用諸如:JWT、TSL 客戶端驗(yàn)證等方案,對(duì)網(wǎng)格中的每一種數(shù)據(jù)請(qǐng)求進(jìn)行授權(quán)。
- 能夠清除數(shù)據(jù),并為更多相關(guān)數(shù)據(jù)留出空間。
- 能夠?qū)?shù)據(jù)持久地保存到磁盤(pán)上。
- 能夠從諸如:RDBMS 或 NoSQL 存儲(chǔ)等其他數(shù)據(jù)源,進(jìn)行數(shù)據(jù)的熱加載(hot-load)。
數(shù)據(jù)網(wǎng)格的使用
在一個(gè)真正的微服務(wù)架構(gòu)系統(tǒng)中,每一項(xiàng)服務(wù)都擁有自己的私有數(shù)據(jù)庫(kù)(即:每個(gè)服務(wù)模型都配有一個(gè)數(shù)據(jù)庫(kù))。
如果其中的任何一項(xiàng)服務(wù)需要橫跨多個(gè)服務(wù)獲取數(shù)據(jù)的話,那么我們就需要以諸如:JSON、XML 或二進(jìn)制格式,來(lái)處理這些服務(wù)的響應(yīng)。
而有些請(qǐng)求既可能使用的是 REST 標(biāo)準(zhǔn)的 HTTP(S)請(qǐng)求,也可能使用 SOAP 請(qǐng)求,還有可能使用 RPC 等請(qǐng)求。
不過(guò),真正的挑戰(zhàn)并非在技術(shù)上,而是在處理諸如安全異常、數(shù)據(jù)驗(yàn)證、握手、網(wǎng)絡(luò)、數(shù)據(jù)解析等失敗的情況下,微服務(wù)將如何應(yīng)對(duì)。
在實(shí)際應(yīng)用中,我們常常會(huì)碰到高度依賴性的問(wèn)題。也就是說(shuō):生產(chǎn)者(producer)服務(wù)中的任何變更都可能會(huì)更改響應(yīng)的結(jié)構(gòu),而消費(fèi)者(consumer)服務(wù)也可能需要跟著適應(yīng)此類變更。
如果消費(fèi)者服務(wù)僅從其他服務(wù)中查詢數(shù)據(jù)(而非請(qǐng)求任何計(jì)算結(jié)果),那么該方式則可能無(wú)效。
為了解決上述問(wèn)題,我們引入了數(shù)據(jù)網(wǎng)格的方法,該方法幾乎能夠提供任意數(shù)量的自定義數(shù)據(jù)存儲(chǔ),并且具有高度可擴(kuò)展性和易于維護(hù)的低延遲響應(yīng)。
在此,我們將 Apache Ignite(https://ignite.apache.org/,以下簡(jiǎn)稱為 Ignite)作為數(shù)據(jù)網(wǎng)格設(shè)計(jì)中的主要組件之一,由它提供具有持久性、彈性和分布式的內(nèi)存平臺(tái)。
此外,Ignite 還提供了多種緩存選項(xiàng),可連接 RDBMS 和 NoSQL 存儲(chǔ),以及計(jì)算服務(wù)等功能。
數(shù)據(jù)定義
通常,若要為基礎(chǔ)架構(gòu)構(gòu)建數(shù)據(jù)網(wǎng)格,所有的微服務(wù)都應(yīng)當(dāng)發(fā)布各自寫(xiě)入網(wǎng)格的數(shù)據(jù)格式。
例如:用戶服務(wù)(即:管理某個(gè)系統(tǒng)中所有用戶信息的服務(wù))應(yīng)當(dāng)發(fā)布所有具有 upsert 和 delete 操作的用戶信息,以及用戶數(shù)據(jù)結(jié)構(gòu)的定義。
同時(shí),此類數(shù)據(jù)定義應(yīng)當(dāng)能夠支持版本控制,以便任何新的服務(wù)都可以查詢到特定的最新版本。
據(jù)此,所有相關(guān)的消費(fèi)者服務(wù)也都可以從“數(shù)據(jù)網(wǎng)格”中查詢到數(shù)據(jù)定義,進(jìn)而構(gòu)建相應(yīng)的服務(wù)功能。
以下是一個(gè)已發(fā)布的用戶數(shù)據(jù)結(jié)構(gòu)(版本 1)的代碼示例。其對(duì)應(yīng)的 URL 為:
https://
如下是對(duì)于用戶數(shù)據(jù)定義版本 2 的查詢代碼,其對(duì)應(yīng)的 URL 為:
https://
高級(jí)設(shè)計(jì)
我們可以使用某個(gè)在線購(gòu)物網(wǎng)站為例,來(lái)展示數(shù)據(jù)網(wǎng)格的系統(tǒng)設(shè)計(jì)。該購(gòu)物網(wǎng)站是采用各種微服務(wù)(例如:用戶服務(wù)、訂單服務(wù)、產(chǎn)品目錄服務(wù)、以及其他服務(wù))來(lái)構(gòu)建的。
這些微服務(wù)有助于實(shí)現(xiàn)從各種目錄中訂購(gòu)產(chǎn)品,并最終將其交付給客戶。下圖是數(shù)據(jù)網(wǎng)格的完整工作流程:
各個(gè)組件服務(wù)
數(shù)據(jù)層
這是數(shù)據(jù)網(wǎng)格的核心,其中部署了 Apache Ignite 的服務(wù)器端模式設(shè)置,并構(gòu)成了“Ignite 服務(wù)器群集”。
在此,Ignite 提供了如下可用于構(gòu)建可擴(kuò)展網(wǎng)格的功能:
- 通過(guò)內(nèi)存中緩存,實(shí)現(xiàn)低延遲的響應(yīng)。
- 分布式的持久存儲(chǔ)。
- 彈性,即:通過(guò)添加節(jié)點(diǎn),實(shí)現(xiàn)水平擴(kuò)展。
- 容錯(cuò),即:數(shù)據(jù)復(fù)制,以及在節(jié)點(diǎn)出現(xiàn)故障時(shí)的自動(dòng)負(fù)載均衡。
- 針對(duì)磁盤(pán)或數(shù)據(jù)庫(kù)的數(shù)據(jù)復(fù)制和持久性。
Ignite 也可以在無(wú)主控的架構(gòu)上工作,并通過(guò)拆分其他節(jié)點(diǎn),只向群集組中添加額外的內(nèi)存內(nèi)(in-memory)緩存空間。
另外,通過(guò) Ignite 提供的各種緩存配置,您可以按需對(duì)其進(jìn)行調(diào)整和增強(qiáng)。此類配置包括:數(shù)據(jù)持久性選項(xiàng)、緩存的逐出策略、以及數(shù)據(jù)復(fù)制等方面。
數(shù)據(jù)網(wǎng)格的 API 網(wǎng)關(guān)
該網(wǎng)關(guān)可以將查詢請(qǐng)求路由到適當(dāng)服務(wù)器上。同時(shí),多個(gè)服務(wù)也可以被注冊(cè)到該網(wǎng)關(guān)上,以便根據(jù)真實(shí)的負(fù)載,來(lái)處理和調(diào)節(jié)各種請(qǐng)求。
查詢服務(wù)與更新服務(wù)
這是一些大規(guī)模的應(yīng)用服務(wù),可用于查詢數(shù)據(jù),或?qū)?shù)據(jù)更新并添加到數(shù)據(jù)層,也就是“Ignite 服務(wù)器群集”上(有關(guān)數(shù)據(jù)層的可視化,請(qǐng)參見(jiàn)上圖)。
查詢服務(wù)設(shè)置將使用 Ignite 的客戶端庫(kù)(即:配置為客戶端模式)連接到 Ignite 服務(wù)器群集,并成為 Ignite 群集拓?fù)渲械囊徊糠帧?/p>
如果這些服務(wù)并不會(huì)被作為 Ignite 的客戶端節(jié)點(diǎn)加入群集拓?fù)洌敲次覀兛梢允褂?Ignite 的瘦客戶端(如:Java Thin Client 或 Node.js Thin Client)去連接到 Ignite 服務(wù)器集群,并執(zhí)行各種緩存操作。
而且,每個(gè)服務(wù)都能夠更新 Ignite 服務(wù)器群集中的一到多個(gè)緩存。
將數(shù)據(jù)推送到數(shù)據(jù)網(wǎng)格雖然會(huì)產(chǎn)生開(kāi)銷,但是我們可以通過(guò)使用異步機(jī)制,或者將數(shù)據(jù)推送到某些 Kafka 的 topic 上來(lái)解決。
在此類 topic 中,數(shù)據(jù)網(wǎng)格的更新服務(wù)(Data Grid Update Service)會(huì)將其推送到 Ignite 的服務(wù)器群集之中。
注意:應(yīng)用服務(wù)會(huì)使用 Ignite 的客戶端庫(kù),來(lái)進(jìn)行各項(xiàng)緩存操作。在默認(rèn)情況下,它們通過(guò)加入 Ignite 服務(wù)器群集拓?fù)洌瑏?lái)充當(dāng)服務(wù)器節(jié)點(diǎn),以參與緩存任務(wù)。
當(dāng)然,這并不是必需的。我們需要在 Ignite 的配置文件中啟用客戶端模式標(biāo)志(即:設(shè)置為 true),或者在應(yīng)用服務(wù)的初始化時(shí),調(diào)用某個(gè)類似的 Ignite API。
有關(guān) Ignite 客戶端和服務(wù)器設(shè)置的更多信息,請(qǐng)參見(jiàn):https://apacheignite.readme.io/docs/clients-vs-servers
使用數(shù)據(jù)網(wǎng)格的示例
在上圖中,最左側(cè)的組件是微服務(wù),其中每個(gè)服務(wù)都有自己的數(shù)據(jù)庫(kù)。在傳統(tǒng)的非數(shù)據(jù)網(wǎng)格方法中,上例中的訂購(gòu)服務(wù)需要針對(duì)用戶服務(wù),去查詢用戶的相關(guān)信息(例如:用戶的電子郵件與地址等)。
而在圣誕節(jié)、感恩節(jié)等銷售旺季,此類訂購(gòu)服務(wù)可能會(huì)遇到大量的交易請(qǐng)求。那么此類訂購(gòu)服務(wù)就必須調(diào)用相應(yīng)的用戶服務(wù),以獲取與交易數(shù)量成比例的用戶相關(guān)信息。
當(dāng)然,訂購(gòu)服務(wù)可以緩存用戶的信息,以避免多個(gè)網(wǎng)絡(luò)的調(diào)用?;蛘?,為了滿足不斷增加的用戶服務(wù)負(fù)載,我們還可以向集群添加更多的用戶服務(wù)節(jié)點(diǎn),以處理各種讀取請(qǐng)求。不過(guò),總的說(shuō)來(lái),數(shù)據(jù)網(wǎng)格更適合于處理此類業(yè)務(wù)場(chǎng)景。
當(dāng)某個(gè)微服務(wù)有數(shù)據(jù)更新時(shí),該數(shù)據(jù)將會(huì)被數(shù)據(jù)網(wǎng)格更新服務(wù)推送到數(shù)據(jù)網(wǎng)格之中。Ignite 服務(wù)器進(jìn)而根據(jù)緩存配置將數(shù)據(jù)插入到緩存里。
此外,由于 Ignite 具有持久性,因此我們可以添加任意數(shù)量的節(jié)點(diǎn),以支持來(lái)自各種服務(wù)的大型數(shù)據(jù)集。
這些 Ignite 服務(wù)器群集既可以通過(guò)原生持久性來(lái)啟用,也可以連接到數(shù)據(jù)庫(kù)上,以便保留各種緩存數(shù)據(jù)。
當(dāng)某個(gè)微服務(wù)需要訪問(wèn)特定的數(shù)據(jù)時(shí),它會(huì)通過(guò)傳遞必要的查詢參數(shù),來(lái)使用數(shù)據(jù)網(wǎng)格的查詢服務(wù)。
由于查詢服務(wù)連接著 Ignite 服務(wù)器,因此它可以從緩存中查詢到數(shù)據(jù)。當(dāng)然,如果數(shù)據(jù)不在緩存中,卻已經(jīng)啟用了持久性,那么 Ignite 則可以從持久性存儲(chǔ)中加載相應(yīng)的數(shù)據(jù)。
在極端情況下,如果緩存和持久性存儲(chǔ)中的數(shù)據(jù)都不可用,那么查詢服務(wù)則可以通過(guò)內(nèi)置的邏輯,將請(qǐng)求重新路由到相應(yīng)的微服務(wù)上,以獲取數(shù)據(jù)并將其插入到緩存中。
同時(shí),該響應(yīng)也會(huì)將請(qǐng)求發(fā)送給消費(fèi)者服務(wù),以便在下一個(gè)請(qǐng)求到來(lái)時(shí),直接從數(shù)據(jù)網(wǎng)格本身獲取對(duì)應(yīng)的數(shù)據(jù)。
由于插入到緩存中的數(shù)據(jù)是基于更新服務(wù)來(lái)部署緩存的,因此它確保了在任何微服務(wù)中的更新數(shù)據(jù),都會(huì)在數(shù)據(jù)網(wǎng)格中可用。
此外,由于 Ignite 具有持久性,因此我們可以添加任意數(shù)量的節(jié)點(diǎn),以支持來(lái)自各種服務(wù)的大型數(shù)據(jù)集。
總結(jié)
本文提供了將消費(fèi)者服務(wù)與生產(chǎn)者服務(wù)相解耦的思路,進(jìn)而讓用戶能夠靈活地向微服務(wù)群添加更多的服務(wù),以構(gòu)建和部署新的功能集。
【51CTO原創(chuàng)稿件,合作站點(diǎn)轉(zhuǎn)載請(qǐng)注明原文作者和出處為51CTO.com】