跟着dubbo3.x学习HTTP/2用JAVA如何实现

HTTP/2介绍

  下面关于HTTP/2的理论参考摘抄于《HTTP/2 协议抓包实战》

HTTP/1.1的问题

  1. 没有充分利用TCP连接资源
    1.1 TCP协议是一个全双工协议,但在HTTP/1.1为一问一答的半双工形式
    (1)HTTP/1.1使用TCP协议中的Keep Alive属性复用现有TCP连接(一问一答)
    (2)HTTP/1.0每次请求都断开TCP连接

    1.2 如果页面需要多个资源,而浏览器限制同域名下的请求并发度,所以通过多线程提高并发不可取 在这里插入图片描述

  2. 头部与公参数据所占用的巨大比例
    2.1 HTTP/1.1 的无状态特性带来的巨大 HTTP 头部与公参,这些数据很可能在用户的使用过程中是不会发生变化

HTTP/2怎样解决问题

  1. 访问该网站:http2.akamai.com/demo ,对 HTTP/2 相较于 HTTP/1.1 速度的提升有一个直观的感受
    1.1 在 HTTP/1.1 请求过程中,浏览器共使用 6 个并发 TCP 链接请求图片数据(符合上文中的提到 Chrome 并发度为 6 的限制)
    1.2 HTTP/2 中因为使用了多路复用,仅在一个 TCP 连接上传输数据,但其传输速度仍然有明显的提高
    在这里插入图片描述
  2. 头部压缩(HPACK算法:有状态 -> 问题2)
    2.1 在客户端和服务器端存储Header的Key-Value数据,下次使用该数据只需要传索引号
    2.2 对整数和字符串采用哈夫曼编码(或ASCII 编码)来进一步压缩
  3. HTTP/2采用二进制的消息格式
    3.1 用HEADERS存放头数据、DATA帧存放请求正文数据
    3.2 每个在HTTP/2连接有其内唯一的一个ID标志(多路复用 -->问题1)
    (1)一个流为一个二进制的双向传输通道
    (2)同一个消息的所有往返帧都处于唯一的流中,在里面传输一系列有先后顺序的数据帧 在这里插入图片描述

Dubbo如何实现的

  1. 《dubbo3.x消费端源码浅析以及Triple协议的实现》中有介绍dubbo Triple协议的实现的地方,下面我们就来了解具体如何实现的
  2. 我们来看一下TripleHttp2Protocol是如何配置pipeline的?
    2.1 通过Http2FrameCodec将HTTP/2的frames解码为Http2Frame对象,并进行pipeline传播
    2.2 TripleServerConnectionHandler只对Ping帧和GoAway帧处理,其他帧都直接进行pipeline传播
    2.3 Http2MultiplexHandler是一个混合处理器,将多个handler添加到pipeline中
    在这里插入图片描述
  3. Http2MultiplexHandler中重点关注TripleHttp2FrameServerHandler、GrpcDataDecoder、TripleServerInboundHandler
    3.1 TripleHttp2FrameServerHandler处理Headers帧和Data帧处理
    3.2 GrpcDataDecoder:如果有压缩标志,则进行相应的解压缩
    3.3 TripleServerInboundHandler:将数据放入serverStream

TripleHttp2FrameServerHandler

  1. 处理Headers帧:TripleHttp2FrameServerHandler#onHeadersRead
    1.1 为invoker的url创建一个UnaryServerStream
    1.2 将UnaryServerStream绑定channel的tri_server_stream属性中(方便后面的handler获取)
    final AbstractServerStream stream = AbstractServerStream.newServerStream(invoker.getUrl(), isUnary);
    stream.service(providerModel.getServiceModel())
            .invoker(invoker)
            .methodName(methodName)
            .setDeCompressor(deCompressor)
            .subscribe(transportObserver);
    channel.attr(TripleConstant.SERVER_STREAM_KEY).set(stream);
    
  2. 处理Data帧:TripleHttp2FrameServerHandler#onDataRead
    2.1 将msg传递给pipeline中的其他handler
    2.2 所有handler处理完后,调用serverStream的完成方法(详细见下面)
     public void onDataRead(ChannelHandlerContext ctx, Http2DataFrame msg) throws Exception {
        super.channelRead(ctx, msg.content());
    
        if (msg.isEndStream()) {
            final AbstractServerStream serverStream = ctx.channel().attr(TripleConstant.SERVER_STREAM_KEY).get();
            if (serverStream != null) {
            	// 在TripleServerInboundHandler中会调用serverStream.inboundTransportObserver().onData(data,false)将数据放入serverStream中
                serverStream.inboundTransportObserver().onComplete();
            }
        }
    }
    

UnaryServerStream的onComplete方法

  1. 将调用任务丢给SerializingExecutor线程池执行
  2. 调用方法在UnaryServerStream$UnaryServerTransportObserver#invoke
    public void invoke() {
    	//使用头元数据构建RpcInvocation并执行headerFilter
    	RpcInvocation invocation = buildUnaryInvocation(getHeaders(), getData());
    	// 对data数据进行序列化 ->unpack方法最终会调用SingleProtobufUtils#deserialize进行反序列化
    	inv.setArguments(new Object[]{unpack(data, getMethodDescriptor().getParameterClasses()[0])});
    	// FilterChainBuilder$CallbackRegistrationInvoker#invoke 使用过滤器链直到调用业务服务方法
    	final Result result = getInvoker().invoke(invocation);
    }
    

束语

  1. 本篇文章通过HTTP1的问题来介绍HTTP2是如何解决的,然后看看Dubbo是如何实现HTTP2服务的
  2. 写完本篇博客后,虽然对HTTP2有了进一步的认识,但心里又有其他疑惑(UnaryServerStream和HTTP2的虚拟流是同一个东西吗?关于头部压缩的具体实现没看到)。有序篇幅原因,留到下一篇文章继续分析吧
    在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值