关于GRPC的讲解
gRPC服务发现&负载均衡
https://segmentfault.com/a/1190000008672912?utm_source=tag-newest
GRPC编程指南
gRPC 介绍
gRPC 是谷歌开源的高性能 RPC 框架。RPC 也即远程方法调用,对于 RPC client 来说,它可以调用远程 server 上的某个方法,看起来就像是在调用本地方法一样。区别就在于,通过 RPC 调用远程方法时,数据经过序列化之后会通过网络发送给远程 server,远程 server 执行方法之后,同样会将返回结果序列化之后发送回 client。在分布式系统中,gRPC 可以用来解耦程序的逻辑,不同组件之间通过 gRPC 进行通信。
gRPC 使用 Protobuf 作为它的数据序列化的工具,Protobuf 会将数据序列化成二进制的数据流。与 JSON 这类文本形式的数据相比,二进制数据显得更加紧凑和便于解析,在网络传输中,二进制数据由于体积更小,传输也更快。另一方面,gRPC 也是跨多种编程语言的,譬如说,一个 Java 的 client 可以与一个 C++ 的 server 通信。
在 Linux 安装 gRPC
在 Ubuntu 16.04 中,通过下面的步骤就可以安装好 gRPC 和 Protobuf。
1
2
3
4
5
6
7
8
9
10
11
|
sudo apt-get install build-essential autoconf libtool libgflags-dev libgtest-dev clang libc++-dev pkg-config unzip
git clone -b $(curl -L http://grpc.io/release) https://github.com/grpc/grpc
cd grpc
git submodule update --init
make
sudo make install
cd third_party/protobuf
sudo ./autogen.sh
sudo ./configure
make
sudo make install
|
构建服务端程序
在创建 gRPC 服务(service)之前,首先需要提供这个服务的接口。Protobuf 除了作为数据序列化工具之外,还可以用来为服务定义接口。例如,下面我们为 Company 服务定义接口:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
syntax = "proto3";
package company;
service Company {
rpc AddEmployee(Employee) returns (EmployeeID) {} // 提交员工信息
rpc ListEmployees(AgeRange) returns (stream Employee) {} // 查询员工信息
}
message Employee {
string name = 1;
int32 age = 2;
}
message EmployeeID {
int32 id = 1;
}
message AgeRange {
int32 low = 1;
int32 high = 2;
}
|
我们为 Company 服务定义了两个方法,AddEmployee()
用于提交员工信息,而ListEmployees()
则用于根据年龄查询员工信息。注意到ListEmployees()
方法的返回值类型是stream Employee
,这表示这个方法会返回多个Employee
消息。
执行下面的命令可以自动生成 ProtoBuf 编解码的代码,以及与 Company 服务相关的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
$ tree
├── cpp
└── protos
└── company.proto
$ protoc -I protos --grpc_out=cpp --plugin=protoc-gen-grpc=`which grpc_cpp_plugin` protos/company.proto
$ protoc -I protos --cpp_out=cpp protos/company.proto
$ tree
├── cpp
│ ├── company.grpc.pb.cc
│ ├── company.grpc.pb.h
│ ├── company.pb.cc
│ └── company.pb.h
└── protos
└── company.proto
|
在company.grpc.ph.h
文件里面,已经定义好了Company::Service
这个抽象基类,我们可以继承这个基类,并提供方法的具体实现。下面我们创建一个company_server.cc
文件,并定义CompanyImpl
这个具体类,同时提供方法的具体实现。值得注意的是,我们需要保证CompanyImpl
提供的方法都是线程安全的,因为这些方法允许被多个 client 同时调用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
// file company_server.cc
#include "company.grpc.pb.h"
#include <iostream>
#include <unordered_map>
#include <mutex>
#include <grpc/grpc.h>
#include <grpc++/server.h>
#include <grpc++/server_builder.h>
#include <grpc++/server_context.h>
#include <grpc++/security/server_credentials.h>
using company::Company;
using company::AgeRange;
using company::Employee;
using company::EmployeeID;
class CompanyImpl final : public Company::Service
{
public:
CompanyImpl()
: nextID_(0) { }
grpc::Status AddEmployee(grpc::ServerContext *context, const Employee *request,
EmployeeID *response) override
{
std::lock_guard<std::mutex> guard(mtx_);
employees_[nextID_] = *request;
response->set_id(nextID_);
++nextID_;
return grpc::Status::OK;
}
grpc::Status ListEmployees(grpc::ServerContext *context, const AgeRange *request,
grpc::ServerWriter<Employee> *writer) override
{
auto low = request->low();
auto high = request->high();
std::lock_guard<std::mutex> guard(mtx_);
for (auto &entry : employees_)
{
auto employee = entry.second;
if (employee.age() >= low && employee.age() <= high)
{
writer->Write(employee); // 调用 Write 写入一个 Employee 消息给client
}
}
return grpc::Status::OK;
}
private:
int32_t nextID_;
std::mutex mtx_;
std::unordered_map<int32_t, Employee> employees_;
};
int main(int argc, char *argv[])
{
std::string addr = "0.0.0.0:5000";
CompanyImpl service;
grpc::ServerBuilder builder;
builder.AddListeningPort(addr, grpc::InsecureServerCredentials());
builder.RegisterService(&service);
auto server = builder.BuildAndStart();
std::cout << "Server listening on " << addr << std::endl;
server->Wait();
return 0;
}
|
构建客户端程序
client 的代码相对简单很多,为了让 client 可以调用 server 提供的方法,首先需要创建一个 stub:
1
2
3
|
// 第二个参数表示不开启 SSL
auto channel = grpc::CreateChannel("localhost:5000", grpc::InsecureChannelCredentials());
auto stub = Company::NewStub(channel);
|
client 通过这个 stub 就可以直接调用 server 提供的方法了。下面我们创建一个company_client.cc
文件,用来对 server 进行测试:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
#include "company.grpc.pb.h"
#include <iostream>
#include <memory>
#include <string>
#include <grpc/grpc.h>
#include <grpc++/channel.h>
#include <grpc++/client_context.h>
#include <grpc++/create_channel.h>
#include <grpc++/security/credentials.h>
using company::Company;
using company::Employee;
using company::EmployeeID;
using company::AgeRange;
class CompanyClient
{
public:
CompanyClient(std::shared_ptr<grpc::Channel> channel)
: stub_(Company::NewStub(channel)) { }
void AddEmployee(const std::string &name, int32_t age)
{
Employee employee;
employee.set_name(name);
employee.set_age(age);
EmployeeID id;
grpc::ClientContext context;
stub_->AddEmployee(&context, employee, &id);
std::cout << "AddEmployee() - new id: " << id.id() << std::endl;
}
void ListEmployeesByAge(int32_t low, int32_t high)
{
AgeRange range;
range.set_low(low);
range.set_high(high);
grpc::ClientContext context;
auto reader = stub_->ListEmployees(&context, range);
Employee employee;
while (reader->Read(&employee))
{
std::cout << "Employee: name = " << employee.name() << ", age = " << employee.age() << std::endl;
}
}
private:
std::unique_ptr<Company::Stub> stub_;
};
int main(int argc, char *argv[])
{
auto channel = grpc::CreateChannel("localhost:5000", grpc::InsecureChannelCredentials());
CompanyClient client(channel);
client.AddEmployee("hello", 10);
client.AddEmployee("world", 20);
client.ListEmployeesByAge(0, 100);
return 0;
}
|
编译好 server 和 client 程序之后就可以运行了:
1
2
|
$ clang++ -std=c++11 -o server -lgrpc++ -lprotobuf -lpthread -lgrpc++_reflection company.pb.cc company.grpc.pb.cc company_server.cc
$ clang++ -std=c++11 -o client -lgrpc++ -lprotobuf -lpthread -lgrpc++_reflection company.pb.cc company.grpc.pb.cc company_client.cc
|
参考资料
关于GRPC的讲解的更多相关文章
- grpc基础讲解和golang实现grpc通信小案例
grpc简介 gRPC由google开发,是一款语言中立.平台中立.开源的远程过程调用系统 gRPC客户端和服务端可以在多种环境中运行和交互,例如用java写一个服务端,可以用go语言写客户端调用 g ...
- 带入gRPC:gRPC Streaming, Client and Server
带入gRPC:gRPC Streaming, Client and Server 原文地址:带入gRPC:gRPC Streaming, Client and Server 前言 本章节将介绍 gRP ...
- gRPC源码分析2-Server的建立
gRPC中,Server.Client共享的Class不是很多,所以我们可以单独的分别讲解Server和Client的源码. 通过第一篇,我们知道对于gRPC来说,建立Server是非常简单的,还记得 ...
- gRPC源码分析0-导读
gRPC是Google开源的新一代RPC框架,官网是http://www.grpc.io.正式发布于2016年8月,技术栈非常的新,基于HTTP/2,netty4.1,proto3.虽然目前在工程化方 ...
- gRPC .NET Core跨平台学习
前些天发布gRPC C# 学习,在.NET Framework 中使用gRPC ,今天来学习 .NET Core gRPC. gRPC 的.NET Core 包在NuGet 上发布了,结合.NET C ...
- gRPC C#学习
前些天gRPC 发布1.0 版本,代表着gRPC 已经正式进入稳定阶段. 今天我们就来学习gRPC C# .而且目前也已经支持.NET Core 可以实现完美跨平台. 传统的.NET 可以通过Mono ...
- .NET Core下使用gRpc公开服务(SSL/TLS)
一.前言 前一阵子关于.NET的各大公众号都发表了关于gRpc的消息,而随之而来的就是一波关于.NET Core下如何使用的教程,但是在这众多的教程中基本都是泛泛而谈,难以实际在实际环境中使用,而该篇 ...
- gRpc NET Core
NET Core下使用gRpc公开服务(SSL/TLS) 一.前言 前一阵子关于.NET的各大公众号都发表了关于gRpc的消息,而随之而来的就是一波关于.NET Core下如何使用的教程,但是在这众多 ...
- ASP.NET Core 3.0 上的gRPC服务模板初体验(多图)
早就听说ASP.NET Core 3.0中引入了gRPC的服务模板,正好趁着家里电脑刚做了新系统,然后装了VS2019的功夫来体验一把.同时记录体验的过程.如果你也想按照本文的步骤体验的话,那你得先安 ...
随机推荐
- kernel32.dll 这个系统模块
详细解读:远程线程注入DLL到PC版微信 一.远程线程注入的原理 1.其基础是在 Windows 系统中,每个 .exe 文件在双击打开时都会加载 kernel32.dll 这个系统模块,该模块中有一 ...
- python数值列表
使用range函数生成数值列表 使用range函数打印1~5的数字 for i in range(1,6): print(i) 输出 1 2 3 4 5 利用range函数生成数值列表 >> ...
- SQLite基础-6.运算符
目录 SQLite 运算符 1. 运算符 2. 算数运算符 3. 比较运算符 4. 逻辑运算符 SQLite 运算符 1. 运算符 首先,问大家运算符是什么?运算符在很多领域均用使用.它也分很多中,常 ...
- sql server 中 like 中文不匹配问题解决就这么简单
原文:sql server 中 like 中文不匹配问题解决就这么简单 MS-SQL Server select * from Book where BookName like'%C语言%' 在SQ ...
- Jenkins+SVN持续环境搭建
需要三台不同环境的服务器,SVN.Jenkins.Tomcat 1.SVN搭建 1.Subversion服务器(SVN服务器) 2.项目对应的版本库 3.版本库中钩子程序(用于触发构建命令) 在我以前 ...
- php通过session来实现登录验证
1.概述 这几天在做一个内部统计管理系统,所有内容需要登录后才能查看.这就需要系统内部每个模块都有登录验证的功能.在网上找了一圈资料,决定用session来做. 2.系统概况 后端语言:php(用的是 ...
- 【操作记录】搭建虚拟机下 java 开发环境
第一步,配置虚拟机 virtualBox 官网下载最新版,安装,选择简体中文. CentOS 官网下载 最小版iso. 新建虚拟机并配置,挂载iso光盘,然后启动. 因为是最小版,安装时可能不支持使用 ...
- 如果你的评论被WordPress的Akismet插件屏蔽,怎么解封?
Akismet是Matt Mullenweg早期创办的一个项目,现在已经是Automattic公司的一个专注于剿杀垃圾评论的产品.在Wordpress用户中使用最多,z-blog也有用户在用,由于垃圾 ...
- Flask:上下文管理
1. werkzurg from werkzur.serving import run_simple def run(environ,start_response): reuturn [b'hello ...
- 异常-try...catch的方式处理异常1
package cn.itcast_02; /* * 我们自己如何处理异常呢? * A:try...catch...finally * B:throws 抛出 * * try...catch...fi ...