面試官:說說你們公司如何做服務路由的?


  點擊上方“JavaEdge”,關注公衆號

設爲“星標”,好文章不錯過!


衆所周知,負載均衡是爲了解決 【務的Consumer】 如何從衆多可用服務節點中選取一個最合適的節點,對其發起調用。

場景導入



但現實中經常還會遇到這樣場景:比如服務X部署在了三個IDC,所有服務節點也就被分成三組,那麼【服務XConsumer】發起調用時,應該如何選擇呢?

這就是服務路由要解決的問題。

什麼是服務路由?



服務消費者在發起服務調用時,必須根據特定規則選擇服務節點,從而滿足某些特定需求。



適用場景


分組調用


爲保證高可用的服務,實現異地多活,一個服務往往不止部署在一個IDC,可能不僅在私有機房,還會在公有云甚至多家公有云部署。服務節點也因IDC不同,分成不同組,這時對於【服務消費者】,選擇調用哪個分組,就需有相應路由規則。

灰度發佈


在服務上線發佈的過程,一般需先在一小部分服務節點上先預發佈服務,驗證業務功能是否符合預期:

  • 符合

    就繼續擴大發布範圍

  • 不符

    就要排查問題,解決後重新發布。

流量切換


在業務線上運行過程中,經常會遇到一些不可抗因素導致業務故障,比如光纜被挖,運營商網絡被攻擊,導致整個機房的服務都不可用。

這時就需按照某個指令,能夠把原來調用這個機房服務的流量切換到其他正常的機房。


讀寫分離


互聯網絕大部分業務讀多寫少,因此在部署服務時,可以把讀寫分開部署。

服務路由規則





條件路由


基於條件表達式的路由規則:

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=>


具體應用場景



排除某服務節點


=> 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.1010.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.95method != 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的節點。大部分業務讀請求遠大於寫請求,而寫請求的重要性往往要遠遠高於讀請求,所以需要把讀寫請求進行分離,以避免讀請求異常影響到寫請求。



腳本路由


基於腳本語言的路由規則,常用的腳本語言比如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));


服務消費者該如何

獲取路由規則





本地配置


路由規則存儲在服務消費者本地上。服務消費者發起調用時,從本地固定位置讀取路由規則,然後按照路由規則選取一個服務節點發起調用。

不排除某些服務消費者有特定的需求,需要定製自己的路由規則,這個時候就適合通過本地配置來定製。




配置中心管理



所有的服務消費者都從配置中心獲取路由規則,由配置中心來統一管理。

服務路由最好是存儲在配置中心中,由配置中心來統一管理。這樣所有服務消費者就不需要在本地管理服務路由,因爲大部分的服務消費者並不關心服務路由的問題,或者說也不需要去了解其中的細節。通過配置中心,統一給各個服務消費者下發統一的服務路由,節省了溝通和管理成本。




動態下發



一般是運維人員或者開發人員,通過服務治理平臺修改路由規則,服務治理平臺調用配置中心接口,把修改後的路由規則持久化到配置中心。因爲服務消費者訂閱了路由規則的變更,於是就會從配置中心獲取最新的路由規則,按照最新的路由規則來執行。

動態下發可以理解爲一種高級功能,它能夠動態地修改路由規則,在某些業務場景下十分有用。比如某個數據中心存在問題,需要把調用這個數據中心的服務消費者都切換到其他數據中心,這時就可以通過動態下發的方式,向配置中心下發一條路由規則,將所有調用這個數據中心的請求都遷移到別的地方。

當然,這三種方式也可以一起使用,這個時候服務消費者的判斷優先級是本地配置>動態下發>配置中心管理。


總結




服務路由簡單說就是爲了實現某些調用的特殊需求,比如分組調用、灰度發佈、流量切換、讀寫分離等。在業務規模比較小的時候,可能所有的服務節點都部署在一起,也就不需要服務路由。但隨着業務規模的擴大、服務節點增多,尤其是涉及多數據中心部署的情況,把服務節點按照數據中心進行分組,或者按照業務的核心程度進行分組,對提高服務的可用性是十分有用的。以微博業務爲例,有的服務不僅進行了核心服務和非核心服務分組,還針對私有云和公有云所處的不同數據中心也進行了分組,這樣的話就可以將服務之間的調用盡量都限定在同一個數據中心內部,最大限度避免跨數據中心的網絡延遲、抖動等影響。

而服務路由具體是在本地配置,還是在配置中心統一管理,也是視具體業務需求而定的。如果沒有定製化的需求,建議把路由規則都放到配置中心中統一存儲管理。而動態下發路由規則對於服務治理十分有幫助,當數據中心出現故障的時候,可以實現動態切換流量,還可以摘除一些有故障的服務節點。


往期推薦


由於不知線程池的bug,某Java程序員叕被祭天

程序員因重複記錄日誌撐爆ELK被辭退!

擁抱Kubernetes,再見了Spring Cloud

JDK爲何自己先破壞雙親委派模型?




目前交流羣已有 800+人,旨在促進技術交流,可關注公衆號添加筆者微信邀請進羣


喜歡文章,點個“在看、點贊、分享”素質三連支持一下~

本文分享自微信公衆號 - JavaEdge(Java-Edge)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章