gRPC和protobuf学习

gRPC || protobuf

2018-11-12		
	17:52 更:
		开发流程应该是这样的,服务间通过gRPC约定的proto传输数据,而与前端联合则是通过json/xml来通信
	18:44更:
	通过gRPC,添加了一个demo,服务间通过proto,而与前端交互则采用JSON,[底层服务接口](https://github.com/ItsFunny/go_dlxy_micro/blob/master/server/article-server/api/service/impl/ArticleRPCServiceImpl.go)
	[上层服务调用接口](https://github.com/ItsFunny/go_dlxy_micro/blob/master/system/admin-system/controller/ArticleController/ArticleController.go)
	orm层贼像Java的jdbc,肯定有框架,但先不学了,都差不多..不足的话就是gRPC第一次接触,有点陌生,以及命名格式还是习惯照着Java的命名格式来命名,另外,未涉及lb

安装:
如果已经安装了proto和protoc-gen-go的话就不用安装了
go get -u github.com/golang/protobuf/{proto,protoc-gen-go}

下载grpc-go
git clone https://github.com/grpc/grpc-go.git $GOPATH/src/google.golang.org/grpc

下载golang/net
git clone https://github.com/golang/net.git $GOPATH/src/golang.org/x/net

#下载golang/text
git clone https://github.com/golang/text.git $GOPATH/src/golang.org/x/text

#下载go-genproto
git clone https://github.com/google/go-genproto.git $GOPATH/src/google.golang.org/genproto
#安装
cd $GOPATH/src/ 也可以一步一步cd ,然后install
go install google.golang.org/grpc

部分总结:
2018-11-08
.proto的编写与Go类似也与Java类似,与Go类似在于 简单的通过message 类名{} 即可,与Java类似在于定义成员变量的方式:string age =1; 而不像Go一样省略分号,类型放后面
为了提供服务,server端必须做以下这2个步骤:1.定义一个struct类型 2.struct类型实现开放的服务接口(这个是需要注册到服务中的类,与SpringCloud不同,但是应该是与Dubbo类似的,SC是基于C,而Dubbo是基于字节码技术)
所以可以总结为大致以下流程
1.先定义一个实现类 (当然可以拥有各种members)
2.实现这个接口(并且遵循SRP)
3.通过grpc.NerServer()获取server之后,通过protoc 编译插件生成的pb.go文件,注册对应的服务,如:
dto.RegisterToUpperServer(server,&ServceImpl{})
4.通过反射:reflection.Register(server) //具体未看源码,现在看源码对我而言太早了
5.最后监听端口即可:server.Serve(listen)
20018-11-08
10:09
什么是gRPC:
  gRPC:高性能,开源的RPC框架,基于HTTP2.0,gRPC目前仅支持protobuf,至于protobuf可以认为是一种通信协议,类似于JSON,XML,但是呢性能更高,并且可以容纳JSON,XML.
  至于具体实现其实类似于Java 阿里的dubbo,都是本地通过reflect调用远程服务,但是我Java用的是SpringCloud体系 …-.- ,不过还好也能慢慢对照着学
  感谢自己对Java花了这么多时间,花费了这么多的精力,学未知的东西,喜欢对照着学,gRPC也可以通过SpringCloud借鉴一二,语言互通
  SprngCloud 服务的调用通过ribbon 实现loadbalance,然后为了方便,开放了一个轮子叫Feign,通过feign 服务A就可以直接开放服务接口(当然SpringCloud使用的是rest的形式),只需要使用@FeignClient 便提供了接口,然后内部的功能与Controller中一一对应
   而gRPC服务的定义是通过protobuf来定义的,下面举一个simple example:
结合offical doc 吧:
1.首先定义一个消息类型: 查询的bo定义

syntax = "proto3";	//表明这是proto3语法,参考JDK1,2,3,4,5,6,7,8,9,10这些玩意

message SearchRequest {
  string query = 1;	//查询的语句
  int32 page_number = 2;	//pageNum 
  int32 result_per_page = 3;	//pageSize 每页显示多少条记录
}
我们发现每个成员变量都有一个unique number {1,2,3} 这是干啥的?
protobuf用二进制传输,而这些数字就是为了标识二进制的(既通过这些数字找到对应的信息),并且友情提示:常用的字段用1-15来标识(因为只会消耗1byte),而16-2047用2个byte,但是注意不能使用19000-19999,因为是其本身所使用的(类似于Java中的native,本地的)

并且protobuf成员变量有其规则:singular 和repeated  ,,字面翻译就是单个和可重复,repeated引申就是Java中的List,可以存放多个值,并且proto3会按序排列,但是注意如果删除某个字段,然后使用的是老版本的.proto的时候可能会发生冲突

并且,单个.proto文件中可以设置多个对象(Java中就是class,而Go中则是struct)

message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
}

message SearchResponse {
 ...
}

定义好之后,我们就可以通过proto compile进行编译生成对应的文件,go 是pd.go文件,Java则是.java,毫无疑问
但是:存在默认值这个概念,protobuf 编译后无法告知是设置了值还是没有设置值,而至于默认值.是依据不同的类型对应不同的默认值,如stirng 对象"" bool 对应false,而repeated 则是empty list

protobuf中的枚举:

message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 result_per_page = 3;
  enum Corpus {
    UNIVERSAL = 0;
    WEB = 1;
    IMAGES = 2;
    LOCAL = 3;
    NEWS = 4;
    PRODUCTS = 5;
    VIDEO = 6;
  }
  Corpus corpus = 4;
}
几个注意点,enum 必须定义一个常量,并且首位必须为0
可以定义多个enum,但是可能会存在重名的情况,所以protobuf提供了几个关键字:option allow_alias=true 这样就可以定义重复字段了

