As shown in the figure above, from the perspective of service invocation, Dubbo provides a wealth of extension points in the call chain, covering load balancing methods, interceptors before and after service location, server processing interceptors, and more. In simple terms, when Dubbo initiates a remote call, the main workflow can be divided into two parts: the consumer side and the server side.
The workflow of the consumer side is as follows:
Invocation
object.Invocation
object to the ClusterFilter
(extension point) for pre-processing the request before the location, such as request parameter conversion, request logging, rate limiting, etc., are performed at this stage.Invocation
object to the Cluster
(extension point) to make decisions on cluster call logic, such as fast failure mode, safe failure mode, etc., are made at this stage.Cluster
calls the Directory
to obtain all available server address information.Directory
calls the StateRouter
(extension point, recommended to use) and Router
(extension point) to filter router information from the addresses of service providers, mainly to select the targets allowed for this call from the full address information, such as traffic routing based on tags, done at this stage.Directory
, the Cluster
calls LoadBalance
(extension point) to select a target for this call from multiple addresses, such as random calls, polling calls, consistent hashing, etc., are made at this stage.Invoker
, the Cluster
passes the Invocation
to the corresponding Invoker
, and waits for the return result; if an error occurs, it executes corresponding decisions (like fast failure, safe failure, etc.).Invoker
with the target address information is obtained, and it will call the Filter
(extension point) for request processing after location (since the number of Filter
instances created on the consumer side is consistent with the number of server addresses, it is recommended to use ClusterFilter
for extension interception if there is no special need to improve performance).Invocation
will be sent to the server over the network.The server side workflow is as follows:
Invocation
.Invocation
object to the Filter
(extension point) for pre-processing of the server request, such as server authentication, logging, rate limiting, etc., are all done at this stage.Invocation
object to the dynamic proxy for the actual server call.Interceptors can implement the interception during the call process of service providers and consumers. Most of the functionalities in Dubbo are based on this extension point, and every remote method execution will trigger this interception, so pay attention to performance impacts.
Among them, on the consumer side, ClusterFilter
is for interception before location, and Filter
is for interception after location. It is recommended to use ClusterFilter
for extension interception to improve performance unless special needs exist.
In Dubbo 3, the interface signatures of Filter
and ClusterFilter
have been unified and abstracted into BaseFilter
, allowing developers to implement their interceptors by implementing the interfaces of Filter
or ClusterFilter
.
If you need to intercept the return state, you can directly implement the BaseFilter.Listener
interface, and Dubbo will automatically recognize and invoke it.
package org.apache.dubbo.rpc;
public interface BaseFilter {
Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException;
interface Listener {
void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation);
void onError(Throwable t, Invoker<?> invoker, Invocation invocation);
}
}
package org.apache.dubbo.rpc;
@SPI(scope = ExtensionScope.MODULE)
public interface Filter extends BaseFilter {
}
package org.apache.dubbo.rpc.cluster.filter;
@SPI(scope = ExtensionScope.MODULE)
public interface ClusterFilter extends BaseFilter {
}
Specifically, if you need the Filter
or ClusterFilter
to take effect on the consumer side, you need to add the @Activate
annotation and specify the value of group
as consumer
.
@Activate(group = CommonConstants.CONSUMER)
If you need the Filter
or ClusterFilter
to take effect on the provider side, you need to add the @Activate
annotation and specify the value of group
as provider
.
@Activate(group = CommonConstants.PROVIDER)
Routing provides the ability to select a batch of suitable target providers for invocation from multiple service providers.
Dubbo routing mainly needs to implement 3 interfaces, which are responsible for the route
method for filtering each invocation, the notify
method for caching after address push, and the stop
method to destroy the routing.
In Dubbo 3, it is recommended to implement the StateRouter
interface, which can provide high-performance routing.
package org.apache.dubbo.rpc.cluster.router.state;
public interface StateRouter<T> {
BitList<Invoker<T>> route(BitList<Invoker<T>> invokers, URL url, Invocation invocation,
boolean needToPrintMessage, Holder<RouterSnapshotNode<T>> nodeHolder) throws RpcException;
void notify(BitList<Invoker<T>> invokers);
void stop();
}
package org.apache.dubbo.rpc.cluster;
public interface Router extends Comparable<Router> {
@Deprecated
List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;
<T> RouterResult<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation,
boolean needToPrintMessage) throws RpcException;
<T> void notify(List<Invoker<T>> invokers);
void stop();
}
Cluster rules provide the ability to aggregate results, fault tolerance, etc., when there are multiple service providers.
package org.apache.dubbo.rpc.cluster.support;
public abstract class AbstractClusterInvoker<T> implements ClusterInvoker<T> {
protected abstract Result doInvoke(Invocation invocation, List<Invoker<T>> invokers,
LoadBalance loadbalance) throws RpcException;
}
Load balancing provides the ability to select one target provider for invocation from multiple service providers.
package org.apache.dubbo.rpc.cluster;
public interface LoadBalance {
<T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;
}