• Grpc Quick Start 之协议分析


    技术介绍

    gRPC是由 google开发的一个高性能、通用的开源RPC框架,主要面向移动应用开发且基于HTTP/2协议标准而设计,同时支持大多数流行的编程语言。

    这里有几个关键词

    • google开发 大公司背景 相对于dubbo2 rpc框架,grpc提供了跨语言的调用 生态更加完整
    • HTTP/2 ,底层基于HTTP2进行数据通信,因此天然支持HTTP REST API 、GRPC接口调用转换

    Quick Start

    官网Example

    • 下载源码代码
    git clone https://github.com/grpc/grpc-go.git 
    
    • 1
    • 下载依赖
    // cd grcp-go
    go mod tidy
    
    • 1
    • 2
    • example 地址

    在这里插入图片描述

    如图,上面的代码案例 展示grpc的入门以及各种特性应用的demo,后面一个个学习下。今天学下下grpc入门级别的demo。代码谓语helloworld目录下

    服务端代码

    package main
    
    import (
    	"context"
    	"flag"
    	"fmt"
    	"log"
    	"net"
    	"google.golang.org/grpc"
    	pb "google.golang.org/grpc/examples/helloworld/helloworld"
    )
    
    var (
    	port = flag.Int("port", 50051, "The server port")
    )
    
    // server is used to implement helloworld.GreeterServer.
    type server struct {
    	pb.UnimplementedGreeterServer
    }
    
    // SayHello implements helloworld.GreeterServer
    func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
    	log.Printf("Received: %v", in.GetName())
    	return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
    }
    
    func main() {
    	flag.Parse()
    	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
    	if err != nil {
    		log.Fatalf("failed to listen: %v", err)
    	}
    	s := grpc.NewServer()
    	pb.RegisterGreeterServer(s, &server{})
    	log.Printf("server listening at %v", lis.Addr())
    	if err := s.Serve(lis); err != nil {
    		log.Fatalf("failed to serve: %v", err)
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    客户端代码

    package main
    
    import (
    	"context"
    	"flag"
    	"log"
    	"time"
    	"google.golang.org/grpc"
    	"google.golang.org/grpc/credentials/insecure"
    	pb "google.golang.org/grpc/examples/helloworld/helloworld"
    )
    
    const (
    	defaultName = "world"
    )
    
    var (
    	addr = flag.String("addr", "localhost:50051", "the address to connect to")
    	name = flag.String("name", defaultName, "Name to greet")
    )
    
    func main() {
    	flag.Parse()
    	// Set up a connection to the server.
    	conn, err := grpc.Dial(*addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
    	if err != nil {
    		log.Fatalf("did not connect: %v", err)
    	}
    	defer conn.Close()
    	c := pb.NewGreeterClient(conn)
    
    	// Contact the server and print out its response.
    	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    	defer cancel()
    	r, err := c.SayHello(ctx, &pb.HelloRequest{Name: *name})
    	if err != nil {
    		log.Fatalf("could not greet: %v", err)
    	}
    	log.Printf("Greeting: %s", r.GetMessage())
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    代码结构如下

    AndydeMacBook-Pro:helloworld andy$ tree
    .
    ├── greeter_client
    │   └── main.go
    ├── greeter_server
    │   └── main.go
    └── helloworld
        ├── helloworld.pb.go
        ├── helloworld.proto
        └── helloworld_grpc.pb.go
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    执行结果

    • 启动服务器
    • 启动客户端
    • 输出结果

    服务端:

    在这里插入图片描述

    客户端:

    在这里插入图片描述

    至此,一个简单的grpc远程调用执行完毕, 接下来使用抓包工具Wireshark 分析下如何利用http2进行数据通信,以及http2数据通信的一些细节。关于Wireshark抓包工具的安装这里不做介绍了。

    抓包分析

    抓包步骤

    选择网卡

    由于Quick Start的demo只是在本机做远程调用,因此选择 loopback 回环网卡,双击进入

    在这里插入图片描述

    过滤参数

    为了防止其他数据的干扰,过滤来源、目标端口为50051的数据即可。过滤参数为:tcp.dstport50051 or tcp.srcport50051。并重新启动客户端

    在这里插入图片描述

    如上图,已经抓到了一次grpc调用的完整的数据包,只是上述的数据偏向底层,无法直观的进行分析,幸运的是wireshark支持HTTP2协议,只需要选择合适的编码就可以让数据展示更加直观。

    选择HTTP2编码
    • 选中任一数据行,右键选择编码

    在这里插入图片描述

    • 选择HTTP2编码

    在这里插入图片描述

    • 展示最终结果

    在这里插入图片描述

    协议分析

    在这里插入图片描述

    结论:

    1. HTTP2 在TCP链接的基础上多了几次数据交互的过程

    2. 在GRPC中 所有的请求默认都转换为HTTP POST请求

    3. POST请求中的URI对应为protobuf文件中定义/package/class/method

      在这里插入图片描述

    4. 一次HTTP请求 将header、body分开发送

    ERROR vs HTTP STATUS CODE

    GRPC异常 与 HTTP状态码对应关系如下:

    HTTP Status CodeGRPC Status Code
    400 Bad RequestINTERNAL
    401 UnauthorizedUNAUTHENTICATED
    403 ForbiddenPERMISSION_DENIED
    404 Not FoundUNIMPLEMENTED
    429 Too Many RequestsUNAVAILABLE
    502 Bad GatewayUNAVAILABLE
    503 Service UnavailableUNAVAILABLE
    504 Gateway TimeoutUNAVAILABLE
    All other codesUNKNOWN

    最佳性能实践

    摘自官方文档:

    • 尽可能的重用利用Channel
    • 保持HTTP2底层TCP连接处于活跃状态,即利用心跳检测保持长链接(即C++通道参数 GRPC_arg_keepalive_TIME_MS)
    • 客户端、服务端双向通信使用 streaming RPC
    • 每个gRPC通道使用0个或更多HTTP/2连接,并且每个连接通常对并发流的数量有限制。当连接上的活动RPC数达到此限制时,其他RPC将在客户端中排队,并且必须等待活动RPC完成后才能发送。具有高负载或长寿命流式RPC的应用程序可能会因为这种排队而出现性能问题。有两种可能的解决方案
      • 每个高负载区域创建独立的Channel通道
      • 使用 gRPC 连接池
  • 相关阅读:
    windows10系统下指定用户配置FTP服务器及多用户登录
    Centos7安装GBase8a V9.5
    微信小程序毕业设计题目计算机维修服务+后台管理系统|前后分离VUE.js
    誉天学员笔记:数通HCIE专题之VLAN&交换机高级特性
    并发编程基础底层原理学习(二)
    原来你是这样的JAVA--[07]聊聊Integer和BigDecimal
    Greenplum数据库外部表——Scan执行节点
    本地部署 ChatTTS
    二、【React脚手架】组件化编码(TodoList案例)
    Tomcat
  • 原文地址:https://blog.csdn.net/u013433591/article/details/127710771