一文了解 Dubbo 3 設定工作原理

2023-01-09 09:00:41

以下是一個 Dubbo 屬性設定的例子 dubbo-spring-boot-samples

  ## application.properties

  # Spring boot application
  spring.application.name=dubbo-externalized-configuration-provider-sample

  # Base packages to scan Dubbo Component: @com.alibaba.dubbo.config.annotation.Service
  dubbo.scan.base-packages=com.alibaba.boot.dubbo.demo.provider.service

  # Dubbo Application
  ## The default value of dubbo.application.name is ${spring.application.name}
  ## dubbo.application.name=${spring.application.name}

  # Dubbo Protocol
  dubbo.protocol.name=dubbo
  dubbo.protocol.port=12345

  ## Dubbo Registry
  dubbo.registry.address=N/A

  ## service default version
  dubbo.provider.version=1.0.0

接下來,我們就圍繞這個範例,分別從設定格式、設定來源、載入流程三個方面對 Dubbo 設定的工作原理進行分析。

1 設定格式

目前Dubbo支援的所有設定都是.properties格式的,包括-DExternalized Configuration等,.properties中的所有設定項遵循一種path-based的設定格式。

在Spring應用中也可以將屬性設定放到application.yml中,其樹層次結構的方式可讀性更好一些。

# 應用級設定(無id)
dubbo.{config-type}.{config-item}={config-item-value}

# 範例級設定(指定id或name)
dubbo.{config-type}s.{config-id}.{config-item}={config-item-value}
dubbo.{config-type}s.{config-name}.{config-item}={config-item-value}

# 服務介面設定
dubbo.service.{interface-name}.{config-item}={config-item-value}
dubbo.reference.{interface-name}.{config-item}={config-item-value}

# 方法設定
dubbo.service.{interface-name}.{method-name}.{config-item}={config-item-value}
dubbo.reference.{interface-name}.{method-name}.{config-item}={config-item-value}

# 方法argument設定
dubbo.reference.{interface-name}.{method-name}.{argument-index}.{config-item}={config-item-value}

1.1 應用級設定(無id)

應用級設定的格式為:設定型別單數字首,無id/name。

# 應用級設定(無id)
dubbo.{config-type}.{config-item}={config-item-value}

類似 applicationmonitormetrics 等都屬於應用級別元件,因此僅允許設定單個範例;而 protocolregistry 等允許設定多個的元件,在僅需要進行單例設定時,可採用此節描述的格式。常見範例如下:

dubbo.application.name=demo-provider
dubbo.application.qos-enable=false

dubbo.registry.address=zookeeper://127.0.0.1:2181

dubbo.protocol.name=dubbo
dubbo.protocol.port=-1

1.2 範例級設定(指定id或name)

針對某個範例的屬性設定需要指定id或者name,其字首格式為:設定型別複數字首 + id/name。適用於 protocolregistry 等支援多例設定的元件。

# 範例級設定(指定id或name)
dubbo.{config-type}s.{config-id}.{config-item}={config-item-value}
dubbo.{config-type}s.{config-name}.{config-item}={config-item-value}
  • 如果不存在該id或者name的範例,則框架會基於這裡列出來的屬性建立設定元件範例。
  • 如果已存在相同id或name的範例,則框架會將這裡的列出的屬性作為已有範例設定的補充,詳細請參考屬性覆蓋
  • 具體的設定複數形式請參考單複數設定對照表

設定範例:

dubbo.registries.unit1.address=zookeeper://127.0.0.1:2181
dubbo.registries.unit2.address=zookeeper://127.0.0.1:2182

dubbo.protocols.dubbo.name=dubbo
dubbo.protocols.dubbo.port=20880

dubbo.protocols.hessian.name=hessian
dubbo.protocols.hessian.port=8089

1.3 服務介面設定

dubbo.service.org.apache.dubbo.samples.api.DemoService.timeout=5000
dubbo.reference.org.apache.dubbo.samples.api.DemoService.timeout=6000

