gRPC的简单使用
前言
八月初的时候,在公司内部做了一个主题为《gRPC的简单使用》的分享,其实就是和小伙伴们扯扯淡,现在抽空回忆一下,也算是一个小小的总结吧。
现在市面上耳熟能详的RPC框架也很多,下面列举几个遇到比较多的。
- 谷歌的gRPC
- 推特的Thrift
- 阿里的Dubbo
- 。。。。
它们都是支持多语言的,相对来说,这三个之中,Dubbo支持的语言略微少一点。现在在一个公司内都能见到多种语言的技术栈都已经是十分常见的事了,好比我司,都有JAVA,C#,Python三种语言了,所以在多语言支持这方面,在技术选型的时候,肯定是要有所考虑的。
下面进入正式的主题,gRPC。
gRPC的简单介绍
gRPC是一个现代的开源高性能RPC框架,可以在任何环境中运行。它可以高效地将数据中心内和跨数据中心的服务连接起来,并支持可插拔的负载平衡、跟踪、健康检查和身份验证。同时,它还把设备,移动应用程序和浏览器连接到后端服务的分布式计算变得很容易。
gRPC有什么优点呢?
- 简单的服务定义 (使用Protocol Buffers定义服务,这是一个功能强大的二进制序列化工具集和语言)
- 跨语言和平台工作 (在微服务式架构中有效地连接多语言服务(10+种语言支持)并能自动为各种语言和平台的服务生成惯用的客户端和服务器存根)
- 快速启动并扩展 (使用单行安装运行时和开发环境,并使用框架每秒扩展到数百万个RPC)
- 双向流媒体和集成的身份验证 (双向流媒体和集成的身份验证 基于http/2的传输的双向流和完全集成的可插拔身份验证)
gRPC在使用的时候有4种模式供我们选择
- 一元RPC(Unary RPCs ):这是最简单的定义,客户端发送一个请求,服务端返回一个结果
- 服务器流RPC(Server streaming RPCs):客户端发送一个请求,服务端返回一个流给客户端,客户从流中读取一系列消息,直到读取所有消息
- 客户端流RPC(Client streaming RPCs ):客户端通过流向服务端发送一系列消息,然后等待服务端读取完数据并返回处理结果
- 双向流RPC(Bidirectional streaming RPCs):客户端和服务端都可以独立向对方发送或接受一系列的消息。客户端和服务端读写的顺序是任意。
我们要根据具体的场景来决定选择那一种。
这里只介绍一元RPC。正常来说,一元RPC应该可以满足我们日常60~70%的需求了吧。
基本用法
gRPC的基本用法可以简单的分为三个点:
- 服务的定义,即proto文件的编写
- 服务端代码编写
- 客户端代码编写
下面我们依次来看一下
服务的定义
既然要定义一个服务,肯定是知道了这个服务要完成什么事之后。
在定义之前,要对proto3和proto2有所了解。不过proto3是推荐的格式。所以我们基本上只要用proto3就可以了。
下面先来看一个后面要用到的proto文件。
syntax = "proto3";
option csharp_namespace = "XXXService";
package UserInfo;
service UserInfoService {
rpc GetList(GetUserListRequest) returns (GetUserListReply){}
rpc GetById(GetUserByIdRequest) returns (GetUserByIdRelpy){}
rpc Save(SaveUserRequest) returns (SaveUserReply){}
}
message GetUserByIdRequest {
int32 id = 1;
}
message GetUserByIdRelpy{
int32 id = 1;
string name = 2;
int32 age = 3;
int64 create_time = 4;
}
message GetUserListRequest {
int32 id = 1;
string name = 2;
}
message GetUserListReply {
message MsgItem {
int32 id = 1;
string name = 2;
int32 age = 3;
int64 create_time = 4;
}
int32 code = 1;
string msg = 2;
repeated MsgItem data = 3;
}
message SaveUserRequest {
string name = 1;
int32 age = 2;
}
message SaveUserReply {
int32 code = 1;
string msg = 2;
}
它有下面的几个部分
- syntax , 指定要用那个版本的语法
- service , 指定rpc服务的接口,简单理解成我们平时定义的接口
- message , 指定要传输的消息体,简单理解成我们平常用的 DTO
- package , 指定包名
- option , 可选参数的定义,不同语言有不同的选项
其实看上去还是比较容易懂的。至少一眼看过去能知道是些什么意思。
如果对proto3还没有了解的,可以参考这个文档Language Guide (proto3),里面很清楚的介绍了一些数据类型和不同语言数据类型的对应关系。
这里有一个要注意的是,时间类型,在proto3中,没有datetime类型,过去很长一段时间,我们是只能用时间戳来表示时间,也就是定义一个长整型,现在是可以用timestamp表处理了。
在写服务端和客户端代码之前,我们需要根据proto文件生成对应的代码。
一个命令即可搞定。
protoc --proto_path=IMPORT_PATH \
--cpp_out=DST_DIR \
--java_out=DST_DIR \
--python_out=DST_DIR \
--go_out=DST_DIR \
--objc_out=DST_DIR \
--csharp_out=DST_DIR \
path/to/file.proto
现在时代进步的这么快,不少语言已经有工具做了集成,可以在build项目的时候就生成对应的文件了,不需要我们再单独去执行一次上面的那个命令。
好比我们的.NET项目,可以在ItemGroup中直接指定Protobuf,然后告诉它,proto文件是那个,是要生成服务端代码还是客户端代码。
可以看看下面这个具体的例子。
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Protobuf Include="Protos\userinfo.proto" GrpcServices="Server" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.1.2" PrivateAssets="All" />
<PackageReference Include="Google.Protobuf" Version="3.8.0" />
<PackageReference Include="Grpc.Core" Version="1.22.0" />
<PackageReference Include="Grpc.Tools" Version="1.22.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>
再往下,就是写代码了。
服务端代码编写
服务端代码分两部分,一部分是服务具体的实现,一部分是服务怎么起来。
先来看看服务的具体实现。
namespace MyBasedServiceA
{
using Grpc.Core;
using System.Linq;
using System.Threading.Tasks;
public class UserInfoServiceImpl : UserInfoService.UserInfoServiceBase
{
public override Task<GetUserByIdRelpy> GetById(GetUserByIdRequest request, ServerCallContext context)
{
var result = new GetUserByIdRelpy();
var user = FakeUserInfoDb.GetById(request.Id);
result.Id = user.Id;
result.Name = user.Name;
result.Age = user.Age;
result.CreateTime = user.CreateTime;
return Task.FromResult(result);
}
public override Task<GetUserListReply> GetList(GetUserListRequest request, ServerCallContext context)
{
var result = new GetUserListReply();
var userList = FakeUserInfoDb.GetList(request.Id, request.Name);
result.Code = 0;
result.Msg = "成功";
result.Data.AddRange(userList.Select(x => new GetUserListReply.Types.MsgItem
{
Id = x.Id,
Age = x.Age,
CreateTime = x.CreateTime,
Name = x.Name
}));
return Task.FromResult(result);
}
public override Task<SaveUserReply> Save(SaveUserRequest request, ServerCallContext context)
{
var result = new SaveUserReply();
var flag = FakeUserInfoDb.Save(request.Name, request.Age);
result.Code = 0;
result.Msg = "成功";
return Task.FromResult(result);
}
}
}
可以看到上面的代码,我们只要继承由proto文件生成的一个基类,然后去重写它的实现,就可以认为是实现了一个服务。这个其实就是写我们具体的业务逻辑,大boss有什么需求,堆上去就好了。
然后来看第二部分,服务怎么起来。
在这里我选择的方案是使用通用主机来跑。当然也可以直接在Startup的Configure
方法中去启动服务。只要能起来就行
gRPC的简单使用的更多相关文章
- gRPC的简单Go例子
gRPC是一个高性能.通用的开源RPC框架,其由Google主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf(Protocol Buffers)序列化协议开发,且支持众多开发 ...
- grpc的简单用例 (golang实现)
这个用例的逻辑很简单, 服务器运行一个管理个人信息的服务, 提供如下的四个服务: (1) 添加一个个人信息 注: 对应于Unary RPCs, 客户端发送单一消息给服务器, 服务器返回单一消息 (2) ...
- grpc的简单用例 (C++实现)
这个用例的逻辑很简单, 服务器运行一个管理个人信息的服务, 提供如下的四个服务: (1) 添加一个个人信息 注: 对应于Unary RPCs, 客户端发送单一消息给服务器, 服务器返回单一消息 (2) ...
- DotnetCore下Grpc的简单使用(基于3.0版本)
目录: 一.简单介绍DotnetCore3.0如何将.proto文件生成对应的服务端和客户端类 二.介绍如何在服务端使用Grpc,以及Grpc需要的条件(HTTP2.TLS) 三.介绍如何创建Grpc ...
- 学习GRPC(一) 简单实现
Grpc 实现流程图 资料 https://grpc.io/docs/quickstart/go/ https://studygolang.com/articles/16627 使用方法 make r ...
- Go微服务 grpc的简单使用
作者:薇文文链接:https://www.jianshu.com/p/20ed82218163来源:简书 准备工作 先安装Protobuf 编译器 protoc,下载地址:https://github ...
- Go语言入门篇-gRPC基于golang & java简单实现
一.什么是RPC 1.简介: RPC:Remote Procedure Call,远程过程调用.简单来说就是两个进程之间的数据交互. 正常服务端的接口服务是提供给用户端(在Web开发中就是浏览器)或者 ...
- ASP.NET Core 3.0 上的gRPC服务模板初体验(多图)
早就听说ASP.NET Core 3.0中引入了gRPC的服务模板,正好趁着家里电脑刚做了新系统,然后装了VS2019的功夫来体验一把.同时记录体验的过程.如果你也想按照本文的步骤体验的话,那你得先安 ...
- gRPC官方文档(概览)
文章来自gRPC 官方文档中文版 概览 开始 欢迎进入 gRPC 的开发文档,gRPC 一开始由 google 开发,是一款语言中立.平台中立.开源的远程过程调用(RPC)系统. 本文档通过快速概述和 ...
随机推荐
- 获取当前时间的MySql时间函数
mysql> select current_timestamp(); +---------------------+ | current_timestamp() | +------------- ...
- ElasticStack学习(四):ElasticSearch文档使用与操作
一.文档的CRUD介绍 ElasticSearch中存在五种操作,分别如下: 1.Index 该操作表示:如果文档的ID不存在,则创建新的文档.若有相同的ID,先删除现有文档,然后再创建新的文档,同时 ...
- Java中session与application的异同
客户端的session 其实是标记了你的请求来自哪个浏览器 问题1:永远都一样吗? 答:重启了浏览器,你的session id就改变了, 结果会导致,再无法取回原来在服务端保存的数据. 问题2:假设客 ...
- VS2013日常使用若干技巧+快捷键
1.注释的方法 1)sqlserver中,单行注释:— — 多行注释:/* 代码 */ 2)C#中,单行注释:// 多行注释:/* 代码 */ 3)C#中多行注释的快捷方式:先选中你要注 ...
- Bzoj 2525 [Poi2011]Dynamite
2525: [Poi2011]Dynamite Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 240 Solved: 120[Submit][Sta ...
- android_MultiAutoCompleteTextView
package cn.com.sxp;import android.app.Activity;import android.os.Bundle;import android.view.View;imp ...
- 【分治】黑白棋子的移动-C++
题目描述 有2n个棋子(n≥4)排成一行,开始为位置白子全部在左边,黑子全部在右边,如下图为n=5的情况: ○○○○○●●●●● 移动棋子的规则是:每次必须同时移动相邻的两个棋子,颜色不限,可以左移也 ...
- HttpClient多文件上传代码及普通参数中文乱码问题解决
该随笔记录了在实际项目中使用HttpClient调用外部api,需上传文件和普通参数的代码. 笔者在使用 HttpClient 调用 http api 接口时,需要服务端上传文件和一些普通参数给 ht ...
- css基础5
今天在这里跟大家分享css基础最核心的部分,浮动和定位.话不多说,直接上干货! 一.浮动 定义:定位元素是相对于其正常位置应该出现的位置.定位元素的位置是相对于自身.父级元素位置.其他元素以及浏览器窗 ...
- HelloDjango 启动!免费带你学Django全栈!
欢迎 追梦 入伙 HelloGitHub-Team,同时为我们带来了完全免费的 HelloDjango 系列教程,全网首发于 HelloGitHub 公众号.让想你的系列文章被跟多人看到,那就来加入我 ...