Python-gRPC实践(3)--使用Python实现gRPC服务

gRPC Python 教程(一): 原理与基本用法 gRPC 基于RPC,有很多优点,使用protobuf 序列化,采用 HTTP/2, 包头压缩,流式处理技术,支持双向通信,支持多语言环境, C++, Python, Go, Java,Rust等。 阅读详情

前言

通过前面的文章了解到了gRPC是什么,以及清楚使用它的优缺点,现在终于可以开始实现一个gRPC服务了。

这里演示的是一个用户与书互动的项目,用户可以通过该项目进行注册,登录,注销等操作,同时也可以上传,查看和评论对应的书籍,通常情况下我们会由一个简单的Web应用来提供这些服务,现在,我们假设这个服务非常庞大,需要把他们按照功能拆分成不同的微服务了,这些服务与Web应用通过gRPC进行通信。

注:由于篇幅原因,不会夹杂大量的源代码,需要跳转到Github中查看,同时对于业务逻辑也不会详细的介绍,所以可能需要一些接口开发经验才容易阅读懂。

1.初始化准备

在创建项目之前,我们需要确定我们的需求是什么,就像开发API接口一样,先了解需求,然后多方根据需求定义好接口,最后才为每个接口编写对应的代码,在这个项目中,我假定了拆分了两个服务,一个是与用户有关, 一个是与书籍有关,书籍部分又细分为书籍管理,书籍社交两部分。为此,先编写了Protobuf文件,之前在中说过,我们创建gRPC对应的Protobuf文件应该放在一个公有的仓库中,这样就方便后续的Protobuf文件升级以及不同语言都能共享同一份Protobuf文件。

所以创建一个gRPC服务的第一步就是先创建一个包含Protobuf文件的仓库,我把它命名为grpc-example-common,具体源码可以通过获取。

这个仓库中pyproject.toml文件的tool.poetry.dependencies部分如下:

[tool.poetry.dependencies]
python = "^3.8"
grpcio = "^1.43.0"
grpcio-tools = "^1.43.0"

通过这部分文件可以知道这个项目是基于Python3.8版本的,然后用到了2个依赖分别是grpcio以及grpcio-tools,其中grpcio是Python的gRPC实现,它是通过c语言翻译的,所以很多底层都是c实现的,如果在使用gRPC框架的过程中找不到对应的使用方法说明,那可以直接到gRPC的c项目中找到对应的函数并查看它的函数说明进而了解该函数的作用;而另一个库grpcio-tools的作用是把proto文件转译为Python代码,不过单靠grpcio-tools转译的代码很难使用,比如是这段代码:

from grpc_example_common.protos.user.user_pb2 import LoginUserResult 


login_user_result: LoginUserResult = LoginUserResult()

这段代码引入了由grpcio-tools通过用户Protobuf文件生成的LoginUserResult对象,开发者在后续想要使用这个对象的时候,IDE是没办法提示你这个对象有什么属性的,只能凭自己的记忆进行填写,或者回到对应的Protobuf文件查看该对象的定义:

message LoginUserResult {
  string uid = 1;
  string user_name = 2;
  string token = 3;
}

发现它有uid,user_name,token三个属性,然后才会在代码填写LoginUserResult对象的属性进行调用:

from grpc_example_common.protos.user.user_pb2 import LoginUserResult 


login_user_result: LoginUserResult = LoginUserResult(
    uid="123",
    user_name="so1n",
    token="aaa"
)
print(login_user_result.uid)
# 123

这时即使填错了,比如uid写为uid1IDE也不会提示有错误,我们需要等到运行时报错才知道是填错了。

这样一个场景是会让开发者非常难受的,明明都定义了一个Protobuf文件,文件中已经写了这个消息有什么属性了,结果生成对应的类却无法让IDE了解它有什么属性(跳进去源码也无法知道),这时就需要通过来解决这一个问题。mypy-protobuf会生成的一份独立的.pyi文件,这样一来IDE就可以帮忙提示这个对象有什么属性了,如图: IDE提醒 此外,通过.pyi文件可以使mypy等工具校验我们的代码类型是否正确,这样在运行前就能知道代码是否有问题。

