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.
Recently, the highly anticipated Dubbo 2.7.5 version was officially released. This version introduces many new features, enhances many existing functionalities, and achieves significant performance improvements. It will be a milestone version for both the Dubbo community and developers alike.
First, from the perspective of service discovery, the new version breaks through the previous interface-level model and introduces an application-level service discovery mechanism - service introspection. Although this mechanism is still in beta, it lays a solid foundation for Dubbo’s alignment with the entire microservices cloud-native system. Thanks to compact protocol design and optimization in code implementation, Dubbo has always performed well in terms of performance, with a further improvement in version 2.7.5. According to stress tests from the official maintenance team, performance in the call chain has improved by 30%. In the cloud-native microservices era, multilingual demand is becoming increasingly common. The universality and penetration of protocols are crucial for building a complete microservice system that connects front-end and back-end services. Dubbo supports HTTP/2 protocol by implementing gRPC protocol while also adding compatibility with Protobuf.
From the perspective of the Java implementation version, Dubbo is a service development framework focused on interface proxies. Service definitions, service publication, and service references are all based on interfaces, while service governance involving service discovery and various rule definitions is also interface-driven. The interface-based approach is a significant advantage of Dubbo, such as shielding developers from remote call details and offering finer governance granularity. However, the service definitions based on interfaces also present issues, such as service compatibility with industry-standard microservice systems.
To address these issues, version 2.7.5 introduces a new service definition/governance mechanism: service introspection, which is essentially a service governance solution based on application granularity. An instance registers a single record to the registry, thoroughly resolving performance bottlenecks related to service propagation, and since this model is inherently equivalent to mainstream microservice systems like SpringCloud and K8S, it removes barriers for Dubbo to interconnect with such heterogeneous systems. For more information on how Dubbo’s service introspection mechanism resolves interoperability issues in heterogeneous microservice systems, please refer to our previous article titled “How Dubbo Becomes the Best Service Development Framework for Connecting Heterogeneous Microservice Systems.”
Here is a basic working principle diagram of the service introspection mechanism.
For more details about the workings of service introspection, please refer to the official documentation and subsequent articles.
Service introspection is complementary to existing mechanisms. The Dubbo framework will continue to maintain interface-level service governance advantages, realizing a scenario where both interface and application granularities complement each other, balancing performance, flexibility, and universality, striving to make Dubbo the best framework for microservice development.
Dubbo RPC protocol is built on TCP, which has many advantages but also some drawbacks, such as limited universality and protocol penetration, and is not very friendly for multi-language implementations. Given its standard HTTP protocol attributes, HTTP/2 undoubtedly offers better universality. It is expected to receive good support across various network devices now or in the future. The reason gRPC chose HTTP/2 as its transport-layer carrier is largely due to this factor. Currently, gRPC’s recognition and adoption in cloud-native and Mesh frameworks are gradually increasing, indicating a trend toward becoming the RPC protocol transport standard. While Dubbo and gRPC are competitors at the protocol level, they emphasize different aspects in framework implementation. Dubbo undeniably offers a richer service development and governance experience.
The intuitive benefits of Dubbo supporting gRPC protocol include:
Starting from version 2.7.5, gRPC (HTTP/2) becomes a first-class citizen in the Dubbo protocol system. Developers needing to do so can activate gRPC protocol in the microservice systems developed with Dubbo without being confined to Dubbo’s own protocol. We similarly expressed this viewpoint in the article “How Dubbo Becomes the Best Service Development Framework for Connecting Heterogeneous Microservice Systems.”
For details on how to develop gRPC (HTTP/2) services in Dubbo, please refer to the article “Exploring Dubbo in Cross-language and Protocol Penetration.” For information on how to enable TLS and use Reactive RPC programming, please refer to the examples. Additionally, the Go version of Dubbo also provides equivalent support for gRPC protocol; please follow the dubbogo community’s release plans for specifics.
Protobuf support is primarily aimed at addressing Dubbo’s cross-language usability.
Cross-language service development involves multiple aspects, requiring language neutrality in service definitions, RPC protocols, and serialization protocols, while also implementing corresponding SDKs for each language. Although due to community contributions, Dubbo has seen gradual improvements in multi-language SDK implementations, already providing client or full implementation versions for Java, Go, PHP, C#, Python, NodeJs, and C, the previously mentioned cross-language friendliness still has many areas for improvement.
In terms of protocol, version 2.7.5 supports gRPC, while Protobuf provides a good solution for service definition and serialization.
In the future, regardless of which language version is used to develop Dubbo services, we can directly use IDL to define services as shown below; please refer to the example.
syntax = "proto3";
option java_multiple_files = true;
option java_package = "org.apache.dubbo.demo";
option java_outer_classname = "DemoServiceProto";
option objc_class_prefix = "DEMOSRV";
package demoservice;
// The demo service definition.
service DemoService {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
The 2.7.5 version performs comprehensive optimization across the entire call chain. According to stress test results, overall QPS performance has improved by nearly 30%, while also reducing memory allocation overhead during the calling process. One notable design point is that version 2.7.5 introduced the concept of ServiceRepository, generating ServiceDescriptor and MethodDescriptor in advance during the service registration phase to reduce resource consumption caused by computing service metadata during RPC calls.
For Dubbo applications prior to 2.7.5, especially some consumer-side applications, when facing a large volume of service consumption with high concurrency (such as gateway scenarios), excessive thread allocation on the consumer side often occurs. Specific problem discussions can be found in the following issue:
https://github.com/apache/dubbo/issues/2013
The improved consumer-side thread pool model effectively solves this problem by reusing blocked threads on the business side.
Old Thread Pool Model
Let’s focus on the Consumer section:
Thread Pool Model Introduced in Version 2.7.5
This way, compared to the old thread pool model where the business thread was responsible for monitoring and parsing the return result, it eliminates the overhead of an extra consumer-side thread pool.
Regarding performance optimization, continuous efforts will be made in subsequent versions, primarily focusing on the following two areas:
Version 2.7.5 has made significant progress in the security of the transmission link. Both the built-in Dubbo Netty Server and the newly introduced gRPC protocol provide a TLS-based secure link transmission mechanism.
The configuration for TLS has a unified entry point, as shown below:
Provider Side
SslConfig sslConfig = new SslConfig();
sslConfig.setServerKeyCertChainPath("path to cert");
sslConfig.setServerPrivateKeyPath(args[1]);
// If mutual cert authentication is enabled
if (mutualTls) {
sslConfig.setServerTrustCertCollectionPath(args[2]);
}
ProtocolConfig protocolConfig = new ProtocolConfig("dubbo/grpc");
protocolConfig.setSslEnabled(true);
Consumer Side
if (!mutualTls) {
sslConfig.setClientTrustCertCollectionPath(args[0]);
} else {
sslConfig.setClientTrustCertCollectionPath(args[0]);
sslConfig.setClientKeyCertChainPath(args[1]);
sslConfig.setClientPrivateKeyPath(args[2]);
}
To ensure flexibility in application startups, the specification of TLS Cert can also be dynamically specified during startup based on deployment environments via -D parameters or environment variables, please see Dubbo’s configuration reading rules and TLS examples.
Dubbo Configuration Reading Rules: /zh-cn/docs/user/configuration/configuration-load-process.html
TLS Examples: https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-ssl
If you are using the gRPC protocol, the protocol negotiation mechanism will be utilized when enabling TLS. Therefore, you must use a Provider that supports the ALPN mechanism, with netty-tcnative being the recommended choice. For specifics, please refer to the gRPC Java community’s summary: https://github.com/grpc/grpc-java/blob/master/SECURITY.md
Regarding the security of service calls, Dubbo will continue to invest in future versions, with the authentication mechanism for service discovery/calls expected to be introduced in upcoming releases.
In the section discussing “Service Introspection,” we mentioned Dubbo’s interface-oriented design, involving programming, service discovery, and service governance through interfaces. With the introduction of application-level service discovery, version 2.7.5 has also optimized the programming entry point, while being compatible with older version APIs, it has added a new application-oriented programming interface - DubboBootstrap.
For example, programming using the Dubbo API previously required this:
ServiceConfig<GreetingsService> service1 = new ServiceConfig<>();
service1.setApplication(new ApplicationConfig("first-dubbo-provider"));
service1.setRegistry(new RegistryConfig("zookeeper://" + zookeeperHost + ":2181"));
service1.export();
ServiceConfig<GreetingsService> service2 = new ServiceConfig<>();
service2.setApplication(new ApplicationConfig("first-dubbo-provider"));
service2.setRegistry(new RegistryConfig("zookeeper://" + zookeeperHost + ":2181"));
service2.export();
Global configuration such as ApplicationConfig, RegistryConfig, ProtocolConfig would need to be configured for each service; moreover, from the perspective of the Dubbo framework, due to the lack of a unified server entry point, some instance-level configurations like ShutdownHook, ApplicationListener, and application-level service governance components lack a loading driver point.
With the introduction of DubboBootstrap, the new programming model becomes simpler and also addresses the lack of an instance-level startup entry.
ProtocolConfig protocolConfig = new ProtocolConfig("grpc");
protocolConfig.setSslEnabled(true);
SslConfig sslConfig = new SslConfig();
sslConfig.setXxxCert(...);
DubboBootstrap bootstrap = DubboBootstrap.getInstance();
bootstrap.application(new ApplicationConfig("ssl-provider"))
.registry(new RegistryConfig("zookeeper://127.0.0.1:2181"))
.protocol(protocolConfig)
.ssl(sslConfig);
ServiceConfig<GreetingsService> service1 = new ServiceConfig<>();
ServiceConfig<GreetingsService> service2 = new ServiceConfig<>();
bootstrap.service(service1).service(service2);
bootstrap.start();
For scenarios subscribing to multiple registries, a new layer of load balancing between registry clusters has been introduced when selecting addresses:
At the Cluster Invoker level, the supported selection strategies include (2.7.5+ version; see documentation for specifics):
Specify Priority
<!-- Addresses from the preferred="true" registry will be prioritized, falling back to others only when no available addresses are found -->
<dubbo:registry address="zookeeper://${zookeeper.address1}" preferred="true" />
Same Zone Priority
<!-- The selection will match with the zone key in the traffic, preferring to dispatch traffic to addresses in the same zone -->
<dubbo:registry address="zookeeper://${zookeeper.address1}" zone="beijing" />
Weighted Round Robin
<!-- Addresses from Beijing and Shanghai clusters will distribute traffic at a ratio of 10:1 -->
<dubbo:registry id="beijing" address="zookeeper://${zookeeper.address1}" weight=”100“ />
<dubbo:registry id="shanghai" address="zookeeper://${zookeeper.address2}" weight=”10“ />
Default, stick to any available
Regarding the multiple registry subscription model, Dubbo also offers a Multi-Registry merging solution. We welcome discussions on the following PR: https://github.com/apache/dubbo/issues/5399
From the perspective of the Dubbo framework itself, version 2.7.5 also involves many refactoring and optimizations (such as the refactoring of the config module), which may not be perceptible to users but are great preparations for future feature development and the introduction of new mechanisms through optimizing the internal structure of the entire Dubbo code.
In future versions, Dubbo will continue to optimize and iterate rapidly, focusing primarily on the following aspects: