Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

Apache Dubbo Administrator & Architecture Guide

Generated June 2026 from apache/dubbo at ee9c190

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

This guide is for the people who operate, integrate, extend, and reason about Apache Dubbo: platform engineers, SREs, architects, and contributors. Where the User Guide shows how to build with Dubbo, this guide explains how Dubbo is built — its layered architecture, the SPI extension model that makes every component swappable, the scope-model domain that governs lifecycle, the deployment topology, the security surface, and the operational levers you pull in production.

It is intentionally exhaustive. The goal is that an engineer (or an AI) could understand, operate, harden, and contribute to a Dubbo-based system from this document alone.


Table of Contents

  1. Executive Summary
  2. Architecture Overview
  3. The SPI Extension Mechanism
  4. The Scope-Model Domain
  5. Repository & Module Map
  6. The Invocation Pipeline
  7. Service Discovery Internals
  8. Requirements & Dependencies
  9. Deployment
  10. Security
  11. Operations
  12. Observability
  13. Performance Tuning
  14. Known Issues & Tech Debt
  15. Contributing
  16. Quick Reference

1. Executive Summary

Apache Dubbo is a Java microservices framework delivered as a large Maven multi-module project (roughly 4,800 files across ~150 modules). It is not an application you run; it is a library set your applications depend on. Its defining architectural property is pervasive extensibility: almost every behavior — protocol, transport, serialization, registry, load balancer, cluster strategy, router, filter, proxy factory — is a named SPI extension resolved at runtime from the classpath. This is what lets one codebase support Triple/HTTP-2, classic TCP, REST, Zookeeper, Nacos, multiple serializers, and a service mesh without conditionals.

Aspect Summary
Language / build Java (source level 1.8, runs on JDK 8–25), Maven multi-module, ${revision} = 3.3.7-SNAPSHOT (this analysis); current stable line 3.3.x
Core idea Interface-based RPC + automatic service discovery + traffic management, all behind swappable SPI extensions
Domain model Three-tier scope hierarchy: FrameworkModel → ApplicationModel → ModuleModel
Config carrier The URL object — every component is parameterized by a URL
Default stack Protocol dubbo (TCP), serialization hessian2, cluster failover, loadbalance random, proxy javassist
Discovery Application-level service discovery (Dubbo 3) with interface-level compatibility
Transport Netty 4 (primary), plus HTTP/1.2/3 and WebSocket remoting modules
Operations A built-in QOS port (telnet + HTTP) for runtime inspection and control

Note

This guide is generated from source at commit ee9c190. Because AST extraction does not parse Java, all reference data here (config fields, extension names, command names, SPI defaults) was read directly from the framework's source and SPI declaration files, not inferred.


2. Architecture Overview

Dubbo is organized as a stack of layers. A call enters at the top (your interface proxy) and descends through cluster, protocol, exchange, transport, and serialization before hitting the wire.

        ┌──────────────────────────────────────────────────────────┐
 config │ ServiceConfig / ReferenceConfig / @DubboService / Bootstrap│  ← you configure here
        ├──────────────────────────────────────────────────────────┤
  proxy │ ProxyFactory (javassist)  — interface ⇄ Invoker            │
        ├──────────────────────────────────────────────────────────┤
registry│ RegistryFactory / ServiceDiscovery / ServiceNameMapping    │  ← discovery + metadata
        ├──────────────────────────────────────────────────────────┤
 cluster│ Cluster (failover…) → Directory → Router → LoadBalance     │  ← fault tolerance + routing
        ├──────────────────────────────────────────────────────────┤
monitor │ Filter chain (validation, auth, metrics, tracing, cache…)  │  ← cross-cutting
        ├──────────────────────────────────────────────────────────┤
protocol│ Protocol (dubbo / tri / rest2 / grpc / injvm)              │  ← Invoker ⇄ Exporter
        ├──────────────────────────────────────────────────────────┤
exchange│ Exchanger / HeaderExchange — request/response semantics    │
        ├──────────────────────────────────────────────────────────┤
transport│ Transporter (Netty4) — Channel, Server, Client            │
        ├──────────────────────────────────────────────────────────┤
 serialize│ Serialization (hessian2 / fastjson2)                     │
        └──────────────────────────────────────────────────────────┘

