Go语言与gRPC的完美结合实战演练

 更新时间:2024年01月18日 09:03:38   作者:Go先锋  
这篇文章主要介绍了Go语言与gRPC的完美结合实战演练,gRPC(Remote Procedure Call)是一种远程过程调用技术,通过压缩和序列化数据来优化网络通信,可以显著提高服务调用的性能和效率

gRPC 的概念

gRPC 是一个高性能、通用的开源 RPC 框架,是一个由 Google 主导开发的 RPC 框架。其以 HTTP/2 为基础通信协议,支持多种语言,通过 protocol buffers 数据格式来实现服务之间的调用。

gRPC 使用 protocol buffers 来实现服务定义和数据序列化。Protocol buffers 是由 Google 开发的数据描述语言,跨平台、跨语言支持良好,性能好、版本兼容性高。

gRPC 框架包含了服务端和客户端两部分。服务端实现 gRPC 服务接口,客户端通过 stub 来调用远程服务。

gRPC 的优势

  • 基于 HTTP/2 设计,性能高,可扩展性强
  • 支持流式传输,低延迟
  • 支持跨语言调用
  • 支持双向流式通信
  • 支持服务发现及负载均衡
  • Protobuf 格式高效便捷

gRPC 适用场景

  • 需要高性能、低延迟的服务通信
  • 要实现异构系统、不同语言间的调用
  • 需要流式数据处理的场景
  • 微服务架构下服务间的通信

gRPC 架构

gRPC 基于 HTTP/2 协议设计,采用 Protocol Buffers 机制序列化结构化数据,主要包含以下组件:

  • Stub:客户端调用 gRPC 服务的接口
  • gRPC Server:实现 gRPC 服务逻辑的服务器
  • Channel:抽象连接,实现 Socket 级别连接及 RPC 交互
  • Protocol Buffers:服务接口描述语言和数据序列化机制

在服务器端通过 Protobuf 接口实现服务,客户端通过 Stub 完成远程调用。

gRPC 通信流程

gRPC 通信流程主要包括:

  • 客户端调用 Stub 接口
  • Stub 序列化参数为 Protobuf 数据
  • 数据通过 HTTP/2 协议发送给服务器
  • 服务器获取请求数据并反序列化
  • 服务器处理请求并序列化返回结果
  • 通过 HTTP/2 返回序列化后的数据
  • 客户端获取响应数据并反序列化

Protobuf 数据格式

Protocol Buffer (Protobuf) 是谷歌推出的一种轻便高效的数据序列化格式,主要用于促进数据在网络间高效传输。

Protobuf 的数据格式主要特点:

  • 跨平台、语言中立
  • 版本兼容
  • 体积小,serialize 后数据大小只有 XML 的 1/10 到 1/3
  • 序列化/反序列化速度快

Protobuf 通过.proto 文件定义数据结构,然后使用 protoc 编译器生成各目标语言的数据访问类。

gRPC 方法的定义

在 .proto 文件中可以定义服务接口和方法

service HelloService {
  rpc SayHello (HelloRequest) returns (HelloResponse);
}

方法可以指定请求参数消息类型和返回值消息类型。

gRPC 服务的实现

Go 语言中实现 gRPC 服务的步骤:

  • 定义服务实现结构体
  • 在结构体中实现服务接口方法
  • 创建 gRPC 服务器
  • 用服务器注册服务

示例:

type HelloServiceImpl struct{}
func (p *HelloServiceImpl) SayHello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloResponse, error) {
   // 方法实现
}
func main() {
  server := grpc.NewServer()
  pb.RegisterMessageServiceServer(server, &HelloServiceImpl{})
  server.Serve(lis)
}

gRPC 客户端调用

Go 语言 gRPC 客户端调用主要分为三步:

  • 建立到 gRPC 服务器的连接
  • 通过连接新建客户端 stub 实例
  • 使用 stub 调用远程服务方法

示例:

conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
client := pb.NewHelloServiceClient(conn)
resp, err := client.SayHello(ctx, req) 

gRPC 高级用法

1. 流式 RPC

gRPC 支持流式 RPC 调用,分为四种类型:

  • 单向流式:客户端流式,只有请求是流
  • 单向流式:服务器流式,只有响应是流
  • 双向流式:客户端和服务器端都可以是流

