This article is more than one year old. Older articles may contain outdated content. Check that the information in the page has not become incorrect since its publication.
We start with the classic working principle diagram of Dubbo; from its design inception, Dubbo has built-in capabilities for service address discovery. Providers register their addresses with the registration center, and consumers subscribe to receive real-time updates about address changes from the registration center. Upon receiving the address list, consumers initiate RPC calls to providers based on specific load balancing strategies.
In this process:
Here, we perform a detailed analysis of the internal data structure of interface-level address discovery.
First, let’s look at the internal data and behaviors of the provider instances in the lower right corner. Applications deployed by providers typically have multiple services, corresponding to services in Dubbo2, each potentially having unique configurations. The service deployment process we discuss here is actually the process of generating address URLs based on service configurations, as shown in the generated address data; similarly, other services will also generate addresses.
Then, consider the address data storage structure of the registration center. The registration center uses service names as the basis for data segmentation, aggregating all address data for a service as child nodes, where the content of child nodes is the actual accessible IP addresses, which corresponds to our Dubbo URLs, formatted as generated by the provider instances.
Here the URL address data is divided into several parts:
Combining the analysis of Dubbo2’s interface-level address model from the previous two pages, along with the basic principle diagram of Dubbo at the outset, we can draw a few conclusions:
This is the true reason why Dubbo2 has always excelled over many service frameworks in usability, service governance functionality, and scalability.
Every entity has two sides, and while the Dubbo2 address model brings ease of use and powerful features, it also imposes some limitations on the horizontal scalability of the entire architecture. This issue is typically imperceptible in average-scale microservice clusters. However, as the cluster scales, when the number of applications and machines within the entire cluster reaches a certain level, the components across the cluster begin to encounter scale bottlenecks. After summarizing the production environment characteristics of several typical users, including Alibaba and ICBC, we identified the following two prominent issues (as indicated in red in the image):
Why does this problem occur? We can illustrate why applications encounter capacity issues easily in the interface-level address model using a specific provider example. In the cyan section, suppose we have a typical Dubbo provider application with 10 RPC services deployed across 100 machine instances. The amount of data generated by this application in the cluster will be “Number of Services * Number of Machine Instances,” or 10 * 100 = 1000 entries. The data expands from two dimensions:
In the face of this problem, under the Dubbo3 architecture, we must rethink two questions:
The design of Dubbo3’s application-level service discovery solution essentially revolves around the two issues mentioned above. The basic idea is that the aggregation elements on the address discovery link, previously referenced as keys, are adjusted from service to application, which is the origin of its name, application-level service discovery. In addition, the content of data synchronized by the registration center has been streamlined significantly, retaining only the core IP and port address data.
This is a detailed analysis of the internal data structure for upgraded application-level address discovery. Compared to the previous interface-level address discovery model, we primarily focus on the changes in the orange section. First, on the provider instance side, instead of each RPC Service registering a separate address data entry, a provider instance will only register one address with the registration center. On the registration center side, addresses are aggregated at the application name level, and under each application name node is the streamlined provider instance address;
The aforementioned adjustments in application-level service discovery simultaneously achieve a reduction in the size and total quantity of address data. However, this also brings new challenges: we lose the foundation of usability and functionality emphasized in Dubbo2 because the transmission of metadata has been streamlined, making it difficult to precisely control the behavior of individual services.
To address this, Dubbo3’s solution is to introduce a built-in MetadataService. Instead of centralized pushing, it transitions to a point-to-point pull model from Consumer to Provider. In this model, the volume of metadata transmission data will no longer be an issue, allowing for the expansion of more parameters and governance data.
Here we focus on the address subscription behavior of the consumer. The consumer reads address data in two steps: first, receiving the streamlined addresses from the registration center, and then calling the MetadataService to read the metadata information from the opposite end. Upon receiving these two data parts, the consumer aggregates the address data and ultimately restores the URL address format similar to Dubbo2 during runtime. Thus, the application-level address model balances performance in address transmission with functionality in operation.
That concludes the background and working principle of application-level service discovery. Next, we will see how Ele.me upgraded to Dubbo3, especially the application-level service discovery process.