gRPC初体验

gRPC是由Google主导开发的RPC框架,使用HTTP/2协议并用ProtoBuf作为序列化工具。其客户端提供Objective-C、Java接口,服务器侧则有Java、Golang、C++等接口,从而为移动端(iOS/Androi)到服务器端通讯提供了一种解决方案。 当然在当下的环境下,这种解决方案更热门的方式是RESTFull API接口。该方式需要自己去选择编码方式、服务器架构、自己搭建框架(JSON-RPC)。gRPC官方对REST的声音是:

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

至于是否要选择用gRPC。对于已经有一套方案的团队,可以参考下。如果是从头来做,可以考虑下gRPC提供的从客户端到服务器的整套解决方案,这样不用客户端去实现http的请求会话,JSON等的解析,服务器端也有现成的框架用。从15年3月到现在gRPC也发展了一年了,慢慢趋于成熟。下面我们就以gRPC的Golang版本看下其在golang上面的表现。至于服务端的RPC,感觉golang标准库的RPC框架基本够用了,没必要再去用另一套方案。

1. 安装protobuf

虽然gRPC也支持protobuf2.x,但是建议还是使用protobuf3.x,尽管还没有正式版本,不过golang版本基本没有什么问题,另外3.x官方支持了Objective-C,这也是我们使用gRPC的初衷:提供一个移动端到服务器的解决方案。去到Protocol Buffers下载最新版本(Version3.0.0 beta2),然后解压到本地。本地需要已经安装好autoconf automake libtool.rpm系列(fedora/centos/redheat)可以用yum安装。Mac上可以用brew进行安装

brew install autoconf automake libtool

然后执行

./configure --prefix=your_pb_install_path

接着

make 
make install
set your_pb_install_path to your $PATH

检查是否安装完成

protoc --version
libprotoc 3.0.0

然后安装golang protobuf直接使用golang的get即可

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

2. 安装gRPC-go

gRPC-go可以通过golang 的get命令直接安装,非常方便。

go get google.golang.org/grpc

这里大家可能比较奇怪,为什么gRPC-go在github的地址是"https://github.com/grpc/grpc-go",但是为什么要用“google.golang.org/grpc”进行安装呢?应该grpc原本是google内部的项目,归属golang,就放在了google.golang.org下面了,后来对外开放,又将其迁移到github上面了,又因为golang比较坑爹的import路径规则,所以就都没有改路径名了。

但是这样就有个问题了。要如何去管理版本呢?这个目前我还没有什么比较好的方法,希望知道的朋友一起分享下。目前想到一个方法是手动下载某个版本,然后写个脚本统一修改代码中的import里面的路径.

3. 示例程序

3.1 protobuf

该示例源自gRPC-go的examples的helloworld。先看PB的描述:

syntax = "proto3";

option objc_class_prefix = "HLW";

package helloworld;

// The greeting 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;
}

这里定义了一个服务Greeter,其中有个API SayHello。其接受参数为HelloRequest类型,返回HelloReply类型。这里HelloRequestHelloReply就是普通的PB定义

服务定义为:

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

service定义了一个server。其中的接口可以是四种类型

  • rpc GetFeature(Point) returns (Feature) {}
    类似普通的函数调用,客户端发送请求Point到服务器,服务器返回相应Feature.
  • rpc ListFeatures(Rectangle) returns (stream Feature) {}
    客户端发起一次请求,服务器端返回一个流式数据,比如一个数组中的逐个元素
  • rpc RecordRoute(stream Point) returns (RouteSummary) {}
    客户端发起的请求是一个流式的数据,比如数组中的逐个元素,服务器返回一个相应
  • rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
    客户端发起的请求是一个流式数据,比如数组中的逐个元素,二服务器返回的也是一个类似的数据结构

后面三种可以参考官方的route_guide示例。

使用protoc命令生成相关文件:

protoc --go_out=plugins=grpc:. helloworld.proto
ls
helloworld.pb.go    helloworld.proto

生成对应的pb.go文件。这里用了plugins选项,提供对grpc的支持,否则不会生成Service的接口。

3.2 服务器端程序

然后编辑服务器端程序:

package main

import (
    "log"
    "net"

    pb "your_path_to_gen_pb_dir/helloworld"
    "golang.org/x/net/context"
    "google.golang.org/grpc"
)

const (
    port = ":50051"
)

// 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", port)
    if err != nil {
        log.Fatalf("failed to listen: %v", err)
    }
    s := grpc.NewServer()
    pb.RegisterGreeterServer(s, &server{})
    s.Serve(lis)
}

这里首先定义一个server结构,然后实现SayHello的接口,其定义在“your_path_to_gen_pb_dir/helloworld”

SayHello(context.Context, *HelloRequest) (*HelloReply, error)

然后调用grpc.NewServer() 创建一个server s。接着注册这个server s到结构server上面 pb.RegisterGreeterServer(s, &server{}) 最后将创建的net.Listener传给s.Serve()。就可以开始监听并服务了,类似HTTP的ListenAndServe。

3.3 客户端程序

客户端程序:

package main

import (
    "log"
    "os"

    pb "your_path_to_gen_pb_dir/helloworld"
    "golang.org/x/net/context"
    "google.golang.org/grpc"
)

const (
    address     = "localhost:50051"
    defaultName = "world"
)

func main() {
    // Set up a connection to the server.
    conn, err := grpc.Dial(address, grpc.WithInsecure())
    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.
    name := defaultName
    if len(os.Args) > 1 {
        name = os.Args[1]
    }
    r, err := c.SayHello(context.Background(), &pb.HelloRequest{Name: name})
    if err != nil {
        log.Fatalf("could not greet: %v", err)
    }
    log.Printf("Greeting: %s", r.Message)
}

这里通过pb.NewGreeterClient()传入一个conn创建一个client,然后直接调用client上面对应的服务器的接口

SayHello(context.Context, *HelloRequest) (*HelloReply, error)

接口,返回*HelloReply 对象。

先运行服务器,在运行客户端,可以看到。

./greeter_server &

./greeter_client
2016/03/10 21:42:19 Greeting: Hello world
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • 1)简介 gRPC负载平衡的主要实现机制是外部负载平衡,即通过外部负载平衡器来向客户端提供更新后的服务器列表。 g...
    Jay_Guo阅读 13,220评论 6 22
  • 主要基于官网介绍的文档总结而来。 需要先了解 protocol buffers 为什么使用gRPC 通过gPRC,...
    kingeasternsun阅读 3,634评论 1 4
  • GRPC是基于protocol buffers3.0协议的. 本文将向您介绍gRPC和protocol buffe...
    二月_春风阅读 17,973评论 2 28
  • 1.先总后分理清思路 “领导,因为王经理上午出差去了,他要出差2天;然后小李家中有事,他要休假一天;赵主任恰巧下午...
    咿呀作语阅读 265评论 2 5