汽车数据流参照表,汽车数据流口诀

首页 > 机动车 > 作者:YD1662023-10-30 13:20:04

图2-21 对比HTTP/1.1和HTTP/2的访问性能

我们都知道,在HTTP/1.x的协议中,浏览器在同一时间对同一域名下的请求数量是有限制的,这会导致大量并发请求阻塞,这个问题也被称为线端阻塞(head-of-line blocking)。同一域名下浏览器支持的连接数,如表2-4所示。HTTP/1.1对不同浏览器连接数的限制不同,很多互联网公司为了解决这个问题,做了大量优化,包括建立多域名,通过CDN缓存大量静态资源等。

HTTP/2是基于二进制协议的,与HTTP/1.x这样的文本协议相比,显然二进制协议性能更高。另外HTTP/2使用报头压缩,降低了网络开销。HTTP/2将HTTP协议通信分解为二进制编码帧的交换,这些帧对应着特定数据流中的消息。所有这些消息都在一个TCP连接内复用,这就是HTTP/2的多路复用机制(Multiplexing)。Benjamin在2015年写的一篇文章中描述了一个简单的例子,如果只请求3个资源,从Web页面开始渲染到加载结束,HTTP/2比HTTP/1.1节省不少时间,如图2-22所示。

汽车数据流参照表,汽车数据流口诀(13)

表2-4 同一域名下浏览器支持的连接数

汽车数据流参照表,汽车数据流口诀(14)

图2-22 HTTP/1.1和HTTP/2调用流程对比


HTTP/2完全兼容HTTP/1.1的语义,HTTP/2和HTTP/1.1的大部分高级语法(例如方法、状态码、头字段和URI)都是相同的。

HTTP/1.1如果要实现长连接,需要设置Connection:keep-alive来控制长连接时间,超时就断开TCP连接。只有在客户端发起请求的时候,服务器端才会响应。所以就算一直给服务器发送心跳包以维持长连接,也不能用来推送,只有客户端不断发起请求给服务器端,服务器才会响应,这就是pull轮询的方式。

HTTP/2引入服务端推送模式,即服务端向客户端发送数据,如图2-23所示。服务器可以对一个客户端请求发送多个响应,HTTP/2打破了严格的请求-响应语义,支持一次请求-多次响应的形式。由于现如今的Web界面丰富多彩,加载的资源往往非常多,服务端实际上已经知道要推送什么内容,但HTTP/1.x的语义只支持客户端发起请求、服务端响应数据。HTTP/2改变了这种模式,只需要客户端发送一次请求,服务端便把所有的资源都推送到客户端。服务器推送的缺点是,在客户端已经缓存了资源的情况下可能会有冗余。这个问题可以通过服务器提示(Server Hint)解决。

汽车数据流参照表,汽车数据流口诀(15)

图2-23 HTTP/2推送模式

HTTP/2和Protobuf的组合——gRPC

gRPC源于被称为Stubby的Google内部项目,Google内部大量使用Stubby进行服务间通信。作为gRPC的前身,Stubby大量依赖Google的其他基础服务,所以不太方便开放出来给社区使用。随着HTTP/2的逐步成熟,2015年初Google开源了gRPC框架。截至2017年12月,gRPC已经发布了1.7.3版本,并且被CNCF(云原生计算基金会)所收录。gRPC在ETCD/Kubernetes上得到了大量使用。

gRPC是基于HTTP/2设计的,因此也继承了HTTP/2相应的诸多特性,这些特性使得其在移动设备上表现得更好,更节省空间、更省电。gRPC目前提供的C、Java和Go语言版本分别是grpc、grpc-java、grpc-go,其中C版本支持C、C 、Node.js、Python、Ruby、Objective-C、PHP和C#。

说了这么多,gRPC到底能够给我们提供哪些优势呢?

· gRPC默认使用Protobuf进行序列化和反序列化,而Protobuf是已经被证明的高效的序列化方式,因此,gRPC的序列化性能是可以得到保障的。

· gRPC默认采用HTTP/2进行传输。HTTP/2支持流(streaming),在批量发送数据的场景下使用流可以显著提升性能——服务端和客户端在接收数据的时候,可以不必等所有的消息全收到后才开始响应,而是在接收到第一条消息的时候就可以及时响应。例如,客户端向服务端发送了一千条update消息,服务端不必等到所有消息接收完毕才开始处理,而是一边接收一边处理。这显然比以前的类HTTP 1.1的方式提供的响应更快、性能更优。gRPC的流可以分为三类:客户端流式发送、服务器流式返回,以及客户端/服务器同时流式处理,也就是单向流和双向流。在我写这本书的时候,Dubbo 3.0正在酝酿中,其中一个显著的变化是新版本将以streaming为内核,而不再是2.0时代的RPC,目的是去掉一切阻塞。

