從0開始學微服務:如何使用服務路由?
什么是服務路由呢?我的理解是服務路由就是服務消費者在發起服務調用時,必須根據特定的規則來選擇服務節點,從而滿足某些特定的需求。
那么服務路由都有哪些應用場景?具體都有哪些規則呢?
服務路由的應用場景
根據我的實踐經驗,服務路由主要有以下幾種應用場景:
- 分組調用。一般來講,為了保證服務的高可用性,實現異地多活的需求,一個服務往往不止部署在一個數據中心,而且出于節省成本等考慮,有些業務可能不僅在私有機房部署,還會采用公有云部署,甚至采用多家公有云部署。服務節點也會按照不同的數據中心分成不同的分組,這時對于服務消費者來說,選擇哪一個分組調用,就必須有相應的路由規則。
- 灰度發布。在服務上線發布的過程中,一般需要先在一小部分規模的服務節點上先發布服務,然后驗證功能是否正常。如果正常的話就繼續擴大發布范圍;如果不正常的話,就需要排查問題,解決問題后繼續發布。這個過程就叫作灰度發布,也叫金絲雀部署。
- 流量切換。在業務線上運行過程中,經常會遇到一些不可抗力因素導致業務故障,比如某個機房的光纜被挖斷,或者發生著火等事故導致整個機房的服務都不可用。這個時候就需要按照某個指令,能夠把原來調用這個機房服務的流量切換到其他正常的機房。
- 讀寫分離。對于大多數互聯網業務來說都是讀多寫少,所以在進行服務部署的時候,可以把讀寫分開部署,所有寫接口可以部署在一起,而讀接口部署在另外的節點上。
上面四種應用場景是實際業務中很常見的,服務路由可以通過各種規則來實現,那么服務路由都有哪些規則呢?
服務路由的規則
根據我的實踐經驗,服務路由主要有兩種規則:一種是條件路由,一種是腳本路由。
1. 條件路由
條件路由是基于條件表達式的路由規則,以下面的條件路由為例,我來給你詳細講解下它的用法。
- condition://0.0.0.0/dubbo.test.interfaces.TestService?category=routers&dynamic=true&priority=2&enabled=true&rule=" + URL.encode(" host = 10.20.153.10=> host = 10.20.153.11")
這里面“condition://”代表了這是一段用條件表達式編寫的路由規則,具體的規則是
- host = 10.20.153.10 => host = 10.20.153.11
分隔符“=>”前面是服務消費者的匹配條件,后面是服務提供者的過濾條件。當服務消費者節點滿足匹配條件時,就對該服務消費者執行后面的過濾規則。那么上面這段表達式表達的意義就是 IP 為“10.20.153.10”的服務消費者都調用 IP 為“10.20.153.11”的服務提供者節點。
如果服務消費者的匹配條件為空,就表示對所有的服務消費者應用,就像下面的表達式一樣。
- => host != 10.20.153.11
如果服務提供者的過濾條件為空,就表示禁止服務消費者訪問,就像下面的表達式一樣。
- host = 10.20.153.10=>
下面我舉一些 Dubbo 框架中的條件路由,來給你講解下條件路由的具體應用場景。
- 排除某個服務節點
- => host != 172.22.3.91
一旦這條路由規則被應用到線上,所有的服務消費者都不會訪問 IP 為 172.22.3.91 的服務節點,這種路由規則一般應用在線上流量排除預發布機以及摘除某個故障節點的場景。
- 白名單和黑名單功能
- host != 10.20.153.10,10.20.153.11 =>
這條路由規則意思是除了 IP 為 10.20.153.10 和 10.20.153.11 的服務消費者可以發起服務調用以外,其他服務消費者都不可以,主要用于白名單訪問邏輯,比如某個后臺服務只允許特定的幾臺機器才可以訪問,這樣的話可以機器控制訪問權限。
- host = 10.20.153.10,10.20.153.11 =>
同理,這條路由規則意思是除了 IP 為 10.20.153.10 和 10.20.153.11 的服務消費者不能發起服務調用以外,其他服務消費者都可以,也就是實現了黑名單功能,比如線上經常會遇到某些調用方不管是出于有意還是無意的不合理調用,影響了服務的穩定性,這時候可以通過黑名單功能暫時予以封殺。
- 機房隔離
- host = 172.22.3.* => host = 172.22.3.*
這條路由規則意思是 IP 網段為 172.22.3.* 的服務消費者,才可以訪問同網段的服務節點,這種規則一般應用于服務部署在多個 IDC,理論上同一個 IDC 內的調用性能要比跨 IDC 調用性能要好,應用這個規則是為了實現同 IDC 就近訪問。
- 讀寫分離
- method = find*,list*,get*,is* => host =172.22.3.94,172.22.3.95
- method != find*,list*,get*,is* => host = 172.22.3.97,172.22.3.98
這條路由規則意思是 find*、get*、is* 等讀方法調用 IP 為 172.22.3.94 和 172.22.3.95 的節點,除此以外的寫方法調用 IP 為 172.22.3.97 和 172.22.3.98 的節點。對于大部分互聯網業務來說,往往讀請求要遠遠大于寫請求,而寫請求的重要性往往要遠遠高于讀請求,所以需要把讀寫請求進行分離,以避免讀請求異常影響到寫請求,這時候就可以應用這種規則。
2. 腳本路由
腳本路由是基于腳本語言的路由規則,常用的腳本語言比如 JavaScript、Groovy、JRuby 等。以下面的腳本路由規則為例,我來給你詳細講解它的用法。
- "script://0.0.0.0/com.foo.BarService?category=routers&dynamic=false&rule=" + URL.encode("(function route(invokers) { ... } (invokers))")
這里面“script://”就代表了這是一段腳本語言編寫的路由規則,具體規則定義在腳本語言的 route 方法實現里,比如下面這段用 JavaScript 編寫的 route() 方法表達的意思是,只有 IP 為 10.20.153.10 的服務消費者可以發起服務調用。
- function route(invokers){
- var result = new java.util.ArrayList(invokers.size());
- for(i =0; i < invokers.size(); i ++){
- if("10.20.153.10".equals(invokers.get(i).getUrl().getHost())){
- result.add(invokers.get(i));
- }
- }
- return result;
- } (invokers));
既然服務路由是通過路由規則來實現的,那么服務消費者該如何獲取路由規則呢?
服務路由的獲取方式
根據我的實踐經驗,服務路由的獲取方式主要有三種:
- 本地配置
顧名思義就是路由規則存儲在服務消費者本地上。服務消費者發起調用時,從本地固定位置讀取路由規則,然后按照路由規則選取一個服務節點發起調用。
- 配置中心管理
這種方式下,所有的服務消費者都從配置中心獲取路由規則,由配置中心來統一管理。
- 動態下發
這種方式下,一般是運維人員或者開發人員,通過服務治理平臺修改路由規則,服務治理平臺調用配置中心接口,把修改后的路由規則持久化到配置中心。因為服務消費者訂閱了路由規則的變更,于是就會從配置中心獲取最新的路由規則,按照最新的路由規則來執行。
根據我的實踐經驗,上面三種方式實際使用時,還是有一定區別的。
一般來講,服務路由最好是存儲在配置中心中,由配置中心來統一管理。這樣的話,所有的服務消費者就不需要在本地管理服務路由,因為大部分的服務消費者并不關心服務路由的問題,或者說也不需要去了解其中的細節。通過配置中心,統一給各個服務消費者下發統一的服務路由,節省了溝通和管理成本。
但也不排除某些服務消費者有特定的需求,需要定制自己的路由規則,這個時候就適合通過本地配置來定制。
而動態下發可以理解為一種高級功能,它能夠動態地修改路由規則,在某些業務場景下十分有用。比如某個數據中心存在問題,需要把調用這個數據中心的服務消費者都切換到其他數據中心,這時就可以通過動態下發的方式,向配置中心下發一條路由規則,將所有調用這個數據中心的請求都遷移到別的地方。
當然,這三種方式也可以一起使用,這個時候服務消費者的判斷優先級是本地配置 > 動態下發 > 配置中心管理。
總結
今天我給你講解了服務路由的作用,簡單來講就是為了實現某些調用的特殊需求,比如分組調用、灰度發布、流量切換、讀寫分離等。在業務規模比較小的時候,可能所有的服務節點都部署在一起,也就不需要服務路由。但隨著業務規模的擴大、服務節點增多,尤其是涉及多數據中心部署的情況,把服務節點按照數據中心進行分組,或者按照業務的核心程度進行分組,對提高服務的可用性是十分有用的。以微博業務為例,有的服務不僅進行了核心服務和非核心服務分組,還針對私有云和公有云所處的不同數據中心也進行了分組,這樣的話就可以將服務之間的調用盡量都限定在同一個數據中心內部,最大限度避免跨數據中心的網絡延遲、抖動等影響。
而服務路由具體是在本地配置,還是在配置中心統一管理,也是視具體業務需求而定的。如果沒有定制化的需求,建議把路由規則都放到配置中心中統一存儲管理。而動態下發路由規則對于服務治理十分有幫助,當數據中心出現故障的時候,可以實現動態切換流量,還可以摘除一些有故障的服務節點。
思考題
在實際業務場景中,經常有一類需求就是一個新功能在全量上線前,會圈一批用戶優先適用,如果使用服務路由功能的話,你覺得可以怎么做?