Golang

关注公众号 jb51net

关闭
首页 > 脚本专栏 > Golang > Go语言gRPC

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

作者: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 的优势

gRPC 适用场景

gRPC 架构

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

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

gRPC 通信流程

gRPC 通信流程主要包括:

Protobuf 数据格式

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

Protobuf 的数据格式主要特点:

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

gRPC 方法的定义

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

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

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

gRPC 服务的实现

Go 语言中实现 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 客户端调用主要分为三步:

示例:

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 安全传输及各种身份认证方式:

3. 错误处理

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

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

您可能感兴趣的文章:
阅读全文