· 基于HTTP/2协议很容易实现负载均衡及流控的方案,可以利用Header做很多事情。

同时,gRPC也不是完美的。相比于非IDL描述的RPC(例如Hession、Kyro)方式,定义proto文件是一个比较麻烦的事情,而且需要额外安装客户端、插件等。另外HTTP/2相比于基于TCP的通信协议,性能上也有显著的差距。

下面通过一个简单的例子来理解一下gRPC的使用方式。假设我们要开发电商中的产品服务,通过id获取产品的信息,主要步骤及实现代码如下。

(1)定义proto文件。

syntax = "proto3";//声明支持的版本是proto3 option java_multiple_files = true;//以外部类模式生成 option java_package = "com.cloudnative.grpc";//声明包名,可选 option java_outer_classname="ProductProtos";//声明类名,可选 message ProductRequest{ int32 id = 1; } message ProductResponse { int32 id = 1; string name = 2; string price = 3; } service ProductService{ rpc GetProduct(ProductRequest) returns(ProductResponse); }

(2)生成相关类。可以采用Protobuf中介绍的方法,在命令行执行protoc生成相关代码。如果使用Maven,则可以通过Maven插件实现。

<build> <extensions> <extension> <groupId>kr.motd.maven</groupId> <artifactId>os-maven-plugin</artifactId> <version>1.5.0.Final</version> </extension> </extensions> <plugins> <plugin> <groupId>org.xolstice.maven.plugins</groupId> <artifactId>protobuf-maven-plugin</artifactId> <version>0.5.0</version> <configuration> <protocArtifact>com.google.protobuf:3.5.1:exe:${os.detected.classifier} </protocArtifact> <pluginId>grpc-java</pluginId> <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.8.0:exe:${os.detected. classifier}</pluginArtifact> <protocExecutable>/usr/local/bin/protoc</protocExecutable> </configuration> <executions> <execution> <goals> <goal>compile</goal> <goal>compile-custom</goal> </goals> </execution> </executions> </plugin> </plugins> </build>

在pom.xml中配置,并且执行mvn compile命令会在target/generated-sources中生成相关类,可以将相关类移到src /main/java目录下备用。

(3)服务端实现代码。一是,实现ProductService。

public class ProductService extends ProductServiceGrpc.ProductServiceImplBase{ private static final Logger logger = Logger.getLogger(GRPCServer.class.getName()); @Override public void getProduct(ProductRequest request, StreamObserver<ProductResponse> responseObserver) { logger.info("接收到客户端的信息:" request.getId()); ProductResponse responsed; if (111==request.getId()){ responsed=ProductResponse.newBuilder().setId(111).setName ("dddd").build(); }else { responsed=ProductResponse.newBuilder().setId(0).setName("---").build(); } responseObserver.onNext(responsed); responseObserver.onCompleted(); } }

二是,实现server代码。

public class GRPCServer{ private static final Logger logger = Logger.getLogger(GRPCServer.class.getName()); private final int port; private final Server server; public GRPCServer(int port){ this.port=port; this.server = ServerBuilder.forPort(port) .addService(new ProductService()) .build(); } /** Start serving requests. */ public void start() throws IOException { this.server.start(); logger.info("Server started, listening on " port); Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { // Use stderr here since the logger may has been reset by its JVM shutdown hook. logger.info("*** shutting down gRPC server since JVM is shutting down"); GRPCServer.this.stop(); logger.info("*** server shut down"); } }); } /** Stop serving requests and shutdown resources. */ public void stop() { if (server != null) { server.shutdown(); } } /** * Await termination on the main thread since the grpc library uses daemon threads. */ private void blockUntilShutdown() throws InterruptedException { if (server != null) { server.awaitTermination(); } } /** * Main method. This comment makes the linter happy. */ public static void main(String[] args) throws Exception { GRPCServer server = new GRPCServer(8888); server.start(); server.blockUntilShutdown(); } }

(4)客户端实现代码。

public class GRPCClient { private static final Logger logger = Logger.getLogger(GRPCServer.class.getName()); public static void main(String[] args) { ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 8888) .usePlaintext(true) .build(); ProductServiceGrpc.ProductServiceBlockingStub blockStub=ProductServiceGrpc.newBlockingStub(channel); ProductResponse response=blockStub.getProduct(ProductRequest.newBuilder().setId(111).build()); logger.info(response.getName()); response=blockStub.getProduct(ProductRequest.newBuilder().setId(2).build()); logger.info(response.getName()); } }

上面是一个简单的实现,关于流式RPC可以参考官方的例子。

来源 公众号 技术琐话 | 王启军

如有侵权请联系删除

上一页1234末页

栏目热文

文档排行

本站推荐

Copyright © 2018 - 2021 www.yd166.com., All Rights Reserved.