Three properties tie the layers together:

  1. The URL is the contract. Every layer reads the parameters it cares about from a shared org.apache.dubbo.common.URL. A registry URL like registry://zk:2181/...?registry=zookeeper is rewritten as it descends — RegistryProtocol turns it into a dubbo://provider:20880/... URL for the actual call. This uniform carrier is why the layers compose without bespoke glue.

  2. Every layer is an SPI. The boundary between layers is a Java interface annotated @SPI, and the concrete implementation is selected by a name in the URL. See §3.

  3. Wrappers add cross-cutting behavior. When the SPI loader instantiates, say, a Protocol, it automatically wraps it in ProtocolFilterWrapper, ProtocolListenerWrapper, ProtocolSerializationWrapper, and ProtocolSecurityWrapper. This is how filters, listeners, and security are woven in without the core protocol knowing about them.


3. The SPI Extension Mechanism

This is the single most important thing to understand about Dubbo. Everything else follows from it.

3.1 @SPI, ExtensionLoader, and named extensions

An extension point is a Java interface annotated @SPI, located in org.apache.dubbo.common.extension. Implementations are declared in META-INF/dubbo/internal/<fully.qualified.InterfaceName> files as name=implementationClass lines — Dubbo's enhanced version of the JDK ServiceLoader.

@SPI(value = "dubbo", scope = ExtensionScope.FRAMEWORK)
public interface Protocol { /* ... */ }
# META-INF/dubbo/internal/org.apache.dubbo.rpc.Protocol
dubbo=org.apache.dubbo.rpc.protocol.dubbo.DubboProtocol
tri=org.apache.dubbo.rpc.protocol.tri.TripleProtocol
grpc=org.apache.dubbo.rpc.protocol.tri.GrpcProtocol
rest2=org.apache.dubbo.rpc.protocol.tri.RestProtocol
injvm=org.apache.dubbo.rpc.protocol.injvm.InjvmProtocol
mock=org.apache.dubbo.rpc.support.MockProtocol

Code obtains an extension by name:

Protocol dubbo = applicationModel.getExtensionLoader(Protocol.class).getExtension("dubbo");

The @SPI value ("dubbo") is the default used when the URL doesn't name one.

3.2 Adaptive extensions

Most layers don't know which implementation to use until call time, when the protocol is in the URL. The @Adaptive mechanism generates a dispatcher that reads the relevant URL parameter and delegates to the right concrete extension:

protocolSPI = getExtensionLoader(Protocol.class).getAdaptiveExtension();
// at call time, protocolSPI.refer(type, url) picks DubboProtocol or TripleProtocol
// based on url.getProtocol()

This is why ReferenceConfig holds a single Protocol protocolSPI yet transparently routes dubbo:// to DubboProtocol and tri:// to TripleProtocol.

3.3 Activate (conditional auto-wiring)

@Activate marks extensions (especially filters and routers) that should be auto-included when certain conditions hold (provider vs consumer side, a URL parameter present, etc.). The cluster and filter chains are assembled by collecting all @Activate extensions that match the current URL — which is how the validation filter, access-log filter, metrics filter, and tracing filter all insert themselves without explicit registration.

3.4 Extension scopes

ExtensionScope controls how widely an extension instance is shared:

Scope Shared across Examples
FRAMEWORK The whole JVM Protocol, ProxyFactory, Serialization
APPLICATION One application RegistryFactory
MODULE One module ConfigInitializer, ConfigPostProcessor

Important

When you extend Dubbo, you do not fork it. You implement the SPI interface, drop a META-INF/dubbo/<InterfaceName> file in your jar, and select your extension by name in config. This is the intended extension path for protocols, registries, serializers, filters, routers, and load balancers. The dubbo-compiler and dubbo-native modules support build-time stub generation and GraalVM native-image hints for this model.


4. The Scope-Model Domain

Dubbo 3 replaced global static state with an explicit, three-tier scope-model hierarchy rooted in org.apache.dubbo.rpc.model. This is what allows multiple isolated Dubbo "applications" in one JVM (multi-tenancy, test isolation, library embedding).

FrameworkModel              (one per JVM by default; shared framework services)
  └── ApplicationModel       (one per application; owns config, registries, deployers)
        └── ModuleModel       (one per module; owns a set of services/references)
