Golang/Python/PHP带你彻底学会gRPC
一、gRPC是什么?
gRPC,其实就是RPC框架的一种,前面带了一个g,代表是RPC中的大哥,龙头老大的意思,另外g也有global的意思,意思是全球化比较fashion,是一个高性能、开源和通用的 RPC 框架,面向服务端和移动端,基于 HTTP/2 设计。
RPC框架是什么?
RPC 框架说白了就是让你可以像调用本地方法一样调用远程服务提供的方法,而不需要关心底层的通信细节。简单地说就让远程服务调用更加简单、透明。
RPC包含了客户端(Client)和服务端(Server)
常见的RPC框架有
- gRPC。谷歌出品
- Thrift。Apache出品
- Dubbo。阿里出品,也是一个微服务框架
gRPC的特性
看官方文档的介绍,有以下4点特性:
- 使用Protocal Buffers这个强大的结构数据序列化工具
- grpc可以跨语言使用
- 安装简单,扩展方便(用该框架每秒可达到百万个RPC)
- 基于HTTP2协议
gRPC使用流程
gprc的使用流程一般是这样的:
- 定义标准的proto文件
- 生成标准代码
- 服务端使用生成的代码提供服务
- 客户端使用生成的代码调用服务
二、Protocol Buffers是什么?
谷歌开源的一种结构数据序列化的工具,比方说JSON、XML也是结构数据序列化的工具,不同的是,
- Protocol Buffers序列化后的数据是不可读的,因为是二进制流
- 使用Protocol Buffer需要事先定义数据的格式(.proto 协议文件),还原一个序列化之后的数据需要使用到这个数据格式
- Protocol Buffer 比 XML、JSON快很多,因为是基于二进制流,比字符串更省带宽,传输速度快
Protocol Buffer语法:查看官方文档
下面演示根据需求开发项目,建议自己运行一下,加深印象
三、需求:开发健身房服务
定义了一个健身房(Gym),提供一个叫健身(Bodybuilding)的远程方法
使用该服务,需要指定人(Person),人有名字(name)和训练动作(actions)两个属性。
对应的协议文件gym.proto文件如下
syntax = "proto3";
//命名空间
package lightweight;
//健身房
service Gym {
rpc BodyBuilding (Person) returns (Reply) {
}
}
//谁在健身
message Person {
string name = 1;
repeated string actions = 2;
}
//结果
message Reply {
int32 code = 1;
string msg = 2;
}
四、最佳实践
下面以Golang、Python、PHP介绍该grpc的使用,代码已经上传到了chenqionghe/grpc-demo
最终目录结构如下图

