远程过程调用系统gRPC

简介

  • gRPC 可以将 Protocol buffers 用作其接口定义语言 ( IDL ) 和底层消息交换格式(也可以使用其他的,例如json)

  • 远程调用,跨语言,更容易创建分布式应用和服务

    概念图

  • 和其他RPC一样,基于服务定义的思想,结合Protocol buffers+gRPC 插件,定义好服务后,服务端实现相应接口,客户端直接调用生成好的方法即可

主要使用场景

  • 低延迟、高度可扩展的分布式系统。
  • 开发与云服务器通信的移动客户端。
  • 设计一个需要准确、高效和语言独立的新协议。
  • 分层设计以实现扩展,例如。身份验证、负载平衡、日志记录和监控等。

核心概念

定义服务

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

message HelloRequest {
  string greeting = 1;
}

message HelloResponse {
  string reply = 1;
}

四种方式

  1. 简单rpc,就像正常调用函数一样

    rpc GetFeature(Point) returns (Feature) {}

流式rpc

解决的问题

  • 传输的数据太大,造成瞬时网络压力
  • 大数据需要接收完才能处理

分类

  1. 服务端流式rpc

    rpc ListFeatures(Rectangle) returns (stream Feature) {}

  2. 客户端流式rpc

    rpc RecordRoute(stream Point) returns (RouteSummary) {}

  3. 双向流式rpc

    rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}

    • 服务端收到请求后,不用等到读取完才响应,可以接收一点,响应一点,官网的原话是:服务器和客户端可以玩“乒乓”

具体介绍看官方文档,现在没用到这块

同步和异步

在 gRPC-Go 中,RPC 以阻塞/同步模式运行,这意味着 RPC 调用等待服务器响应,并且将返回响应或错误。

看来只能自己起goroutine了,但这样很麻烦,野生goroutine需要自己去维护异常处理和日志

设置超时

可主动终止RPC

示例

定义服务helloworld.proto

syntax = "proto3";

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

利用buf生成代码

  1. 执行buf mod init生成buf.yaml

  2. 配置buf,buf.gen.yaml

    # 配置protoc生成规则
    version: v1
    managed:
     enabled: true
     go_package_prefix:
     # proto文件中不使用option定义包名称,因为proto生成代码可以放在不同项目中使用,因此在buf.gen.yaml中进行定义
       default: helloworld
       except:
         - buf.build/googleapis/googleapis
    plugins:
     # 使用go插件生成go代码
     - name: go
       out: ./
       opt: paths=source_relative
     # 使用go-grpc插件生成grpc代码
     - name: go-grpc
       out: ./
       opt:
         - paths=source_relative
         - require_unimplemented_servers=false
    
  3. 执行buf generate 生成helloworld.pb.gohelloworld_grpc.pb.go

创建服务端

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
}
  • 继承生成的默认实现类
  • 重写实现接口方法

启动服务端

    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)
    }
  • 监听端口
  • 创建 gRPC 服务器的实例
  • 向 gRPC 服务器注册我们的服务实现
  • 调用Serve()服务器以进行阻塞等待,直到进程被杀死或被Stop()调用

创建客户端

    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())
  • 创建 gRPC通道来与服务器通信
  • 可以使用DialOptions在服务需要时设置身份验证凭据(例如,TLS、GCE 凭据或 JWT 凭据)
  • 创建客户端
  • 调用服务方法
作者:Yuyy
博客:https://yuyy.info
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