在 proto 文件中使用 stream 关键字定义:

rpc ClientStream(stream HelloRequest) returns (HelloResponse);
rpc ServerStream(HelloRequest) returns (stream HelloResponse); 
rpc Bidirectional(stream HelloRequest) returns (stream HelloResponse);

2. 证书和认证

gRPC 支持 SSL/TLS 安全传输及各种身份认证方式:

  • SSL/TLS 传输级安全保障
  • 支持基于证书、Token 和 AWS IAM 等认证手段

3. 错误处理

gRPC 框架定义了状态码和错误模型,客户端可以根据状态码判断 RPC 调用是否成功:

  • OK:调用成功
  • Cancelled:调用被取消
  • Unknown:未知错误
  • InvalidArgument:参数无效
  • DeadlineExceeded:超时错误等

4. 超时和取消

gRPC 支持请求级别的超时控制,通过 Context 指定超时时间,还可以通过 Context 取消正在执行的 RPC。

5. gRPC 拦截器

gRPC 支持在服务器端和客户端使用拦截器(Interceptor)拦截请求:

  • 客户端拦截器:拦截出站请求及响应
  • 服务端拦截器:拦截入站请求及响应

主要用于日志记录、监控等功能。

6. gRPC 元数据

gRPC 通过自定义元数据提供请求上下文等附加信息。可以在请求和响应中设置和获取元数据。

7. gRPC 路由

gRPC 支持按服务方法特征进行请求路由,路由选择不同的后端服务。主要通过 gRPC intestine 实现。

8. 和 HTTP/2 的对比

功能点gRPCHTTP/2
连接方式persistent connectionpersistent connection
数据格式ProtobufJSON
数据压缩支持不支持
流式传输支持不支持
IDL 接口定义支持不支持

gRPC 实践案例

1. 简单 RPC 服务端与客户端

简单的 gRPC Server 端和 Client 端示例,演示基本的 RPC 服务开发、注册和调用流程。

// server
   type Server struct{}
   func (s *Server) SayHello(ctx context.Context, in *pb.StringRequest) (*pb.StringReply, error) {
     return &pb.StringReply{Value: "Hello " + in.Value}, nil
   }
   func main() {
     grpcServer := grpc.NewServer()
     pb.RegisterMessageServiceServer(grpcServer, &Server{})
     grpcServer.Serve(lis) 
   }
   // client
   conn, _ := grpc.Dial("localhost:1234", grpc.WithInsecure())
   client := pb.NewStringServiceClient(conn)
   reply, _ := client.SayHello(context.Background(), &pb.StringRequest{Value: "world"})
   fmt.Println(reply.Value)

2. 带参数验证的 RPC 服务

示例在 gRPC 服务中实现参数校验逻辑,如果参数名称不符合规范,将返回错误。

  // server
   type Server struct{}
   func (s *Server) SayHello(ctx context.Context, in *pb.StringRequest) (*pb.StringReply, error) {
       if ok := validate(in.Value); !ok {
           return nil, status.Error(codes.InvalidArgument, "Invalid parameter")
       }
       return &pb.StringReply{Value: "Hello " + in.Value}, nil 
   }
   // client
   r, err := client.SayHello(context.Background(), &pb.StringRequest{Value: "World!"})
   if err != nil {
     //错误处理 
   }
   

通过状态码和错误信息,客户端可以明确判断是什么原因导致的调用异常。

3. 客户端、服务端流 RPC

示例实现了客户端流式 RPC 和服务器流式 RPC。客户端可以通过流方式连续发送多个请求,服务器端可以返回流式的响应。

// server
   type Server struct { }
   func (s *Server) ClientStream
   (stream pb.StringService_ClientStreamServer) error {
       for {
           in, err := stream.Recv()
           // 处理
           stream.SendAndClose(&pb.StringReply{})
       } 
   }
   // client
   stream, _ := client.ClientStream(context.Background()) 
   for {
       stream.Send(&pb.StringRequest{}) 
   }
   reply, _ := stream.CloseAndRecv() 

4. 双向流 RPC