Golang
1. 安装protoc
地址:protobuf/releases
我是mac,用的是这个地址:protoc-3.11.4-osx-x86_64.zip
解压后放到了可以访问的bin即可
2. 安装protoc-gen-go
protoc依赖该工具生成代码
go get -u github.com/golang/protobuf/protoc-gen-go
gogoprotobuf的protoc-gen-gofast插件生成的文件更复杂,性能也更高,安装如下
go get github.com/gogo/protobuf/protoc-gen-gofast
3. 安装grpc包
这是要代码里需要使用的,go get直接安装不了,手动克隆
git clone https://github.com/grpc/grpc-go.git $GOPATH/src/google.golang.org/grpc
git clone https://github.com/golang/net.git $GOPATH/src/golang.org/x/net
git clone https://github.com/golang/text.git $GOPATH/src/golang.org/x/text
git clone https://github.com/google/go-genproto.git $GOPATH/src/google.golang.org/genproto
cd $GOPATH/src/
go install google.golang.org/grpc
4. 生成代码
#!/usr/bin/env bash
protoDir="../protos"
outDir="../languages/golang/gym"
protoc -I ${protoDir}/ ${protoDir}/*proto --go_out=plugins=grpc:${outDir}
protoc工具参数解释:
- -I: 指定import路径,可以指定多个-I参数,编译时按顺序查找,不指定默认当前目录
- -go_out:指定og语言的访问类
- plugins:指定依赖的插件
使用gofast将go_out=plugins=grpc:${outDir}改为gofast_out=plugins=grpc:${outDir}
执行,然后我们会看到在golang目录生成了该代码

5. 定义服务端
package main
import (
"app/lightweight"
"context"
"fmt"
"google.golang.org/grpc"
"log"
"net"
)
const (
port = ":50051"
)
// server继承自动生成的服务类
type server struct {
lightweight.UnimplementedGymServer
}
// 服务端必须实现了相应的接口BodyBuilding
func (s *server) BodyBuilding(ctx context.Context, in *lightweight.Person) (*lightweight.Reply, error) {
fmt.Printf("%s正在健身, 动作: %s\n", in.Name, in.Actions)
return &lightweight.Reply{Code: 0, Msg: "ok",}, nil
}
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
lightweight.RegisterGymServer(s, &server{})
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
6. 定义客户端
package main
import (
"app/lightweight"
"context"
"fmt"
"google.golang.org/grpc"
"log"
"time"
)
const (
address = "localhost:50051"
)
func main() {
// Set up a connection to the server.
conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := lightweight.NewGymClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
r, err := c.BodyBuilding(ctx, &lightweight.Person{
Name: "chenqionghe",
Actions: []string{"深蹲", "卧推", "硬拉"},
})
if err != nil {
log.Fatalf("error: %v", err)
}
fmt.Printf("code: %d, msg: %s", r.Code, r.Msg)
}
7. 运行代码
golang目录结果是现在是这样的
.
├── client.go
├── go.mod
├── go.sum
├── lightweight
│ └── gym.pb.go
└── server.go
运行服务端和客户端,效果如下

可以看到,chenqionghe去健身成功
Python
1. 安装grpc包
pip install grpcio
2. 安装protobuf
pip install protobuf
3. 安装grpc的protobuf编译工具
包含了protoc编译器和生成代码的插件
pip install grpcio-tools
4. 生成代码
#!/usr/bin/env bash
protoDir="../protos"
outDir="../languages/python/gym/"
python3 -m grpc_tools.protoc -I ${protoDir}/ --python_out=${outDir} --grpc_python_out=${outDir} ${protoDir}/*proto

5. 定义服务端
from concurrent import futures
import logging
import grpc
# 支持新的包
import sys
sys.path.append("lightweight")
import lightweight.gym_pb2_grpc as gym_pb2_grpc
import lightweight.gym_pb2 as gym_pb2
class Gym(gym_pb2_grpc.GymServicer):
def BodyBuilding(self, request, context):
print(f"{request.name}在健身, 动作: {list(request.actions)}")
return gym_pb2.Reply(code=0, msg='ok')
def serve():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
gym_pb2_grpc.add_GymServicer_to_server(Gym(), server)
server.add_insecure_port('[::]:50051')
server.start()
server.wait_for_termination()
if __name__ == '__main__':
logging.basicConfig()
serve()
6. 定义客户端
from __future__ import print_function
import logging
import grpc
# 支持导入新的包
import sys
sys.path.append("lightweight")
import lightweight.gym_pb2_grpc as gym_pb2_grpc
import lightweight.gym_pb2 as gym_pb2
def run():
with grpc.insecure_channel('localhost:50051') as channel:
stub = gym_pb2_grpc.GymStub(channel)
response = stub.BodyBuilding(gym_pb2.Person(
name='chenqionghe', actions=['深蹲', '卧推', '硬拉']
))
print(f'code: {response.code}, msg:{response.msg}')
if __name__ == '__main__':
logging.basicConfig()
run()
7. 运行代码
目录结构如下,分别运行
├── client.py
├── lightweight
│ ├── gym_pb2.py
│ └── gym_pb2_grpc.py
└── server.py

可以看到,chenqionghe去健身成功
PHP
1. 安装protoc
地址:protobuf/releases
我是mac,用的是这个地址:protoc-3.11.4-osx-x86_64.zip
解压后放到了可以访问的bin即可
2. 安装grpc扩展
方式一:pecl安装
pecl install grpc
将扩展加入到php.ini
extension=grpc.so
3. 安装protobuf扩展
pecl install protobuf
将扩展加入到php.ini
extension=protobuf.so
4. 安装生成代码的插件grpc_php_plugin
该插件用来生成PHP的gRPC代码
git clone -b v1.27.0 https://github.com/grpc/grpc
cd grpc && git submodule update --init && make grpc_php_plugin
注意:这个过程耗时比较久,请做好心理准备(可以在.gitmodules文件中看到依赖的仓库比较多)
画风是这样的

如果grpc_php_plugin安装不上,mac系统可以直接copy我已经编译好的grpc_php_plugin
安装完成画风

最终会在bins/opt下生成grpc_php_plugin文件,我们把它移动到/usr/local/bin下
5. 生成代码
#!/usr/bin/env bash
protoDir="../protos"
outDir="../languages/php/lightweight"
protoc -I ${protoDir}/ ${protoDir}/*proto --go_out=plugins=grpc:${outDir}
protoc --proto_path=${protoDir} \
--php_out=${outDir} \
--grpc_out=${outDir} \
--plugin=protoc-gen-grpc=/usr/local/bin/grpc_php_plugin \
${protoDir}/*.proto
生成代码如下

6. 定义客户端
1.创建composer.json文件并执行
{
"name": "gym",
"require": {
"grpc/grpc": "^v1.3.0",
"google/protobuf": "^v3.3.0"
},
"autoload": {
"psr-4": {
"GPBMetadata\\": "lightweight/GPBMetadata/",
"Lightweight\\": "lightweight/Lightweight/"
}
}
}
执行composer install
2.创建客户端文件client.php
<?php
/**
* 客户端使用示例
* @author chenqionghe
*/
require dirname(__FILE__) . '/vendor/autoload.php';
//初始化要去的健身房
$client = new \Lightweight\GymClient('127.0.0.1:50051', [
'credentials' => Grpc\ChannelCredentials::createInsecure(),
]);
//带上自己的卡和运动计划
$request = new \Lightweight\Person();
$request->setName("chenqionghe");
$request->setActions(['深蹲', '卧推', '硬拉']);
//去健身房健身
list($response, $status) = $client->BodyBuilding($request)->wait();
echo sprintf("code: %s, msg: %s \n", $response->getCode(), $response->getMsg());
注意:php不支持grpc的服务端,建议服务端起一个上面的golang或者python中的server
这里我用的是golang的
7. 运行代码

