Dubbo3 舊路由規(guī)則

2022-04-01 11:08 更新

在 Dubbo 2.6.x版本以及更早的版本中配置路由規(guī)則

路由規(guī)則 (2.2.0 以上版本支持 )決定一次 dubbo 服務(wù)調(diào)用的目標(biāo)服務(wù)器,分為條件路由規(guī)則和腳本路由規(guī)則,并且支持可擴(kuò)展 (路由規(guī)則擴(kuò)展點(diǎn):路由擴(kuò)展)。

寫入路由規(guī)則

向注冊(cè)中心寫入路由規(guī)則的操作通常由監(jiān)控中心或治理中心的頁面完成

RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181"));
registry.register(URL.valueOf("route://0.0.0.0/com.foo.BarService?category=routers&dynamic=false&rule=" + URL.encode("host = 10.20.153.10 => host = 10.20.153.11")));

其中:

  • ?route://? 表示路由規(guī)則的類型,支持條件路由規(guī)則和腳本路由規(guī)則,可擴(kuò)展,必填。
  • ?0.0.0.0 ?表示對(duì)所有 IP 地址生效,如果只想對(duì)某個(gè) IP 的生效,請(qǐng)?zhí)钊刖唧w IP,必填。
  • ?com.foo.BarService ?表示只對(duì)指定服務(wù)生效,必填。
  • ?group=foo? 對(duì)指定服務(wù)的指定group生效,不填表示對(duì)未配置group的指定服務(wù)生效
  • ?version=1.0?對(duì)指定服務(wù)的指定version生效,不填表示對(duì)未配置version的指定服務(wù)生效
  • ?category=routers? 表示該數(shù)據(jù)為動(dòng)態(tài)配置類型,必填。
  • ?dynamic=false? 表示該數(shù)據(jù)為持久數(shù)據(jù),當(dāng)注冊(cè)方退出時(shí),數(shù)據(jù)依然保存在注冊(cè)中心,必填。
  • ?enabled=true ?覆蓋規(guī)則是否生效,可不填,缺省生效。
  • ?force=false ?當(dāng)路由結(jié)果為空時(shí),是否強(qiáng)制執(zhí)行,如果不強(qiáng)制執(zhí)行,路由結(jié)果為空的路由規(guī)則將自動(dòng)失效,可不填,缺省為 ?false?。
  • ?runtime=false? 是否在每次調(diào)用時(shí)執(zhí)行路由規(guī)則,否則只在提供者地址列表變更時(shí)預(yù)先執(zhí)行并緩存結(jié)果,調(diào)用時(shí)直接從緩存中獲取路由結(jié)果。如果用了參數(shù)路由,必須設(shè)為 true,需要注意設(shè)置會(huì)影響調(diào)用的性能,可不填,缺省為 ?false?。
  • ?priority=1 ?路由規(guī)則的優(yōu)先級(jí),用于排序,優(yōu)先級(jí)越大越靠前執(zhí)行,可不填,缺省為 0。
  • ?rule=URL.encode("host = 10.20.153.10 => host = 10.20.153.11")? 表示路由規(guī)則的內(nèi)容,必填。

條件路由規(guī)則

基于條件表達(dá)式的路由規(guī)則,如:?host = 10.20.153.10 => host = 10.20.153.11?

規(guī)則:

  • ?=>? 之前的為消費(fèi)者匹配條件,所有參數(shù)和消費(fèi)者的 URL 進(jìn)行對(duì)比,當(dāng)消費(fèi)者滿足匹配條件時(shí),對(duì)該消費(fèi)者執(zhí)行后面的過濾規(guī)則。
  • ?=> ?之后為提供者地址列表的過濾條件,所有參數(shù)和提供者的 URL 進(jìn)行對(duì)比,消費(fèi)者最終只拿到過濾后的地址列表。
  • 如果匹配條件為空,表示對(duì)所有消費(fèi)方應(yīng)用,如:?=> host != 10.20.153.11?
  • 如果過濾條件為空,表示禁止訪問,如:?host = 10.20.153.10 =>?

表達(dá)式:

參數(shù)支持:

  • 服務(wù)調(diào)用信息,如:method, argument 等,暫不支持參數(shù)路由
  • URL 本身的字段,如:protocol, host, port 等
  • 以及 URL 上的所有參數(shù),如:application, organization 等

條件支持:

  • 等號(hào) ?=? 表示"匹配",如:?host = 10.20.153.10?
  • 不等號(hào)? !=? 表示"不匹配",如:?host != 10.20.153.10?

值支持:

  • 以逗號(hào)? , ?分隔多個(gè)值,如:?host != 10.20.153.10,10.20.153.11?
  • 以星號(hào)? * ?結(jié)尾,表示通配,如:?host != 10.20.*?
  • 以美元符 ?$? 開頭,表示引用消費(fèi)者參數(shù),如:?host = $host?

