配置運作方式
以下是 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
格式,包含 -D
、外部化配置
等。.properties
中的所有配置項都遵循 基於路徑
的配置格式。
在 Spring 應用程式中,您也可以將屬性配置放在 application.yml
中,樹狀階層結構更易於閱讀。
# Application-level configuration (no id)
dubbo.{config-type}.{config-item}={config-item-value}
# Instance-level configuration (specify id or name)
dubbo.{config-type}s.{config-id}.{config-item}={config-item-value}
dubbo.{config-type}s.{config-name}.{config-item}={config-item-value}
# Service interface configuration
dubbo.service.{interface-name}.{config-item}={config-item-value}
dubbo.reference.{interface-name}.{config-item}={config-item-value}
# method configuration
dubbo.service.{interface-name}.{method-name}.{config-item}={config-item-value}
dubbo.reference.{interface-name}.{method-name}.{config-item}={config-item-value}
# Method argument configuration
dubbo.reference.{interface-name}.{method-name}.{argument-index}.{config-item}={config-item-value}
1.1 應用程式層級配置(無 id)
應用程式層級配置的格式為:配置類型單數前綴,無 id/name。
# Application-level configuration (no id)
dubbo.{config-type}.{config-item}={config-item-value}
類似 application
、monitor
、metrics
等都屬於應用程式層級的元件,因此只允許配置單一實例;而 protocol
、registry
等允許多個元件配置,當只需要單例配置時,採用本節描述的格式。常見範例如下
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。適用於 protocol
、registry
等支援多個配置的元件。
# Instance-level configuration (specify id or 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 或名稱的實例,框架將使用此處列出的屬性作為對現有實例配置的補充。詳細信息,請參閱 [屬性覆蓋](../principle#32-Attribute Override)。
- 請參閱 [單數和複數配置比較表] (../principle#17-single and plural configuration item comparison table)
配置示例
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
方法配置
方法配置格式
# method configuration
dubbo.service.{interface-name}.{method-name}.{config-item}={config-item-value}
dubbo.reference.{interface-name}.{method-name}.{config-item}={config-item-value}
# Method argument configuration
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 是一個映射對象,支持 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 個設置參數] (https://datatracker.ietf.org/doc/html/rfc7540#section-6.5.2)
配置格式如下
# Notify the peer header of the upper limit of compressed index tables
dubbo.rpc.tri.header-table-size=4096
# Enable server-side push function
dubbo.rpc.tri.enable-push=false
# Notify the peer of the maximum number of concurrent streams allowed
dubbo.rpc.tri.max-concurrent-streams=2147483647
# Declare the window size of the sender
dubbo.rpc.tri.initial-window-size=1048576
# Set the maximum number of bytes for the frame
dubbo.rpc.tri.max-frame-size=32768
# Notify the peer of the maximum number of uncompressed bytes in the 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 標籤名稱和屬性名稱可以組合使用,用“.”分隔。每行一個屬性。
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 配置中有多個標籤,則可以使用“id”來區分。如果未指定 id,則將應用於所有標籤。
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 配置項的單數和複數比較表
複數配置的命名方式與常規單詞的複數形式相同
- 以字母 y 結尾時,去掉 y 並改為 ies
- 以字母 s 結尾時,添加 es
- 其他情況添加 s
| 配置類型 | 單數配置 | 複數配置 | | ———————————— | ————— ———————————————— | —- ———————————- | | 應用程序 | dubbo.application.xxx=xxx | dubbo.applications.{id}.xxx=xxx
dubbo.applications.{name}.xxx=xxx | | 協議 | dubbo.protocol.xxx=xxx | dubbo.protocols.{id}.xxx=xxx
dubbo.protocols.{name}.xxx=xxx | | 模塊 | dubbo.module.xxx=xxx | dubbo.modules.{id}.xxx=xxx
dubbo.modules.{name}.xxx=xxx | | 註冊中心 | dubbo.registry.xxx=xxx | dubbo.registries.{id}.xxx=xxx | | 監控中心 | dubbo.monitor.xxx=xxx | dubbo.monitors.{id}.xxx=xxx | | 配置中心 | dubbo.config-center.xxx=xxx | dubbo.config-centers.{id}.xxx=xxx | | 元數據中心 | dubbo.metadata-report.xxx=xxx | dubbo.metadata-reports.{id}.xxx=xxx | | ssl | dubbo.ssl.xxx=xxx | dubbo.ssls.{id}.xxx=xxx | | 指標 | dubbo.metrics.xxx=xxx | dubbo.metricses.{id}.xxx=xxx | | 提供者 | dubbo.provider.xxx=xxx | dubbo.providers.{id}.xxx=xxx | | 消費者 | dubbo.consumer.xxx=xxx | dubbo.consumers.{id}.xxx=xxx | | 服務 | dubbo.service.{interfaceName}.xxx=xxx | 無 | | 引用 | dubbo.reference.{interfaceName}.xxx=xxx | 無 | | 方法 | dubbo.service.{interfaceName}.{methodName}.xxx=xxx
dubbo.reference.{interfaceName}.{methodName}.xxx=xxx | 無 | | 參數 | dubbo.service.{interfaceName}.{methodName}.{arg-index}.xxx=xxx | 無 |
2 配置來源
Dubbo 默認支持 6 個配置來源
- JVM 系統屬性,JVM -D 參數
- 系統環境變量,JVM 進程的環境變量
- 外部化配置,[外部化配置] (#33-externalized configuration),從配置中心讀取
- 應用程序配置,應用程序屬性配置,從 Spring 應用程序環境中提取以“dubbo”開頭的屬性集
- 通過 API/XML/註解等編程接口收集的配置,可以理解為一種配置來源,是一種直接面向用戶編程的配置收集方式
- 從類路徑中讀取配置文件 dubbo.properties
關於 dubbo.properties 屬性
- 如果 classpath 下有多個 dubbo.properties 文件,例如兩個 jar 包都包含 dubbo.properties,dubbo 會隨機選取一個載入,並印出錯誤日誌。
- Dubbo 能自動載入 classpath 根目錄下的 dubbo.properties,但也可以使用 JVM 參數指定路徑:
-Ddubbo.properties.file=xxx.properties
。
2.1 覆蓋關係
如果同一個配置項透過多個配置來源指定,配置項之間會互相覆蓋,具體的覆蓋關係和優先順序請參考下一節。
3. 配置載入流程
3.1 處理流程
Dubbo 配置載入大致分為兩個階段
- 第一階段是在 DubboBootstrap 初始化之前,Spring 上下文啟動時解析處理 XML 配置/註解配置/Java-config 或執行 API 配置程式碼,建立 config bean 並加入到 ConfigManager 中。
- 第二階段是 DubboBootstrap 初始化流程,會從配置中心讀取外部化配置,依次處理實例級別屬性配置和應用級別屬性配置,最後重新整理所有配置實例的屬性,即[屬性覆蓋](../principle#32-屬性覆蓋)。
3.2 屬性覆蓋
屬性覆蓋發生的場景可能有兩種,兩種可能同時發生
- 不同的配置來源配置了相同的配置項
- 相同的配置來源,但不同層級指定了相同的配置項
3.2.1 不同的配置來源
3.2.1 相同的配置來源
屬性覆蓋指的是使用配置的屬性值覆蓋 config bean 實例的屬性,類似於 Spring 的 [PropertyOverrideConfigurer](https://spring-docs.dev.org.tw/spring-framework/docs/current/javadoc-api/org/springframework/beans/ factory/config/PropertyOverrideConfigurer.html)。
屬性資源配置器,用於覆蓋應用程式上下文定義中 bean 的屬性值。它將屬性文件中的值推送到 bean 定義中。配置行的預期格式如下
beanName.property=value
但與 PropertyOverrideConfigurer
不同的是,Dubbo 的屬性覆蓋有多種匹配格式,優先順序由高到低為
#1. Instance-level configuration of the specified id
dubbo.{config-type}s.{config-id}.{config-item}={config-item-value}
#2. Specify the instance-level configuration of the name
dubbo.{config-type}s.{config-name}.{config-item}={config-item-value}
#3. Application-level configuration (singular configuration)
dubbo.{config-type}.{config-item}={config-item-value}
屬性覆蓋處理流程
按照優先順序由高到低搜尋,如果找到以此前綴開頭的屬性,則使用此前綴提取屬性,並忽略後續的配置。
3.3 外部化配置
外部化配置的目的之一是為了實現配置的集中管理,業界在這一塊已經有很多成熟的專業配置系統,例如 Apollo、Nacos 等,Dubbo 做的主要是保證能夠與這些系統協同工作。
外部化配置與其他本地配置在內容和格式上沒有任何區別,可以簡單理解為 dubbo.properties
的外部化儲存,配置中心更適合提取一些公共配置例如註冊中心、元數據中心配置等用於集中管理。
# Centralized management of registration center address, metadata center address and other configurations can achieve a unified environment and reduce development-side perception.
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
優先順序 預設情況下,外部化配置的優先順序高於本地配置,因此這裡配置的內容會覆蓋本地配置的值。關於各種配置形式之間的[覆蓋關係](#21-覆蓋關係)有單獨的章節說明。
作用域 外部化配置分為全域和應用兩個層級,全域配置所有應用共享,應用級別配置由每個應用自行維護,僅對自身可見。目前支援的擴展實現包括 Zookeeper、Apollo、Nacos。
3.3.1 如何使用外部化配置
- 新增 config-center 配置
<dubbo:config-center address="zookeeper://127.0.0.1:2181"/>
- 在對應的配置中心(zookeeper、Nacos 等)新增全域配置項,以 Nacos 為例如下
啟用外部配置後,理論上應用程式內不再需要配置註冊中心、元數據中心、協議、服務質量(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 互動讀取配置。
// The application loads its own configuration
Map<String, String> dubboConfigurations = new HashMap<>();
dubboConfigurations.put("dubbo.registry.address", "zookeeper://127.0.0.1:2181");
dubboConfigurations.put("dubbo.registry.simplified", "true");
//Throw the organized configuration into the Dubbo framework
ConfigCenterConfig configCenter = new ConfigCenterConfig();
configCenter.setExternalConfig(dubboConfigurations);