随着系统架构从集中式单点服务器到分布式微服务方向的迁移,RPC是一个不可回避的话题.如何在系统中引入对开发者友好,性能可靠的RPC服务是一个值得深思的问题.
在调研了Thrift,gRPC,zerorpc等方案后,基于以下2点最后选择了zerorpc:
虽然zerorpc可以直接嵌入当前系统框架中,但是还是有一些问题需要去考虑解决
- rpc 接口如何定义
- rpc 服务如何启动
- 高并发情况下客户端的可靠性
在当前的系统中大量使用Celery,djang-celery定义Task的方式是在每个install app中定义 tasks.py
文件,然后通过 @task
装饰器来生成Task.所以这里为了方便定义rpc interface设计一套类似于Celery的规范.需要输出rpc interface的app下面创建 rpcs.py
文件
rpc.register
装饰器用来注册函数到rpc服务上,可选参数:
- name: 客户调用方法名称, 没有写的情况下就是func name如get_ticket
- stream: 默认False, 如果为True, 则使用zerorpc的流式响应传输, 数据量比较大的情况时使用, 返回可迭代对象
我们来看看 eebo.core.utils.zrpc
如何来实现这个注册过程:
通过一个类方法来往类上面绑定方法,需要注意的是 name
的定义必须是全局唯一的.
现在我们有了定义rpc interface的方法,下面来看看如何启动rpc server.
runrpc.py
是一个Django management commands 文件需要放到某个install app目录的 management/commands
下面,启动服务器:
autodiscover_rpc
自动发现rpc interface注册函数get_server
生成zerorpc server对象
在 get_server
中对zerorpc注册了2个中间件, SentryMiddleware
用于捕获rpc interface抛出的异常发送到sentry, ServerExecMiddleware
用于处理Django db connection,看看代码:
在每个rpc interface被调用前与调用后都调用 close_old_connections
关闭db connection,这里是为了实现 django.db
中对请求处理前与处理后注册信号:
目的是保证在rpc interface中使用ORM时,connection没有超时断开.
由于rpc的调用是阻塞的,不能全局只创建一个client.但是也不能每个请求都创建client,所以这里参考 redis-py
的client实现,定义一个支持连接池的zerorpc client.
这里直接复用了 redis-py
定义的连接池,当前系统使用gunicorn + gevent的方式启动Django服务,所以 queue_class
使用了gevent的 LifoQueue
.
在使用过程中还发现了这个问题:
需要打个补丁解决:
技术的选型需要契合项目实际情况,不要盲目上新技术引入不必要的成本.为了推广方案,必须全局的考虑方案是否易使用,是否易部署.
完整代码:
Original: https://www.cnblogs.com/rangger/p/9801594.html
Author: 派对实验室
Title: 在Django中使用zerorpc
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/564180/
转载文章受原作者版权保护。转载请注明原作者出处!