背景介紹
現在很多的公司都在用dubbo、springcloud做為服務化/微服務的開發框架,服務化之后應用越來越多,鏈路越來越長,服務環境的治理變的很困難。比如:研發團隊的人很多的,同時有幾個分支在開發和測試,會造成多個同名的服務存在,為了避免不同feature之間的服務不串調,很多研發人員會改服務的版本號來避免這種情況;還有一種情況是因為修改服務版本號,調用鏈鏈路上所有的節點都需要修改,存在浪費機器資源的現象。
需求場景描述
- 穩定的測試環境一般是有測試的同學維護的,上面的代碼一般是驗證完成(即將上線)的分支,或者就是和線上代碼保持一致的分支(基准代碼);
- 下圖中需求1是正在開發的某個需求,它涉及了2個需要改動的應用A和B,由於他們在需求1里(代碼也切分支),我們稱需求1里面的應用A為A1,需求1里面的應用B為B1;
- 同理,需求2也是正在開發的某個需求,因為它和需求1同時開發,涉及的應用也有重合,所以稱為並發需求。需求2中的應用A為A2,應用B為B2,應用E為E2;
- 在不修改服務版本號的情況下,需求1的研發人員希望A1直接調用下游B,然后B調用C1,因為應用B、C、D在需求1里面是沒有代碼變更的,所以完整的調用鏈路如下:A1->B->C1->D->E
- 需求2中有代碼變更的應用是A2、B2、E2,不需要更變的是C、D,所以完成的調用鏈路如下:A2->B2->C->D->E2
總結起來:
研發只希望調用本需求內應用,如果鏈路中某個應用沒有代碼變更,則調用穩定環境中的應用(保證鏈路能走通,並且把這種邏輯路由的關系傳遞到下游應用中)
談dubbo路由
dubbo框架內部自帶路由的,它支持2種路由規則:ConditionRouter、ScriptRouter,MockInvokersSelector暫時不討論。
1、 其中ConditionRouter表示條件路由,條件表達式以 => 分割為whenRule和thenRule:
例子:*
condition://0.0.0.0/com.foo.BarService?category=routers&dynamic=false&rule=" + URL.encode("host = 10.20.153.10 => host = 10.20.153.11"
- 從url根據RULE_KEY獲取路由條件路由內容
- rule.indexOf("=>") 分割路由內容: =>前面是消費者條件(when),=>后面是provider的條件(then)
- 分別調用parseRule(rule) 解析路由為whenRule和thenRules
ConditionRouter執行route方法:
- 如果url不滿足when條件即過來條件, 不過濾返回所有invokers
- 遍歷所有invokers判斷是否滿足then條件, 將滿足條件的加入集合result
- Result不為空,有滿足條件的invokers返回
- Result為空, 沒有滿足條件的invokers, 判斷參數FORCE_KEY是否強制過來,如果強制過濾返回空, 不是返回所有即不過濾
ConditionRouter的點評
ConditionRouter並不是適合我們的需求,因為我們需要是配合簡單運維實現自動路由,不需要開發人員寫額外代碼和配置,很顯然ConditionRouter=>后面的then條件是固定的一個provider或者一組provider,而不能動態路由;第二點是ConditionRouter在穩定測試環境的應用上也需要在URL里面打上路由標識,這就違反了我們初衷:不需要開發人員寫額外代碼和配置
2、 ScriptRouter表示腳本路由
通過url的RULE_KEY參數獲取腳本內容,然后通過java的腳本引擎執行腳本代碼, dubbo的測試用例都是通過javascript作為腳本但是理論上也支持groovy, jruby腳本
- 從url獲取腳本類型javascript, groovy等等
- 從url根據RULE_KEY獲取路由規則內容
- 根據腳本類型獲取java支持的腳本執行引擎
ScriptRouter的點評
ScriptRouter雖然比ConditionRouter靈活,可以在消費端執行腳本來控制路由的邏輯,但是還是有同樣的問題,對於穩定的測試環境里的應用也需要配置路由腳本,不能做到真正的少配置、少運維、少寫額外代碼
邏輯路由的方案
我們分析了場景和需求,又分析現有的dubbo路由方案的不滿足,現在來來看一下一種可行的方案:
- 邏輯路由provider和consumer都通過URL來獲取路由標識
- 最小運維開支:通過申請應用環境的時候,在機器打上環境變量
- 最小的dubbo框架改動:在LoadBalance和AbstractClusterInvoker上修改邏輯路由方案
show me code
具體實現的代碼,我放在github上,變更也不大,分支
- 在LoadBalance和AbstractClusterInvoker上修改邏輯路由主要邏輯
- 在provider注冊服務的URL時,加上邏輯路由的標識
- dubbox新增加了一個依賴:logical-router,這是我自己寫的小的jar包,方便之后做擴展(比如rest入口的應用程序,自啟動的應用程序等等)
- 運維相關:只需要給申請相同的邏輯路由標識應用的機器,打上相同的環境變量:LOGICAL_ROUTER_ENV
diff文件
更方便的查看變更:diff文件