方法設定

方法設定格式:

# 方法設定
dubbo.service.{interface-name}.{method-name}.{config-item}={config-item-value}
dubbo.reference.{interface-name}.{method-name}.{config-item}={config-item-value}

# 方法argument設定
dubbo.reference.{interface-name}.{method-name}.{argument-index}.{config-item}={config-item-value}

方法設定範例:

dubbo.reference.org.apache.dubbo.samples.api.DemoService.sayHello.timeout=7000
dubbo.reference.org.apache.dubbo.samples.api.DemoService.sayHello.oninvoke=notifyService.onInvoke
dubbo.reference.org.apache.dubbo.samples.api.DemoService.sayHello.onreturn=notifyService.onReturn
dubbo.reference.org.apache.dubbo.samples.api.DemoService.sayHello.onthrow=notifyService.onThrow
dubbo.reference.org.apache.dubbo.samples.api.DemoService.sayHello.0.callback=true

等價於XML設定:

<dubbo:reference interface="org.apache.dubbo.samples.api.DemoService" >
    <dubbo:method name="sayHello" timeout="7000" oninvoke="notifyService.onInvoke"
                  onreturn="notifyService.onReturn" onthrow="notifyService.onThrow">
        <dubbo:argument index="0" callback="true" />
    </dubbo:method>
</dubbo:reference>

1.4 引數設定

parameters引數為map物件,支援xxx.parameters=[{key:value},{key:value}]方式進行設定。

dubbo.application.parameters=[{item1:value1},{item2:value2}]
dubbo.reference.org.apache.dubbo.samples.api.DemoService.parameters=[{item3:value3}]

1.5 傳輸層設定

triple協定採用Http2做底層通訊協定,允許使用者自定義Http2的6個settings引數

設定格式如下:

# 通知對端header壓縮索引表的上限個數
dubbo.rpc.tri.header-table-size=4096

# 啟用伺服器端推播功能
dubbo.rpc.tri.enable-push=false

# 通知對端允許的最大並行流數
dubbo.rpc.tri.max-concurrent-streams=2147483647

# 宣告傳送端的視窗大小
dubbo.rpc.tri.initial-window-size=1048576

# 設定幀的最大位元組數
dubbo.rpc.tri.max-frame-size=32768

# 通知對端header未壓縮的最大位元組數
dubbo.rpc.tri.max-header-list-size=8192

等價於yml設定:

dubbo:
  rpc:
    tri:
      header-table-size: 4096
      enable-push: false
      max-concurrent-streams: 2147483647
      initial-window-size: 1048576
      max-frame-size: 32768
      max-header-list-size: 8192

1.6 屬性與XML設定對映規則

可以將 xml 的 tag 名和屬性名組合起來,用 ‘.’ 分隔。每行一個屬性。

  • dubbo.application.name=foo 相當於 <dubbo:application name="foo" />
  • dubbo.registry.address=10.20.153.10:9090 相當於 <dubbo:registry address="10.20.153.10:9090" />

如果在 xml 設定中有超過一個的 tag,那麼你可以使用 ‘id’ 進行區分。如果你不指定id,它將作用於所有 tag。

  • dubbo.protocols.rmi.port=1099 相當於 <dubbo:protocol id="rmi" name="rmi" port="1099" />
  • dubbo.registries.china.address=10.20.153.10:9090 相當於 <dubbo:registry id="china" address="10.20.153.10:9090" />

1.7 設定項單複數對照表

複數設定的命名與普通單詞變複數的規則相同:

  1. 字母y結尾時,去掉y,改為ies
  2. 字母s結尾時,加es
  3. 其它加s
