Triple X 全新升级背景
在 Dubbo 的早期应用中,虽然其在数据中心内部的服务互通中展现了卓越的性能,但随着技术演进和应用场景的扩展,原有架构逐渐暴露出了一些瓶颈。这些瓶颈在跨区域、跨云的环境中尤为明显,尤其是在 Web 框架与 RPC 框架之间的频繁切换中,开发复杂性和系统性能都受到了影响。
传统架构的痛点主要体现在:
局限于数据中心内的应用场景:在跨地域或跨云应用中,Dubbo 的传统架构缺乏对广域环境的原生支持,导致开发者需要在多种协议和框架中切换,增加了复杂性。
南北向与东西向流量的双重挑战:在现代微服务架构下,传统的 RPC 框架往往更侧重南北向流量优化,而服务间(东西向)通信的性能要求日益增加,对传统 Dubbo 架构提出了新的挑战。
云原生与跨语言互操作性要求:随着云原生技术的普及,系统需要对 HTTP 协议有更深层次的支持,并具备跨语言的通信能力,然而传统 Dubbo 在这一点上并未原生优化。
Triple X 的变革和突破: Triple X 的诞生,直接回应了这些痛点,它不仅延续了 Dubbo 一贯的高性能通信能力,还实现了与 gRPC 协议的全面兼容,通过支持 HTTP/1、HTTP/2、HTTP/3 等协议,为跨云、跨区域的广泛应用场景提供了更具灵活性和高效性的解决方案。
Triple X 核心能力概述
全面支持南北向与东西向流量:Triple X 无缝支持从客户端到服务器的南北向流量及服务间通信的东西向流量,并确保灵活转换,提升通信链路的整体效率。
遵循 gRPC 协议标准:Triple X 遵循了 gRPC 协议标准,支持通过 Protobuf 进行通信,与 gRPC 服务无缝交互,扩展了 Dubbo 的跨语言、跨平台通信能力。
基于 HTTP 协议,原生支持云原生架构:Triple X 构建于 HTTP/1、HTTP/2 和 HTTP/3 协议栈之上,全面优化了网络通信性能,并与现代云原生基础设施无缝集成,支持各种网关和服务网格。
高性能优化:Triple X 提供了极致的性能提升,尤其在高并发和弱网环境下表现卓越,极大提高了系统吞吐量与响应速度。
平滑迁移与框架兼容:支持从现有的 Spring Web 项目无缝迁移,开发者无需更改现有代码即可切换至 Triple X,提升性能,并保留对 Spring MVC 等框架的支持。
高扩展性:Triple X 新引入 20+ SPI 扩展点,支持自定义核心行为,包括路由映射、参数解析、序列化及异常处理等。显著提升框架的灵活性和可定制性,使开发者能够根据特定业务需求和场景自定义行为,提高开发效率并降低定制化成本。
ChannelPipeline
org.apache.dubbo.remoting.transport.netty4.NettyConnectionClient
org.apache.dubbo.remoting.transport.netty4.NettyConnectionClient#initBootstrap
org.apache.dubbo.rpc.protocol.tri.TripleHttp2Protocol#configClientPipeline
io.netty.handler.codec.http2.Http2MultiplexHandler
Dubbo 使用的是Netty框架,Http2 Stream 多路复用,而Netty 对于每一个Stream 都会创建一个子Channel,子Channel 也会有自己的 ChannelPipeline
在一个Connection上,ChannelPipeline的配置如下:
SslClientTlsHandler(可选 加密传输)
Http2FrameCodec HTTP2 Frame编解码器
Http2MultiplexHandler HTTP2多路复用的支持
TripleGoAwayHandler http2 GoAway 帧(类型0x7) 用于启动链接关闭或发出严重错误状态信号
TripleTailHandler 避免内存泄漏
Http2FrameCodec codec = Http2FrameCodecBuilder.forClient()
handlers.add(new ChannelHandlerPretender(codec));
handlers.add(new ChannelHandlerPretender(new Http2MultiplexHandler(new ChannelDuplexHandler())));
handlers.add(new ChannelHandlerPretender(new TriplePingPongHandler(UrlUtils.getCloseTimeout(url))));
handlers.add(new ChannelHandlerPretender(new TripleGoAwayHandler()));
handlers.add(new ChannelHandlerPretender(new TripleTailHandler()));
org.apache.dubbo.remoting.transport.netty4.NettyConnectionClient#initBootstrap
protected void initBootstrap() {
Bootstrap bootstrap = new Bootstrap();
bootstrap
.group(NettyEventLoopFactory.NIO_EVENT_LOOP_GROUP.get())
.option(ChannelOption.SO_KEEPALIVE, true)
.option(ChannelOption.TCP_NODELAY, true)
.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
bootstrap.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
NettyChannel nettyChannel = NettyChannel.getOrAddChannel(ch, getUrl(), getChannelHandler());
ChannelPipeline pipeline = ch.pipeline();
if (sslContext != null) {
pipeline.addLast("negotiation", new SslClientTlsHandler(sslContext));
}
//TripleHttp2Protocol
protocol.configClientPipeline(getUrl(), operator, nettySslContextOperator);
}
});
this.bootstrap = bootstrap;
}
org.apache.dubbo.rpc.protocol.tri.TripleHttp2Protocol#configClientPipeline
@Override
public void configClientPipeline(URL url, ChannelOperator operator, ContextOperator contextOperator) {
TripleConfig tripleConfig = ConfigManager.getProtocolOrDefault(url).getTripleOrDefault();
Http2FrameCodec codec = Http2FrameCodecBuilder.forClient()
.gracefulShutdownTimeoutMillis(10000)
.initialSettings(new Http2Settings()
.headerTableSize(tripleConfig.getHeaderTableSizeOrDefault())
.pushEnabled(tripleConfig.getEnablePushOrDefault())
.maxConcurrentStreams(tripleConfig.getMaxConcurrentStreamsOrDefault())
.initialWindowSize(tripleConfig.getInitialWindowSizeOrDefault())
.maxFrameSize(tripleConfig.getMaxFrameSizeOrDefault())
.maxHeaderListSize(tripleConfig.getMaxHeaderListSizeOrDefault()))
.frameLogger(CLIENT_LOGGER)
.validateHeaders(false)
.build();
// codec.connection().local().flowController().frameWriter(codec.encoder().frameWriter());
List<ChannelHandler> handlers = new ArrayList<>();
handlers.add(new ChannelHandlerPretender(codec));
handlers.add(new ChannelHandlerPretender(new Http2MultiplexHandler(new ChannelDuplexHandler())));
handlers.add(new ChannelHandlerPretender(new TriplePingPongHandler(UrlUtils.getCloseTimeout(url))));
handlers.add(new ChannelHandlerPretender(new TripleGoAwayHandler()));
handlers.add(new ChannelHandlerPretender(new TripleTailHandler()));
operator.configChannelHandler(handlers);
}
在Stream 上,ChannelPipeline的配置如下:
TripleCommandOutBoundHandler 命令输出
TripleHttp2ClientResponseHandler 对服务端响应的处理
org.apache.dubbo.rpc.protocol.tri.h12.http2.Http2TripleClientStream#initStreamChannel
@Override
protected TripleStreamChannelFuture initStreamChannel(Channel parent) {
Http2StreamChannelBootstrap bootstrap = new Http2StreamChannelBootstrap(parent);
bootstrap.handler(new ChannelInboundHandlerAdapter() {
@Override
public void handlerAdded(ChannelHandlerContext ctx) {
ctx.channel()
.pipeline()
.addLast(new TripleCommandOutBoundHandler())
.addLast(new TripleHttp2ClientResponseHandler(createTransportListener()));
}
});
TripleStreamChannelFuture streamChannelFuture = new TripleStreamChannelFuture(parent);
writeQueue.enqueue(CreateStreamQueueCommand.create(bootstrap, streamChannelFuture));
return streamChannelFuture;
}```
## Triple协议TripleProtocol
消费方的调用流程体系,首先得引用服务,创建对应的Invoker.
Triple服务的引用代码
org.apache.dubbo.rpc.protocol.tri.TripleProtocol#refer
```java
@Override
public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
optimizeSerialization(url);
ExecutorService streamExecutor = getOrCreateStreamExecutor(url.getOrDefaultApplicationModel(), url);
AbstractConnectionClient connectionClient = Http3Exchanger.isEnabled(url)
? Http3Exchanger.connect(url)
: PortUnificationExchanger.connect(url, new DefaultPuHandler());
TripleInvoker<T> invoker =
new TripleInvoker<>(type, url, acceptEncodings, connectionClient, invokers, streamExecutor);
invokers.add(invoker);
return invoker;
}
服务引用
服务引用
org.apache.dubbo.rpc.protocol.tri.TripleProtocol#refer 服务引用
org.apache.dubbo.rpc.protocol.tri.TripleInvoker#TripleInvoker 实例化Invoker
org.apache.dubbo.remoting.transport.netty4.NettyConnectionManager#connect 实例化Connection
org.apache.dubbo.remoting.transport.netty4.NettyConnectionClient#initBootstrap 构建Bootstrap
org.apache.dubbo.remoting.transport.AbstractClient#connect 建立连接
服务调用
org.apache.dubbo.rpc.protocol.tri.TripleInvoker#doInvoke Triple协议调用
org.apache.dubbo.rpc.protocol.tri.TripleInvoker#invokeUnary Unary调用
org.apache.dubbo.rpc.protocol.tri.TripleInvoker#createRequest 请求元数据
org.apache.dubbo.rpc.protocol.tri.stream.ClientStreamFactory#createClientStream 开启stream
org.apache.dubbo.rpc.protocol.tri.h12.http2.Http2TripleClientStream 开启stream
org.apache.dubbo.rpc.protocol.tri.observer.ClientCallToObserverAdapter#onNext 观测适配器
org.apache.dubbo.rpc.protocol.tri.call.TripleClientCall#sendMessage 发送消息
org.apache.dubbo.rpc.protocol.tri.stream.Stream#sendHeader 发送Header 帧
org.apache.dubbo.rpc.model.PackableMethod#packRequest 打包消息 序列化
org.apache.dubbo.rpc.protocol.tri.stream.ClientStream#sendMessage 发送DATA帧
org.apache.dubbo.rpc.protocol.tri.observer.ClientCallToObserverAdapter#onCompleted 完成事件
org.apache.dubbo.rpc.protocol.tri.call.ClientCall#halfClose 发送endSteam Stream半关闭状态
服务调用完整堆栈
halfClose:229, TripleClientCall (org.apache.dubbo.rpc.protocol.tri.call)
onCompleted:55, ClientCallToObserverAdapter (org.apache.dubbo.rpc.protocol.tri.observer)
invokeUnary:284, TripleInvoker (org.apache.dubbo.rpc.protocol.tri)
doInvoke:171, TripleInvoker (org.apache.dubbo.rpc.protocol.tri)
doInvokeAndReturn:249, AbstractInvoker (org.apache.dubbo.rpc.protocol)
invoke:192, AbstractInvoker (org.apache.dubbo.rpc.protocol)
invoke:71, ListenerInvokerWrapper (org.apache.dubbo.rpc.listener)
invoke:40, RpcExceptionFilter (org.apache.dubbo.rpc.filter)
invoke:349, FilterChainBuilder$CopyOfFilterChainNode (org.apache.dubbo.rpc.cluster.filter)
invoke:96, ConsumingFilter (cn.itbox.uap.dubbo.filter)
invoke:349, FilterChainBuilder$CopyOfFilterChainNode (org.apache.dubbo.rpc.cluster.filter)
invoke:197, FilterChainBuilder$CallbackRegistrationInvoker (org.apache.dubbo.rpc.cluster.filter)
invoke:106, ReferenceCountInvokerWrapper (org.apache.dubbo.rpc.protocol)
invoke:800, ServiceDiscoveryRegistryDirectory$InstanceWrappedInvoker (org.apache.dubbo.registry.client)
invokeWithContext:412, AbstractClusterInvoker (org.apache.dubbo.rpc.cluster.support)
doInvoke:82, FailoverClusterInvoker (org.apache.dubbo.rpc.cluster.support)
invoke:366, AbstractClusterInvoker (org.apache.dubbo.rpc.cluster.support)
invoke:46, RouterSnapshotFilter (org.apache.dubbo.rpc.cluster.router)
invoke:349, FilterChainBuilder$CopyOfFilterChainNode (org.apache.dubbo.rpc.cluster.filter)
invoke:109, MonitorFilter (org.apache.dubbo.monitor.support)
invoke:349, FilterChainBuilder$CopyOfFilterChainNode (org.apache.dubbo.rpc.cluster.filter)
invoke:57, MetricsClusterFilter (org.apache.dubbo.rpc.cluster.filter.support)
invoke:349, FilterChainBuilder$CopyOfFilterChainNode (org.apache.dubbo.rpc.cluster.filter)
invoke:53, FutureFilter (org.apache.dubbo.rpc.protocol.dubbo.filter)
invoke:349, FilterChainBuilder$CopyOfFilterChainNode (org.apache.dubbo.rpc.cluster.filter)
invoke:40, ContextHolderParametersSelectedTransferFilter (org.apache.dubbo.spring.security.filter)
invoke:349, FilterChainBuilder$CopyOfFilterChainNode (org.apache.dubbo.rpc.cluster.filter)
invoke:86, MetricsFilter (org.apache.dubbo.metrics.filter)
invoke:38, MetricsConsumerFilter (org.apache.dubbo.rpc.cluster.filter.support)
invoke:349, FilterChainBuilder$CopyOfFilterChainNode (org.apache.dubbo.rpc.cluster.filter)
invoke:40, ConsumerClassLoaderFilter (org.apache.dubbo.rpc.cluster.filter.support)
invoke:349, FilterChainBuilder$CopyOfFilterChainNode (org.apache.dubbo.rpc.cluster.filter)
invoke:60, ObservationSenderFilter (org.apache.dubbo.tracing.filter)
invoke:349, FilterChainBuilder$CopyOfFilterChainNode (org.apache.dubbo.rpc.cluster.filter)
invoke:119, ConsumerContextFilter (org.apache.dubbo.rpc.cluster.filter.support)
invoke:349, FilterChainBuilder$CopyOfFilterChainNode (org.apache.dubbo.rpc.cluster.filter)
invoke:197, FilterChainBuilder$CallbackRegistrationInvoker (org.apache.dubbo.rpc.cluster.filter)
invoke:101, AbstractCluster$ClusterFilterInvoker (org