3

gRPC简介

 1 year ago
source link: https://blog.p2hp.com/archives/11189
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

gRPC(Remote Procedure Calls)

GRPC是一个高性能、通用的开源RPC框架,基于底层HTTP/2协议标准协议层Protobuf序列化协议开发,支持众多的开发语言。

gRPC 也是基于以下理念:定义一个服务,指定其能够被远程调用的方法(包含参数和返回类型)。在服务端实现这个接口,并运行一个 gRPC服务器来处理客户端调用。在客户端拥有一个存根能够像服务端一样的方法。

gRPC使用protocol buffers作为接口描述语言(IDL)以及底层的信息交换格式


  1. 基于 HTTP/2 之上的二进制协议(Protobuf 序列化机制);
  2. 一个连接上可以多路复用,并发处理多个请求和响应;
  3. 多种语言的类库实现;
  4. 服务定义文件和自动代码生成(.proto 文件和 Protobuf 编译工具)。
  5. RPC 还提供了很多扩展点,用于对框架进行功能定制和扩展,例如,通过开放负载均衡接口可以无缝的与第三方组件进行集成对接(Zookeeper、域名解析服务、SLB 服务等)

https://www.colabug.com/4616436.html


Simple RPC

简单rpc ,这就是一般的rpc调用,一个请求对象对应一个返回对象

proto语法:

rpc simpleHello(Person) returns (Result) {}
Server-side streaming RPC

服务端流式rpc,一个请求对象,服务端可以传回多个结果对象

proto语法:

rpc serverStreamHello(Person) returns (stream Result) {}
Client-side streaming RPC

客户端流式rpc 客户端传入多个请求对象,服务端返回一个响应结果

proto语法:

rpc clientStreamHello(stream Person) returns (Result) {}
Bidirectional streaming RPC

双向流式rpc,结合客户端流式rpc和服务端流式rpc,可以传入多个对象,返回多个响应对象

proto语法:

rpc biStreamHello(stream Person) returns (stream Result) {}

golang版本的grpc要求go版本要在1.6以上

install gRPC

使用go get命令安装grpc

$ go get -u google.golang.org/grpc

由于某些不可逆原因,上面命令会报连接超时,可以到github上将项目clone$GOPATH/src/google.golang.org/

$ cd $GOPATH/src/google.golang.org
$ git clone [email protected]:grpc/grpc-go.git grpc
install Protocol Buffers v3
$ apt install protobuf-compiler
install protoc plugin

安装golang版本对应的protobuf生成工具

$ go get -u github.com/golang/protobuf/protoc-gen-go

运行demo

进入example目录

$ cd $GOPATH/src/google.golang.org/grpc/examples/helloworld

删除原来的helloworld.pb.go文件,并使用protoc生成自己生成一个

$ rm helloworld/helloworld.pb.go // 删除原来的helloworld.pb.go文件
$ protoc -I helloworld/ helloworld/helloworld.proto --go_out=plugins=grpc:helloworld // 根据 .proto 文件生成对应的.go文件

编写grpc接口时,在.proto文件定义接口通信数据格式和接口信息,然后通过protoc自动生成对应的go代码,大大方便了开发

  • -I PATH:specify the directory in which to search for imports. May be specified multiple times; directories will be searched in order. If not given, the current working directory is used.
  • --go_out:指定输出go代码
  • plugins=grpc.proto中的servicegrpc扩展的功能,需要使用grpc插件进行解析才能生成对应的接口定义代码。

运行 grpc servergrpc client

$ go run greeter_server/main.go // 启动grpc server
$ go run greeter_client/main.go // 启动grpc client

如果helloworld下面没有greeter_server和greeter_client文件夹执行下列两种其中一种命令

$ go get -u google.golang.org/grpc/examples/helloworld/greeter_client
$ go get -u google.golang.org/grpc/examples/helloworld/greeter_server
$ go get -u google.golang.org/grpc

开发一个求和的grpc接口

定义.proto文件

proto目录下创建接口描述文件sum.proto文件:

Message命名采用驼峰命名方式,字段命名采用小写字母加下划线分隔方式
Enums类型名采用驼峰命名方式,字段命名采用大写字母加下划线分隔方式
即便业务上不需要参数也必须指定一个请求消息,一般会定义一个空message。

syntax = "proto3"; // 使用 proto3,没写默认proto2。建议grpc配合proto3使用,兼容性更高

// java生成选项
option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";

package proto; // 生成的go所属的package

// 需要序列化的结构体
message SumResp {
    int64 sum = 1;
}

message SumReq {
    int64 a = 1;
    int64 b = 2;
}

service CalcSvc {
    // 每个rpc接口声明都必须有且一个参数和一个返回值
    rpc Sum(SumReq) returns (SumResp) {}
}
根据接口描述文件生成源码

进入proto目录,执行

$ protoc sum.proto --go_out=plugins=grpc:.

可以看到,在本目录下生成sum.pb.go文件,且packageproto

开发服务端接口

首先查看生成的sum.pb.go文件,可以看到根据sum.proto文件中的CalcSvc接口定义生成了对应的接口:

// CalcSvcServer is the server API for CalcSvc service.
type CalcSvcServer interface {
    // 每个rpc接口声明都必须有且一个参数和一个返回值
    Sum(context.Context, *SumReq) (*SumResp, error)
}

开发服务端接口只要就是根据这些接口定义实现具体的业务逻辑

在项目下创建service/main.go

package main

import (
    "context"
    "google.golang.org/grpc"
    "google.golang.org/grpc/reflection"
    "grpc-demo/proto" //路径可能不同,看自己的proto包放在哪个目录下
    "log"
    "net"
)

// 类型断言
var _ proto.CalcSvcServer = new(CalcSvc)

type CalcSvc struct{}

func (CalcSvc) Sum(ctx context.Context, req *proto.SumReq) (resp *proto.SumResp, err error) {
    // 建议使用GetA,不要直接使用req.A,可能存在req=nil的情况
    a := req.GetA() 
    b := req.GetB()
    log.Println("request coming ...")
    return &proto.SumResp{
        Sum: a + b,
    }, err
}

func main() {
    lis, err := net.Listen("tcp", ":8888")
    if err != nil {
        log.Fatal(err)
    }
    // 注册服务到gRPC
    s := grpc.NewServer()
    proto.RegisterCalcSvcServer(s, &CalcSvc{})
    // 启用Server Reflection,可以使用gRPC CLI去检查services
    // https://github.com/grpc/grpc-go/blob/master/Documentation/server-reflection-tutorial.md
    reflection.Register(s)
    // 启动服务
    if err := s.Serve(lis); err != nil {
        log.Fatal(err)
    }
}
客户端访问

在项目下创建client/main.go

package main

import (
    "context"
    "google.golang.org/grpc"
    "grpc-demo/proto" //路径可能不同,看自己的proto包放在哪个目录下
    "log"
)

func main() {
    // 创建gRPC连接
    // WithInsecure option 指定不启用认证功能
    conn, err := grpc.Dial(":8888", grpc.WithInsecure())
    if err != nil {
        log.Fatal(err)
    }
    // 创建gRPC client
    client := proto.NewCalcSvcClient(conn)
    // 请求gRPC server
    resp, err := client.Sum(context.Background(), &proto.SumReq{
        A: 5,
        B: 10,
    })
    if err != nil {
        log.Fatal(err)
    }
    log.Printf("5 + 10 = %d", resp.GetSum())
}
$ go run service/main.go &
$ go run client/main.go

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK