威哥一直琢磨着怎么搭建.net下的微服务,但是要实现微服务,必须要解决进程间的服务接口通讯,总不能做出了微服务体系,结果在一个局域网机制内的分布式服务间的通讯还得走rest的Http请求,这不是明显的资源浪费吗。所以威哥尝试了Google的Grpc。

GRPC是一个开源RPC框架,于2015年3月开源,其由Google主要面向移动应用开发并基于HTTP/2协议标准而设计,基于Protobuf 3.0(Protocol Buffers)序列化协议,主流语言都支持。目前提供 C、Java 和 Go 语言版本,分别是:grpc, grpc-java, grpc-go. 其中 C 版本支持 C, C++, Node.js, Python, Ruby, Objective-C, PHP 和 C# 支持。

讲到GRPC,大家可能不明白,GRPC是为了解决RPC(Remote Procedure Call)是远程过程调用而设计的一套框架。就像上面威哥说的微服务之间的进程通讯我们希望能够使用高效服务请求,而不是绕到外网走HTTP请求,同时我们更希望一组微服务内的互相调用是无感知的,就和调用本进程内的方法接口一样,直接开箱即用。那GRPC就是提供这样请求的一套框架工具。当然,有同学问为什么不直Socket,还是基于TCP协议,效率更高,这个也不是不能,但是太繁琐了,威哥也没看到有哪个架构微服务之间的通讯是通过Socket实现的。当然如果是Java,倒是可以通过Dubbo直接走TCP协议做微服务间的进程通讯。

下面威哥贴2张七层网络模型图,Http协议运行在应用层,TCP协议运行在传输层,如果.net能使用Dubbo就好了。

srpc grpc 比较 grpc和rpc_grpc

srpc grpc 比较 grpc和rpc_微服务_02

威哥解释下,RPC跟HTTP不是对立面,RPC中可以使用HTTP作为通讯协议。RPC是一种设计、实现框架,通讯协议只是其中一部分。而且Google的GRPC本身就是基于Http/2协议的。http2采用二进制传输,相较于文本传输的http1来说更加安全可靠。而且Http2可以多路复用。具体的区别大家可以去查查。

RPC的本质是提供了一种轻量无感知的跨进程通信的方式,在分布式机器上调用其他方法与本地调用无异(远程调用的过程是透明的,你并不知道这个调用的方法是部署在哪里,通过PRC能够解耦服务)。RPC是根据语言的API来定义的,而不是基于网络的应用来定义的,调用更方便,协议私密更安全、内容更小效率更高。

概念性的东西就不在做多说了。我们直接开始Coding吧。

GRPC在.net需要生成协议代码,生成协议代码需 protoc.exe、grpc_csharp_plugin.exe工具。

在.net framework 项目下引用安装 Grpc.Tools 会得到protoc.exe、grpc_csharp_plugin.exe。

1.新建工程GrpcClient、GrpcServer和GrpcLibrary

   添加 - 新建项目 - 控制台应用 GrpcClient、GrpcServer。

   添加 - 新建项目 - 类库 GrpcLibrary。 工程中的三个项目情况如下:

srpc grpc 比较 grpc和rpc_微服务_03

2.安装程序包Grpc

   三个项目GrpcClient、GrpcServer、GrpcLibrary均安装程序包Grpc。右键点击解决方案,打开NuGet。

srpc grpc 比较 grpc和rpc_微服务_04

开始安装Grpc:

srpc grpc 比较 grpc和rpc_srpc grpc 比较_05

3.安装程序包Google.Protobuf 

三个项目GrpcClient、GrpcServer、GrpcLibrary均安装程序包Google.Protobuf 。

srpc grpc 比较 grpc和rpc_grpc_06

4.安装程序包Grpc.Tools

 类库GrpcLibrary安装程序包Grpc.Tools。

srpc grpc 比较 grpc和rpc_srpc grpc 比较_07

