Apache Dubbo is a high-performance, Java-native Web and RPC framework for building enterprise-grade microservices. You define an ordinary Java interface, publish its implementation as a service provider, and call it from a service consumer as if it were a local method — Dubbo handles the networking, serialization, service discovery, load balancing, and fault tolerance for you.
This guide is for the people who build applications with Dubbo: backend and microservice developers writing providers and consumers in Java or Spring Boot. It covers installation, the everyday API and configuration surface, the protocols and registries you will choose between, traffic-management features, day-to-day operations, troubleshooting, and a complete configuration reference.
Note
Dubbo is polyglot. This guide documents the Java SDK (the
apache/dubborepository). Sibling implementations exist for Go, Python, PHP, Rust, Erlang, and Node.js/Web. The concepts carry over, but the code in this guide is Java.
Table of Contents
- What Dubbo Does
- Quick Start (5 minutes)
- Installation
- Core Concepts
- Defining a Service Provider
- Consuming a Service
- Configuration Essentials
- Protocols
- Registries and Service Discovery
- Traffic Management
- Common Tasks (Recipes)
- Operating a Running Application (QOS)
- Troubleshooting
- Frequently Asked Questions
- Configuration Reference
1. What Dubbo Does
A microservice system has two recurring needs: services need to call each other, and callers need to find callees that move around as instances scale up, down, and redeploy. Dubbo solves both, plus the operational concerns that come with them.
| Capability | What you get |
|---|---|
| Remote invocation (RPC) | Call a remote service through a normal Java interface. Multiple wire protocols: Triple (gRPC-compatible, HTTP/2), Dubbo2 (TCP), REST, and pluggable custom protocols. |
| Service discovery | Providers register themselves in a registry (Zookeeper, Nacos, …); consumers subscribe and discover live instances automatically. |
| Traffic management | Cluster fault-tolerance (failover, failfast, …), six load-balancing strategies, routing rules, and method-level configuration. |
| Observability | Built-in metrics (Micrometer/Prometheus) and distributed tracing (OpenTelemetry, Zipkin, Brave). |
| Security | Token authentication, TLS, serialization allow-listing, and a permission-gated operations port. |
| Extensibility | Almost every component is a swappable SPI extension — you can replace protocols, registries, serializers, filters, routers, and load balancers without forking. |
Tip
If you are starting a brand-new service, prefer the Triple protocol. It runs over HTTP/2, is gRPC- and cURL-compatible, works through service meshes, and is the protocol Dubbo invests in going forward. The classic
dubboTCP protocol remains the default for interface-based RPC and is fully supported.
2. Quick Start (5 minutes)
This is the smallest possible Dubbo system: one shared interface, one provider, one consumer, all wired with the programmatic (Bootstrap) API and an in-process registry-free setup is not used — a registry makes the example realistic. We use Zookeeper.
2.1 The shared interface
Put this in a module both sides depend on:
package org.apache.dubbo.demo;
public interface GreetingService {
String sayHello(String name);
}
2.2 The provider
package org.apache.dubbo.demo.provider;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.ServiceConfig;
import org.apache.dubbo.config.bootstrap.DubboBootstrap;
import org.apache.dubbo.demo.GreetingService;
public class Provider {
public static void main(String[] args) {
ServiceConfig<GreetingService> service = new ServiceConfig<>();
service.setInterface(GreetingService.class);
service.setRef((name) -> "Hello, " + name);
DubboBootstrap.getInstance()
.application(new ApplicationConfig("first-dubbo-provider"))
.registry(new RegistryConfig("zookeeper://127.0.0.1:2181"))
.service(service)
.start()
.await();
}
}
2.3 The consumer
package org.apache.dubbo.demo.consumer;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ReferenceConfig;
import org.apache.dubbo.config.RegistryConfig;
import org.apache.dubbo.config.bootstrap.DubboBootstrap;
import org.apache.dubbo.demo.GreetingService;
public class Consumer {
public static void main(String[] args) {
ReferenceConfig<GreetingService> reference = new ReferenceConfig<>();
reference.setInterface(GreetingService.class);
DubboBootstrap.getInstance()
.application(new ApplicationConfig("first-dubbo-consumer"))
.registry(new RegistryConfig("zookeeper://127.0.0.1:2181"))
.reference(reference)
.start();
GreetingService greetingService = reference.get();
System.out.println(greetingService.sayHello("Dubbo"));
}
}
2.4 Run it
# 1. Start a Zookeeper registry (Docker is the fastest path)
docker run -d --name zookeeper -p 2181:2181 zookeeper:3.9
# 2. Start the provider, then the consumer (two JVMs)
java org.apache.dubbo.demo.provider.Provider
java org.apache.dubbo.demo.consumer.Consumer
Expected consumer output:
Hello, Dubbo
Important
The interface (
GreetingService) must be on the classpath of both provider and consumer. Dubbo binds providers and consumers by the service's fully-qualified interface name (plus optionalgroupandversion), not by a generated stub. Keep the interface in a shared artifact.
3. Installation
Dubbo is consumed as a set of Maven artifacts under the org.apache.dubbo group. You do not "install Dubbo" as a standalone program — you add it to your application's build.
3.1 Version and compatibility
| Dubbo line | JDK support | Status |
|---|---|---|
3.3.x |
1.8 – 25 | Current, actively maintained — Triple, REST, Spring Boot starters, native-image, JDK 25 |
3.2.x |
1.8 – 17 | Maintained — metrics & tracing, thread-pool isolation, native image |
3.1.x |
1.8 – 17 | Stable, not actively maintained |
Note
This guide is generated from source at commit
ee9c190(development line3.3.7-SNAPSHOT). For application dependencies, use the latest stable3.3.xrelease (3.3.6at time of writing) rather than a-SNAPSHOT. Snapshot builds are for contributors, not production.
3.2 Plain Maven / Gradle
The cleanest way to pin a consistent set of versions is the Dubbo BOM.
Maven (BOM + dependency)
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-bom</artifactId>
<version>3.3.6</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
</dependency>
<!-- pick a registry -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-zookeeper</artifactId>
</dependency>
</dependencies>
Gradle (Kotlin DSL)
dependencies {
implementation(platform("org.apache.dubbo:dubbo-bom:3.3.6"))
implementation("org.apache.dubbo:dubbo")
implementation("org.apache.dubbo:dubbo-registry-zookeeper")
}
Tip
The umbrella
dubboartifact pulls in the core plus the common protocols and serializers. As you move to production you will usually depend on specific modules instead (dubbo-rpc-triple,dubbo-remoting-netty4,dubbo-serialization-hessian2, a registry, a config center, a metadata report) to keep the dependency tree lean. See the Admin Guide for the full module map.
3.3 Spring Boot
For Spring Boot applications, add a starter and configure everything in application.yml.
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>3.3.6</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-zookeeper-curator5-spring-boot-starter</artifactId>
<version>3.3.6</version>
</dependency>
Note
On JDK 17+, the build automatically uses
dubbo-spring-boot-3-autoconfigure(Spring Boot 3 / Jakarta). On JDK 8–11 it uses the Spring Boot 2 autoconfigure path. You add the samedubbo-spring-boot-startereither way.
3.4 Which add-on modules?
Dubbo's functionality is split across optional modules so you only ship what you use. The most common ones:
| Need | Add this artifact |
|---|---|
| Zookeeper registry / config center | dubbo-registry-zookeeper, dubbo-zookeeper-curator5-spring-boot-starter |
| Nacos registry | dubbo-registry-nacos, dubbo-nacos-spring-boot-starter |
| Triple (gRPC/HTTP-2) protocol | dubbo-rpc-triple |
| Classic Dubbo TCP protocol | dubbo-rpc-dubbo, dubbo-remoting-netty4 |
| Hessian2 serialization (default) | dubbo-serialization-hessian2 |
| Fastjson2 serialization | dubbo-serialization-fastjson2 |
| Metrics + tracing | dubbo-observability-spring-boot-starter, dubbo-tracing-otel-zipkin-spring-boot-starter |
| Operations port (telnet/HTTP) | dubbo-qos |
| Sentinel flow control | dubbo-sentinel-spring-boot-starter |
| Seata distributed transactions | dubbo-seata-spring-boot-starter |
4. Core Concepts
You only need a handful of concepts to be productive. Deeper internals live in the Admin Guide.
Provider : An application that exposes a service implementation. It registers its address in the registry.
Consumer : An application that calls a service. It discovers providers from the registry and invokes them.
Service interface
: A plain Java interface, shared by both sides, that defines the remotable methods. The interface's fully-qualified name (optionally narrowed by group and version) is the service's identity.
Registry : The directory where providers publish their addresses and consumers look them up — Zookeeper, Nacos, and others. Dubbo 3 defaults to application-level service discovery (instances register once per application, not once per interface), which scales to far larger clusters than the older interface-level model.
Protocol
: The wire format and transport for a remote call (dubbo, tri, rest2, injvm, …). A single provider can expose the same service over several protocols at once.
Invoker
: Dubbo's internal abstraction of "a callable target." Your interface proxy ultimately calls an Invoker; cluster, routing, and load balancing all manipulate invokers.
URL
: The universal configuration carrier. Every component is configured by a URL such as dubbo://10.0.0.1:20880/org.apache.dubbo.demo.GreetingService?timeout=3000&version=1.0.0. You rarely write these by hand, but you will see them in logs and the operations port.
Note
A call flows: your proxy → Cluster (fault tolerance) → Router (filter candidates) → LoadBalance (pick one) → Filter chain → Protocol → network → provider. Each stage is a configurable, swappable extension.
5. Defining a Service Provider
There are three ways to publish a service. Pick the one that matches your stack.
5.1 Spring Boot — @DubboService (recommended)
Annotate your implementation with @DubboService. Component-scanning picks it up and Dubbo exports it on startup.
import org.apache.dubbo.config.annotation.DubboService;
import org.apache.dubbo.demo.GreetingService;
@DubboService(version = "1.0.0", group = "demo", timeout = 3000)
public class GreetingServiceImpl implements GreetingService {
@Override
public String sayHello(String name) {
return "Hello, " + name;
}
}
Enable Dubbo and point component-scanning at your packages:
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableDubbo(scanBasePackages = "org.apache.dubbo.demo.provider")
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
# application.yml
dubbo:
application:
name: demo-provider
registry:
address: zookeeper://127.0.0.1:2181
protocol:
name: tri
port: 50051
Tip
@EnableDubbois the umbrella annotation — it combines@DubboComponentScan(find@DubboService/@DubboReferencebeans) and@EnableDubboConfig(bind thedubbo.*properties). Use@DubboComponentScanalone if you only need scanning.
5.2 Programmatic — ServiceConfig + DubboBootstrap
When you are not on Spring, use the Bootstrap API (shown in the Quick Start). Build a ServiceConfig, set the interface and the implementation ref, and register it with DubboBootstrap.
ServiceConfig<GreetingService> service = new ServiceConfig<>();
service.setInterface(GreetingService.class);
service.setRef(new GreetingServiceImpl());
service.setVersion("1.0.0");
service.setGroup("demo");
service.setTimeout(3000);
DubboBootstrap.getInstance()
.application(new ApplicationConfig("demo-provider"))
.registry(new RegistryConfig("zookeeper://127.0.0.1:2181"))
.protocol(new ProtocolConfig("tri", 50051))
.service(service)
.start()
.await();
5.3 XML
For legacy Spring XML applications:
<dubbo:application name="demo-provider"/>
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<dubbo:protocol name="tri" port="50051"/>
<bean id="greetingService" class="org.apache.dubbo.demo.provider.GreetingServiceImpl"/>
<dubbo:service interface="org.apache.dubbo.demo.GreetingService"
ref="greetingService" version="1.0.0" group="demo"/>
5.4 Per-service options worth knowing
Every attribute below is available on @DubboService, ServiceConfig, and <dubbo:service>:
| Attribute | Meaning | Default |
|---|---|---|
version |
Service version; consumers must match | "" |
group |
Logical grouping for the same interface | "" |
timeout |
Per-call timeout in ms | -1 (inherit/1000) |
retries |
Retry count on failover (excludes first try) | -1 (→ 2) |
loadbalance |
Default load balancer for this service | empty (→ random) |
cluster |
Fault-tolerance strategy | empty (→ failover) |
weight |
Static weight for load balancing | -1 |
executes |
Max concurrent executions on the provider | -1 (unlimited) |
token |
Require a token from consumers (auth) | "" |
deprecated |
Mark service deprecated (warns consumers) | false |
register |
Whether to register in the registry | true |
accesslog |
Enable access logging (true or a file path) |
"" |
filter |
Extra filters in the invocation chain | {} |
serialization |
Serialization for this service | inherit |
mcpEnabled |
Expose as an MCP (Model Context Protocol) tool | false |
Tip
Set common values once on
dubbo.provider.*(see §7) and override per-service only when needed. A@DubboService(timeout = 5000)overridesdubbo.provider.timeout.
6. Consuming a Service
6.1 Spring Boot — @DubboReference
Inject a remote service into any Spring bean with @DubboReference:
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;
@Service
public class GreetingClient {
@DubboReference(version = "1.0.0", group = "demo", timeout = 3000, check = false)
private GreetingService greetingService;
public String greet(String name) {
return greetingService.sayHello(name);
}
}
Important
The
versionandgroupon@DubboReferencemust match the provider's@DubboService. A mismatch is the single most common cause ofNo provider available for the service …(see Troubleshooting).
6.2 Programmatic — ReferenceConfig
ReferenceConfig<GreetingService> reference = new ReferenceConfig<>();
reference.setInterface(GreetingService.class);
reference.setVersion("1.0.0");
reference.setGroup("demo");
reference.setCheck(false);
GreetingService service = reference.get(); // returns the proxy
String result = service.sayHello("Dubbo");
Caution
ReferenceConfigis heavyweight: it holds a live invoker and a connection. Cache and reuse the proxy returned byget(). Never create a newReferenceConfigper call — that leaks connections. (The class itself is documented as expensive; for new code the Spring/Bootstrap paths manage its lifecycle for you.)
6.3 Asynchronous calls
Declare your interface method to return CompletableFuture, or use RpcContext to retrieve the future of a synchronous-looking method:
// Interface-declared async
CompletableFuture<String> future = greetingService.sayHelloAsync("Dubbo");
future.whenComplete((reply, ex) -> System.out.println(reply));
// Context-based async on a sync signature
RpcContext.getServiceContext().asyncCall(() -> greetingService.sayHello("Dubbo"))
.whenComplete((reply, ex) -> System.out.println(reply));
6.4 Generic calls (no interface on the classpath)
When the consumer does not have the interface class (gateways, test tools), use a generic reference:
ReferenceConfig<GenericService> reference = new ReferenceConfig<>();
reference.setInterface("org.apache.dubbo.demo.GreetingService");
reference.setGeneric("true");
GenericService generic = reference.get();
Object result = generic.$invoke(
"sayHello",
new String[]{"java.lang.String"},
new Object[]{"Dubbo"});
6.5 The check flag
By default, a consumer checks at startup that at least one provider exists, and fails fast if not. Set check = false to allow the consumer to start before its providers do (common in dev and in systems that boot in arbitrary order).
7. Configuration Essentials
Dubbo configuration is organized into config components, each with a dubbo.<component>.* property prefix. For Spring Boot you set them in application.yml; the same keys exist as XML elements and config-object setters.
dubbo:
application:
name: order-service # required: the application identity
qos-enable: true # operations port on/off
qos-port: 22222
registry:
address: nacos://127.0.0.1:8848
protocol:
name: tri # tri | dubbo | rest2 | grpc
port: 50051
provider:
timeout: 3000 # default timeout for all exported services
retries: 2
loadbalance: roundrobin
consumer:
check: false # don't fail consumer startup if provider absent
timeout: 3000
config-center:
address: nacos://127.0.0.1:8848
metadata-report:
address: nacos://127.0.0.1:8848
7.1 The configuration components
| Prefix | Config object | Purpose |
|---|---|---|
dubbo.application |
ApplicationConfig |
Application name, QOS, metadata, probes, shutdown |
dubbo.registry / dubbo.registries |
RegistryConfig |
Where to register/discover services |
dubbo.protocol / dubbo.protocols |
ProtocolConfig |
Wire protocol(s) and server tuning |
dubbo.provider |
ProviderConfig |
Defaults applied to all exported services |
dubbo.consumer |
ConsumerConfig |
Defaults applied to all references |
dubbo.config-center |
ConfigCenterConfig |
External dynamic configuration source |
dubbo.metadata-report |
MetadataReportConfig |
Where service metadata is published |
dubbo.module |
ModuleConfig |
Module-scoped settings |
dubbo.metrics |
MetricsConfig |
Metrics collection |
dubbo.tracing |
TracingConfig |
Distributed tracing |
dubbo.ssl |
SslConfig |
TLS certificates |
Note
Use the singular prefix (
dubbo.registry) for a single instance, and the plural prefix with an id (dubbo.registries.zk.address: …) when you have more than one registry or protocol. A service can then point at a specific one by id.
7.2 Configuration precedence
When the same setting appears in multiple places, Dubbo resolves it in this order (highest wins):
- JVM
-Dsystem properties (e.g.-Ddubbo.protocol.port=50052) - External config center (Nacos/Zookeeper/Apollo dynamic config)
- Environment variables (
DUBBO_PROTOCOL_PORT) application.yml/dubbo.propertiesin your application- Per-service/reference annotation or XML attributes
- Built-in defaults
Tip
A bare
dubbo.propertiesfile on the classpath is still honored — it's the lowest-friction way to set a handful of values without Spring. The property key isdubbo.<component>.<field>.
A complete field-by-field reference for every config component is in §15.
8. Protocols
A protocol is the wire format plus transport. You choose it with dubbo.protocol.name (or per service). A provider can expose multiple protocols simultaneously by configuring several dubbo.protocols.*.
| Name | Transport | When to use |
|---|---|---|
dubbo |
Single long-lived TCP connection, Hessian2 by default | The classic, highest-throughput interface RPC. Default protocol. |
tri (Triple) |
HTTP/2 | gRPC- and cURL-compatible, mesh-friendly, streaming. Recommended for new services. |
grpc |
HTTP/2 | Native gRPC interop. |
rest2 |
HTTP/1.1 | Expose services as REST endpoints. |
injvm |
In-process | Local calls within the same JVM — no network. Chosen automatically when provider and consumer share a JVM. |
Note
The default protocol is
dubbo, the default serialization ishessian2, the default proxy factory isjavassist, and the default cluster strategy isfailover— all confirmed from the framework's SPI definitions.
8.1 Triple, the gRPC/HTTP-friendly protocol
Triple speaks HTTP/2 and accepts plain HTTP/JSON, so you can call a Dubbo service with curl — no Dubbo client required:
curl -v -d '{"name":"dubbo"}' \
-H 'Content-Type: application/json' \
http://127.0.0.1:50051/org.apache.dubbo.demo.hello.GreeterService/sayHello
Server-streaming works the same way (the method returns a stream):
curl -v -d '{"name":"dubbo"}' \
-H 'Content-Type: application/json' \
http://127.0.0.1:50051/org.apache.dubbo.demo.hello.GreeterService/sayHelloStream
Tip
If you use Protobuf IDL, the
dubbo-maven-plugingenerates the Java stubs. Add the plugin to your build and runmvn dubbo:compileto turn.protofiles into Dubbo Triple stubs.
8.2 Exposing two protocols at once
dubbo:
protocols:
tri:
name: tri
port: 50051
dubbo:
name: dubbo
port: 20880
@DubboService(protocol = {"tri", "dubbo"})
public class GreetingServiceImpl implements GreetingService { /* ... */ }
9. Registries and Service Discovery
The registry is how consumers find providers. Configure it with dubbo.registry.address using a protocol://host:port URL.
| Registry | Address scheme | Module |
|---|---|---|
| Zookeeper | zookeeper://host:2181 |
dubbo-registry-zookeeper |
| Nacos | nacos://host:8848 |
dubbo-registry-nacos |
| Multicast | multicast://224.5.6.7:1234 |
dubbo-registry-multicast (dev/testing only) |
| Multiple | composite of several registries | dubbo-registry-multiple |
dubbo:
registry:
address: zookeeper://127.0.0.1:2181
timeout: 10000 # connect timeout (ms)
check: true # fail startup if registry unreachable
group: dubbo # namespace within the registry
9.1 Application-level vs interface-level discovery
Dubbo 3 introduced application-level service discovery: each application instance registers once, and the mapping from interface to application is stored as metadata. This dramatically reduces the number of registry entries compared to Dubbo 2's interface-level model (one entry per interface per instance), which is what lets Dubbo scale to very large clusters. Dubbo 3 supports both and migrates transparently; you generally do not need to configure it.
Warning
A registry being briefly unreachable should not take your application down. By default consumers cache the last-known provider list and keep working. However, with
dubbo.registry.check: true, startup will fail if the registry is down. In environments where the registry (e.g. Zookeeper) is a weak dependency, setcheck: falseso a registry outage during boot doesn't crash the app — this is a known sharp edge (see issue #16178).
9.2 Multiple registries
dubbo:
registries:
beijing:
address: zookeeper://bj-zk:2181
shanghai:
address: nacos://sh-nacos:8848
A service can register to a subset: @DubboService(registry = {"beijing"}). With multiple subscriptions, consumers use the zone-aware cluster by default to prefer the nearest zone.
10. Traffic Management
10.1 Cluster fault tolerance
The cluster strategy decides what happens when a call fails. Set it with cluster on a service/reference, or dubbo.provider.cluster / dubbo.consumer.cluster.
| Strategy | Behavior | Use for |
|---|---|---|
failover (default) |
Retry on another provider (up to retries) |
Idempotent reads |
failfast |
Fail immediately, no retry | Non-idempotent writes |
failsafe |
Swallow the exception, log it, return null | Best-effort (audit logs) |
failback |
Return immediately, retry failed calls in background | Notifications, eventually-consistent |
forking |
Call several providers in parallel, take the first success | Low-latency reads, costlier |
broadcast |
Call all providers; fail if any fails | Cache/config invalidation |
available |
Call the first available provider | Simple |
mergeable |
Call a group and merge results | Aggregation across groups |
@DubboReference(cluster = "failfast", retries = 0)
private OrderWriteService orderWriteService;
Caution
failoverretries on failure. For non-idempotent operations (create order, charge card) this can cause duplicate side effects. Always usefailfast(orretries = 0) for writes.
10.2 Load balancing
When more than one provider qualifies, the load balancer picks one. Set it with loadbalance.
| Strategy | How it picks |
|---|---|
random (default) |
Weighted random |
roundrobin |
Weighted round-robin |
leastactive |
Provider with the fewest in-flight calls |
shortestresponse |
Provider with the lowest recent response time |
consistenthash |
Same arguments → same provider (sticky) |
adaptive |
Adaptive, load-aware selection |
dubbo:
consumer:
loadbalance: leastactive
10.3 Method-level configuration
You can tune individual methods, not just whole services:
@DubboReference(
methods = {
@Method(name = "sayHello", timeout = 5000, retries = 0),
@Method(name = "sayHelloStream", timeout = 30000)
}
)
private GreetingService greetingService;
10.4 Routing and dynamic rules
Dubbo supports condition, tag, script, affinity, and mesh routers for canary releases, traffic isolation, and gray deployments. These rules are typically pushed through the config center at runtime rather than hard-coded. The router architecture and rule syntax are covered in depth in the Admin Guide.
Tip
Tag routing is the simplest canary mechanism: tag a provider (
dubbo.provider.tag: gray) and have a consumer request that tag at runtime viaRpcContext.getClientAttachment().setAttachment("dubbo.tag", "gray"). Onlygray-tagged providers will serve the call.
11. Common Tasks (Recipes)
11.1 Set a global default timeout and retries
dubbo:
provider:
timeout: 3000
retries: 2
consumer:
timeout: 3000
11.2 Require token authentication on a service
@DubboService(token = "true") // Dubbo generates a random token
public class SecureServiceImpl implements SecureService { }
Consumers that discover the provider through the registry receive the token automatically; direct (peer-to-peer) callers without it are rejected.
11.3 Enable access logging
dubbo:
provider:
accesslog: /var/log/dubbo/access.log # or `true` to log via the framework logger
11.4 Enable metrics and tracing
Add dubbo-observability-spring-boot-starter and a tracing starter, then:
dubbo:
metrics:
protocol: prometheus
enable-jvm-metrics: true
tracing:
enabled: true
sampling:
probability: 0.1
tracing-exporter:
zipkin-config:
endpoint: http://localhost:9411/api/v2/spans
11.5 Graceful shutdown
Dubbo registers a JVM shutdown hook that drains in-flight requests before exiting. Tune the drain window:
dubbo:
application:
shutwait: 10s
Note
When Dubbo runs inside Spring, the framework coordinates shutdown with Spring's lifecycle so it doesn't tear down beans Spring still needs. You can disable Dubbo's own hook entirely with
-Ddubbo.service.shutdown.waitset appropriately or theIGNORE_LISTEN_SHUTDOWN_HOOKproperty when an external supervisor owns shutdown.
11.6 Direct (peer-to-peer) invocation — skip the registry
Handy for local testing against a known provider:
@DubboReference(url = "tri://127.0.0.1:50051")
private GreetingService greetingService;
11.7 Kubernetes / service mesh
Set dubbo.consumer.mesh-enable: true (or meshEnable on a reference). In mesh mode, Triple is required and Dubbo resolves the provider through the Kubernetes service DNS (<service>.<namespace>.svc.<cluster-domain>), letting Envoy/Istio handle routing. The cluster domain defaults to cluster.local and the mesh port to 80.
12. Operating a Running Application (QOS)
Dubbo ships an operations port (the "QOS" port) that exposes runtime commands over telnet and HTTP. Enable it via dubbo.application.qos-enable: true (default port 22222).
dubbo:
application:
qos-enable: true
qos-port: 22222
qos-accept-foreign-ip: false # only localhost by default — keep it that way in prod
Connect with telnet and run help to list commands:
telnet localhost 22222
Or call a command over HTTP:
curl http://localhost:22222/ls
12.1 The command set
| Command | What it does |
|---|---|
ls |
List exported (provider) and subscribed (consumer) services and their status |
ps |
Show ports and their bound services |
online / offline |
Register / deregister all services (graceful in/out of rotation) |
onlineApp / offlineApp |
Online/offline by application name |
onlineInterface / offlineInterface |
Online/offline a single interface |
getConfig |
Dump effective configuration |
getAddress |
Show the resolved address list for a service |
invoke |
Invoke a service method from the console |
select |
Choose among candidate providers for a manual invoke |
count |
Count invocations over an interval |
version |
Print the Dubbo version |
live / ready / startup |
Liveness / readiness / startup probes (Kubernetes-friendly) |
shutdown / gracefulShutdown |
Shut the application down (gracefully drains first) |
publishMetadata |
Re-publish service metadata to the metadata center |
getOpenAPI |
Export the OpenAPI document for REST/Triple services |
loggerInfo / switchLogger / switchLogLevel |
Inspect and change logging at runtime |
enableSimpleProfiler / enableDetailProfiler / disableSimpleProfiler / disableDetailProfiler |
Toggle the invocation profiler |
setProfilerWarnPercent |
Tune the profiler's slow-call warning threshold |
enableRouterSnapshot / disableRouterSnapshot / getRouterSnapshot / getEnabledRouterSnapshot / getRecentRouterSnapshot |
Capture routing decisions for debugging |
serializeCheckStatus / serializeWarnedClasses |
Inspect serialization allow-list status |
quit |
Close the telnet session |
Caution
The QOS port can change your application's runtime behavior (
offline,shutdown,switchLogLevel). Never expose it to untrusted networks. Keepqos-accept-foreign-ip: false(localhost only) in production and restrict it further withqos-anonymous-access-permission-levelandqos-anonymous-allow-commandsif you must open it. See the Admin Guide security section.
12.2 Kubernetes probes
Wire the QOS HTTP probes into your pod spec:
livenessProbe:
httpGet: { path: /live, port: 22222 }
readinessProbe:
httpGet: { path: /ready, port: 22222 }
startupProbe:
httpGet: { path: /startup, port: 22222 }
13. Troubleshooting
Error: No provider available for the service <interface>
Cause: No provider is registered for that exact interface + group + version, or the consumer started before any provider registered, or the registry is unreachable.
Solution:
- Confirm the provider is up and registered (
telnet localhost 22222→lson the provider). - Verify
groupandversionmatch exactly between@DubboServiceand@DubboReference. - Check the registry address is identical on both sides.
- For boot-order issues, set
check = falseon the reference so it resolves lazily.
Prevention: Keep group/version in shared constants; use check: false in environments where boot order is not guaranteed.
Error: Failed to check the status of the service … No provider available … from the url …
Cause: The consumer's startup availability check timed out — same root causes as above, surfaced at ReferenceConfig.get().
Solution: Same as above. To stop startup from blocking on this check, set check = false.
Error: In mesh mode, a triple protocol must be specified
Cause: mesh-enable is on but no Triple protocol is configured.
Solution: Configure dubbo.protocol.name: tri (mesh mode requires HTTP/2 Triple) and ensure providedBy is set.
Error: dubbo.consumer.timeout setting too long leads to OOM
Cause: A very large consumer-side timeout lets requests pile up faster than they complete, exhausting heap (reported in issue #16294).
Solution: Keep timeouts realistic (seconds, not minutes). Combine with actives/executes limits to bound concurrency, and use failfast for writes so failed calls don't accumulate.
Error: NoClassDefFoundError: com/google/gson/JsonSyntaxException on JDK 25
Cause: A known JDK 25 + ServiceLoader interaction where an optional Gson dependency isn't on the classpath (issues #16295, #16296).
Solution: Use a Dubbo 3.3.x build with JDK 25 support and ensure Gson is present if you use components that need it; otherwise pin to JDK 21 for now.
Hessian2 deserialization sets fields to default/null
Cause: Hessian2 may not run field-initialization code during deserialization, assigning defaults instead (issue #15805). This is a serialization-format behavior, not a Dubbo bug.
Solution: Don't rely on field initializers running on the deserialized object; set values explicitly, or switch the affected service to serialization: fastjson2.
Provider start fails when Zookeeper is down
Cause: Zookeeper treated as a hard dependency at startup (issue #16178).
Solution: Set dubbo.registry.check: false so a weakly-dependent registry being down doesn't block startup; the app will register once the registry recovers.
NetUtils.matchIpExpression(...) fails to parse a normal IPv4 address with port
Cause: Edge case in IP-expression matching with a port suffix (issue #16308).
Solution: Specify host and port separately in config rather than embedding a port in an IP-match expression; upgrade to a release where it's fixed.
Tip
Most "it won't connect" problems are a
group/versionmismatch or a registry-address typo. Use the QOSlsandgetAddresscommands on both sides before digging deeper — they show exactly what each side thinks it is exporting and subscribing to.
14. Frequently Asked Questions
Q: Do I need Spring to use Dubbo?
No. The programmatic DubboBootstrap API works without Spring. Spring Boot is the most popular path, but it's optional.
Q: Which protocol should I choose, dubbo or tri?
For brand-new services, tri (Triple) — it's HTTP/2, gRPC- and cURL-compatible, and mesh-friendly. For maximum-throughput interface RPC between Java services, the classic dubbo TCP protocol is excellent and remains the default.
Q: Can one provider expose several protocols?
Yes. Configure multiple dubbo.protocols.* and list them on the service (protocol = {"tri","dubbo"}).
Q: How do consumers find providers?
Through the registry (Zookeeper, Nacos, …). Providers register their address; consumers subscribe and receive live updates. For testing you can bypass the registry with a direct url.
Q: What's the difference between group and version?
version is for evolving the same logical service over time (e.g. 1.0.0 vs 2.0.0); group is for parallel variants of the same interface (e.g. tenant A vs B, or read vs write groups). Both participate in service identity, so consumer and provider must agree.
Q: Is the registry a single point of failure?
No. Consumers cache the provider list and keep calling even if the registry goes down — as long as you don't force check: true at startup. Treat the registry as needed for discovery changes, not for every call.
Q: How do I call a Dubbo service without the Java interface?
Use a generic reference (setGeneric("true") + $invoke), or expose the service over Triple/REST and call it with plain HTTP/JSON.
Q: What serialization does Dubbo use?
hessian2 by default. fastjson2 is also bundled. Serialization is an SPI, so you can add others. Dubbo enforces a serialization allow-list for security (see Admin Guide).
Q: How do I take an instance out of rotation for a deploy?
Use the QOS offline command (or offlineApp) to deregister gracefully, deploy, then online again. Combine with gracefulShutdown to drain in-flight calls.
Q: Does Dubbo work on the latest JDK?
Dubbo 3.3.x supports JDK 8 through 25. Some very new JDK versions have known edge cases (see Troubleshooting); track the version-compatibility table in the README.
Q: Can I call a Dubbo (Java) service from Go/Python/Node? Yes — use the Triple protocol (gRPC-compatible) and the matching Dubbo SDK for that language, or plain gRPC/HTTP clients.
15. Configuration Reference
Every field below is a real property on its config object, exposed as dubbo.<prefix>.<field> (kebab-case in YAML), as an attribute on the corresponding annotation/XML element, and as a setter on the config class.
15.1 dubbo.application (ApplicationConfig)
| Field | Purpose |
|---|---|
name |
Required. Application identity (used for app-level discovery) |
version |
Application version |
owner, organization, architecture, environment |
Descriptive metadata |
logger |
Logging framework adapter (slf4j, log4j2, jcl, …) |
compiler |
Bytecode compiler (javassist, jdk) |
registry-ids |
Which registries this app uses |
qos-enable |
Turn the operations port on/off |
qos-port |
Operations port (default 22222) |
qos-host |
Bind host for the operations port |
qos-accept-foreign-ip |
Allow non-localhost connections to QOS (keep false in prod) |
qos-accept-foreign-ip-whitelist |
Allowed remote IPs for QOS |
qos-anonymous-access-permission-level |
Permission level for unauthenticated QOS access |
qos-anonymous-allow-commands |
Commands permitted anonymously |
qos-check |
Validate QOS config |
metadata-type |
local or remote metadata storage |
metadata-service-protocol, metadata-service-port |
Metadata service exposure |
shutwait |
Graceful-shutdown drain window |
register-mode |
interface, instance, or all (discovery model) |
register-consumer |
Whether consumers register themselves |
enable-empty-protection |
Ignore empty provider pushes (avoid wiping the address list) |
serialize-check-status, auto-trust-serialize-class, trust-serialize-class-level, check-serializable |
Serialization security controls |
executor-management-mode |
Thread-pool management (default, isolation) |
liveness-probe, readiness-probe, startup-probe |
Custom probe implementations |
dump-enable, dump-directory |
Thread/heap dump on overload |
parameters |
Arbitrary extra parameters |
15.2 dubbo.registry (RegistryConfig)
| Field | Purpose |
|---|---|
address |
Required. protocol://host:port registry URL |
protocol |
Registry protocol (zookeeper, nacos, multicast, …) |
username, password |
Registry credentials |
port |
Registry port (if not in address) |
group, version |
Namespace within the registry |
timeout |
Connect timeout (ms) |
session |
Session timeout (ms) |
file |
Local cache file for the provider list |
check |
Fail startup if the registry is unreachable |
register, subscribe |
Whether to register / subscribe |
dynamic |
Auto-deregister on shutdown |
simplified |
Register a reduced URL (less registry data) |
use-as-config-center, use-as-metadata-center |
Reuse this registry for config / metadata |
zone, weight, preferred |
Multi-registry zone routing |
register-mode |
Discovery model override |
enable-empty-protection |
Empty-push protection |
secure |
TLS to the registry |
parameters |
Extra parameters |
15.3 dubbo.protocol (ProtocolConfig)
| Field | Purpose |
|---|---|
name |
Protocol id (dubbo, tri, rest2, grpc, injvm) |
host |
Bind/advertise host |
port |
Listen port |
contextpath |
Context path (HTTP-based protocols) |
serialization |
Serializer (hessian2, fastjson2) |
prefer-serialization |
Preferred serializer negotiation |
threadpool |
Thread-pool type (fixed, cached, limited, eager) |
corethreads, threads, iothreads |
Thread-pool sizing |
alive, queues |
Pool keep-alive and queue depth |
accepts |
Max accepted connections |
payload |
Max request/response size (bytes) |
buffer |
Network buffer size |
heartbeat |
Heartbeat interval (ms) |
accesslog |
Access logging |
transporter, exchanger, dispatcher, networker |
Remoting layer plug points |
server, client |
Server/client transport impls |
codec |
Codec |
telnet, prompt |
Telnet handler and prompt |
status |
Status checkers |
keep-alive |
Keep connections alive |
ssl-enabled |
TLS for this protocol |
register |
Register this protocol's services |
ext-protocol, preferred-protocol |
Extended/preferred protocol negotiation |
json-check-level |
JSON validation strictness |
15.4 dubbo.provider (ProviderConfig)
Provider-side defaults inherited by every exported service. In addition to the service attributes in §5.4: host, port, contextpath, threadpool, threadname, threads, iothreads, alive, queues, accepts, codec, charset, payload, buffer, transporter, exchanger, dispatcher, networker, server, client, telnet, prompt, status, wait, export-thread-num, export-background.
15.5 dubbo.consumer (ConsumerConfig)
Consumer-side defaults inherited by every reference (plus the reference attributes from §5.4): threadpool, corethreads, threads, queues, shareconnections (connections shared across references), url-merge-processor, refer-thread-num, refer-background, mesh-enable.
15.6 Other components
dubbo.config-center(ConfigCenterConfig) — external dynamic configuration (address,protocol,group,namespace,timeout,check,highest-priority).dubbo.metadata-report(MetadataReportConfig) — where service metadata is published (address,username,password,timeout,group).dubbo.metrics(MetricsConfig) — metrics protocol and JVM/aggregation toggles.dubbo.tracing(TracingConfig) —enabled, sampling probability, baggage, and exporter (Zipkin/OTLP) endpoints.dubbo.ssl(SslConfig) — certificate/key/trust-cert paths for TLS.
Note
Spring Boot generates IDE auto-completion metadata for these properties from the Javadoc on the config classes, so your editor will suggest and document them as you type. The authoritative source for any field's exact semantics is always the config class in
dubbo-common.