mypy-protobuf的使用方法十分的简单,它以grpcio-tools的一个插件来运行,具体的使用方法如下:

# 定义生产文件的存放目录,通常都会在指定的目录下生成一个proto的文件夹
target_p = "xxx"
# 定义proto文件的目录
sourct_p = "xxx"
python -m grpc_tools.protoc \
    # 指定xxx_pb2文件和xxx_pb2_grpc文件生成位置,通常我们都让他们在同一个文件夹生产
    --python_out=./$target_p \
    --grpc_python_out=./$target_p \
    # 指定proto文件的位置
    -I. \
    $source_p/user/*.proto
# 上面是标准的grpcio-tools执行的标准语句
    # 指定`mypy-protobuf`生成xxx_pb2和xxx_pb2_grpc对应的pyi文件的位置,必须与xxx_pb2和xxx_pb2_grpc位置保持一致
    --mypy_grpc_out=./$target_p \
    --mypy_out=./$target_p \

只要运行了这段命令,grpc_tools就能在对应的路径下生成Protobuf对应的代码和对应的pyi文件,不过当前的grpcio-tools默认生成的代码所在的目录名是protos,它认为这个目录是在项目对应的根目录下生成的,如果我们指定在某个子目录下生产对应的代码,那么在运行程序时会直接报错,因为生成的代码文件中有一个大概长成这样的语句:

# xxx为proto文件的名
from protos.xxx import

这意味着它永远都是从项目的根目录开始引入的protos包,但我们根目录却没有这个包,所以就会报错,这时就需要手动把生成的语句替换为:

# xxx为proto文件的名
from .xxx import

这样就可以完美运行了,但是每个文件手动改一下会非常的麻烦,因为每次生成代码后都要手动更改代码,同时由于项目存在多个Protobuf文件,每个文件都需要执行一次命令才能生成对应的代码。对于一个开发者来说,最讨厌的就是一直执行重复的工作,这种工作是非常烦心的, 所以需要编写了一个脚本来自动的把所有Protobuf文件转为Python代码(也就是项目中的gen_rpc.sh文件),该脚本如下:

# 设置脚本运行的Python环境 
export VENV_PREFIX=""
if [ -d 'venv' ] ; then
    export VENV_PREFIX="venv/bin/"
fi
if [ -d '.venv' ] ; then
    export VENV_PREFIX=".venv/bin/"
fi

echo 'use venv path:' ${VENV_PREFIX}

# 设置生成的存放Python代码的proto文件夹的目录 
target_p='grpc_example_common'
# 设置Proyobuf文件所在位置
source_p='protos'
# 设置生成protobuf代码文件的文件名 
service_list=("book" "user")

# 清理之前生成的代码
rm -r "${target_p:?}/${source_p:?}"*
# 创建对应的文件夹
mkdir -p "${target_p:?}/${source_p:?}"

# 批处理
for service in "${service_list[@]}"
do
  # 生成proto文件对应的Python代码逻辑,每个proto文件执行一次
  mkdir -p "${target_p:?}/${source_p:?}/${service:?}"
  echo  "from proto file:" $source_p/"$service"/*.proto "gen proto py file to" $target_p/$source_p
  ${VENV_PREFIX}python -m grpc_tools.protoc \
    --mypy_grpc_out=./$target_p \
    --mypy_out=./$target_p \
    --python_out=./$target_p \
    --grpc_python_out=./$target_p \
    -I. \
    $source_p/"$service"/*.proto

  # 创建一个__init__文件,这样一来这个文件夹就是一个包了,下面转换为from . import语句才能生效
  touch $target_p/$source_p/"$service"/__init__.py
  # fix grpc tools bug
  sed -i "s/from protos.$service import/from . import/" $target_p/$source_p/$service/*.py
done

这样一来,我们通过Protobuf文件生成Python代码的操作就非常省心了,不管Protobuf文件有何改动,只要通过调用命令后就能在grpc_example_common.protos目录下看到已经生成的最新的Python代码,目前grpc_example_common的项目结构如下:

├── grpc_example_common    # Python与gRPC相关的调用
│   ├── helper
│   ├── __init__.py
│   ├── interceptor
│   └── protos             # 生成的对应Python代码
├── protos                 # Protobuf文件
│   ├── book
│   └── user
├──.flake8                 # 格式化工具的配置
├──.pre-commit-config.yaml # 格式化工具的配置
├── gen_rpc.sh             # 通过proto文件生成Python gRPC调用代码的脚本
├── mypy.ini               # 格式化工具的配置
├── pyproject.toml         # Python项目配置文件
├── README.md
├── requirements-dev.txt   # 测试环境的依赖文件
├── requirements.txt       # 正式环境的依赖文件
└── setup.py 

通过项目结构可以看出还有其它的东西,这是我为了方便,我还在这个项目中添加一些Python与gRPC相关的调用封装,把它当做一个Python的自定义包。

需要注意的是,每修改一次Protobuf文件应该视为一次版本发布,当生成完Protobuf文件的对应代码后,我们需要提交代码并打上对应的tag,这样其它项目才能引用到对应的版本代码。

grpc_example_common目录下还有其它常用的封装,将会在后续章节介绍。

2.编写gRPC服务项目

目前这个演示的项目有两个子gRPC项目,他们的结构很像,所以这一节以来阐述如何创建一个gRPC服务。

该项目的代码结构如下:

├── tests                 # 存放测试用例
│   ├── __init__.py
│   └── test_user.py
├── user_grpc_service     # 项目代码真正所在的位置
│   ├── dal               #   service代码,一般用于查询Mysql,Redis的逻辑
│   ├── handler           #   业务逻辑代码,继承对应Protobuf文件生成的类
│   ├── helper            #   其它代码封装。
│   └── __init__.py
├── app.py                # 项目代码入口
├── mypy.ini              # mypy配置文件
├── pyproject.toml        # 项目配置文件
└── user.sql              # 项目初始化SQL

首先,该项目会通过如下配置引入一些依赖:

[tool.poetry.dependencies]
python = "^3.8"
DBUtils = "^3.0.0"
PyMySQL = "^1.0.2"
c
python对于grpc的简单操作(一) python对grpc的简单操作,以及图片如何通过grpc在客户端和服务端之间传输 阅读详情

相关推荐

Python-gRPC实践(1)--gRPC简介

接触gRPC比较早, 但我不怎么喜欢在Python中使用gRPC, 因为Python中的官方gRPC框架易用性太烂了, 只提供基本功能, 附带的其他功能要不就不完善, 要不文档就只有简单几句话, 啥东西都得去原本的项目找, 用起来都不顺心(毕竟不是Goole的亲儿子,支持的力度肯定比较少)。吐槽归吐糟, 但是还是得用, 因为其他语言的项目都用了gRPC, 不同团队服务的通信需要依赖gRPC进行通信, 所以这块硬骨头还是得啃下去。

Saki_Python的博客 387

Python3搭建gRPC服务(入门版)

这是一篇关于gRPC入门的快速文档,预计需要10分钟左右阅读时间,读完后你可以大概了解gRPC的概念和开发简单的gRPC服务Demo,本文适合基于Python3构建快速的gRPC服务,同时提供以下进阶材料1、gRPC进阶文章(后续会更新)2、同步视频教程(后续会更新)3、其他相关联文章,包括pytest进行gRPC测试,python3客户端测试java/golang grpc服务端(后续会更新)

Saki_Python的博客 1848

python中RPC使用(gRPC)

简单介绍 远程过程调用(英语:Remote Procedure Call,缩写为 RPC,也叫远程程序调用)是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程。如果涉及的软件采用面向对象编程,那么远程过程调用亦可称作远程调用或远程方法调用。 gRPC是由Google公司开源的高性能RPC框架。支持多语言、多平台,其消息协议使用Google自家开源的Protocol Buffers协议机制(proto3) 序列化,传输使用HTTP/2标准,

u013919855的博客 1800

Python3搭建gRPC服务(进阶版一)之Protocol Buffers基础概念

本文主要介绍gRPC中重要的部分Protocol Buffers,预计需要花费15分钟左右的时间,阅读后你将收获以下知识,如果大家觉得有收获,记得一键三连,后续继续为大家输出更多有价值的文章!!!Protocol Buffers是一个跨语言,跨平台可扩展的数据结构序列化的一个工具语言,和JSON类似,但比JSON更小,更高效,通过Protocol Buffers提供的工具可以生成多种语言的源代码,可以轻松的构建接口入参,返回值以及序列化。客户端和服务端进行接口调用时,入参数据,返回值数据,调用哪个接口都是需

Saki_Python的博客 344

多模态RAG实战:为LLM装上视觉之眼,实现图文混合文档智能问答

检索增强生成(RAG)技术通过结合外部知识库,有效缓解了大语言模型(LLM)的幻觉问题,并扩展了其知识边界。其核心原理是将文档切分、向量化后存入向量数据库,在问答时通过语义检索召回相关上下文,辅助LLM生成更精准的答案。这项技术的核心价值在于,它为大模型应用提供了一种低成本、高效率的知识注入与实时更新方案,广泛应用于智能客服、知识库问答、文档分析等场景。随着应用深入,纯文本RAG在处理产品手册、学术论文、设计图纸等富含视觉信息的文档时面临瓶颈。本文聚焦的**多模态RAG**和**视觉理解**技术,正是为了解

weixin_30698527的博客 722

KUKA-外部自动运行模板程序——个人设计模式&思路

用于说明KUKA与西门子PLC外部自动交互模板的设计思路与使用流程

qq_39024187的博客 5603

用InVEST做碳中和规划?手把手教你计算城市碳储量与热岛效应

本文详细介绍了如何利用InVEST模型进行城市碳中和规划的科学评估。通过手把手教学,演示了如何使用该模型的碳存储与城市热岛缓解模块,从数据准备、模型运行到结果解读,量化评估不同规划方案下的碳储量变化与热岛效应缓解潜力,为城市规划者提供科学的决策依据。

weixin_29201313的博客 821

车载监控系统升级指南:如何用XS9950A替换TP9950实现高清视频解码(附配置代码)

本文提供了从TP9950升级至XS9950A车载视频解码芯片的完整实战指南。详细解析了硬件设计调整、PCB布局要点,并重点分享了通过I2C配置寄存器实现高清HDCCTV视频解码与同轴音频集成的软件驱动代码与调试技巧,助力工程师平滑完成系统升级。

weixin_29268637的博客 364

地震数据可视化必备:5分钟读懂SEGY道头字段全解析(含坐标定位指南)

本文深入解析了SEGY文件格式中道头坐标字段的提取与可视化方法。针对地震数据处理中的常见痛点,详细介绍了sx/sy、gx/gy等关键坐标字段的二进制解析、比例因子应用、单位转换及常见问题解决方案,并提供了实用的Python代码示例,帮助开发者实现从SEGY文件到三维空间可视化的完整流程。

echo99的专栏 1009

UE4项目迁移指南:如何无缝导入外部.uasset文件并保持材质关联

本文详细解析了将外部.uasset文件无缝导入UE4项目的专业方法。针对手动复制文件时常见的材质关联丢失问题,提供了使用引用查看器进行诊断和修复的实用技巧,并推荐使用引擎内置的“迁移”功能确保资源依赖关系的完整性,帮助开发者高效整合项目资源。

t8u9v0的博客 1045

基于 MFC C++ 的心电监测客户端

4. **报警功能**:使用 `PlaySound` 播放报警音(需准备 `alert.wav` 文件),界面显示报警状态。

寒寒豆豆软件公司的博客 90

Open3D——平面点云凸多边形轮廓提取【2025最新版】

平面点云凸多边形轮廓提起,博客长期更新,本文最近更新时间为:2025年1月6日。

点云侠的博客 6752

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

上一篇: Python-gRPC实践(2)--Protocol Buffer
下一篇: 【django开发手册】Django 中使用自定义用户模型:一个比自带 User 更强的选择
Python_P叔
博客等级 码龄3年 5445粉丝 827原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值