Model Owns Lifecycle driver
FrameworkModel Framework-scoped extensions, the shared executor repository FrameworkModelCleaner (destroy listener)
ApplicationModel ConfigManager (all config beans), application deployer, service repository, bean factory DefaultApplicationDeployer
ModuleModel The module's exported services and references DefaultModuleDeployer

Each model carries a ScopeBeanFactory (a lightweight DI container) and a Deployer that drives startup/shutdown. ConfigScopeModelInitializer registers the deployers and the DefaultConfigValidator when the models are created.

Note

The deployer is the orchestration heart. DefaultApplicationDeployer.start() initializes config, starts the config center and metadata report, exports the internal metadata service, registers services, and starts the QOS server. When Dubbo is embedded in Spring, modules are marked isLifeCycleManagedExternally() so Spring drives their lifecycle and Dubbo's shutdown hook waits for Spring before tearing down (see DubboShutdownHook).

4.1 Why this matters operationally

  • Graceful shutdown is coordinated at the ApplicationModel level: the shutdown hook flips all services to read-only, drains in-flight calls up to shutwait, and only then destroys the application.
  • Multiple applications in one JVM each get their own ApplicationModel, so their registries, config, and services don't collide — useful for gateways and test harnesses.
  • Config resolution is per-ApplicationModel via its ConfigManager, which is why the precedence rules in the User Guide are evaluated per application.

5. Repository & Module Map

Dubbo's ~150 Maven modules group into functional families. The table lists the families and the headline modules in each; the suffix convention is dubbo-<area>-<impl>.

