大家可以发现,Go越来越流行,在微服务方面,Go展示很大的优势性.随着微服务的兴起,现在越来越多的 rpc 框架 开始出现,前段时间自己学习搭建了一下 grpc ,在这里记录一下.

gRPC

grpc 是谷歌开源的rpc框架,基于http2实现,并支持跨语言,目前基本涵盖了主流语言.跨语言的实现主要得益于protobuf,通过编写proto文件,通过protobuf工具生成对应语言的类库进行使用.

gRPC 是什么?

在 gRPC 里客户端应用可以像调用本地对象一样直接调用另一台不同的机器上服务端应用的方法,使得您能够更容易地创建分布式应用和服务。与许多 RPC 系统类似,gRPC 也是基于以下理念:定义一个服务,指定其能够被远程调用的方法(包含参数和返回类型)。在服务端实现这个接口,并运行一个 gRPC 服务器来处理客户端调用。在客户端拥有一个存根能够像服务端一样的方法。
Golang 微服务 —— grpc

安装protobuf

方法一

  • brew安装protobuf
    安装brew
ruby -e "$(curl -fsSL  https://raw.githubusercontent.com/Homebrew/install/master/install)"
  • 使用brew安装protoc
brew install protobuf

方法二

  • 编译安装
    Github下载对应版本protobuf
https://github.com/google/protobuf/releases
  • 解压编译
tar -zxvf protobuf-3.7.1.tar.gz
cd protocbuf
./autogen.sh
./configure --prefix=/usr/local/protobuf
make
make install
  • 配置环境变量
sudo  vim .bash_profile
export PROTOBUF=/usr/local/protobuf
export PATH=$PROTOBUF/bin:$PATH
  • 测试安装结果
➜  ~ protoc --version
libprotoc 3.7.1

安装gRPC和protoc插件

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

grpc实践

编写一个user.proto文件

syntax = "proto3"; // 指定proto版本

package proto; // 指定包名

// The user service definition.
service User {
    // Sends a getUser request
    rpc GetUser (GetUserReq) returns (GetUserResp) {
    }
}

// The request message containing the user's id.
message GetUserReq {
    int64 userId = 1;
}

// The response message containing the user info
message GetUserResp {
    UserInfo user = 1;
}

message UserInfo {
    int64 userId = 1;
    string userName = 2;
    string userProfile = 3;
    int64 userAge = 4;
}

编译文件

在当前目录打开终端输入如下命令,自动生成 user.pb.go文件

protoc -I . --go_out=plugins=grpc:. ./user.proto

编写server

server.go

package main

import (
    "context"
    "google.golang.org/grpc"
    "google.golang.org/grpc/grpclog"
    "net"
    pb "sample/grpc/proto"
)

const (
    // Address gRPC服务地址
    Address = "127.0.0.1:50052"
)

// 定义userService并实现约定的接口
type UserService struct{}

// UserService ...
var userService = UserService{}

func (*UserService) GetUser(ctx context.Context, req *pb.GetUserReq) (*pb.GetUserResp, error) {
    userResp := new(pb.GetUserResp)
    if req.UserId != 0 {
        userInfo := new(pb.UserInfo)
        userInfo.UserId = 10001
        userInfo.UserName = "diycoder"
        userInfo.UserAge = 25
        userInfo.UserProfile = "https://avatars0.githubusercontent.com/u/10173558?s=460&v=4"
        userResp.User = userInfo
    }
    return userResp, nil
}

func main() {
    listen, err := net.Listen("tcp", Address)
    if err != nil {
        grpclog.Fatalf("failed to listen: %v", err)
    }

    // 实例化grpc Server
    s := grpc.NewServer()

    // 注册UserService
    pb.RegisterUserServer(s, &userService)
    grpclog.Println("Listen on " + Address)
    s.Serve(listen)
}

编写client

client.go

package main

import (
    "encoding/json"
    "fmt"
    "golang.org/x/net/context"
    "google.golang.org/grpc"
    "google.golang.org/grpc/grpclog"
    "log"
    pb "sample/grpc/proto" // 引入proto包
)

const (
    // Address gRPC服务地址
    Address = "127.0.0.1:50052"
)

func main() {
    // 连接
    conn, err := grpc.Dial(Address, grpc.WithInsecure())

    if err != nil {
        grpclog.Fatalln(err)
    }

    defer conn.Close()

    // 初始化客户端
    c := pb.NewUserClient(conn)

    // 调用方法
    reqBody := new(pb.GetUserReq)
    reqBody.UserId = 10001
    r, err := c.GetUser(context.Background(), reqBody)
    if err != nil {
        log.Fatalf("could not greet: %v", err)
    }
    bytes, err := json.Marshal(r.User)
    if err != nil {
        log.Fatal(fmt.Sprintf("json Marshal err = %v", err))
    }
    log.Printf("User: %s", string(bytes))
    grpclog.Println(string(bytes))
}

测试grpc

go run server.go 
go run client.go                                
2019/05/03 21:23:53 User: {"userId":10001,"userName":"diycoder","userProfile":"https://avatars0.githubusercontent.com/u/10173558?s=460\u0026v=4","userAge":25}

参考链接
gRPC
gRPC 官方文档中文版

文章目录