写点什么

netty 系列之: 性能为王! 创建多路复用 http2 服务器

作者:程序那些事
  • 2021 年 12 月 08 日
  • 本文字数:1952 字

    阅读完需:约 6 分钟

netty系列之:性能为王!创建多路复用http2服务器

简介在之前的文章中,我们提到了在 netty 的客户端通过使用 Http2FrameCodec 和 Http2MultiplexHandler 可以支持多路复用,也就是说在一个连接的 channel 基础上创建多个子 channel,通过子 channel 来处理不同的 stream,从而达到多路复用的目的。


既然客户端可以做到多路复用,同样的服务器端也可以,今天给大家介绍一下如何在 netty 的服务器端打造一个支持 http2 协议的多路复用服务器。


多路复用的基础 netty 中对于 http2 多路复用的基础类是 Http2FrameCodec、Http2MultiplexHandler 和 Http2MultiplexCodec。


Http2FrameCodec 是将底层的 HTTP/2 frames 消息映射成为 netty 中的 Http2Frame 对象。


有了 Http2Frame 对象就可以通过 Http2MultiplexHandler 对新创建的 stream 开启不同的 channel。


Http2MultiplexCodec 是 Http2FrameCodec 和 Http2MultiplexHandler 的结合体,但是已经不再被推荐使用了。


因为 Http2FrameCodec 继承自 Http2ConnectionHandler,而 Http2MultiplexHandler 继承自 Http2ChannelDuplexHandler,所以这两个类可以同时在客户端和服务器端使用。


客户端使用 Http2FrameCodecBuilder.forClient().build()来获得 Http2FrameCodec,而服务器端通过 Http2FrameCodecBuilder.forServer().build()来获得 Http2FrameCodec。


多路复用在 server 端的使用配置 TLS 处理器对于服务器端,同样需要处理 TLS 和普通 clear text 两种情况。对于 TLS 来说,我们需要自建 ProtocolNegotiationHandler 继承自 ApplicationProtocolNegotiationHandler,然后实现 configurePipeline 方法,在其中分别处理 http2 和 http1.1 的连接:


protected void configurePipeline(ChannelHandlerContext ctx, String protocol) {    if (ApplicationProtocolNames.HTTP_2.equals(protocol)) {        //添加多路复用支持        ctx.pipeline().addLast(Http2FrameCodecBuilder.forServer().build());        ctx.pipeline().addLast(new Http2MultiplexHandler(new CustMultiplexHttp2Handler()));        return;    }
if (ApplicationProtocolNames.HTTP_1_1.equals(protocol)) { ctx.pipeline().addLast(new HttpServerCodec(), new HttpObjectAggregator(MAX_CONTENT_LENGTH), new CustHttp1Handler("ALPN Negotiation")); return; }
throw new IllegalStateException("未知协议: " + protocol);}
复制代码


首先添加 Http2FrameCodec,然后添加 Http2MultiplexHandler。因为 Http2MultiplexHandler 已经封装了多路复用的细节,所以自定义的 handler 只需要实现正常的消息处理逻辑即可。


因为 Http2FrameCodec 已经对消息进行了转换成为 HTTP2Frame 对象,所以只需要处理具体的 Frame 对象:


public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {    if (msg instanceof Http2HeadersFrame) {        onHeadersRead(ctx, (Http2HeadersFrame) msg);    } else if (msg instanceof Http2DataFrame) {        onDataRead(ctx, (Http2DataFrame) msg);    } else {        super.channelRead(ctx, msg);    }}
复制代码


配置 clear text upgrade 对于 h2c 的升级来说,需要向 pipline 中传入 sourceCodec 和 upgradeHandler 两个处理器。


sourceCodec 可以直接使用 HttpServerCodec。


upgradeHandler 可以使用 HttpServerUpgradeHandler。


HttpServerUpgradeHandler 的构造函数需要传入一个 sourceCodec 和一个 upgradeCodecFactory。


sourceCodec 我们已经有了,再构造一个 upgradeCodecFactory 即可:


private static final UpgradeCodecFactory upgradeCodecFactory = protocol -> {    if (AsciiString.contentEquals(Http2CodecUtil.HTTP_UPGRADE_PROTOCOL_NAME, protocol)) {        return new Http2ServerUpgradeCodec(                Http2FrameCodecBuilder.forServer().build(),                new Http2MultiplexHandler(new CustMultiplexHttp2Handler()));    } else {        return null;    }};
复制代码


从代码中可以看出,upgradeCodecFactory 内部又调用了 Http2FrameCodec 和 Http2MultiplexHandler。这和使用 TLS 的处理器是一致的。


    final ChannelPipeline p = ch.pipeline();    final HttpServerCodec sourceCodec = new HttpServerCodec();    p.addLast(sourceCodec);    p.addLast(new HttpServerUpgradeHandler(sourceCodec, upgradeCodecFactory));
复制代码


总结通过上述方式,就可以创建出支持多路复用的 http2 netty 服务器了。


本文的例子可以参考:learn-netty4


本文已收录于 http://www.flydean.com/33-netty-multiplex-http2server/


最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!


欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

发布于: 22 小时前阅读数: 18
用户头像

关注公众号:程序那些事,更多精彩等着你! 2020.06.07 加入

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧,尽在公众号:程序那些事!

评论

发布
暂无评论
netty系列之:性能为王!创建多路复用http2服务器