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的资料请关注脚本之家其它相关文章!

相关文章

  • 一文详解go同步协程的必备工具WaitGroup

    一文详解go同步协程的必备工具WaitGroup

    这篇文章主要为大家介绍了一文详解go同步协程的必备工具WaitGroup使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • 教你用go语言实现比特币交易功能(Transaction)

    教你用go语言实现比特币交易功能(Transaction)

    每一笔比特币交易都会创造输出,输出都会被区块链记录下来。给某个人发送比特币,实际上意味着创造新的 UTXO 并注册到那个人的地址,可以为他所用,今天通过本文给大家分享go语言实现比特币交易功能,一起看看吧
    2021-05-05
  • Go语言定时任务cron的设计与使用

    Go语言定时任务cron的设计与使用

    这篇文章主要为大家详细介绍了Go语言中定时任务cron的设计与使用,文中的示例代码讲解详细,对我们深入掌握Go语言有一定的帮助,需要的可以参考下
    2023-11-11
  • goland 清除所有的默认设置操作

    goland 清除所有的默认设置操作

    这篇文章主要介绍了goland 清除所有的默认设置操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04
  • Go语言数据结构之插入排序示例详解

    Go语言数据结构之插入排序示例详解

    这篇文章主要为大家介绍了Go语言数据结构之插入排序示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • golang(gin)的全局统一异常处理方式,并统一返回json

    golang(gin)的全局统一异常处理方式,并统一返回json

    这篇文章主要介绍了golang(gin)的全局统一异常处理方式,并统一返回json,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • GoLang OS包以及File类型详细讲解

    GoLang OS包以及File类型详细讲解

    go中对文件和目录的操作主要集中在os包中,下面对go中用到的对文件和目录的操作,做一个总结笔记。在go中的文件和目录涉及到两种类型,一个是type File struct,另一个是type Fileinfo interface
    2023-03-03
  • 一文详解Go语言中Mutex互斥锁

    一文详解Go语言中Mutex互斥锁

    Golang中的Mutex互斥锁是一种常用的并发控制机制,用于保护共享资源的访问,在本文中,我们将深入探讨Mutex互斥锁的原理、日常使用、锁结构以及运行机制,需要的朋友可以参考下
    2023-12-12
  • golang接口的正确用法分享

    golang接口的正确用法分享

    这篇文章主要介绍了golang接口的正确用法分享的相关资料,需要的朋友可以参考下
    2023-09-09
  • Golang语言如何高效拼接字符串详解

    Golang语言如何高效拼接字符串详解

    最近在做性能优化,有个函数里面的耗时特别长,看里面的操作大多是一些字符串拼接的操作,而字符串拼接在 golang 里面其实有很多种实现,下面这篇文章主要给大家介绍了关于Golang语言如何高效拼接字符串的相关资料,需要的朋友可以参考下
    2021-11-11

最新评论