前言
Apache Dubbo 3.3 对 Triple 协议做了升级,现在 Dubbo 不仅可以处理东西向流量,也可以处理南北向流量。
**东西向流量(East-West Traffic) **
指数据中心或网络内部同级设备/服务之间的通信。例如,微服务之间的内部调用。
南北向流量(North-South Traffic)
指网络外部用户与内部服务之间的通信。例如,客户端访问微服务。
之前的 Dubbo 一般只用来处理服务内部的高性能RPC调用,外部用户要想访问 Dubbo 服务,只能再额外部署一个网关层,网关负责把 HTTP 协议转换成 dubbo 协议。这样一来,不仅网络多了一跳增加时延,维护难度也大大增加。
另外,由于需要在 Web 框架和 RPC 框架之间频繁切换,开发复杂度和性能均有影响,比如:
- 针对 Web 框架和 RPC 框架的诸如:日志、监控、拦截器、异常处理等,都需要重复开发
- Web 框架和 RPC 框架都有自己处理任务的线程池,系统需要在二者之间频繁切换,影响性能
Apache Dubbo 3.3 Triple X 协议的诞生,直接回应了这些痛点。支持东西向流量,只是 Triple X 其中一个特性,完整功能参考:Apache Dubbo 3.3 全新发布:Triple X 领衔,开启微服务通信新时代
安装&使用
最新的版本目前是3.3.5
,如果只用 dubbo,引入下面一个依赖即可。
xml
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>3.3.5</version>
</dependency>
RestService 服务开发,因为要处理南北向流量,需要通过@Mapping
等注解声明请求路径和参数等信息。
java
@Mapping(path = "/")
public interface RestService {
@Mapping(path = "/hello", method = HttpMethods.GET)
String hello(@Param("name") String name);
}
public class RestServiceImpl implements RestService {
@Override
public String hello(String name) {
return "hello " + name;
}
}
接着,启动服务即可。如下代码,服务暴露的端口是 50000,协议名是简写的tri
。
java
public class Provider {
public static void main(String[] args) {
ServiceConfig<RestService> serviceConfig = new ServiceConfig<>();
serviceConfig.setInterface(RestService.class);
serviceConfig.setRef(new RestServiceImpl());
ApplicationConfig applicationConfig = new ApplicationConfig("provider");
applicationConfig.setQosEnable(false);
DubboBootstrap.getInstance()
.application(applicationConfig)
.protocol(new ProtocolConfig("tri", 50000))
.service(serviceConfig)
.registry(new RegistryConfig("N/A"))
.start().await();
}
}
triple 默认支持 HTTP1和HTTP2,如果要使用HTTP3需要引入额外依赖。现在,通过IP+端口就可以直接以 http 协议访问服务了。
bash
$ curl 127.0.0.1:50000/hello\?name=triple
"hello triple"
整合Spring Boot
单独用 Dubbo 开发比较少,一般都是整合 Spring Boot 一起用。要整合 Spring Boot,引入下面依赖:
xml
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>3.3.5</version>
</dependency>
application.yml
配置 Dubbo 协议部分
yaml
dubbo:
protocol:
name: tri
port: 50000
Dubbo 默认支持 Spring Web 注解,所以用 Dubbo 写 Web API 和之前几乎没区别,如下所示:
没有@RestController
,但是必须加@DubboService
java
@DubboService
@RequestMapping
public class MyRestController {
@GetMapping("/hello")
public String hello(@RequestParam("name") String name) {
return "hello " + name;
}
}
启动类上加@EnableDubbo
启用 Dubbo,访问 50000 端口即可访问服务。
bash
$ curl 127.0.0.1:50000/hello?name=triple
"hello triple"
分端口混合模式
如果旧项目已经用 Spring MVC 开发了一些 API,但是新的 API 想用 Dubbo 开发,可以用区分端口的混合模式部署。区分端口,也就是 Web 容器占用一个端口,Dubbo 占用一个端口,彼此之间互不干扰。
项目同时依赖spring-boot-starter-web
和 Dubbo
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>3.3.5</version>
</dependency>
application.yml
分别配置 Web 容器端口和 Dubbo 协议端口
yaml
server:
port: 8080
dubbo:
protocol:
name: tri
port: 50000
这样一来,之前的 API 通过 8080 端口访问,Dubbo API 通过 50000 端口访问,互不影响。
一种更方便的写法,在 Controller 上同时加@Controller
和@DubboService
注解,8080 和 50000 端口都可以访问这个 API。但是要注意,Spring MVC 的所有功能并非 Dubbo 都支持,实测下来发现 Spring 的Web拦截器和全局异常处理,通过Dubbo访问是不生效的。
同端口混合模式
如果不想 Dubbo 再额外占用端口,也可以采用不区分端口的混合模式部署。
引入下面这个依赖
xml
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-3-autoconfigure</artifactId>
<version>3.3.5</version>
</dependency>
application.yml
把 triple 协议端口和server.port
配置相同,Dubbo 将不再占用新端口,可复用 Spring Boot 已有 servlet 监听端口来接入 HTTP 流量,符合filter-url-patterns
路径的请求会转交给 Dubbo 处理。
yaml
server:
port: 8080
dubbo:
protocol:
name: tri
port: 8080
triple:
servlet:
enabled: true
filter-url-patterns: /dubbo/*
filter-order: -1000000
你可能会感到好奇,不监听新端口,Dubbo 是怎么处理请求的呢?
实际上,在引入上述依赖后,Spring 启动会触发 DubboTripleAutoConfiguration 自动装配,并向容器注册一个FilterRegistrationBean
,它会向 Servlet 容器注册一个jakarta.servlet.Filter
实现,只要它的优先级比默认的org.springframework.web.filter.OncePerRequestFilter
高,就可以提前接管 Web 流量。

Dubbo 注册的是 TripleFilter,只要请求路径匹配,它将接管请求,不通过后续 Filter。并且内置了 HTTP1和HTTP2的支持。

异常处理
全局异常处理是基本操作,服务端处理异常需要返回一个友好的信息给到客户端。
默认发生异常时,Dubbo 会封装成 ErrorResponse 对象返回
java
@Data
public class ErrorResponse {
private String status;
private String message;
}
默认 status = 500,message 是异常信息,例如:
json
{
"message": "name is null",
"status": "500"
}
但是,一般系统会封装自己的错误码和错误信息,而且会区分是一般的业务异常,还是系统异常。Dubbo 的处理方式显得过于简单粗暴,所以我们要定义自己的异常处理器。
Triple 异常处理器实现 org.apache.dubbo.remoting.http12.ExceptionHandler 接口,如下所示:
java
@Activate
public class CustomExceptionHandler implements ExceptionHandler<Throwable, HttpResult> {
@Override
public HttpResult handle(Throwable throwable, RequestMetadata metadata, MethodDescriptor descriptor) {
if (throwable instanceof BizException exception) {
return HttpResult.builder().status(200)
.body(JSON.toJSONString(R.failed(exception.getCode(), exception.getMessage())))
.build();
}
return HttpResult.builder().status(500)
.body("system error")
.build();
}
}
Tips:CustomExceptionHandler 需要 Dubbo SPI 激活
如果发生业务异常,会正常返回 HttpStatus=200,body 示例:
json
{
"code": 400,
"message": "name is too long"
}
如果是非业务异常,会返回 HttpStatus=500,body:system error
过滤器
之前 dubbo 协议的过滤器是基于 org.apache.dubbo.rpc.Filter 接口实现的,参数只能拿到 Invoker 和 Invocation。
java
Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException;
这对基于 HTTP 的 triple 协议来说显然不够友好,HTTP 协议的拦截我们一般会基于 Query Parameters 或 Headers 去做一些诸如:参数验签、认证授权、路由等操作,我们更熟悉的应该是 HttpRequest HttpResponse 对象。
所以,Dubbo 也提供了新的过滤器接口 org.apache.dubbo.rpc.protocol.tri.rest.filter.RestFilter,如下所示,过滤器实现验签、鉴权等操作,前提是需要 SPI 激活。
java
@Activate(group = "provider", order = 100)
public class CustomRestFilter implements RestFilter {
@Override
public void doFilter(HttpRequest request, HttpResponse response, FilterChain chain) throws Exception {
// todo 参数验签...
String sign = request.header("sign");
// todo 认证鉴权...
String authorization = request.header("Authorization");
chain.doFilter(request, response);
}
}
RestFilter 还有一个内部接口 Listener,用于修改响应结果,或者发生异常时返回自定义信息。
java
interface Listener {
default void onResponse(Result result, HttpRequest request, HttpResponse response) throws Exception {}
default void onError(Throwable t, HttpRequest request, HttpResponse response) throws Exception {}
}
尾巴
Apache Dubbo 3.3 通过升级 Triple 协议,不仅支持东西向流量(服务间调用),也扩展至南北向流量(外部访问服务)。这一改进消除了额外部署网关层的需求,减少了时延和维护难度。Triple协议默认支持HTTP1/HTTP2,并可选择支持HTTP3。
异常处理和过滤器功能也得到了优化,提供了更灵活、友好的处理方式。Triple 协议通过 SPI 激活的ExceptionHandler
和RestFilter
接口,使开发者可以自定义异常响应和请求拦截。
这些改进使Dubbo在微服务架构中更具灵活性和扩展性,适应多样化的应用场景。