示例:

  1. 排除預(yù)發(fā)布機(jī):
    ?=> host != 172.22.3.91?
    
  2. 白名單 (注意:一個(gè)服務(wù)只能有一條白名單規(guī)則,否則兩條規(guī)則交叉,就都被篩選掉了):
    host != 10.20.153.10,10.20.153.11 =>?
  3. 黑名單:
    host = 10.20.153.10,10.20.153.11 =>?
  4. 服務(wù)寄宿在應(yīng)用上,只暴露一部分的機(jī)器,防止整個(gè)集群掛掉:
    => host = 172.22.3.1*,172.22.3.2*
  5. 為重要應(yīng)用提供額外的機(jī)器:
    application != kylin => host != 172.22.3.95,172.22.3.96
  6. 讀寫分離:
    method = find*,list*,get*,is* => host = 172.22.3.94,172.22.3.95,172.22.3.96 method != find*,list*,get*,is* => host = 172.22.3.97,172.22.3.98
  7. 前后臺(tái)分離:
    application = bops => host = 172.22.3.91,172.22.3.92,172.22.3.93 application != bops => host = 172.22.3.94,172.22.3.95,172.22.3.96
  8. 隔離不同機(jī)房網(wǎng)段:
    host != 172.22.3.* => host != 172.22.3.*
  9. 提供者與消費(fèi)者部署在同集群內(nèi),本機(jī)只訪問本機(jī)的服務(wù):
    => host = $host

腳本路由規(guī)則

腳本路由規(guī)則(注意:腳本沒有沙箱約束,可執(zhí)行任意代碼,存在后門風(fēng)險(xiǎn)) 支持 JDK 腳本引擎的所有腳本,比如:javascript, jruby, groovy 等,通過 type=javascript 參數(shù)設(shè)置腳本類型,缺省為 javascript。

"script://0.0.0.0/com.foo.BarService?category=routers&dynamic=false&rule=" + URL.encode("(function route(invokers) { ... } (invokers))")

基于腳本引擎的路由規(guī)則,如:

(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)); // 表示立即執(zhí)行方法

標(biāo)簽路由規(guī)則

標(biāo)簽路由規(guī)則 (該特性在 2.7.0 以上版本支持) ,當(dāng)應(yīng)用選擇裝配標(biāo)簽路由(TagRouter)之后,一次 dubbo 調(diào)用能夠根據(jù)請(qǐng)求攜帶的 tag 標(biāo)簽智能地選擇對(duì)應(yīng) tag 的服務(wù)提供者進(jìn)行調(diào)用。

服務(wù)提供者

  1. 給應(yīng)用裝配標(biāo)簽路由器:
@Bean
public ApplicationConfig applicationConfig() {
    ApplicationConfig applicationConfig = new ApplicationConfig();
    applicationConfig.setName("provider-book");
    applicationConfig.setQosEnable(false);
    // instruct tag router
    Map<String,String> parameters = new HashMap<>();
    parameters.put(Constants.ROUTER_KEY, "tag");
    applicationConfig.setParameters(parameters);
    return applicationConfig;
}
  1. 給應(yīng)用設(shè)置具體的標(biāo)簽:
@Bean
public ProviderConfig providerConfig(){
	ProviderConfig providerConfig = new ProviderConfig();
	providerConfig.setTag("red");
	return providerConfig;
}

應(yīng)用未裝配 tag 屬性或服務(wù)提供者未設(shè)置 tag 屬性,都將被認(rèn)為是默認(rèn)的應(yīng)用,這些默認(rèn)應(yīng)用將會(huì)在調(diào)用無法匹配 provider 時(shí)當(dāng)作降級(jí)方案。

服務(wù)消費(fèi)者

RpcContext.getContext().setAttachment(Constants.TAG_KEY,"red");

請(qǐng)求標(biāo)簽的作用域?yàn)槊恳淮?invocation,使用 attachment 來傳遞請(qǐng)求標(biāo)簽,注意保存在 attachment 中的值將會(huì)在一次完整的遠(yuǎn)程調(diào)用中持續(xù)傳遞,得益于這樣的特性,我們只需要在起始調(diào)用時(shí),通過一行代碼的設(shè)置,達(dá)到標(biāo)簽的持續(xù)傳遞。

目前僅僅支持 hardcoding 的方式設(shè)置 dubboTag。注意到 RpcContext 是線程綁定的,優(yōu)雅的使用 TagRouter 特性,建議通過 servlet 過濾器(在 web 環(huán)境下),或者定制的 SPI 過濾器設(shè)置 dubboTag。

規(guī)則描述

  1. dubbo.tag=red 時(shí)優(yōu)先選擇 tag=red 的 provider。若集群中不存在與請(qǐng)求標(biāo)記對(duì)應(yīng)的服務(wù),可以降級(jí)請(qǐng)求 tag=null 的 provider,即默認(rèn) provider。
  2. dubbo.tag=null 時(shí),只會(huì)匹配 tag=null 的 provider。即使集群中存在可用的服務(wù),若 tag 不匹配就無法調(diào)用,這與規(guī)則1不同,攜帶標(biāo)簽的請(qǐng)求可以降級(jí)訪問到無標(biāo)簽的服務(wù),但不攜帶標(biāo)簽/攜帶其他種類標(biāo)簽的請(qǐng)求永遠(yuǎn)無法訪問到其他標(biāo)簽的服務(wù)。
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)