By Zou Yixian (GitHub ID: @zouyx), an open-source enthusiast. He works in the SheIn supply chain department and is responsible for the supply chain open platform.
In the Apache/dubbo-go (hereinafter referred to as Dubbo-go) community, some members wanted configuration files to be placed not only locally, but also in the configuration management center. It’s critical to answer: what is the difference between being placed locally and in the configuration management center?
If the configuration files are placed locally, you have to restart the system after each update, making it difficult to manage configuration files and preventing real-time updates from taking effect right away. Local files also rely on manual versioning, which greatly increases the costs and difficulty of O&M in microservice scenarios.
The configuration management center provides centralized configuration file management, real-time synchronization of file updates, centralized version control, and permission management.
Based on the preceding background, let’s summarize the following purposes:
- Compatibility with the configuration files in Dubbo’s existing configuration center, and reduction of the learning cost of new language stacks.
- Support for multiple configuration file formats.
- Support for mainstream configuration centers and adaptation in different scenarios to achieve highly scalable configuration delivery.
In Dubbo-go, the configuration center is responsible for the following scenarios:
- As an externalized configuration center that stores the dubbo.properties configuration file, the key is usually the file name, such as dubbo.properties, and the value is the content of the configuration file.
- Stores individual configuration items, such as toggle items and constant values.
- Stores service governance rules. Keys are organized in the format of “service name + rule type”, whereas values indicate specific governance rules.
For now, Dubbo-go primarily supports all open-source configuration centers supported by Dubbo, including:
- Apollo: It is a distributed configuration center developed by the framework department of Ctrip. It centrally manages the configuration of different environments and clusters of applications. After making a configuration change, it pushes the change to the application end in real-time. Features such as standard permissions and process management make it suitable for scenarios such as microservice configuration management.
- ZooKeeper: It is a distributed and open-source coordination service for distributed applications. It is the open-source implementation of Google’s Chubby and an important component of Hadoop and HBase. ZooKeeper provides consistency service for distributed applications, including configuration maintenance, domain service, distributed synchronization, and group services.
- Nacos: It is an open-source configuration management component of Alibaba. It provides a set of easy-to-use features to help in implementing dynamic service discovery, service configuration management, and service and traffic management.
However, considering that some companies have their own R&D configuration centers, or there are configuration centers that are currently popular but not supported by Dubbo, such as etcd, we focus on designing a mechanism that allows us, including users, to quickly access different configuration centers by extending the interfaces with new implementations.
Then, how do we implement this in Dubbo-go? The answer is to use the dynamic plug-in mechanism, which loads different implementations of configuration center on-demand at startup.
These functions are implemented in an independent sub-project. Check out this page for more information.
Design of Dubbo-go
The original design logic ensures Dubbo-go reads the local configuration file after startup, loads it into the memory, reads the information of the registry through the configuration file to obtain the information about the service provider, and registers the service consumer.
In this logic, some of you may be confused about why we need to read the local configuration file now if we have agreed to use the configuration center. The reason is that the information that Dubbo-go reads is divided into two parts:
1) The object that functions as the configuration center.
2) The metadata in the configuration center.
For example, if ZooKeeper is used as the configuration center, the link information of ZooKeeper is metadata. After all, we must obtain the link information before we can connect to ZooKeeper.
During the renovation, the following issues need to be considered:
1) How can we support multiple configuration centers? How can we load data on demand?
By abstracting the
DynamicConfiguration class, developers can quickly support multiple configuration centers. After you import a specified component package, Dubbo-go loads the required components into the memory during startup so that they can be called on demand by applications, as shown by the cells in the green background in the following figure.
2) When is the configuration loading phase of the configuration center?
This happens after Dubbo-go reads configuration files. Specifically, Dubbo-go reads and analyzes the information of configuration centers from local configuration files. Then, it initializes configuration center links, reads /dubbo/config/dubbo/dubbo.properties and /dubbo/config/dubbo /
<Application name>/dubbo.properties, and loads them to the memory to overwrite the original configurations. Next, it monitors configuration changes, and updates the changes to the memory in real-time, as shown by the cells in the blue background in the following figure.
After loading the corresponding modules of a configuration center, add each configuration center module to register its initialization classes in the initialization phase.
The key of the whole dynamic configuration center is the DynamicConfigurationFactory class, which is used to create a link for a configuration center by parsing the internal custom URL of the configuration center, obtaining its protocol type, and extracting its parameters.
For example: Make the following configuration in the configuration file:
Dubbo-go parses it internally to the following format:
Then, Dubbo-go uses it internally to initialize the configuration center link.
Note: The internal protocol in this example is available everywhere in Dubbo-go. A thorough understanding of the internal protocol is helpful for interpreting Dubbo-go code.
This interface specifies the functions to be implemented in each configuration center, as described below.
- Data Deserialization: Currently, only the Properties converter is available. For more information, see DefaultConfigurationParser.
- Add Listeners: This feature adds logic to monitor data changes depending on the implementation of the configuration center client.
- Delete Listeners: This feature deletes the existing listeners. Due to the limitation of the configuration center client, Nacos Client does not provide this function yet.
- Obtain Route Configurations: This feature obtains route table configurations.
- Obtain Application-level Settings: This feature obtains application-level settings, such as the protocol type.
This phase prioritizes the compatibility with the existing Dubbo design to reduce learning costs for users. Dubbo-admin implements application-level configuration management as the service provider, whereas Dubbo-go implements configuration delivery management as the consumer. The following section uses ZooKeeper as an example to analyze the overall processes of service providers and consumers.
Manage Storage Configurations
Dubbo-admin adds a global configuration in configuration management, and corresponding configuration nodes are automatically generated in ZooKeeper. The contents of the nodes are the configurations set in Dubbo-admin.
- /dubbo/config/dubbo/dubbo.properties corresponds to the global configuration file.
<Application name>/dubbo.properties corresponds to the application configuration file.
The preceding figure shows the storage structures of the Dubbo.properties files respectively in ZooKeeper and Apollo:
- The namespaces of the two applications are both Dubbo.
- The global-level group is Dubbo and is shared among all applications. The application-level group name is the demo-provider of an application’s name, which is valid only for the application.
- key: dubbo.properties
- app_id is specified as needed and defaults to Dubbo. This value is preferably consistent with the namespace of ZooKeeper.
- Cluster is specified as needed and is preferably consistent with the ZooKeeper group.
- Namespace is dubbo.properties.
The biggest difference between ZooKeeper and Apollo is the node where Dubbo.properties are located.
Implement Support for Configuration Centers
The following uses Apollo as an example to describe how to support a new configuration center.
Choose a Client and SDK for the Configuration Center
This example uses the Apollo Go Client obtained from https://github.com/zouyx/agollo
Note: If you cannot find the client, you can implement it yourself.
The storage structure of each configuration center has its own characteristics. Therefore, when Dubbo uses an external configuration center, it adopts a different structure of storage configuration nodes. In dubbo-configcenter, find the configuration center that you want to support. In this example, Apollo is located in ApolloDynamicConfiguration.java.
As the annotations show, Apollo namespace = governance (governance.properties) is used for governance rules, and namespace = dubbo (dubbo.properties) is used for configuration files.
Create a new client creation method. We recommend creating a single client at a time.
The following methods are required and used to obtain the configuration of a configuration center. In these methods, the namespace of the configuration file is Apollo.
- GetInternalProperty: It exists in the configuration file and is used to obtain the value based on the key.
- GetRule: It obtains the governance configuration file.
- GetProperties: It obtains the entire configuration file.
Choose the implementation method. If this method is not implemented, the configuration in Dubbo-go cannot be dynamically updated.
Use the default implementations of Parser and SetParser, which are Properties converters by default.
For more information, see dubbo-go-apollo.
From the preceding design, let’s depict its application.
To use a configuration center, you only need to import the related dependencies. The configuration center is implemented after package initialization. For example, you may load ZooKeeper or Apollo as the configuration center as shown below.
To implement the configuration center, loading is only part of the process. For example, after loading ZooKeeper, you also need to connect to the configuration center, that is, the metadata of the configuration center mentioned earlier, which is configured locally. For example:
If Apollo is used as the configuration center, create namespace: dubbo.properties in advance for configuration management.
This document will not elaborate on the more specific implementation process. If you are interested, we recommend that you check the source code. Your continued interest in and contributions to the code are welcome.
Though the configuration center is compact, its functions are complete. Although the preceding methodology is imperfect, it is developing on the right track from the overall architecture perspective. In terms of scalability, its performance is good. Currently, it supports a limited number of configuration centers, which are actually ZooKeeper and Apollo, and only supports configuration files with the properties extension. While this already meets the requirements of basic application scenarios, it still has some way to go until it is optimized.
Future enhancements include:
1) Nacos (pending release)
2) etcd (under development)
3) Consul (not supported at present)
4) Additional configuration file formats, such as YML and XML