grpc的使用

原创内容,转载请注明出处

Posted by Weakyon Blog on November 10, 2016

一 安装

先安装protobuf的C库

然后安装protoc工具

go get -u github.com/golang/protobuf/proto

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

最后安装gRPC-go

go get google.golang.org/grpc

二 使用

首先写一个proto协议文件test.proto

syntax = "proto3";

package test;

service Test {
    rpc Ping(TestRequest) returns (TestResponse) {}
}

message TestRequest {
    string name = 1;
}

message TestResponse {
    string message = 1;
}

这里的name = 1,代表着协议中字段的顺序,当扩展字段后,该值不能变,否则会导致协议不一致

生成代码

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

编写服务端代码

  
package main

import (
        "google.golang.org/grpc"
        test "./test"
        "net"
        "golang.org/x/net/context"
)

type server struct{}

func (s *server) Ping(ctx context.Context, in *test.TestRequest) (*test.TestResponse, error) {
        return &test.TestResponse{Message: "Hello " + in.Name}, nil
}

func main() {
        lis, err := net.Listen("tcp","127.0.0.1:50051")
        if err != nil {
                return
        }
        s := grpc.NewServer()
        test.RegisterTestServer(s, &server{})
        s.Serve(lis)
}

编写客户端性能测试代码

  
package main

import (
        "google.golang.org/grpc"
        test "./test"
        "golang.org/x/net/context"
        "fmt"
        "time"
)

var count, lastcount int64

func main() {
        conn,err := grpc.Dial("127.0.0.1:50051",grpc.WithInsecure())
        if err != nil {
                fmt.Println(err)
                return
        }
        defer conn.Close()
        c := test.NewTestClient(conn)
        for i := 0;i != 100;i++ {
                go func() {
                        for ;; {
                                _, err := c.Ping(context.Background(), &test.TestRequest{Name: "cy"})
                                if err != nil {
                                        fmt.Println(err)
                                        return
                                }
                                count++
                        }
                }()
        }
        for ;; {
                lastcount = count
                time.Sleep(time.Second)
                fmt.Println(count - lastcount)
        }
}

扩展

这只是最简单的应用

实际的使用是需要扩展的,因为GRPC只能连接某个固定IP,所以实际使用的时候需要和etcd或者zookeeper结合封装

server端在etcd上注册服务路径

client端在etcd的服务路径上获取server的IP,选取其中一个来访问。

实际的使用可能是这样

//s中包含了grpc.Server
s = service.NewServer()
test.RegisterTestServer(s.grpcServer,&testServer{})
//用grpc监听端口,并且将IP端口注册在etcd的Path上
s.Listen("ip:port","etcdURL+Path")
//etcd的服务路径上获取server的IP,全部建立连接
s = service.NewClientManager("etcdURL+Path")
//随机获取一个conn来连接
c = test.NewTestClient(s.GetConn())
c.Test1(context.Background(),&test.TestRequest{})

还有更加复杂的情况

例如一个主从系统的实现

总结在下一篇博客好了

10 Nov 2016