问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

快速上手gRPC与protobuf:从入门到实战

创作时间:
作者:
@小白创作中心

快速上手gRPC与protobuf:从入门到实战

引用
CSDN
1.
https://blog.csdn.net/theaipower/article/details/145710643

gRPC是一种高性能、开源和通用的RPC框架,它基于HTTP/2协议标准设计,支持多种编程语言。而protobuf是一种数据序列化协议,用于在不同系统之间传输数据。本文将从微服务架构出发,介绍gRPC和protobuf的基本概念,并通过一个具体的实例,帮助读者快速上手gRPC和protobuf的开发。

一、微服务

在微服务架构出现之前,传统的单体架构存在诸多问题:一旦某个服务宕机,可能会导致整个应用无法使用;资源伸缩性差,只能整体应用进行伸缩;代码耦合度高,可维护性差。

微服务架构通过将应用拆分为多个小型服务,每个服务独立运行,可以独立部署和扩展。所有请求通过网关进行路由,可以将公共功能集中到网关或单独的服务中,如统一认证中心。

在微服务架构中,服务之间通过网络进行调用,需要使用RPC(远程过程调用)协议。为了提高传输效率,通常会使用自定义协议进行TCP调用。同时,由于服务可能分布在多台机器上,还需要引入服务治理,包括服务发现、服务容错和链路追踪等功能。

二、gRPC介绍

gRPC是一个语言和平台无关的开源RPC框架,支持多种语言的客户端和服务端交互。它默认使用Protocol Buffers作为数据序列化协议,可以将数据结构转换为二进制格式进行传输,具有高效、紧凑的特点。

序列化与反序列化

  • 序列化:将数据结构或对象转换成二进制串的过程。
  • 反序列化:将在序列化过程中所产生的二进制串转换成数据结构或对象的过程。

三、protobuf

protobuf是Google开源的一种数据序列化协议,具有以下特点:

  • 二进制格式:需要编码和解码,本身不具有可读性。
  • 传输效率高:序列化后的数据比JSON和XML更小,适合网络传输。
  • 跨平台支持:支持多种编程语言。
  • 快速的序列化和反序列化:性能优于JSON和XML。

protobuf编译器安装

  1. 下载protobuf编译器(protoc):
  1. 安装Go专用的protobuf生成器:
    go install github.com/golang/protobuf/protoc-gen-go@latest
    

protobuf文件编写

创建一个简单的protobuf文件(user.proto):

syntax = "proto3";
option go_package = "../service";
package service;

message User {
  string username = 1;
  int32 age = 2;
}

使用protobuf编译器生成Go代码:

protoc --go_out=./ .\user.proto

protobuf使用示例

在Go中使用protobuf进行序列化和反序列化:

package main

import (
    "fmt"
    "google.golang.org/protobuf/proto"
    "protobuflearn/service"
)

func main() {
    user := &service.User{
        Username: "zhou",
        Age:      18,
    }

    // 序列化
    marshal, err := proto.Marshal(user)
    if err != nil {
        panic(err)
    }

    // 反序列化
    newUser := &service.User{}
    err = proto.Unmarshal(marshal, newUser)
    if err != nil {
        panic(err)
    }

    fmt.Println(newUser.String())
}

protobuf文件结构

  • message:定义消息类型,类似于C++中的class或Go中的struct。
  • 字段选项:可以使用required(默认)、optionalrepeated来定义字段属性。

消息嵌套

可以定义多个消息类型,并进行嵌套:

message UserInfo {
  repeated User info = 1;
}

定义服务

可以在protobuf文件中定义RPC服务:

service SearchService {
  rpc Search (SearchRequest) returns (SearchResponse);
}

四、gRPC实例

gRPC基于HTTP/2协议,支持流式传输和双向流式调用。下面通过一个简单的商品库存查询服务来演示gRPC的使用。

服务端实现

  1. 定义protobuf文件(product.proto):

    syntax = "proto3";
    option go_package = "../service";
    package service;
    
    message ProductRequest {
      int32 prod_id = 1;
    }
    
    message ProductResponse {
      int32 prod_stock = 1;
    }
    
    service ProdService {
      rpc GetProductStock(ProductRequest) returns (ProductResponse);
    }
    
  2. 生成Go代码:

    protoc --go_out=plugins=grpc:./ .\product.proto
    
  3. 实现服务端逻辑(product.go):

    package service
    
    import "context"
    
    var ProductService = &productService{}
    
    type productService struct{}
    
    func (p *productService) GetProductStock(ctx context.Context, request *ProductRequest) (*ProductResponse, error) {
      stock := p.GetStockById(request.ProdId)
      return &ProductResponse{ProdStock: stock}, nil
    }
    
    func (p *productService) GetStockById(id int32) int32 {
      return 100
    }
    
  4. 编写服务端主程序:

    package main
    
    import (
      "log"
      "net"
    
      "google.golang.org/grpc"
      "protobuflearn/service"
    )
    
    func main() {
      rpcServer := grpc.NewServer()
      service.RegisterProdServiceServer(rpcServer, service.ProductService)
    
      listener, err := net.Listen("tcp", ":8002")
      if err != nil {
        log.Fatalf("net.Listen err: %v", err)
      }
    
      rpcServer.Serve(listener)
    }
    

客户端实现

  1. 编写客户端代码:
    package client
    
    import (
      "context"
      "fmt"
      "log"
    
      "google.golang.org/grpc"
      "google.golang.org/grpc/credentials/insecure"
      "protobuflearn/client/service"
    )
    
    func main() {
      conn, err := grpc.Dial(":8002", grpc.WithTransportCredentials(insecure.NewCredentials()))
      if err != nil {
        log.Fatalf("服务端出错,连接不上: %v", err)
      }
      defer conn.Close()
    
      productServiceClient := service.NewProdServiceClient(conn)
      request := &service.ProductRequest{
        ProdId: 123,
      }
    
      resp, err := productServiceClient.GetProductStock(context.Background(), request)
      if err != nil {
        log.Fatal("调用gRPC方法错误: ", err)
      }
    
      fmt.Println("调用gRPC方法成功,ProdStock = ", resp.ProdStock)
    }
    

通过以上步骤,你已经完成了一个简单的gRPC服务的开发。希望这篇文章能帮助你快速入门gRPC和protobuf的开发。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号