來自:孤獨煙(微訊號:zrj_guduyan)
引言
OK,如下圖所示
那顯而易見,做服務隔離的目的就是避免服務之間相互影響。畢竟誰也不能說自己的微服務百分百可用,如果不做隔離,一旦一個服務出現了問題,整個系統的穩定性都會受到影響!
因此,做服務隔離是很有必要的。那麼怎麼隔離呢?
- 按種類隔離
- 按使用者隔離
OK,接下來開始細說這兩種方式!
正文
種類隔離
其實按照服務種類隔離要從兩個緯度來說:即服務提供方和服務呼叫方!
假設我們一個系統有三個服務:訂單服務,庫存服務,支付服務!有如下呼叫關係:
OK,我們先明確一點,上面有幾個服務扮演服務提供方的角色?
一共是三個:支付服務(給使用者提供服務)、庫存服務(給支付服務提供服務)、訂單服務(給支付服務提供服務)
有幾個服務扮演服務呼叫方的角色?
一共是一個:支付服務(呼叫訂單服務和庫存服務)
針對服務提供方這個角度而言,怎麼做隔離呢?
很簡單,每一個服務乃至其對應的資料庫,給一個伺服器部署就行!這樣某個服務出現了故障,就不會相互影響,達到一種物理層面上的隔離!
什麼,你們公司伺服器不夠?瞭解一下《微服務為什麼一定要用docker》
針對服務呼叫方這個角度而言,怎麼做隔離呢?
OK,先明白一點,服務呼叫方不做隔離會出現什麼情況?如圖所示
一個請求過來,佔用支付服務中的Tomcat的一個執行緒。然後,該執行緒去順序呼叫訂單服務和庫存服務!那麼,一旦庫存服務出問題了,這個Tomcat的執行緒就一直卡在那,無法傳回!與此同時,頁面上源源不斷的有請求過來,會把Tomcat裡頭的執行緒池資源全部消耗完畢!對於後面的請求,Tomcat就無法響應!
因此,如果不針對被調服務做服務隔離,一個被調服務出問題,就將導致呼叫方服務不可用!
那怎麼隔離呢?
這裡介紹一種執行緒池隔離方式,給每個微服務都初始化出一個執行緒池,如下圖所示,給訂單服務和庫存服務都初始化出一個執行緒池,不使用Tomcat執行緒池中的執行緒直接呼叫,而是用相應執行緒池中的執行緒去呼叫!
OK,如果此時庫存服務不可用了呢?
庫存服務執行緒池會被迅速塞滿,此時後面進來的新請求發現庫存服務執行緒池滿啦,於是乎就不去調庫存服務,直接傳回!如下圖所示
ps
:目前業內有訊號量隔離和執行緒池隔離兩種隔離方式,這裡舉的是執行緒池隔離!
怎麼實現呢?
可以瞭解一下Hytrix、Sentinel、以及Resilience4j如何和你的專案結合起來使用!Resilience4j只提供訊號量隔離!
使用者隔離
OK,我們先明白一點這裡的租戶和使用者不是一個概念!
- 使用者: 一個環境/系統的一個使用者即該環境/系統的一個使用者。
- 租戶:使用者從某種粒度上被分到若干組內,每組成為一個租戶。
這裡的組可以這麼理解:使用者根據一定的特徵去做分組,比如是VIP的一組,不是VIP的一組。又或者北方的使用者一組,南方的使用者一組。按照自己的業務場景來分組。
那麼所謂的使用者隔離,就是按照不同的分組形成不同的服務實體。這樣某個服務實體掛了,隻影響對應分組的使用者,而不是全部使用者!
有如下三種方式!
- 方式一:每個租戶有獨立的服務和獨立的資料庫
- 方式二:每個租戶有共享的服務和獨立的資料庫
- 方式三:每個租戶有共享的服務和共享的資料庫
下麵開始逐個說明
方式一
每個租戶有獨立的服務和獨立的資料庫!
這個在生產上一般是這麼做,如下所示
如圖所示,使用者在請求的時候會經過閘道器!閘道器根據tenant_id
識別出對應的服務實體,進行轉發。至於用什麼當閘道器,我們用的是Zuul。
方式二
每個租戶有共享的服務和獨立的資料庫!
這個在生產上一般是這麼做,如下所示
如圖所示,使用者在請求的時候會經過閘道器,閘道器將資料轉發給使用者服務!使用者服務根據tenant_id
確定該操作哪一個資料庫!
OK,這個時候大家應該有一個疑問,
在專案程式碼中,怎麼確定該操作的資料庫?
好,這個就是ORM框架,動態選擇資料源的問題!我以國內流行的hibernate
和mybatis
來進行說明!
(1)hibernate
方式
在4.0版本hibenate
開始支援多租戶架構,即對不同租戶使用獨立資料庫!大家可以搜尋一個配置,叫hibernate.multiTenancy
。該值有一個value值為
DATABASE:一個租戶一個database。
將這項的value值設為DATABASE
後,還需要給hibernate.tenant_identifier_resolver
配置項賦值,即告訴hibernate,如何解析出tenant_id
。以及給hibernate.multi_tenant_connection_provider
配置項賦值,即告訴hibernate如何以租戶特有的方式獲取資料連線!
ps:
看不懂的童鞋略過,懂hibernate的童鞋自然懂這個配置!
(2)mybatis
方式
mybatis
沒提供這種多租戶架構的支援!我們必須要擴充套件AbstractRoutingDataSource
抽象類,實現多資料源切換!
嫌麻煩?
OK,介紹你一個外掛叫mybatis plus
可以實現這種動態資料源切換!
API地址都給你貼出來了:
https://mp.baomidou.com/guide/dynamic-datasource.html
ps
:我只能給你點一下思路,自己去查。因為具體如何配置,都可以寫一篇文章!我很不愛寫這種貼配置的文章,覺得含金量不高,所以大家根據我的思路去實現即可!
方式三
每個租戶有共享的服務和共享的資料庫!
這個在生產上一般是這麼做,如下所示
如圖所示,使用者在請求的時候會經過閘道器,閘道器將資料轉發給使用者服務!使用者服務根據tenant_id
確定運算元據庫中的哪一行記錄!
老規矩,和你們說一下在ORM中難點在哪!以mybatis為例,所有的sql上都要加一句
AND t.tenant_id = ?
是不是覺得很麻煩?怎麼解決呢?
(1)hibernate
方式
利用hibernate filter
配置, OR-Mapping配置檔案使用Filter,可以在進行資料查詢時自動過濾資料!
如下所示
<class name="User" table="user_tb">
//省略
"tenantFilter" condition="tenant_id = :tenantFilterParam" />
class>
ps:
看不懂的童鞋略過,懂hibernate的童鞋自然懂這個配置!
(2)mybatis
方式
mybatis
中有一個東西叫做自定義Interceptor
,可以攔截出你要執行的sql,然後動態拼上你的租戶條件即可!
嫌麻煩?
OK,介紹你一個外掛叫mybatis plus
可以實現這種多租戶的更改,可以動態的解析出sql,增加上條件!
API地址都給你貼出來了:
https://mp.baomidou.com/guide/tenant.html
總結
本文介紹了服務隔離的分類,以及在生產上具體是怎麼做的,希望大家有所收穫!