在Django中使用zerorpc

随着系统架构从集中式单点服务器到分布式微服务方向的迁移,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/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球