前言
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,引入下面一個依賴即可。
<dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo</artifactId><version>3.3.5</version>
</dependency>
RestService 服務開發,因為要處理南北向流量,需要通過@Mapping
等注解聲明請求路徑和參數等信息。
@Mapping(path = "/")
public interface RestService {@Mapping(path = "/hello", method = HttpMethods.GET)String hello(@Param("name") String name);
}public class RestServiceImpl implements RestService {@Overridepublic String hello(String name) {return "hello " + name;}
}
接著,啟動服務即可。如下代碼,服務暴露的端口是 50000,協議名是簡寫的tri
。
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 協議訪問服務了。
$ curl 127.0.0.1:50000/hello\?name=triple
"hello triple"
整合Spring Boot
單獨用 Dubbo 開發比較少,一般都是整合 Spring Boot 一起用。要整合 Spring Boot,引入下面依賴:
<dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId><version>3.3.5</version>
</dependency>
application.yml
配置 Dubbo 協議部分
dubbo:protocol:name: triport: 50000
Dubbo 默認支持 Spring Web 注解,所以用 Dubbo 寫 Web API 和之前幾乎沒區別,如下所示:
沒有@RestController
,但是必須加@DubboService
@DubboService
@RequestMapping
public class MyRestController {@GetMapping("/hello")public String hello(@RequestParam("name") String name) {return "hello " + name;}
}
啟動類上加@EnableDubbo
啟用 Dubbo,訪問 50000 端口即可訪問服務。
$ curl 127.0.0.1:50000/hello?name=triple
"hello triple"
分端口混合模式
如果舊項目已經用 Spring MVC 開發了一些 API,但是新的 API 想用 Dubbo 開發,可以用區分端口的混合模式部署。區分端口,也就是 Web 容器占用一個端口,Dubbo 占用一個端口,彼此之間互不干擾。
項目同時依賴spring-boot-starter-web
和 Dubbo
<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 協議端口
server:port: 8080
dubbo:protocol:name: triport: 50000
這樣一來,之前的 API 通過 8080 端口訪問,Dubbo API 通過 50000 端口訪問,互不影響。
一種更方便的寫法,在 Controller 上同時加@Controller
和@DubboService
注解,8080 和 50000 端口都可以訪問這個 API。但是要注意,Spring MVC 的所有功能并非 Dubbo 都支持,實測下來發現 Spring 的Web攔截器和全局異常處理,通過Dubbo訪問是不生效的。
同端口混合模式
如果不想 Dubbo 再額外占用端口,也可以采用不區分端口的混合模式部署。
引入下面這個依賴
<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 處理。
server:port: 8080
dubbo:protocol:name: triport: 8080triple:servlet:enabled: truefilter-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 對象返回
@Data
public class ErrorResponse {private String status;private String message;
}
默認 status = 500,message 是異常信息,例如:
{"message": "name is null","status": "500"
}
但是,一般系統會封裝自己的錯誤碼和錯誤信息,而且會區分是一般的業務異常,還是系統異常。Dubbo 的處理方式顯得過于簡單粗暴,所以我們要定義自己的異常處理器。
Triple 異常處理器實現 org.apache.dubbo.remoting.http12.ExceptionHandler 接口,如下所示:
@Activate
public class CustomExceptionHandler implements ExceptionHandler<Throwable, HttpResult> {@Overridepublic 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 示例:
{"code": 400,"message": "name is too long"
}
如果是非業務異常,會返回 HttpStatus=500,body:system error
過濾器
之前 dubbo 協議的過濾器是基于 org.apache.dubbo.rpc.Filter 接口實現的,參數只能拿到 Invoker 和 Invocation。
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 激活。
@Activate(group = "provider", order = 100)
public class CustomRestFilter implements RestFilter {@Overridepublic 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,用于修改響應結果,或者發生異常時返回自定義信息。
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在微服務架構中更具靈活性和擴展性,適應多樣化的應用場景。