可以看到,chenqionghe去健身成功,yes,就是这么easy!
五、如何调试gRPC
我们都知道rest api是可用curl和postman这样的工具来调试的,grpc也有类似的工具,对应的分别是grpcurl和grpcui
grpcurl-命令行工具
类似curl,可以直接用来发送请求调用远程的grpc服务,官方地址请看grpcurl
安装
brew直接安装
brew install grpcurl
也可以使用go get安装
go get github.com/fullstorydev/grpcurl
go install github.com/fullstorydev/grpcurl/cmd/grpcurl
使用
注意grpcl是基于反射,需要在启动服务前添加这样一行代码
reflection.Register(s)
1.查询服务列表
grpcurl -plaintext 127.0.0.1:50051 list

2.查询服务提供的方法
grpcurl -plaintext 127.0.0.1:50051 list lightweight.Gym

3.查看更详细的描述
grpcurl -plaintext 127.0.0.1:50051 describe lightweight.Gym

4.获取类型信息
grpcurl -plaintext 127.0.0.1:50051 describe lightweight.Person

5.调用服务方法
grpcurl -plaintext -d '{"name":"chenqionghe","actions":["深蹲","卧推","硬拉"]}' 127.0.0.1:50051 lightweight.Gym/BodyBuilding

grpcui-界面工具
简单的说,就是gRPC中的postman,能带你飞起来那种,官方地址grpcui
安装
go get github.com/fullstorydev/grpcui
go install github.com/fullstorydev/grpcui/cmd/grpcui
使用
运行web界面,指定grpc的地址
grpcui -plaintext localhost:50051

提示Web UI的地址为http://127.0.0.1:50791
访问出来以下界面

直接把所有服务和方法都列出来了,真的是相当人性化
我们来使用一下,传递参数

返回结果如下

到服务端查看,已经正常的接收到请求

