关注 grpc 很久了,终于今天看见nginx 即将原生支持grpc后,在go里,跑起了第一个 hello world

Google主导开发的RPC框架,用HTTP/2协议,用ProtoBuf序列化

多种语言client/server,为移动端(iOS/Android)到server 端通讯提供了一种解决方案

RESTFull API接口需要自己去选择编码方式、服务器架构、自己搭建框架(JSON-RPC)

gRPC官方对REST的声音:

  • 和REST一样遵循HTTP协议(HTTP/2),但是gRPC提供了全双工流
  • 和传统的REST不同的是gRPC使用了静态路径,从而提高性能
  • 用一些格式化的错误码代替了HTTP的状态码更好的标示错误

是否用gRPC?

已经有一套方案的团队,可以参考下

从头做,可以考虑下gRPC提供的从客户端到服务器的整套解决方案,这样不用客户端去实现http的请求会话,JSON等的解析,服务器端也有现成的框架用

安装

先装好protoc命令 ,可以用yum apt,win 就直接下载解压github里的release二进制

go get -u github.com/golang/protobuf/proto // golang protobuf 库
go get -u github.com/golang/protobuf/protoc-gen-go //protoc --go_out 工具
go get -u google.golang.org/grpc

可选
//gogo
go get -u github.com/gogo/protobuf/protoc-gen-gogo
//gofast
go get -u github.com/gogo/protobuf/protoc-gen-gofast

protoc命令、protoc-gen-go命令、grpc-go包

  • protoc

命令来自 https://github.com/google/protobuf

用来生成 pb 以下语言的序列/反序列化代码

  --cpp_out=OUT_DIR           Generate C++ header and source.

  --csharp_out=OUT_DIR        Generate C# source file.

  --java_out=OUT_DIR          Generate Java source file.

  --javanano_out=OUT_DIR      Generate Java Nano source file.

  --js_out=OUT_DIR            Generate JavaScript source.

  --objc_out=OUT_DIR          Generate Objective C header and source.

  --php_out=OUT_DIR           Generate PHP source file.

  --python_out=OUT_DIR        Generate Python source file.

  --ruby_out=OUT_DIR          Generate Ruby source file.

  • protoc-gen-go、protoc-gen-gogo、protoc-gen-gofast

protoc能生成那么多语言的代码,但居然本身没有产生go的代码,需要调用如protoc-gen-go这样的插件!!!

protoc-gen-go 来自 https://github.com/golang/protobuf

注意protoc和protoc-gen-go在github的路径,一个是 google一个是golang

  • grpc-go

https://github.com/grpc/grpc-go 这里的代码对应的包名是: google.golang.org/grpc 这里只是一些公共函数库

protoc 和 protoc-gen-go 这两个工具都不在这里

gRPC-go在github的地址是 https://github.com/grpc/grpc-go,但是为什么要用google.golang.org/grpc进行安装?

grpc原是google内部项目,归属golang,放在google.golang.org下,后来对外开放,又迁移到github,golang比较坑爹的import路径规则,就没有改路径名

安装小总结

go里运行grpc,一般安装4个东西,protoc和三个go get的东西

protoc-gen-gogo和protoc-gen-gofast可选

#protoc –go_out=plugins=grpc

protoc --go_out=. message.proto

产生的只是 protobuffer 文件序列化和反序列化的代码

protoc --go_out=plugins=grpc:. message.proto

第二个产生的则除了第一个的代码外,还增加服务器和客户端通讯、实现的公共库代码

gogoprotobuf

gogoprotobuf完全兼容google protobuf,主要在goprotobuf之上extend了一些option

可以修饰field/enum/message/package(即对整个文件都有效)

protoc --gofast_out=plugins=grpc:. my.proto

demo

message.pb

syntax = "proto3";

package pb;

// The greeter service definition.
service Greeter {
// Sends a greeting
    rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
string name = 1;
}

// The response message containing the greetings
message HelloReply {
string message = 1;
}
D:\workspace\go\grpc\src\ddatsh.com\pb>protoc --go_out=plugins=grpc:. message.pb

server

package main

import (
    "net"
    "log"
    "google.golang.org/grpc"
    "ddatsh.com/pb"
    "context"
)

// server is used to implement helloworld.GreeterServer.
type server struct{}

// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
    return &pb.HelloReply{Message: "Hello " + in.Name}, nil
}

func main() {
    lis, err := net.Listen("tcp", ":50051")
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }
    s := grpc.NewServer()
    pb.RegisterGreeterServer(s, &server{})
    s.Serve(lis)
}

client

package main

import (
    "google.golang.org/grpc"
    "log"
    "ddatsh.com/pb"
    "context"
)

func main() {
    conn, err := grpc.Dial("localhost:50051",grpc.WithInsecure())
    if err != nil {
        log.Fatalf("did not connect: %v", err)
    }
    defer conn.Close()
    c := pb.NewGreeterClient(conn)
    r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: "dd"})
    if err != nil {
        log.Fatalf("could not greet: %v", err)
    }
    log.Printf("Greeting: %s", r.Message)
}

gRPC HTTP协议转换

coreos的博客,转载到了grpc官方博客gRPC with REST and Open APIs

etcd3改用grpc后为了兼容原来的api,同时要提供http/json方式的API

为满足这需求,要么开发两套API,要么实现一种转换机制,他们选择了后者

协议转换的网关grpc-gateway,接收客户端请求,然后决定直接转发给grpc服务还是转给http服务,当然,http服务也需要请求grpc服务获取响应,然后转为json响应给客户端