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}
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文件中参数类型好像必须是自定义类型,而不能是简单的文本类型
并且这个接口的实现需要由服务端实现,然后提供给客户端,供其使用