Family Key modules Responsibility
Core dubbo-common URL, SPI/ExtensionLoader, scope models, config bean classes, utilities, constants
Config dubbo-config-api, dubbo-config-spring, dubbo-config-spring6 ServiceConfig/ReferenceConfig, DubboBootstrap, Spring annotations & XML, autowiring
RPC / protocols dubbo-rpc-api, dubbo-rpc-dubbo, dubbo-rpc-triple, dubbo-rpc-injvm Invoker/Exporter/Protocol, the dubbo and Triple protocols, in-JVM calls
Cluster dubbo-cluster Cluster strategies, directories, routers (condition/tag/script/affinity/mesh), load balancers
Registry dubbo-registry-api, -zookeeper, -nacos, -multicast, -multiple Service registration & discovery, app-level discovery, migration
Remoting dubbo-remoting-api, -netty4, -netty, -http12, -http3, -websocket, -zookeeper-curator5 Transports, channels, the exchange layer
Serialization dubbo-serialization-api, -hessian2, -fastjson2 Wire serializers + the security wrapper
Metadata dubbo-metadata-api, -report-zookeeper, -report-nacos, -definition-protobuf Service metadata, name mapping, metadata centers
Config center dubbo-configcenter-zookeeper, -nacos, -apollo, -file External dynamic configuration sources
Metrics / tracing dubbo-metrics-api, -default, -prometheus, -otlp, dubbo-tracing Observability collection and export
Spring Boot dubbo-spring-boot-autoconfigure, -3-autoconfigure, -actuator, -starters/* Auto-config and the user-facing starters
Plugins dubbo-qos, dubbo-auth, dubbo-security, dubbo-spring-security, dubbo-filter-*, dubbo-rest-*, dubbo-mcp, dubbo-native, dubbo-compiler, dubbo-maven-plugin Operations port, auth, REST/OpenAPI, MCP, native image, codegen
Compatibility dubbo-compatible com.alibaba.dubbo.* shims for migrating from Dubbo 2.x
Distribution dubbo-distribution/*, dubbo-bom, dubbo-dependencies-bom Shaded "all" jar, BOMs
Demo / test dubbo-demo/*, dubbo-test/* Runnable examples and the test harness

Tip

When wiring a production app, depend on the leaf modules you need (one protocol, one registry, one serializer, the starters) rather than the umbrella dubbo artifact, to keep the classpath minimal and the attack surface small.

5.1 The com.alibaba.dubbo.* compatibility layer

dubbo-compatible ships deprecated shims under the old com.alibaba.dubbo package (e.g. com.alibaba.dubbo.config.annotation.Service, com.alibaba.dubbo.remoting.Server). They exist only to ease migration from Dubbo 2.x. Do not use them in new code — they are marked @Deprecated and delegate to the org.apache.dubbo.* equivalents.


6. The Invocation Pipeline

A consumer call traverses this sequence; understanding it is essential for debugging latency, retries, and routing.

  1. Proxy — The javassist ProxyFactory generated a dynamic proxy for your interface. Calling a method produces an RpcInvocation.
  2. Cluster invoker — The proxy's Invoker is a cluster invoker (default FailoverClusterInvoker). It owns fault tolerance.
  3. Directory — Supplies the current candidate Invoker list (a RegistryDirectory for registry-backed references, kept live by registry pushes; a StaticDirectory for direct URLs).
  4. Router chain — Filters the candidate list by condition/tag/script/affinity/mesh rules. Routers are dynamic — rules push from the config center.
  5. LoadBalance — Picks one invoker from the survivors (default RandomLoadBalance).
  6. Filter chain — @Activate filters run in order (validation, auth, access log, metrics, tracing, generic, …). This is where cross-cutting concerns live.
  7. Protocol invoker — The protocol-specific invoker (DubboInvoker, Triple invoker) serializes and sends over the transport.
  8. Exchange + transport — HeaderExchanger adds request/response correlation; Netty4 carries the bytes.

On the provider side the mirror image runs: transport → codec/serialization → exchange → protocol Exporter → provider-side filter chain → your implementation, dispatched on a configurable thread pool.

Note

The ZoneAwareClusterInvoker → FailoverClusterInvoker(RegistryDirectory) nesting you see in logs is the multi-registry case: the zone-aware layer picks a registry, the failover layer picks a provider within it. Single-registry references collapse to one cluster layer.

6.1 Where retries happen — and the danger

failover retries at step 2 (cluster), re-running steps 3–8 on a different invoker. Because retries re-enter the full pipeline, a non-idempotent operation can execute more than once. The framework cannot know which methods are idempotent — operators and developers must set cluster=failfast or retries=0 for writes. This is the most common production correctness pitfall.


7. Service Discovery Internals

7.1 Application-level discovery (the Dubbo 3 model)

In Dubbo 2, every interface registered one node per instance — a 100-instance app exposing 50 interfaces created 5,000 registry entries. Dubbo 3 registers one node per application instance and stores the interface → application mapping separately as metadata. The pieces:

  • ServiceDiscovery — registers/queries application instances (ServiceDiscoveryRegistryFactory, registry name service-discovery-registry).
  • ServiceNameMapping — resolves which application(s) provide a given interface, published at export time.
  • Metadata report (dubbo-metadata-report-*) — stores per-revision service metadata (methods, parameters, config) so consumers can reconstruct the full provider URL from a lightweight instance registration.
  • Migration (dubbo-registry-api .../client/migration) — lets a cluster run interface-level and application-level discovery simultaneously and shift between them without downtime, controlled by a migration rule.

7.2 Empty-protection

enable-empty-protection (on application and registry config) guards against a registry pushing an empty provider list (e.g. during a registry hiccup) and wiping a consumer's working address list. When enabled, an empty push is ignored and the last-known-good list is retained. Keep this on in production.


8. Requirements & Dependencies

8.1 Runtime requirements

Requirement Value
JDK 8 minimum (source level 1.8); supported through 25 on the 3.3.x line
Build Maven 3.x; dubbo-maven-plugin for Protobuf/Triple stub generation
Registry One of Zookeeper, Nacos (production); Multicast for dev only
Optional infra Config center, metadata center (often the same Zookeeper/Nacos), Prometheus, Zipkin/OTLP collector

8.2 Key third-party dependencies (from dubbo-dependencies-bom)

Dependency Version Used by
Netty 4 4.x Primary transport (dubbo-remoting-netty4)
Spring Framework 5.3.39 (and legacy 4.3.30) dubbo-config-spring
Spring Boot 2.7.18 (3.x via -3-autoconfigure) Starters
Curator 5.9.0 Zookeeper client
Zookeeper 3.7.2 Zookeeper registry
Nacos client 2.5.2 Nacos registry
Hessian 4.0.66 Default serialization
Fastjson2 2.0.62 Alternative serialization
gRPC 1.78.0 Triple/gRPC interop
Jackson 2.21.3 JSON/REST
Micrometer / OpenTelemetry / Zipkin (BOM-managed) Metrics & tracing

Caution

Dubbo deliberately gives consumers control over transitive versions: the starters use <exclusions> heavily (e.g. excluding spring-boot-starter-logging in favor of log4j2, and Netty/logback from the Zookeeper client). When you upgrade Dubbo, re-verify your effective dependency tree (mvn dependency:tree) — version skew between Dubbo's expected client libraries (Curator, Nacos client, Netty) and yours is a frequent source of NoSuchMethodError at runtime.


9. Deployment

Dubbo deploys as part of your application — there is no Dubbo server to run. The deployment concerns are about topology, process model, and the supporting infrastructure.

9.1 Topology

        ┌─────────────┐         register/heartbeat        ┌──────────────┐
        │  Provider 1 │ ───────────────────────────────▶ │              │
        │  :20880(tcp)│                                    │   Registry   │
        │  :50051(tri)│ ◀── subscribe (provider list) ──── │  (ZK/Nacos)  │
        └─────────────┘                                    │              │
              ▲  ▲                                          │  + Config    │
   RPC call   │  │ heartbeat                                │  + Metadata  │
              │  └──────────────┐                           └──────────────┘
        ┌─────────────┐         │                                   ▲
        │  Consumer   │ ────────┘ discover + invoke                 │
        │             │ ──────────────────────────────────────────►│ publish metadata
        └─────────────┘
  • Providers open one port per protocol (e.g. 20880 for dubbo, 50051 for tri), register in the registry, and publish metadata.
  • Consumers subscribe, cache the address list locally (dubbo.registry.file), and call providers directly — the registry is not in the data path.
  • The registry/config/metadata roles are often the same Zookeeper or Nacos cluster (use-as-config-center, use-as-metadata-center).

9.2 Containers & Kubernetes

  • Expose each protocol port and the QOS port (22222).
  • Wire the QOS HTTP probes (/live, /ready, /startup) into liveness/readiness/startup probes.
  • For service mesh, set mesh-enable: true and use Triple; Dubbo resolves providers via Kubernetes DNS (<svc>.<ns>.svc.cluster.local) and lets Envoy/Istio route. The default cluster domain is cluster.local and mesh port 80.
  • The dubbo-native module provides GraalVM native-image hints and a sample Dockerfile (GraalVM CE) for AOT-compiled, fast-start, low-footprint deployments.

9.3 Graceful rollout

  1. offline (or offlineApp) via QOS to deregister the instance — consumers stop routing to it within a refresh cycle.
  2. Wait for in-flight calls to drain (shutwait).
  3. Deploy the new version.
  4. online to re-register.

Tip

Combine the QOS offline/online commands with your orchestrator's preStop hook so rolling deploys drain cleanly without dropped requests.


10. Security

Dubbo's security surface spans the wire, the serializer, authentication, and the operations port. Harden all four.

10.1 The QOS operations port — the highest-risk surface

The QOS port (22222) can offline, shutdown, switchLogLevel, and invoke arbitrary methods. Treat it like a management interface:

  • It binds localhost-only by default (qos-accept-foreign-ip: false). Keep it that way.
  • If remote access is unavoidable, set qos-accept-foreign-ip-whitelist to explicit IPs and lower qos-anonymous-access-permission-level / restrict qos-anonymous-allow-commands.
  • Never route the QOS port through an ingress or expose it publicly.

Caution

Exposing the QOS port to an untrusted network is equivalent to handing out a remote shutdown and arbitrary-invoke button for your service. This is the #1 Dubbo misconfiguration to audit.

10.2 Serialization allow-listing

Java deserialization is a classic RCE vector. Dubbo defends with a serialization security wrapper and a class allow-list:

  • serialize-check-status (STRICT / WARN / DISABLE) controls enforcement.
  • auto-trust-serialize-class + trust-serialize-class-level govern which classes may be deserialized.
  • serializeCheckStatus and serializeWarnedClasses QOS commands report what's being blocked or warned.

Warning

Two real serialization hazards from the issue tracker: (1) classes with a writeReplace() method can bypass the Hessian2 Serializable security check (#16287) — audit such classes; (2) Hessian2 may skip field-initialization on deserialization, yielding nulls/defaults (#15805). Prefer fastjson2 for affected payloads and keep serialize-check-status at STRICT in production. Run with the allow-list enabled; do not set it to DISABLE to "fix" a deserialization error — fix the allow-list entry instead.

10.3 Authentication & transport security

  • Token auth (token = "true" on a service) requires consumers to present a registry-distributed token; blocks unauthorized direct callers.
  • dubbo-auth provides request signing/authentication filters; dubbo-spring-security / dubbo-spring6-security integrate Spring Security context propagation across RPC calls.
  • TLS via dubbo.ssl.* (SslConfig) and ssl-enabled per protocol encrypts the wire; dubbo.registry.secure secures the registry connection.

10.4 Disclosure process

Security issues are reported through the Apache process documented in the repository's SECURITY.md. Do not file security bugs as public GitHub issues.


11. Operations

11.1 The QOS command catalog

Connect via telnet localhost 22222 or HTTP (curl http://localhost:22222/<command>). Full command set (read directly from the @Cmd declarations):

Category Commands
Inspection ls, ps, pwd, cd, getConfig, getAddress, count, version, help, greeting
Service rotation online, offline, onlineApp, offlineApp, onlineInterface, offlineInterface
Lifecycle live, ready, startup, shutdown, gracefulShutdown, quit
Invocation invoke, select
Metadata publishMetadata, getOpenAPI
Logging loggerInfo, switchLogger, switchLogLevel
Profiler enableSimpleProfiler, enableDetailProfiler, disableSimpleProfiler, disableDetailProfiler, setProfilerWarnPercent
Router debug enableRouterSnapshot, disableRouterSnapshot, getRouterSnapshot, getEnabledRouterSnapshot, getRecentRouterSnapshot
Serialization serializeCheckStatus, serializeWarnedClasses
Metrics metrics_default

11.2 Runtime diagnosis playbook

Symptom QOS commands to run
"Consumer can't find provider" ls (both sides), getAddress <service>
"Calls routed to the wrong instance" enableRouterSnapshot then getRecentRouterSnapshot
"Some calls are slow" enableDetailProfiler, setProfilerWarnPercent, then inspect logs
"Need more log detail without restart" switchLogLevel DEBUG, revert with switchLogLevel INFO
"Deserialization blocked" serializeCheckStatus, serializeWarnedClasses
"Draining for deploy" offline, wait, deploy, online

11.3 Logging

Dubbo abstracts logging via dubbo.application.logger (slf4j, log4j2, jcl, …). The demos use log4j2 and exclude spring-boot-starter-logging. Error logs carry stable error codes (e.g. CLUSTER_NO_VALID_PROVIDER, CONFIG_FAILED_SHUTDOWN_HOOK) defined in LoggerCodeConstants — grep logs by code for precise diagnosis.


12. Observability

Dubbo ships first-class metrics and tracing, enabled through starters and dubbo.metrics.* / dubbo.tracing.*.

  • Metrics (dubbo-metrics-*): Micrometer-based, exportable to Prometheus (dubbo-metrics-prometheus) or OTLP (dubbo-metrics-otlp). Covers RPC QPS/RT/error rates, thread pools, registry events, and JVM metrics. Add dubbo-observability-spring-boot-starter.
  • Tracing (dubbo-tracing): Micrometer Tracing bridges to Brave/Zipkin or OpenTelemetry (OTLP or Zipkin export). Starters: dubbo-tracing-brave-zipkin-spring-boot-starter, dubbo-tracing-otel-zipkin-spring-boot-starter, dubbo-tracing-otel-otlp-spring-boot-starter. Configure sampling with dubbo.tracing.sampling.probability.
  • Actuator: dubbo-spring-boot-actuator exposes Dubbo health/info endpoints.
dubbo:
  metrics:
    protocol: prometheus
    enable-jvm-metrics: true
  tracing:
    enabled: true
    sampling: { probability: 0.1 }
    tracing-exporter:
      otlp-config: { endpoint: http://otel-collector:4318/v1/traces }

13. Performance Tuning

Lever Where Guidance
Protocol dubbo.protocol.name dubbo (TCP) for max throughput between Java services; tri for HTTP/2/mesh
Thread pool dubbo.protocol.threadpool (fixed/cached/limited/eager) + threads, corethreads, queues Size to provider workload; eager grows before queuing
Thread isolation dubbo.application.executor-management-mode: isolation Give heavy services their own pool so one can't starve others
IO threads dubbo.protocol.iothreads Netty event-loop sizing (default = cores)
Connections connections / dubbo.consumer.shareconnections Share or dedicate TCP connections per reference
Payload cap dubbo.protocol.payload Max message size; raise carefully (memory)
Serialization dubbo.protocol.serialization hessian2 default; fastjson2 can be faster for some shapes
Load balance loadbalance leastactive/shortestresponse smooth out slow nodes; adaptive is load-aware
Concurrency limits actives (consumer), executes (provider) Bound in-flight calls to prevent overload/OOM (see #16294)

Tip

Use the QOS profiler (enableDetailProfiler + setProfilerWarnPercent) in a canary to find slow methods before tuning blindly. Pair leastactive load balancing with actives limits so a degraded provider sheds load instead of accumulating it.


14. Known Issues & Tech Debt

Drawn from the project's own issue tracker at this commit — useful context for operators choosing versions.

Issue Area Operator action
#16295 / #16296 JDK 25 + ServiceLoader/Gson NoClassDefFoundError Use a 3.3.x build with JDK 25 support, or pin JDK 21; ensure Gson present if needed
#16294 Large consumer.timeout → OOM Keep timeouts realistic; bound concurrency with actives/executes
#16178 Provider start fails when ZK (weak dep) is down dubbo.registry.check: false
#15805 Hessian2 skips field init on deserialize Set fields explicitly or use fastjson2
#16287 writeReplace() bypasses Hessian2 Serializable security check Audit such classes; keep allow-list STRICT
#16308 NetUtils.matchIpExpression mis-parses IPv4+port Separate host/port in config; upgrade
#16117 CompositeInputStream.close() may leak streams Tracking; upgrade when fixed
#16214 Spring Boot 4 compatibility not yet available Stay on supported Spring Boot 2.7/3.x lines

Structural debt worth knowing: the com.alibaba.dubbo.* compatibility layer is dead weight for new projects (don't depend on it); the source level is still 1.8, so the codebase cannot use modern Java language features internally even while supporting JDK 25 at runtime; and the SPI metadata files (META-INF/dubbo/internal/*) are the source of truth for extension wiring but are easy to miss when reviewing — a missing line silently disables an extension.


15. Contributing

  • Build: mvn clean install (Maven multi-module). The ${revision} property sets the version across all modules — do not hard-code versions in child POMs.
  • Code style: enforced via the codestyle module and the Maven compiler config; run the formatter before submitting.
  • Adding an extension: implement the @SPI interface, add a META-INF/dubbo/<InterfaceName> mapping line, and a test. Do not add conditionals to core — the SPI is the extension seam.
  • Spring config metadata: config fields live in dubbo-common's org.apache.dubbo.config.* classes; their Javadoc is harvested to generate spring-configuration-metadata.json for IDE auto-completion (a dedicated compatible module copies the classes and substitutes @NestedConfigurationProperty). Follow the Javadoc conventions ("The xxx" for nouns, "Whether to xxx, default value is true" for booleans) so the generated metadata is correct.
  • Conduct & security: see CODE_OF_CONDUCT.md, CONTRIBUTING.md, and SECURITY.md at the repo root.

Note

Because Java AST tooling does not parse this codebase for extraction, the authoritative reference for any contributor question is the source itself — start from the @SPI interface for the layer you're changing and the META-INF/dubbo/internal/<interface> file that wires its implementations.


16. Quick Reference

Default extensions

Layer Default Alternatives
Protocol dubbo tri, grpc, rest2, injvm, mock
Cluster failover failfast, failsafe, failback, forking, broadcast, available, mergeable, zone-aware
LoadBalance random roundrobin, leastactive, shortestresponse, consistenthash, adaptive
Serialization hessian2 fastjson2
Proxy factory javassist jdk
Registry (none) zookeeper, nacos, multicast, multiple, service-discovery-registry

Default ports

Port Purpose
20880 dubbo (TCP) protocol — conventional default
50051 Triple (tri) — conventional example port
22222 QOS operations (telnet + HTTP)

Scope-model hierarchy

FrameworkModel  →  ApplicationModel  →  ModuleModel
(JVM/global)       (per application)     (per module's services/refs)

Configuration precedence (highest first)

-D system properties → external config center → environment variables → application.yml/dubbo.properties → annotation/XML attributes → built-in defaults.

Essential QOS commands

ls · getAddress · online / offline · gracefulShutdown · enableDetailProfiler · getRecentRouterSnapshot · switchLogLevel · serializeCheckStatus