下面演示了如何使用 gRPC 完成双向流 RPC 的编码实现。客户端和服务器端都可以独立地通过流发送多个请求或响应。

// server
type Server struct{} 
func (s *Server) Bidirectional(
      stream pb.StringService_BidirectionalServer) error
   { 
    for {
        in, err := stream.Recv()
        if err != io.EOF {
         // 处理请求
         stream.Send(&pb.StringReply{})
        }
     }
   }
   // client
   stream, _ := client.Bidirectional(context.Background())
   go func() {
     for {
       stream.Send(&pb.StringRequest{})
     } 
   }()
   for {
     reply, err := stream.Recv()
     if err != nil {
       break
     } 
   }

总结

通过实践表明,Go 语言结合 gRPC 框架可以方便高效地实现各类 RPC 服务。gRPC 优化了网络资源利用效率,支持复杂数据交互模式,整体提高了分布式服务架构的性能。

gRPC 的优点包括高效、跨平台、流式传输等。但也存在需要应用 HTTP/2 特性的学习成本,以及被限制在 Protobuf 生态内等问题。

随着云原生技术体系的逐步完善, gRPC 在微服务和 Service Mesh 体系中的地位日益突出,它的重要性会持续提升。预计 gRPC 会越来越多地用于云原生基础设施的打造。

以上就是Go语言与gRPC的完美结合实战演练的详细内容,更多关于Go语言gRPC的资料请关注脚本之家其它相关文章!

相关文章

  • Golang实现四种负载均衡的算法(随机,轮询等)

    Golang实现四种负载均衡的算法(随机,轮询等)

    本文介绍了示例介绍了Golang 负载均衡的四种实现,主要包括了随机,轮询,加权轮询负载,一致性hash,感兴趣的小伙伴们可以参考一下
    2021-06-06
  • go内存缓存BigCache之Entry封装源码阅读

    go内存缓存BigCache之Entry封装源码阅读

    这篇文章主要介绍了go内存缓存BigCache之Entry封装源码阅读
    2023-09-09
  • Go语言sync.Cond基本使用及原理示例详解

    Go语言sync.Cond基本使用及原理示例详解

    这篇文章主要为大家介绍了Go语言sync.Cond基本使用及原理示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • Golang中channel的原理解读(推荐)

    Golang中channel的原理解读(推荐)

    channel主要是为了实现go的并发特性,用于并发通信的,也就是在不同的协程单元goroutine之间同步通信。接下来通过本文给大家介绍Golang中channel的原理解读,感兴趣的朋友一起看看吧
    2021-10-10
  • Go 代码生成工具详解

    Go 代码生成工具详解

    这篇文章主要介绍了Go 代码生成工具详解,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-03-03
  • Golang指针的操作以及常用的指针函数

    Golang指针的操作以及常用的指针函数

    本文主要介绍了Golang指针的操作以及常用的指针函数,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-05-05
  • golang配置文件解析器之goconfig框架的使用详解

    golang配置文件解析器之goconfig框架的使用详解

    goconfig是一个易于使用,支持注释的 Go 语言配置文件解析器,该文件的书写格式和 Windows 下的 INI 文件一样,本文主要为大家介绍了goconfig框架的具体使用,需要的可以参考下
    2023-11-11
  • 使用Go中的Web3库进行区块链开发的案例

    使用Go中的Web3库进行区块链开发的案例

    区块链作为一种分布式账本技术,在近年来取得了巨大的发展,而Golang作为一种高效、并发性强的编程语言,被广泛用于区块链开发中,本文将介绍如何使用Golang中的Web3库进行区块链开发,并提供一些实际案例,需要的朋友可以参考下
    2023-10-10
  • go mod 依赖管理的具体使用

    go mod 依赖管理的具体使用

    在Go语言开发中,依赖管理是一项非常重要的工作,Go mod作为官方的包管理工具已经成为了Go语言依赖管理的首选方式,本文就来介绍一下go mod 依赖管理的具体使用,具有一定的参考价值,感兴趣的可以了解一下
    2024-01-01
  • GoLang中的加密方法小结

    GoLang中的加密方法小结

    这篇文章主要介绍了GoLang中的加密方法。具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02

最新评论