开始食用grpc(之一)
开始食用grpc(之一)
转载请注明出处:https://www.cnblogs.com/funnyzpc/p/9501353.html
```
记一次和一锅们压马路,路过一咖啡厅(某巴克),随口就问随行的锅门:你能从那咖啡厅看到什么?
当时的那家某巴克处于闹市,也正值周末,屋外屋内喝咖啡的人几近乎十分的安静,使用电脑的,刷手机的、做作业的。。。而且大都是年轻人和中年人。
锅门撂了句:一群屌丝呗 (;¬_¬)
。。。白了他一眼(¬_¬)
( ...其实想教唆他进去看看美女,歇歇脚来着 ๑乛◡乛๑ )
.......
许久之后,也就是最近看到诗人余秀华的一句话后忽有所感,原句是:
“反正是背负慢慢凋残的孤独,耀眼的孤独,义无反顾的孤独”
这才明白他们是在消费孤独,也为孤独所消费; 他们是,周围的人是,还有 ( ∙̆ .̯ ∙̆ )
那~ 孤独的结果是什么呢 ?
```
这次讲下大系统通讯必备的一项组件:rpc,rpc有很多 如 dubbo、thirft、feign、motan、grpc 等~,这其中有字符串方式的也有二进制流方式的;整体来说二进制方式的一般会较字符串方式的快许多,字符形式的的慢,但是简单;而二进制方式的 序列化和跨平台较为麻烦些;我个人选取rpc时一般综合考虑一下几点:
A>传输方式是否是二进制
B>是否长期支持
C>是否支持跨平台,开源组件是否丰富
C+>是否支持异步调用
D>有无明显的bug或缺点
E>维护和开发是否有好
综合下来,个人坚定之选择grpc,这个初出茅庐(2015年发布)的东东,十分强大:
>> http2流方式
>> 自带异步特性
>> 跨平台(支持11种语言)
>> 无需zookeeper这类单独的服务中心
>> 对开发人员比较友好
>> 服务调用方可设置请求头
当然缺点也是存在的:需要单独写proto文件(生成目标语言的一套语法定义)、变量为null时会赋予默认初始值、链式调用(还好调用接口较为单一,只是语法较为怪异)...
如果您在意以上缺点,可绕过本文哈~
ok,现在开始我开始讲grpc,内容大致有四:
A->grpc的简单配置 (本节)
A>简单grpc编写 (本节)
B>复杂grpc proto服务文件编写 (本节)
C>双向流式调用方法及注意事项 (下一节)
D>grpc安全问题及拦截器 (下一节)
grpc的配置:
这里我的工程是基于springboot,同时为简化开发起见,我使用 grpc-spring-boot-starter ,开始之前先感谢这位开发者为简化grpc的java平台简化了太多的开发,同时也为springcloud融合做了太多共享,非常感谢~!
这里,首先得准备三个springboot模块,这三个模块包含:grpc proto3文件生成模块、grpc 客户端、grpc 服务端,我的工程结构大致是这样子的(工程是多模块的):
这里面的三个模块一看就懂,就不细讲啦~,准备好这三个模块后,依次配置依赖包及参数:
服务端(preview-grpc-server):
pom.xml中依赖包配置>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId></dependency><dependency><groupId>net.devh</groupId><artifactId>grpc-client-spring-boot-autoconfigure</artifactId><version>RELEASE</version></dependency>
<!-- 由于我的工程是多模块的,若不作为jar包引入,也可以将preview-grpc-lib中的java文件拷贝到当前工程内也可 --> <dependency> <groupId>com.github.carvechris</groupId> <artifactId>preview-grpc-lib</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
配置文件yml(如果是properties文件也可参照此配置):
1 grpc: 2 server: 3 port: 2804 4 5 spring: 6 application: 7 name: preview-grpc-server
(注意:一定要定义应用名称,在调用的时候会用到应用名称的,这里是:preview-grpc-server)
客户端(preview-grpc-client):
pom.xml文件依赖包配置>
<dependency><groupId>net.devh</groupId><artifactId>grpc-client-spring-boot-starter</artifactId><version>1.4.0.RELEASE</version> </dependency> <!-- 由于我的工程是多模块的,若不作为jar包引入,也可以将preview-grpc-lib中的java文件拷贝到当前工程内也可 -->
<dependency> <groupId>com.github.carvechris</groupId> <artifactId>preview-grpc-lib</artifactId> <version>1.0-SNAPSHOT</version></dependency>
yml配置文件参数:
1 grpc: 2 client: 3 preview-grpc-server: 4 host: 5 - 127.0.0.1 6 port: 7 - 2804 8 enableKeepAlive: true 9 keepAliveWithoutCalls: true
proto文件生成模块(preview-grpc-lib)配置:
pom.xml文件依赖包配置:
1 <!--依赖配置--> 2 <dependencies> 3 <dependency> 4 <groupId>io.grpc</groupId> 5 <artifactId>grpc-netty</artifactId> 6 <version>${grpc.version}</version> 7 </dependency> 8 <dependency> 9 <groupId>io.grpc</groupId> 10 <artifactId>grpc-protobuf</artifactId> 11 <version>${grpc.version}</version> 12 </dependency> 13 <dependency> 14 <groupId>io.grpc</groupId> 15 <artifactId>grpc-stub</artifactId> 16 <version>${grpc.version}</version> 17 </dependency> 18 </dependencies> 19 20 <!--proto3文件生成java代码插件配置--> 21 <build> 22 <extensions> 23 <extension> 24 <groupId>kr.motd.maven</groupId> 25 <artifactId>os-maven-plugin</artifactId> 26 <version>${os.plugin.version}</version> 27 </extension> 28 </extensions> 29 <plugins> 30 <plugin> 31 <groupId>org.xolstice.maven.plugins</groupId> 32 <artifactId>protobuf-maven-plugin</artifactId> 33 <version>${protobuf.plugin.version}</version> 34 <configuration> 35 <protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}</protocArtifact> 36 <pluginId>grpc-java</pluginId> 37 <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact> 38 </configuration> 39 </plugin> 40 </plugins> 41 </build>
配置完成,这里需要特别说明一下:server模块和client模块的web服务各占一个端口,另外,server模块还会给grpc单独分配一个端口,就我的preview-grpc-server来说:
服务名称(name)是:preview-grpc-server
服务占用的端口是:2804
切记,不论是web服务还是grpc服务的端口都不能重复,同时一定要理清楚web服务和grpc服务所占用的端口和ip。
简单grpc服务(helloworld.proto)编写:
这里我先展示下我的生成模块的大致样子:
需要说明的是:编写的proto文件均在proto目录下,java目录下是proto文件生成的java代码,这里的java文件是从target目录总复制到java目录下的,包名一定要与proto里面声明的包名一致!
java代码生成模块proto3服务文件(helloworld.proto)的编写:
1 syntax = "proto3"; 2 3 // 是否拆分类文件 4 option java_multiple_files = true; 5 // 生成的文件所在的包 6 option java_package = "com.funnyzpc.xxx.grpc.lib.hello"; 7 // 输出类主文件(此配置可选) 8 option java_outer_classname = "HelloWorldProto"; 9 10 // 定义一个服务 11 service Simple { 12 // Sends a greeting 13 rpc SayHello (HelloRequest) returns (HelloReply) { 14 } 15 } 16 17 // 请求体定义 18 message HelloRequest { 19 string name = 1; 20 } 21 22 // 响应体定义 23 message HelloReply { 24 string message = 1; 25 }
现在开始使用idea提供的快捷功能生成客户端和服务端java文件(当然也可以使用mvn命令手动生成):
将生成的java文件复制到应用目录:
(注意:复制后一定要清理target目录,不然文件重复会报错!)
在客户端(preview-grpc-client)编写一个grpc服务请求类(GrpcSimpleService.java):
1 @Service 2 public class GrpcSimpleService { 3 4 @GrpcClient("preview-grpc-server") 5 private Channel serverChannel; 6 7 public String sendMessage(String name) { 8 SimpleGrpc.SimpleBlockingStub stub = SimpleGrpc.newBlockingStub(serverChannel); 9 HelloReply response = stub.sayHello(HelloRequest.newBuilder().setName(name).build()); 10 return response.getMessage(); 11 } 12 }
在服务端(preview-grpc-server)编写对应的grpc的服务类:
1 /** 2 * 简单grpc服务类 3 */ 4 @GrpcService(SimpleGrpc.class) 5 public class GrpcServerService extends SimpleGrpc.SimpleImplBase { 6 private static final Logger LOG=LoggerFactory.getLogger(GrpcServerService.class); 7 8 @Override 9 public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) { 10 HelloReply reply = HelloReply.newBuilder().setMessage("Hello ===> " + req.getName()).build(); 11 responseObserver.onNext(reply); 12 responseObserver.onCompleted(); 13 } 14 15 }
上面的@GrpcService是grpc组件的注解,注解中必须声明所使用的grpc(生成的类中的)服务类,同时还可以声明所使用的拦截器(可选)
OK,现在添加一个控制器(在preview-grpc-client中编写一个控制器),试试看:
完美,。。。可能有人proto文件一知半解,接下来进入下一节。
复杂grpc proto服务文件编写:
首先,我先推荐两个官方网站,若能理解官网内容,可绕过本节
grpc java平台api及样例>
https://grpc.io/docs/quickstart/java.html
protocol buffers,proto3文件语法>
https://developers.google.com/protocol-buffers/docs/proto3?hl=zh-cn
一般在跨应用调用时,所传递的参数有时候为复杂对象,比如这样{page_no:1,page_size:20,data:{name:XXX,type:2}},这里就写好的复杂层级对象讲解下:
(MultiObject.proto)
1 syntax = "proto3"; 2 3 // option java_multiple_files = true; 4 option java_package = "com.github.carvechris.security.grpc.lib.multi"; 5 6 service MultiObjService{ 7 rpc queryObj (MultiObjReq) returns (MultiObjResp) { 8 9 } 10 11 } 12 13 message MultiObjReq{ 14 int32 page_no=1; 15 int32 page_size=2; 16 MultiObjDataReq data=3; 17 } 18 19 message MultiObjDataReq{ 20 string name=1; 21 int32 type=2; 22 } 23 24 message MultiObjResp{ 25 string req_str=1; 26 MultiObjFirstResp first=2; 27 } 28 message MultiObjFirstResp{ 29 string f_content=1; 30 MultiObjNextResp next=2; 31 32 } 33 message MultiObjNextResp{ 34 string n_content =1; 35 }
文件中定义一个服务 必须以关键字 service 开始,上面的 MultiObjReq 与 MultiObjResp 分别为服务的请求和响应对象,这两个对象在生成java文件后,每个请求对象都是一个单独的类(可在一个java中也可不在,若不在需要定义:option java_multiple_files = true;),不管是请求对象还是响应对象,都需要单独声明这个对象以及对象中的变量类型及所处的位置,就像这样:
1 message MultiObjReq{ 2 int32 page_no=1; 3 int32 page_size=2; 4 MultiObjDataReq data=3; 5 }
自定义类型需要在单独定义,比如"MultiObjDataReq";在上面这个例子中,定义的请求对象MultiObjReq的第一个字段为 page_no,第一个为page_size,第三个为定义的一个对象,每个参数开始需标明当前字段类型,如果这个字段是自定义类型时无需定义数据类型(但是一定要有参数序号,当然也可以定义一个map类型);另外,通用字段类型同go语言的数据类型(参照以上链接);注意,请求或响应对象定义时必须以关键字message开始。
另外,请注意,如果某个字段是个列表(java中的List),需要在字段或者对象前添加关键字 repeated ,这样:
//返回体数据定义 message GrpcResp {string sign=3;string msg=4;repeated datas detail=5; }message datas{uint64 id=1;string address=2;double isadmin=3; }
现在展示上面的MultiObject.proto文件 所编写的客户端和服务端类:
客户端(preview-grpc-client):
(GrpcMultiObjClientService.java)
1 @Service 2 public class GrpcMultiObjClientService { 3 4 @GrpcClient("preview-grpc-service") 5 private Channel serverChannel; 6 7 public Object testMultiObj() { 8 9 MultiObject.MultiObjDataReq reqData=MultiObject.MultiObjDataReq.newBuilder() 10 .setName("queryName") 11 .setType(33) 12 .build(); 13 14 MultiObject.MultiObjReq req=MultiObject.MultiObjReq.newBuilder() 15 .setPageNo(11) 16 .setPageSize(22) 17 .setData(reqData) 18 .build(); 19 20 MultiObjServiceGrpc.MultiObjServiceBlockingStub stb=MultiObjServiceGrpc.newBlockingStub(serverChannel); 21 MultiObject.MultiObjResp resp=stb.queryObj(req); 22 23 Map<String,Object> reMap=new HashMap<>(); 24 reMap.put("getFContent",resp.getFirst().getFContent()); 25 reMap.put("getNContent",resp.getFirst().getNext().getNContent()); 26 reMap.put("getReqStr",resp.getReqStr()); 27 return reMap; 28 } 29 30 }
服务端(preview-grpc-server):
(GrpcMultiObjService.java)
1 @GrpcService(MultiObjServiceGrpc.class) 2 public class GrpcMultiObjService extends MultiObjServiceGrpc.MultiObjServiceImplBase{ 3 private static final Logger LOG=LoggerFactory.getLogger(GrpcMultiObjService.class); 4 5 @Override 6 public void queryObj(MultiObject.MultiObjReq request,StreamObserver<MultiObject.MultiObjResp> responseObserver) { 7 8 LOG.info("MultiObjServiceGrpc>start"); 9 Map<String,Object> reqData=new HashMap<String,Object>(); 10 reqData.put("getPageNo",request.getPageNo()); 11 reqData.put("getPageSize",request.getPageSize()); 12 reqData.put("getName",request.getData().getName()); 13 reqData.put("getType",request.getData().getType()); 14 15 MultiObject.MultiObjNextResp next=MultiObject.MultiObjNextResp.newBuilder().setNContent("n_content").build(); 16 MultiObject.MultiObjFirstResp first=MultiObject.MultiObjFirstResp.newBuilder().setFContent("f_content").setNext(next).build(); 17 MultiObject.MultiObjResp resp=MultiObject.MultiObjResp.newBuilder().setReqStr(JSON.toJSONString(reqData)).setFirst(first).build(); 18 19 responseObserver.onNext(resp); 20 responseObserver.onCompleted(); 21 LOG.info("MultiObjServiceGrpc>end"); 22 } 23 24 }
现在是 2018-08-26 02:13:42
由于在双向流编写及测试环节碰到些问题,耽搁了许久,此次会将双向流和安全及拦截器放在下一篇讲,各位,晚安 (=。=)
转载于:https://www.cnblogs.com/funnyzpc/p/9501353.html
开始食用grpc(之一)相关推荐
- RPC 笔记(03)— gRPC 概念、安装、编译、客户端和服务端示例
1. gRPC 概念 gRPC 是 Google 开源的一款高性能的 RPC 框架.GitHub 上介绍如下: gRPC is a modern, open source, high-performa ...
- etcd 笔记(04)— etcd 网关与 gRPC 网关
1. etcd 网关 etcd 网关是一个简单的 TCP 代理,可将网络数据转发到 etcd 集群.网关是无状态且透明的,它既不会检查客户端请求,也不会干扰集群响应,支持多个 etcd 服务器实例,并 ...
- php 长连接心跳_支持gRPC长链接,深度解读Nacos2.0架构设计及新模型
作者 | 杨翊(席翁) Nacos PMC 来源|阿里巴巴云原生公众号 Nacos 简介 Nacos 在阿里巴巴起源于 2008 年五彩石项目,该项目完成了微服务拆分和业务中台建设,随着云计算和开源环 ...
- grpc 传递上下文_grpc 源码笔记 02:ClientConn
上篇笔记中梳理了一把 resolver 和 balancer,这里顺着前面的流程走一遍入口的 ClientConn 对象. ClientConn // ClientConn represents a ...
- SpringBoot整合Grpc实现跨语言RPC通讯
什么是gRPC gRPC是谷歌开源的基于go语言的一个现代的开源高性能RPC框架,可以在任何环境中运行.它可以有效地连接数据中心内和跨数据中心的服务,并提供可插拔的支持,以实现负载平衡,跟踪,健康检查 ...
- gRPC简介及简单使用(C++)
gRPC是一个现代的.开源的.高性能远程过程调用(RPC)框架,可以在任何平台运行.gRPC使客户端和服务器端应用程序能够透明地进行通信,并简化了连接系统的构建.gRPC支持的语言包括C++.Ruby ...
- 在Windows和Linux上编译gRPC源码操作步骤(C++)
gRPC最新发布版本为v1.23.0,下面以此版本为例说明在Windows和Linux下编译过程. Windows7/10 vs2103编译gRPC源码操作步骤: 1. 需要本机已安装Git.CMak ...
- 支持 gRPC 长链接,深度解读 Nacos 2.0 架构设计及新模型
点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 作者 | 杨翊(席翁) Nacos PMC Nacos ...
- Gonet2 游戏server框架解析之gRPC提高(5)
上一篇blog是关于gRPC框架的基本使用,假设说gRPC仅仅是远程发几个參数,那和一个普通的http请求也没多大区别了. 所以今天我就来学习一下gRPC高级一点的用法. 流! 流能够依据用法,分为单 ...
最新文章
- java hello world
- Goods:注册页面保存User功能发送邮件以及激活功实现
- Python 项目实践二(下载数据)第四篇
- OpenCV学习笔记之图像融合
- Spring Framework 3.2 M1发布
- 百度CTO王海峰:百度翻译每日翻译量已达到千亿字符
- 软件工程 第四章 概要设计
- 通过模板生成Excel表格——XLSTransformer
- 随机生成手机号的java代码
- 并发和并行的区别(图解)
- CSDN博客排版格式入门
- Openstack Zoning – Region/Availability Zone/Host Aggregate
- linux 删除文件名带括号的文件
- 人穷久了或者累久了会sb
- MapReduce经典案例总结
- FFmpeg 命令详解
- 为什么需要TCP加速?TCP怎么加速呢?
- Cocos Creator 2D Effect 入门 (1)
- 人+山=仙,人+谷=俗
- 雷军 1994 年写的代码,像诗一样优雅,不服不行~