对象中引用其他的对象

message SearchResponse {
  repeated Result results = 1;
}

message Result {
  string url = 1;
  string title = 2;
  repeated string snippets = 3;
}
当编译结束之后,生成的go文件是一个[]*string slice

可能遇到的情况:
1):当引用message B的时候B中存在于A相同的成员变量 ----这点跳过,是通过import 来避免的 ,没实现过,所以先跳过

嵌套类

message SearchResponse {
  message Result {
    string url = 1;
    string title = 2;
    repeated string snippets = 3;
  }
  repeated Result results = 1;
}

几个注意点:
1):嵌套类我将他与Java中的内部类做相似比较,当然static这点不知道protobuf有没有,内部类可以被外部类(非parent)所使用:

message OtherMessage{ repeated SearchResponse.Result result}

protobuf doc 内容太多了,慢慢看吧

gRpc
gRPC是基于protobuf 的,那么protobuf又如何rpc的呢,其实类似于Java 阿里的Dubbo,都是通过reflect 实现的,

protobuf的service type:
方法很简单,只需要声明方法名称,参数和返回值类型即可:

service SearchService {
  rpc Search (SearchRequest) returns (SearchResponse);	//这个函数表明这是一个rpc函数,参数类型为SearchRequest
  返回类型是SearchResponse
}

官网上也给出了意见:
The most straightforward RPC system to use with protocol buffers is gRPC: a language- and platform-neutral open source RPC system developed at Google. gRPC works particularly well with protocol buffers and lets you generate the relevant RPC code directly from your .proto files using a special protocol buffer compiler plugin.
通过protocol buffer compiler plugin 生成相关的rpc代码

个人理解,与SC想比较:
SC通过Feign来开放接口,每个FeignClient都是interfaces(fallback除外),那我可以认为gRPC也是,但是不同的是我们需要实现这些service,举个例子
A服务需要调用B服务开放的接口serviceB
SC:

		@FeignClient public class BserverFeignService { 
			@GetMapping("/test")public String serviceB(){...}
		}
gRPC:(以下所有皆是个人见解,毕竟才学Go20天左右)
	需要定义一个proto,并且应该是每个需要开放的接口的某种类型的服务,如用户服务内部有权限,用户信息操作等服务,则分别需要定义2个.proto,体现SRP
	当然在这个情况下先直接单个.proto即可:
message ServerB{
}
service IUserService {
    rpc serviceB (ServerB) returns (ServerB);
}
在写的时候发现,就是.proto文件中参数类型好像必须是自定义类型,而不能是简单的文本类型

并且这个接口的实现需要由服务端实现,然后提供给客户端,供其使用

你可能感兴趣的:(Go)