Config Type 單數設定 複數設定
application dubbo.application.xxx=xxx dubbo.applications.{id}.xxx=xxx
dubbo.applications.{name}.xxx=xxx
protocol dubbo.protocol.xxx=xxx dubbo.protocols.{id}.xxx=xxx
dubbo.protocols.{name}.xxx=xxx
module dubbo.module.xxx=xxx dubbo.modules.{id}.xxx=xxx
dubbo.modules.{name}.xxx=xxx
registry dubbo.registry.xxx=xxx dubbo.registries.{id}.xxx=xxx
monitor dubbo.monitor.xxx=xxx dubbo.monitors.{id}.xxx=xxx
config-center dubbo.config-center.xxx=xxx dubbo.config-centers.{id}.xxx=xxx
metadata-report dubbo.metadata-report.xxx=xxx dubbo.metadata-reports.{id}.xxx=xxx
ssl dubbo.ssl.xxx=xxx dubbo.ssls.{id}.xxx=xxx
metrics dubbo.metrics.xxx=xxx dubbo.metricses.{id}.xxx=xxx
provider dubbo.provider.xxx=xxx dubbo.providers.{id}.xxx=xxx
consumer dubbo.consumer.xxx=xxx dubbo.consumers.{id}.xxx=xxx
service dubbo.service.{interfaceName}.xxx=xxx
reference dubbo.reference.{interfaceName}.xxx=xxx
method dubbo.service.{interfaceName}.{methodName}.xxx=xxx
dubbo.reference.{interfaceName}.{methodName}.xxx=xxx
argument dubbo.service.{interfaceName}.{methodName}.{arg-index}.xxx=xxx

2 設定來源

Dubbo 預設支援 6 種設定來源:

  • JVM System Properties,JVM -D 引數
  • System environment,JVM程序的環境變數
  • Externalized Configuration,外部化設定,從設定中心讀取
  • Application Configuration,應用的屬性設定,從Spring應用的Environment中提取"dubbo"打頭的屬性集
  • API / XML /註解等程式設計介面採集的設定可以被理解成設定來源的一種,是直接面向用戶程式設計的設定採集方式
  • 從classpath讀取組態檔 dubbo.properties

關於dubbo.properties屬性:

  1. 如果在 classpath 下有超過一個 dubbo.properties 檔案,比如,兩個 jar 包都各自包含了 dubbo.properties,dubbo 將隨機選擇一個載入,並且列印錯誤紀錄檔。
  2. Dubbo 可以自動載入 classpath 根目錄下的 dubbo.properties,但是你同樣可以使用 JVM 引數來指定路徑:-Ddubbo.properties.file=xxx.properties

2.1 覆蓋關係

如果通過多種設定來源指定了相同的設定項,則會出現設定項的互相覆蓋,具體覆蓋關係和優先順序請參考下一小節。

3 設定載入流程

3.1 處理流程

Dubbo 設定載入大概分為兩個階段:

  • 第一階段為DubboBootstrap初始化之前,在Spring context啟動時解析處理XML設定/註解設定/Java-config 或者是執行API設定程式碼,建立config bean並且加入到ConfigManager中。
  • 第二階段為DubboBootstrap初始化過程,從設定中心讀取外部設定,依次處理範例級屬性設定和應用級屬性設定,最後重新整理所有設定範例的屬性,也就是屬性覆蓋

3.2 屬性覆蓋

發生屬性覆蓋可能有兩種情況,並且二者可能是會同時發生的:

  1. 不同設定源設定了相同的設定項
  2. 相同設定源,但在不同層次指定了相同的設定項

3.2.1 不同設定源

3.2.1 相同設定源

屬性覆蓋是指用設定的屬性值覆蓋config bean範例的屬性,類似Spring PropertyOverrideConfigurer 的作用。

Property resource configurer that overrides bean property values in an application context definition. It pushes values from a properties file into bean definitions.
Configuration lines are expected to be of the following form:

beanName.property=value

但與PropertyOverrideConfigurer的不同之處是,Dubbo的屬性覆蓋有多個匹配格式,優先順序從高到低依次是:

