⾃ 2012 年 Google 前瞻性地提出 QUIC 传输协议,历经⼗年迭代,HTTP/3 作为 HTTP/2 的继任者,在 2022 年 IETF 正式标准化 HTTP/3 为 RFC9114。HTTP/3 凭借其对 QUIC 协议的深度整合以及从 TCP 向 UDP 的底层连接转型,迅速赢得了业界的⼴泛接纳。截⽌到2022年11⽉,全球已有超过四分之⼀的⽹站部署了 HTTP/3 技术,如下图。⼀个崭新的⾼速、⾼效⽹络时代正逐步拉开帷幕。

在当前的开源⽹络通信领域中,诸如 Netty、NGINX 以及 gRPC 等主流框架正竞相投入资源研发各⾃的 HTTP/3 实现⽅案,以紧跟时代步伐。然而,在这⼀浪潮中,作为知名的 RPC 通信框架 Dubbo,⽬前仅对 HTTP/2 提供了⽀持。HTTP/3 协议本⾝所蕴含的诸多优势不容忽视,例如摒弃队头阻塞问题、实现 0 RTT 握⼿延迟以及连接迁移等特性,这些都极⼤地提升了通信效率,扩展⾄ HTTP/3 成为⼀种必然趋势,将 HTTP/3 引⼊ RPC 框架不仅能够为开发者提供更为多样化的选择,⽽且有助于他们构建出性能更卓越的应⽤系统。
为什么以前的 RPC 要自研协议?
早期的 RPC 框架(如 Dubbo)选择自研传输协议而不是使用 HTTP 的主要原因在于性能优化和灵活性,具体来说有以下几点:
-
性能开销低:HTTP 协议的设计初衷是面向互联网应用,支持请求-响应模型、状态码、头部、Cookie 等功能,导致其头部开销较大。此外,HTTP 基于文本协议传输,序列化和反序列化的性能较低。Dubbo 的自研协议一般是基于二进制的协议,序列化速度快、数据体积小,相比 HTTP 消耗的带宽更少,延迟也更低。
-
保持长连接:在 RPC 中,保持客户端和服务端之间的长连接是常见的需求,这样可以在连接建立后持续发送多次请求,节省连接建立的开销。而早期的 HTTP 协议则没有较好的长连接复用能力(相较 HTTP/2 或 HTTP/3)。
-
双向通信能力:RPC 框架的设计是为了支持高并发、大量小数据包的实时通信。HTTP 协议是请求-响应模型,天然不支持双向通信和请求的异步处理。自研协议则能支持请求和响应的独立性以及双向通信,从而更符合 RPC 的场景需求。
-
序列化和数据压缩:Dubbo 使用自研的协议能根据业务场景选择最优的序列化方式(如 Hessian),而不是只能使用 HTTP 中的 JSON、XML 等标准序列化方式,这样的设计进一步提升了数据传输效率和速度。
-
业务需求定制化:Dubbo 的自研协议可以更灵活地定制各种特性,如链路追踪、流量控制、服务治理等。由于 HTTP 是通用协议,虽然可以扩展,但在性能和实现难度上都有很大限制。
长连接?多路复用? HTTP协议的性能发展
HTTP 协议在过去几代的发展中,通过引入长连接、多路复用、头部压缩等特性逐步提升了性能,经历了 HTTP/1.0 到 HTTP/3 的演进。下面分别介绍各个版本中提升性能的关键特性。
HTTP/1.0
- 短连接:HTTP/1.0 使用短连接,即每个请求-响应对都需要新建一个 TCP 连接,导致频繁的连接建立与关闭,开销较大。
- 无状态:请求之间没有状态,服务器不知道客户端的历史请求,效率较低。
HTTP/1.1
-
长连接:HTTP/1.1 引入了 Connection: keep-alive,允许复用 TCP 连接,即多个请求共享一个连接,减少了连接建立与关闭的开销。
-
管道化(Pipelining):允许客户端在同一连接上并行发送多个请求,无需等待上一个请求结束(减少了等待时间),但服务端必须按顺序返回响应,这一机制由于易出现“队头阻塞”而实际使用较少。
-
分块传输编码:支持分块传输,服务端可以将响应数据分成多个块,边生成边发送,不必等整个响应生成完成。
HTTP/2
-
多路复用(Multiplexing):HTTP/2 在一个 TCP 连接上允许多个请求并行进行,解决了 HTTP/1.1 的队头阻塞问题,实现了真正的多请求复用。
-
二进制分帧:HTTP/2 将 HTTP 请求与响应分解为二进制帧传输,以 stream 为单位,通过标记帧的类型区分请求和响应。
-
头部压缩:引入了 HPACK 算法压缩请求头部,降低数据传输量。
-
服务器推送(Server Push):服务器可以主动向客户端推送资源(如页面依赖的 CSS 或 JavaScript),无需等待客户端请求。
HTTP/3
-
基于 QUIC 协议:HTTP/3 采用 UDP 作为传输层协议,结合 QUIC 实现了连接迁移、0-RTT 连接建立、多路复用等特性。
-
无队头阻塞:QUIC 的设计中每个流独立传输,因此即便其中一个请求超时,也不会影响其他请求,真正消除了队头阻塞。
-
快速握手和连接迁移:QUIC 实现了 0-RTT 和 1-RTT 连接建立,显著减少了延迟,并支持网络迁移(例如设备从 WiFi 切换到 4G),可以复用现有连接。
gRPC 与 HTTP2 的发展关联
gRPC 是基于 HTTP/2 协议开发的,因此其设计和性能与 HTTP/2 的发展紧密关联。HTTP/2 为 gRPC 提供了基础传输层,支持高效的流式通信、二进制帧和多路复用等关键特性。以下是 gRPC 和 HTTP/2 之间的重要关联:
-
二进制传输:HTTP/2 支持二进制数据帧,而 gRPC 则利用了这一特性,将消息内容以 Protocol Buffers 编码并以二进制格式传输。这使得 gRPC 相比传统文本协议的性能更高,占用带宽更小,处理速度更快。
-
多路复用:HTTP/2 的多路复用功能允许在单一 TCP 连接上并行传输多个请求和响应,消除 HTTP/1.1 中的队头阻塞问题。gRPC 在这种基础上,能让多个远程调用并行进行,无需为每个请求创建独立连接,极大地提升了吞吐量和性能,尤其在网络延迟较大的场景下优势明显。
-
流式传输:HTTP/2 的流机制和优先级管理,使得 gRPC 能够支持四种数据流模式,使 gRPC 非常适合实时数据流和长连接场景:
- 简单 RPC(Unary RPC):客户端向服务器发送一个请求并接收一个响应。
- 服务器流式 RPC:客户端发送一个请求,服务器发送一系列响应流。
- 客户端流式 RPC:客户端发送一系列请求流,服务器只返回一个响应。
- 双向流式 RPC:客户端和服务器之间进行双向、实时的消息流传输。
-
头部压缩:HTTP/2 引入的 HPACK 头部压缩机制,通过减少头部大小和减少重复头部传输,降低了带宽占用。gRPC 通过使用 HTTP/2 的头部压缩,使请求的元数据更加紧凑,减少了带宽和延迟开销,特别适用于大量 RPC 调用的场景。
-
单一连接上的多请求:HTTP/2 支持在一个 TCP 连接中多路复用多个请求,这一特性在 gRPC 中非常重要,因为它允许高并发的远程调用在一个连接中进行,大大减少了连接的建立和释放消耗。gRPC 使用单一持久连接,以降低网络资源的占用,尤其适合微服务通信。
-
长连接和服务端推送:HTTP/2 的 Server Push 和长连接机制,可以为 gRPC 提供高效的双向通信通道。虽然 gRPC 没有直接使用 HTTP/2 的 Server Push 功能,但利用了其持久连接特性,以支持服务器主动向客户端推送数据的功能。
-
安全性:gRPC 默认使用 HTTP/2 的 TLS(传输层安全协议)提供的加密通道,以确保通信安全性。在 HTTP/2 的支持下,gRPC 提供了更安全的数据传输途径,尤其是在跨网关和不同网络环境下通信时,保证了数据的安全传输。
gRPC 充分利用了 HTTP/2 的核心功能,将其应用于现代高效的远程过程调用框架中,使得 gRPC 能够在低延迟、高并发、长连接等场景下表现出色。
UDP 比 TCP 快吗?
一般来说,UDP 的传输速度确实比 TCP 快,但这种速度差异主要体现在其不同的协议设计上:
-
连接机制:TCP 是面向连接的协议,在数据传输前需要建立连接,结束后需要四次挥手断开连接;UDP 是无连接协议,不需要建立和断开连接,数据可以直接发出。
-
可靠性机制:TCP 提供可靠性保障,通过确认和重传机制确保数据不丢失、按顺序到达,适用于需要数据完整性的场景,但这也带来了额外的延迟;UDP 不保证数据传输的可靠性,没有重传和确认机制,因此在数据丢失或顺序错乱时不会补救,这使其更快。
-
流量控制和拥塞控制:TCP 内置流量控制和拥塞控制,根据网络情况动态调整数据传输速率,以避免网络拥堵和丢包;UDP 没有流量控制机制,只负责将数据尽快发送到目标,因此速度更快,但在网络拥堵时可能导致数据大量丢失。
-
适用场景:UDP 适合对速度要求高、对数据丢失不敏感的应用,例如视频直播、在线游戏、语音通信等;TCP 适合对数据完整性和顺序有严格要求的应用,如文件传输、邮件、网页加载等。
为什么要使用 HTTP3?
使用 HTTP/3 的原因主要在于它通过 基于 UDP 的 QUIC 协议克服了 HTTP/2 和 TCP 协议中的一些瓶颈,尤其在高延迟和不稳定网络环境中。以下是 HTTP/3 的关键优势和设计原因:
-
头阻塞问题解决:在 HTTP/2 中,所有的请求在同一个 TCP 连接上复用,但 TCP 是按顺序传输的,一旦一个请求的包丢失,整个 TCP 连接都会等待该包重传,从而造成“队头阻塞”问题;HTTP/3 使用基于 UDP 的 QUIC 协议,实现了更细粒度的控制。如果一个数据包丢失,QUIC 只会重传该包而不影响其他数据流,避免了队头阻塞,提高了传输效率。
-
连接建立速度更快:HTTP/3 中基于 QUIC 的连接建立非常快速。传统的 TCP 连接需要三次握手,且配合 TLS 加密还需要额外的延迟。QUIC 将握手和加密结合在一起,仅需一次往返即可建立安全连接,减少延迟;连接建立的快速性在需要频繁建立短连接的场景中尤为明显。
-
改善丢包情况下的性能:QUIC 通过 UDP 实现传输层特性,不受 TCP 丢包重传机制的影响。在丢包率较高的环境中,如移动网络,HTTP/3 的性能表现比 HTTP/2 更为稳定;这使得 HTTP/3 尤其适合移动设备用户体验,减少因网络波动造成的速度下降。
-
更好的连接迁移能力:QUIC 支持连接迁移,即用户在切换网络(如 WiFi 切换到 4G)时不需要重新建立连接。QUIC 能识别连接的唯一 ID,使用户在网络切换时可以继续复用原有的连接,不会中断服务;这种特性对于现代移动应用尤为重要,提升了网络切换情况下的稳定性和用户体验。
-
内置的流量控制和加密:QUIC 内置了加密和流量控制机制,简化了应用层的设计需求,提升了安全性。HTTP/3 强制加密传输,默认提供 TLS 1.3,加密性能和连接建立速度更快。
QUIC 提供了更高效的连接管理、更稳定的数据传输和更强的适应能力,使得现代网络应用尤其是在移动设备上的性能大幅提升。
HTTP3 在 RPC 中的应用
Netty 在 Java 生态中是一个举足轻重的网络框架,他们目前正在孵化 QUIC 及 HTTP3 项目,HTTP3 基于自家的 QUIC 来开发,而 QUIC 的主要实现是 cloudflare 用Rust 语言开发的 quiche 项目,quiche 是一个高性能、功能齐全的 QUIC 和 HTTP/3 实现。它提供了一个低级 API 来处理 QUIC 数据包和处理连接状态。
Dubbo over http3
目前主流的 RPC 框架中,Dubbo 在 3.3 版本的 Triple X 协议中引入了Netty 的 HTTP3 实现,作为它的传输模块详情你可以看这里。简单来说,它是把 HTTP3 的数据帧转为了原先支持的 HTTP2 数据帧,可以看看这个方法的具体显示,Http3ClientFrameCodec 编码器的 channelRead 方法如下:
public void channelRead(ChannelHandlerContext ctx, Object msg) {
if (msg instanceof Http3HeadersFrame) {
Http2HeadersAdapter headers = new Http2HeadersAdapter(((Http3HeadersFrame) msg).headers());
boolean endStream = headers.contains(TripleHeaderEnum.STATUS_KEY.getKey());
ctx.fireChannelRead(new DefaultHttp2HeadersFrame(headers, endStream));
} else if (msg instanceof Http3DataFrame) {
ctx.fireChannelRead(new DefaultHttp2DataFrame(((Http3DataFrame) msg).content()));
} else if (msg instanceof Http3GoAwayFrame) {
ctx.fireUserEventTriggered(new DefaultHttp2GoAwayFrame(((Http3GoAwayFrame) msg).id()));
} else {
ctx.fireChannelRead(msg);
}
}
笔者对于 Dubbo 使用 HTTP3 的方式有两点不认同。
-
第一点是上面的直接转化 HTTPP3 数据帧为 HTTP2 数据帧的方式,这种直接的暴力转化真的合适吗?可以了解到的是,HTTP2 通过多路复用与头部压缩解决了性能问题,许多 RPC 框架正在使用 HTTP2 协议作为通信协议,比如 gRPC、Dubbo,在性能方面与自研的 RPC 协议别无二致,QUIC 是将 TCP 协议栈在用户态精简的实现了一遍,HTTP3 就基于QUIC 将 HTTP2 再实现了一遍,所以在特性基本上是差不多的,比如多路复用与数据流,所以 Dubbo 的做法好像也没什么问题,将 HTTP3 直接套用在 HTTP2 上,但是有 3 点问题是比较大的,首先是项目的拓展性问题,Dubbo 这样做无疑是将 HTTP3 与HTTP2 耦合在一起了,未来是拓展更多功能时,可能会增加开发量;其次是功能兼容问题,比如说 HTTP3 的连接 ID 与 TSL 这两个内置功能,HTTP2 无法做到直接兼容;还有就是 QUIC 的扩展,Google 为了尽力专注于 QUIC 的核心特性,以及为了赶上发布进度,最初计划为核心协议一部分的几个特性已被推迟,计划到 QUIC 第二版或以后的版本中完成,比如说前向纠错与多路径 这些功能在未来可能会被推出,所以未来 Netty 可能会对当前的代码进行扩展,那么以后 Dubbo 是跟进还是不跟进呢?这也是一个问题。
-
第二点是 Dubbo 在作为一个 40k+ star 的项目,在稳定发行版本使用了 netty 的 incubator 孵化包。详细见这里。
<dependency> <groupId>io.netty.incubator</groupId> <artifactId>netty-incubator-codec-http3</artifactId> </dependency>
这种做法显然是不合适的,首先是 Netty-http3 本身还是一个孵化项目,它可能有一些 Bug 或者性能问题还没有解决,稳定性不够,其次是 Netty 所使用的 quiche 项目本身也不是行业事实标准,没有经过大规模生产系统的检验,源头就是不可靠的。所谓笔者对稳定发行的项目直接使用 netty 的孵化包表示质疑。
Palmx over http3
Palmx 是笔者对一个基本的 RPC 项目进行二次开发的项目,目标是成为次世代的 RPC 框架。其核心能力就是基于HTTP/3 的高性能传输协议。与 Dubbo 类似,也是使用 Netty 放入孵化包:
<dependency>
<groupId>io.netty.incubator</groupId>
<artifactId>netty-incubator-codec-http3</artifactId>
<version>0.0.27.Final</version>
</dependency>
<dependency>
<groupId>io.netty.incubator</groupId>
<artifactId>netty-incubator-codec-quic</artifactId>
<version>0.0.20.Final</version>
</dependency>
核心服务端是通过一个 Http3.newQuicServerCodecBuilder() 得到了一个 ChannelHandler,其中将自定义的 RPC 调用处理器Http3RpcInvocationHandler 加入到 Channel 的 pipeline 中,接受 RPC 请求,代码如下:
ChannelHandler channelHandler = Http3.newQuicServerCodecBuilder()
.maxIdleTimeout(500000, TimeUnit.MILLISECONDS)
.initialMaxData(10000000)
.initialMaxStreamDataBidirectionalLocal(1000000)
.initialMaxStreamDataBidirectionalRemote(1000000)
.initialMaxStreamsBidirectional(2000) // 设置最大并发双向流数
.initialMaxStreamsUnidirectional(2000) // 设置最大并发单向流数
.tokenHandler(InsecureQuicTokenHandler.INSTANCE)
.handler(new ChannelInitializer<QuicChannel>() {
@Override
protected void initChannel(QuicChannel ch) {
// Called for each connection
ch.pipeline().addLast(new Http3ServerConnectionHandler(
new ChannelInitializer<QuicStreamChannel>() {
@Override
protected void initChannel(QuicStreamChannel ch) {
ch.pipeline().addLast(new Http3RpcInvocationHandler() {
});
}
}));
}
}).build();
RPC 调用处理器 Http3RpcInvocationHandler 继承于 Http3RequestStreamInboundHandler,需要重写两个 channelRead 方法,分别处理 Http3HeadersFrame 和 Http3DataFrame 数据,其中关于调用的信息在参数是 Http3DataFrame 数据帧的方法中,方法执行流程是将数据帧解析出来,然后通过 InvokeHandler.的 doInvoke 方法处理具体的 RPC 请求。详细实现如下:
public class Http3RpcInvocationHandler extends Http3RequestStreamInboundHandler {
@Override
protected void channelRead(
ChannelHandlerContext ctx, Http3HeadersFrame frame) {
ReferenceCountUtil.release(frame);
}
@Override
protected void channelRead(
ChannelHandlerContext ctx, Http3DataFrame frame) {
// 解析出 RpcMessage
RpcMessage rpcMessage = MessageCodecHelper.decodeRpcMessage(frame.content());
// 获取 RpcInvocation
RpcInvocation rpcInvocation = (RpcInvocation) rpcMessage.getData();
// 执行调用于获取结果
RpcResponse rpcResponse = InvokeHandler.doInvoke(rpcInvocation);
// 设置返回参数
rpcResponse.setSequenceId(rpcMessage.getSequenceId());
RpcMessage rpcMessage2 = new RpcMessage(rpcResponse.getSequenceId(), rpcResponse);
rpcMessage2.setMessageType(PalmxConstants.NETTY_RPC_RESPONSE_MESSAGE);
// 编码
ByteBuf encode = MessageCodecHelper.encode(rpcMessage2);
int len = encode.readableBytes();
// 编入响应头
ctx.write(getDefaultHttp3HeadersFrame(len));
// 写入响应踢
DefaultHttp3DataFrame defaultHttp3DataFrame = new DefaultHttp3DataFrame(encode); ctx.writeAndFlush(defaultHttp3DataFrame).addListener(QuicStreamChannel.SHUTDOWN_OUTPUT);
ReferenceCountUtil.release(frame);
}
}
这就是 HTTP3 的 RPC 的服务端实现,客户端的核心实现从动态代理请求开始,PalmxClient#sendAndExpect,当开启 HTTP3 后,请求会从 NettyHttp3Client 的 doSend 发出,主要实现是经过负载均衡后,获取一个 QuicStreamChannel,将 Http3HeadersFrame 与 Http3DataFrame 写入这个 Channel,再异步等待客户端返回,获取到异步结果后,由动态代理返回到真实的请求上,这就完成了一次 HTTP3 RPC 调用。其核心方法 doSend 详细代码如下:
protected Object doSend(RpcMessage rpcMessage) {
// ... 省略
QuicStreamChannel quicStreamChannel = getQuicStreamChannel(socketAddress);
Http3HeadersFrame frame = new DefaultHttp3HeadersFrame();
//...
quicStreamChannel.write(frame);
ByteBuf encode = MessageCodecHelper.encode(rpcMessage);
DefaultHttp3DataFrame defaultHttp3DataFrame = new DefaultHttp3DataFrame(encode);
quicStreamChannel.writeAndFlush(defaultHttp3DataFrame);
// 准备一个 Promise,并将其加入到 RpcResponsePacketHandler 的集合中,以该请求的序列化为键
DefaultPromise<Object> promise = new DefaultPromise<>(quicStreamChannel.eventLoop());
Http3RpcResponseHandler.map.put(rpcMessage.getSequenceId(), promise);
promise.await();
// 取出结果
if (promise.isSuccess()) {
Object result = promise.getNow();
quicStreamChannel.closeFuture();
return result;
}
// 省略...
}
这就是 Palmx 项目基于 HTTP3 的简单实现。
RPC 通信的未来发展
通信技术在快速发展,RPC 技术也要与时具进,当前前沿的网络通信技术有 Google 未能完成的 QUIC v2,以及一些内核旁路技术,还有就是通过智能网卡去提升网络传输效率。这些新技术以后也能在 RPC 领域得到恰当的应用。
QUIC v2
QUIC v2 是 QUIC 协议的一个更新版本,由 IETF 进行标准化开发,用于改进原始 QUIC 协议 (QUIC v1) 的特性和性能。QUIC v2 主要目的是确保协议更加稳定、安全,特别是在复杂的网络环境中,并且具备更强的兼容性和灵活性。
QUIC v2 的关键改进
-
优化连接建立和恢复:QUIC v2 更注重连接的快速建立和丢包后的恢复速度,特别在网络条件恶劣的情况下提供更低的延迟和更高的稳定性。
-
增强的加密和安全性:QUIC v2 保持了 v1 的强加密机制,并修复了一些已知的潜在安全隐患。它进一步优化了加密握手,使得连接建立更快。
-
版本协商机制:QUIC v2 引入了更强的版本协商功能,使得服务器和客户端能够在多种 QUIC 版本下实现无缝通信。如果客户端发起的连接请求版本不匹配,服务器可以自动协商切换到一个兼容的 QUIC 版本。
-
协议灵活性提升:QUIC v2 进行了许多底层改进,以适应未来可能的新特性或扩展,使协议更具扩展性。这意味着 QUIC v2 更容易支持未来的新特性。
-
更好的兼容性:在一些 NAT、代理、或者其他复杂网络环境中,QUIC v1 有时会遇到兼容性问题,QUIC v2 针对这些情况进行了优化,从而提升了在广泛网络条件下的适用性。
主要应用场景
- Web 服务加速:HTTP/3 使用 QUIC 作为传输协议层,QUIC v2 带来的连接建立和恢复性能优化,可以更好地支持 Web 服务的高速访问。
- 实时通信与视频传输:由于 QUIC v2 的低延迟和快速恢复特性,它在实时通信和视频传输等对时延敏感的应用场景中非常有用。
- 移动设备网络:QUIC v2 能适应较差的网络环境,对于网络条件频繁变动的移动设备连接更加稳定。
内核旁路
内核旁路(Kernel Bypass)是一种网络加速技术,旨在绕过操作系统内核的网络协议栈,直接将网络数据从网卡传递到用户空间的应用程序。这种方式减少了数据在内核中处理的开销,从而提高网络传输的速度和效率。
内核旁路的工作原理
通常情况下,网络数据包会经过以下流程:
- 从网络接口传输到内核:数据包从网卡进入内核协议栈,由内核管理网络协议(如 TCP/IP)。
- 内核处理后传输到用户空间:内核将处理后的数据包交付给用户空间应用程序。
内核旁路通过让应用程序直接从网卡读取或写入数据,跳过内核协议栈和上下文切换,从而提高网络性能。常见的内核旁路技术包括:
- DPDK(Data Plane Development Kit):提供用户空间数据包处理的库。
- RDMA(Remote Direct Memory Access):允许远程数据访问,尤其适用于分布式存储和高性能计算。
- XDP(eXpress Data Path):Linux 内核中的一个扩展,通过在网卡驱动层处理数据包,降低内核处理成本。
RDMA
RDMA(Remote Direct Memory Access,远程直接内存访问)是一种网络技术,允许一台计算机直接访问另一台计算机的内存,而无需经过操作系统内核的干预。这种技术显著降低了延迟和 CPU 资源消耗,使得数据可以更高效地在不同机器之间传输,因此被广泛应用在高性能计算(HPC)、分布式存储系统和大数据分析等场景。
RDMA 的工作原理是通过让数据直接从一台计算机的内存传输到另一台计算机的内存,绕过了操作系统内核的网络协议栈。它主要依靠硬件(如 RDMA 支持的网卡,即 RNIC)来处理数据的传输过程,包括分段和重组,减少了数据包传输过程中的 CPU 占用和上下文切换。
DPDK
DPDK(Data Plane Development Kit)是一个用于高性能数据包处理的开源软件开发工具集。它主要解决了在网络设备(如网络接口卡)中进行数据包处理时所面临的性能瓶颈问题。
基本原理
- 用户态驱动: DPDK 运行在用户态,而非内核态。传统的网络栈通常需要在内核态和用户态之间进行频繁的上下文切换,这对于高性能应用来说是一个瓶颈。DPDK 的用户态驱动能够绕过内核,直接在用户态进行数据包处理,从而提高性能。
- 零拷贝: DPDK 支持零拷贝技术,避免了在数据包传递过程中的内存拷贝操作。这通过使用大页(huge pages)技术和内存映射(mmap)来实现,减少了对内存的频繁操作,提高了数据包处理的效率。
- 多队列与多核: DPDK 利用多队列和多核的特性,实现并行处理多个数据包。每个队列可以分配给不同的核,从而在多核处理器上实现并行处理,提高整体处理能力。
FPGA
FPGA(Field-Programmable Gate Array)是一种可编程逻辑器件,具有在硬件级别重新配置其内部电路的能力。它主要用于在硬件中实现特定的功能,相对于固定的硬件电路,具有更高的灵活性。
基本原理
- 可编程逻辑单元(PLU): FPGA 包含大量的可编程逻辑单元,这些单元可以通过配置位流进行重新编程。PLU 可以用于实现各种逻辑电路,从简单的逻辑门到复杂的处理器。
- 可编程连接: FPGA 中的连接结构是可编程的,可以通过配置来建立不同的信号路径。这使得设计者可以在逻辑单元之间创建灵活的连接,实现特定的电路结构。
- 硬性和软性处理器: 一些 FPGA 包含硬性处理器核心,如 ARM Cortex 等,也可以通过配置实现软性处理器。这使得 FPGA 可以用于特定任务的定制处理器设计。
在未来,相信这些在通信方向的前沿技术也能在 RPC 领域大放异彩。
参考文章
- 突破单台服务器的性能极限:https://pphc.lvwenhan.com/part-three/large-scale-load-balancing/section-5
- 为什么基于 UDP 设计的可靠传输协议普遍比传统 TCP 快?:https://www.zhihu.com/question/609087404/answer/3316384763
- 如何基于 UDP 协议实现可靠传输?:https://xiaolincoding.com/network/3_tcp/quic.html
- 详解 KCP 协议的原理和实现:https://luyuhuang.tech/2020/12/09/kcp.html
- 基于 KCP 的 TCP/UDP 多通道开源框架:https://juejin.cn/post/7134888107907743774
- QUIC 协议原理分析:https://zhuanlan.zhihu.com/p/32553477
- 一文读懂 QUIC 协议:https://zhuanlan.zhihu.com/p/655070575
- QUIC 在腾讯的实践及性能优化 :https://zhuanlan.zhihu.com/p/32560981
- 腾讯 TQUIC 网络传输协议:https://mp.weixin.qq.com/s/Sf8JsZKeZYxT9WBZrh_etg
- 快速 UDP 网络连接协议:https://juejin.cn/post/7066993430102016037
- HTTP/3核心概念之QUIC:https://livevideostack.cn/news/quic-the-core-concept-of-http-3/
- HTTP/3 原理实战:https://mp.weixin.qq.com/s/MHYMOYHqhrAbQ0xtTkV2ig
- HTTP/3 协议 push promise:https://blog.csdn.net/GMingZhou/article/details/110765230
- HTTP/3 进步与问题:https://www.zhihu.com/question/302412059/answer/3145012307
- 深入剖析 HTTP3 协议:https://www.nginx.org.cn/article/detail/422
- QUIC v2:https://www.kancloud.cn/kancloud/http3-explained/1395041
- 为什么有 HTTP 协议,还要有 Websocket 协议:https://mp.weixin.qq.com/s/Pl9Nf8HR3MYbc5Y1bMOl0w
- 探索 HTTP 协议的世界 :https://juejin.cn/post/7356867483829583881
- 软件工程师需要了解的网络知识:从铜线到 HTTP:https://pphc.lvwenhan.com/tech-epic/2018/network-for-software-engineer
- Triple 协议性能调优报告:https://github.com/apache/dubbo/issues/10597
- 将近2万字的 Dubbo 原理解析:https://developer.aliyun.com/article/808571#slide-8
- grpc 四种通信模式及其应用场景选型:https://blog.csdn.net/inthat/article/details/118719020
- 一文看懂 DPDK:https://cloud.tencent.com/developer/article/1198333
- 详谈RDMA技术原理和三种实现方式:https://www.51cto.com/article/648715.html
- 深入理解 RDMA 的软硬件交互机制:https://mp.weixin.qq.com/s/mppfRPxGALSOWdP9vXplUg
- Linux内核的TCP协议栈和内核旁路的选择:https://www.cnblogs.com/huangfuyuan/p/9238437.html
- TCP/IP协议栈到底是内核态的好还是用户态的好?:https://blog.csdn.net/dog250/article/details/80532754
- TCP 的那些事儿(上):https://coolshell.cn/articles/11564.html
- TCP 的那些事儿(下):https://coolshell.cn/articles/11609.html
- Linux 系统网络收包流程:https://www.thebyte.com.cn/network/networking.html