OK,到这里,分别演示了Golang、Python、PHP使用gRPC的例子,以及gRPC调试工具,就是这么简单粗暴!light weight baby !
Golang/Python/PHP带你彻底学会gRPC的更多相关文章
- gRPC Golang/Python使用
gRPC Golang/Python使用 以前开发网站都是用http协议,学过TCP/IP协议的人都知道,在传输层TCP的基础上,应用层HTTP就是填充了一定规则的文本. 1.gRPC使用和介绍 工作 ...
- 漫谈grpc 3:从实践到原理,带你参透 gRPC
原文链接:万字长文 | 从实践到原理,带你参透 gRPC 大家好,我是煎鱼. gRPC 在 Go 语言中大放异彩,越来越多的小伙伴在使用,最近也在公司安利了一波,希望这一篇文章能带你一览 gRPC ...
- ubuntu14.04 python自带版本升级
ubuntu14.04 python自带版本升级 sudo add-apt-repository ppa:fkrull/deadsnakes-python2. sudo apt-get update ...
- paip.性能跟踪profile原理与架构与本质-- python扫带java php
paip.性能跟踪profile原理与架构与本质-- python扫带java php ##背景 弄个个输入法音标转换atiEnPH工具,老是python性能不的上K,7k记录浏览过k要30分钟了. ...
- (四)python自带解释器(LDIE)的使用
什么是IDE? Integrated Development Environment(集成开发环境) 打个不恰当的比方,如果说写代码是制作一件工艺品,那IDE就是机床.再打个不恰当的比方,PS就是图片 ...
- python自带库及第三方库api察看
今天发现一个很有意思的功能,python自带了所有库的文档查看器,配置如下: 配置pydoc服务,cmd中输入如下代码: python –m pydoc –p 1234 回车后 ,使用过程中,该窗口不 ...
- python自带的web服务器
python自带的web服务器 python自带的包可以建立简单的web服务器 BaseHTTPServer 提供基本的web服务和处理类 SimpleHTTPServer 包含执行get请求的Sim ...
- [转]关于python中带下划线的变量和函数的意义
Python 的代码风格由 PEP 8 描述.这个文档描述了 Python 编程风格的方方面面.在遵守这个文档的条件下,不同程序员编写的 Python 代码可以保持最大程度的相似风格.这样就易于阅读, ...
- 【Python】【BugList12】python自带IDLE执行print(req.text)报错:UnicodeEncodeError: 'UCS-2' codec can't encode characters in position 93204-93204
[代码] # -*- coding:UTF-8 -*- import requests if __name__ == '__main__': target = 'https://unsplash.co ...
随机推荐
- C#的静态方法和实例化方法的区别
C#的静态方法和实例化方法的区别 在大多数时候,我们写一个方法,会把方法区分为实例化方法和静态方法.而当被问到静态方法和实例化方法的区别的时候,我在写这篇文章的前10分钟,或许我会回答:"静 ...
- inotify+rsync实时同步
主服务器上安装inotify和rsync,备用服务器上安装rsync 主服务器上修改/etc/rsyncd.conf配置文件 三. 创建密码文件,防火墙设置,客户端和服务器端都要做如下操作 echo ...
- 吴裕雄--天生自然python学习笔记:python 用pygame模块检测键盘事件和鼠标事件
用户可通过键盘输入来操控游戏中角色的运动,取得键盘事件的方法有以下两种 : 常用的按键与键盘常数对应表 : 按下右箭头键,蓝色小球会 向 右移动:按住右箭头键不放 , 球体会快速 向 右移 动, 若到 ...
- 使用mui框架开发App,当input获取焦点时,键盘弹出,底部导航栏上升。
转自 https://blog.csdn.net/elementFei/article/details/72917393 感谢 问题: 使用mui框架开发App,当input获取焦点时,键盘弹出,底部 ...
- day05-装饰器作业
装饰器的重要内容 functools.wraps 带参数的装饰器 多个装饰器装饰同一个函数 一.编写一个装饰器,为多个函数添加登陆认证的功能.具体:只需要登录一次,后面被装饰的函数不需要重新登陆. F ...
- Vscode 下 PlantUML 插件的安装(windows and ubuntu)
目录 Windows 下安装 JAVA 安装环境配置: 测试 Ubuntu 16.04 下安装 Windows 下安装 Vscode graphviz PlantUML JAVA(推荐长期稳定版本,官 ...
- 安装Rational Rose启动报错:无法启动此程序,因为计算机中丢失 suite objects.dll。
运行Rational Rose的时候如果出现这样的错误,先检查环境变量有没有common的地址,如果没有直接配上就OK:配置如下:D:\Program Files\Rational\Common; 我 ...
- Excel-DNA项目只用1个文件实现Ribbon CustomUI和CustomTaskpane定制【VB.Net版】
Excel-DNA项目中的自定义功能区和自定义任务窗格需要用到各种命名空间.添加所需文件,才能实现.后来我发现可以把所有代码都写在Class1.vb这个默认文件中. 大家可以在Visual Studi ...
- HTTP协议八种请求类型介绍
HTTP 协议中共定义了八种方法或者叫“动作”来表明对 Request-URI 指定的资源的不同操作方式,具体介绍如下: OPTIONS:返回服务器针对特定资源所支持的HTTP请求方法.也可以利用向W ...
- deeplearning.ai 构建机器学习项目 Week 1 机器学习策略 I
这门课是讲一些分析机器学习问题的方法,如何更快速高效的优化机器学习系统,以及NG自己的工程经验和教训. 1. 正交化(Othogonalization) 设计机器学习系统时需要面对一个问题是:可以尝试 ...