#1. 指定id的範例級設定
dubbo.{config-type}s.{config-id}.{config-item}={config-item-value}

#2. 指定name的範例級設定
dubbo.{config-type}s.{config-name}.{config-item}={config-item-value}

#3. 應用級設定(單數設定)
dubbo.{config-type}.{config-item}={config-item-value}

屬性覆蓋處理流程:

按照優先順序從高到低依次查詢,如果找到此字首開頭的屬性,則選定使用這個字首提取屬性,忽略後面的設定。

3.3 外部化設定

外部化設定目的之一是實現設定的集中式管理,這部分業界已經有很多成熟的專業設定系統如 Apollo, Nacos 等,Dubbo 所做的主要是保證能配合這些系統正常工作。

外部化設定和其他本地設定在內容和格式上並無區別,可以簡單理解為 dubbo.properties 的外部化儲存,設定中心更適合將一些公共設定如註冊中心、後設資料中心設定等抽取以便做集中管理。

# 將註冊中心地址、後設資料中心地址等設定集中管理,可以做到統一環境、減少開發側感知。
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.registry.simplified=true

dubbo.metadata-report.address=zookeeper://127.0.0.1:2181

dubbo.protocol.name=dubbo
dubbo.protocol.port=20880

dubbo.application.qos.port=33333
  • 優先順序
    外部化設定預設較本地設定有更高的優先順序,因此這裡設定的內容會覆蓋本地設定值,關於各設定形式間的覆蓋關係 有單獨一章說明。

  • 作用域
    外部化設定有全域性和應用兩個級別,全域性設定是所有應用共用的,應用級設定是由每個應用自己維護且只對自身可見的。當前已支援的擴充套件實現有 Zookeeper、Apollo、Nacos。

3.3.1 外部化設定使用方式

  1. 增加 config-center 設定
<dubbo:config-center address="zookeeper://127.0.0.1:2181"/>
  1. 在相應的設定中心(zookeeper、Nacos 等)增加全域性設定項,如下以 Nacos 為例:

開啟外部化設定後,registry、metadata-report、protocol、qos 等全域性範圍的設定理論上都不再需要在應用中設定,應用開發側專注業務服務設定,一些全域性共用的全域性設定轉而由運維人員統一設定在遠端設定中心。

這樣能做到的效果就是,應用只需要關心:

  • 服務暴露、訂閱設定
  • 設定中心地址
    當部署到不同的環境時,其他設定就能自動的被從對應的設定中心讀取到。

舉例來說,每個應用中 Dubbo 相關的設定只有以下內容可能就足夠了,其餘的都託管給相應環境下的設定中心:

dubbo
  application
    name: demo
  config-center
    address: nacos://127.0.0.1:8848

3.3.2 自行載入外部化設定

所謂 Dubbo 對設定中心的支援,本質上就是把 .properties 從遠端拉取到本地,然後和原生的設定做一次融合。理論上只要 Dubbo 框架能拿到需要的設定就可以正常的啟動,它並不關心這些設定是自己載入到的還是應用直接塞給它的,所以Dubbo還提供了以下API,讓使用者將自己組織好的設定塞給 Dubbo 框架(設定載入的過程是使用者要完成的),這樣 Dubbo 框架就不再直接和 Apollo 或 Zookeeper 做讀取設定互動。

// 應用自行載入設定
Map<String, String> dubboConfigurations = new HashMap<>();
dubboConfigurations.put("dubbo.registry.address", "zookeeper://127.0.0.1:2181");
dubboConfigurations.put("dubbo.registry.simplified", "true");

//將組織好的設定塞給Dubbo框架
ConfigCenterConfig configCenter = new ConfigCenterConfig();
configCenter.setExternalConfig(dubboConfigurations);

歡迎在 https://github.com/apache/dubbo 給 Dubbo Star。
搜尋關注官方微信公眾號:Apache Dubbo,瞭解更多業界最新動態,掌握大廠面試必備 Dubbo 技能