【问题标题】:Django + Activemq and long running connections in the WebserverDjango + Activemq 和 Web 服务器中的长时间运行连接
【发布时间】:2018-05-25 17:25:14
【问题描述】:

多年来,我一直在使用 stomp.py 和 stompest 与 activemq 进行通信,效果很好,但这主要是使用独立的 python 守护程序。

我想使用网络服务器中的这两个库与后端进行通信,但在不为每个请求创建新连接的情况下,我无法找到如何做到这一点。

是否有安全处理网络服务器中 TCP 连接的标准方法?在其他语言中,该级别的某种全局对象将用于连接池。

【问题讨论】:

  • 请注意,由于我们的基础架构的工作方式,我一直在使用 activemq,因此我并不是真的可以选择离开。
  • 您的 django 实例每秒处理(或应该)处理多少个请求?
  • 这是一个高吞吐量系统的管理/管理应用程序。它本身不应该有十几个用户。
  • 那你为什么要关心连接池呢?
  • “标准做法”是在Django前面使用Nginx来执行连接池和处理慢客户端。但这对于管理应用程序来说并不重要,因为 Nginx 仅在您每秒处理数百或数千个请求时才真正重要。

标签: python django stomp stomp.py


【解决方案1】:

HTTP 是一种同步协议。每个等待的客户端在等待响应时都会消耗服务器资源(CPU、内存、文件描述符)。这意味着网络服务器必须快速响应。 HTTP Web 服务器不应在响应请求时阻止外部长时间运行的进程。

解决方案是异步处理请求。有两个主要选项:

  1. 使用轮询。

    POST 将新任务推送到消息队列:

    POST /api/generate_report
    {
         "report_id": 1337
    }
    

    GET 检查 MQ(或数据库)的结果:

    GET /api/report?id=1337
    {
        "ready": false
    }
    
    GET /api/report?id=1337
    {
        "ready": true,
        "report": "Lorem ipsum..."
    }
    

    Django生态系统中的异步任务通常使用Celery来实现,但你可以直接使用任何MQ。

  2. 使用 WebSockets。

有用的链接:

  1. What are Long-Polling, Websockets, Server-Sent Events (SSE) and Comet?
  2. https://en.wikipedia.org/wiki/Push_technology
  3. https://www.reddit.com/r/django/comments/4kcitl/help_in_design_for_long_running_requests/
  4. https://realpython.com/asynchronous-tasks-with-django-and-celery/
  5. https://blog.heroku.com/in_deep_with_django_channels_the_future_of_real_time_apps_in_django

编辑:

这是一个伪代码示例,说明如何重用与 MQ 的连接:

projectName/appName/services.py:

import stomp

def create_connection():
    conn = stomp.Connection([('localhost', 9998)])
    conn.start()
    conn.connect(wait=True)
    return conn

print('This code will be executed only once per thread')
activemq = create_connection()

projectName/appName/views.py:

from django.http import HttpResponse
from .services import activemq

def index(request):
    activemq.send(message='foo', destination='bar')
    return HttpResponse('Success!')

【讨论】:

  • 哦,我真的很喜欢频道的外观。超出了我的范围,但真的很酷。最终,我真正需要的是一种方法来做 django-celery 允许的事情:就像接受一个 Web 请求并在消息代理中排队一些东西,而不需要为每个请求创建到消息代理的新 TCP 连接。除了 ActiveMQ 和 STOMP。我会接受这个答案,因为即使我的问题没有得到解决,它也给了我一些观点。
  • @user3253945 只是将连接对象设置为模块级变量,每个线程只有一个连接。该连接将在每个请求上重复使用。
  • 模块级变量只评估一次(在第一次导入期间)。它们是一种“全局”对象。因此,在另一个模块(模块 == 任何.py 文件)中创建一个连接并将其导入您需要的任何地方。我添加了一个示例。
  • 这不是一个坏主意。可能需要一些仔细的编码以避免陷入糟糕的状态并处理 Keepalives,但它可能会起作用。绝对意味着我将不得不限制 gunicorn 的线程数,以确保我没有太多的活动连接。谢谢!
猜你喜欢
  • 2014-09-22
  • 2019-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-22
  • 2020-08-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多