5.自定义服务

  在项目GrpcLibrary里添加HelloWorld.proto用以生成代码。可以直接在GrpcLibrary项目下新建一个类或者文本文件,修改后缀为.proto,此处用来定义接口。输入下面内容,威哥定义了2个接口:

syntax = "proto3";
 package GrpcLibrary;
 service GrpcService {
   rpc SayHello (HelloRequest) returns (HelloReply) {}
   rpc GetWeGe (WilliamRequest) returns (WilliamReply) {}
 }
  
 message HelloRequest {
   string name = 1;
 }
  
 message HelloReply {
   string message = 1;
 }message WilliamRequest {
   string name = 1;
 }
  
 message WilliamReply {
   string message = 1;
 }

注意:上面威哥分别定义了2个接口:SayHello (HelloRequest);GetWeGe (WilliamRequest)。像微服务的话,大家照着自行定义就好了,方法内部属性大家随便定义。

6.生成协议代码

在解决方案的packages包里面找到grpc_csharp_plugin.exe和protoc.exe,把它们复制到GrpcLibrary项目的文件夹下。这2个exe文件,怕同学们找不到,威哥直接截图吧,但是系统是32位的或者是Linux或者IOS的,大家自己到对应文件下找。

srpc grpc 比较 grpc和rpc_srpc grpc 比较_08

srpc grpc 比较 grpc和rpc_Server_09

完成上面操作之后,大家新建一个文本文件,之后在文本中输入下面内容报错:

protoc -I . --csharp_out . --grpc_out . --plugin=protoc-gen-grpc=grpc_csharp_plugin.exe HelloWorld.proto

现在打开上面创建好的文本文件,之后另存为后缀cmd的文件:

srpc grpc 比较 grpc和rpc_grpc_10

OK,现在已经可以开始生成协议代码了。大家直接点击ProtocGenerate.cmd运行。会出现下面截图中的文件:

srpc grpc 比较 grpc和rpc_RPC_11

 

7.开始实现服务端

在GrpcServer项目下新建类GrpcImpl,截图和代码如下,注意,GrpcServer项目需要把GrpcLibrary项目引入,客户端也要引入GrpcLibrary层:

srpc grpc 比较 grpc和rpc_RPC_12

public class GrpcImpl: GrpcService.GrpcServiceBase
     {
         // 实现SayHello方法
         public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
         {
             return Task.FromResult(new HelloReply { Message = "威哥服务1返回:Hello," + request.Name });
         }        public override Task<WilliamReply> GetWeGe(WilliamRequest request, ServerCallContext context)
         {
             return Task.FromResult(new WilliamReply { Message = "威哥服务2返回:" + request.Name });
         }
     }

8.实现客户端服务

注意也需要引入GrpcLibrary。下面是客户端代码:

class Program
     {
         static void Main(string[] args)
         {
             Channel channel = new Channel("127.0.0.1:9007", ChannelCredentials.Insecure);            var client = new GrpcService.GrpcServiceClient(channel);
             var reply = client.SayHello(new HelloRequest { Name = "威哥" });
             Console.WriteLine($"来自:{reply.Message}");            var reply2 = client.GetWeGe(new WilliamRequest { Name = "大熊_二次服务请求" });
             Console.WriteLine($"来自:{reply2.Message}");            channel.ShutdownAsync().Wait();
             Console.WriteLine("任意键退出...");
             Console.ReadKey();
         }
     }

9.调试查看结果

先启动服务端,之后再启动客户端。必须先有服务哈。

运行服务端如下:

srpc grpc 比较 grpc和rpc_srpc grpc 比较_13

运行客户端如下:

srpc grpc 比较 grpc和rpc_RPC_14

OK,威哥终于写完了,童鞋们一起共勉吧,其实威哥不想做.net了,还是更爱Java,现在要找工作了,如何抉择了,Java Web方向缺乏经验。