7

我刚刚想到的东西:

假设我正在为我的 Django 站点编写视图代码,我犯了一个错误并创建了一个无限循环。

每当有人试图访问视图时,分配给请求的工作人员(无论是 Gevent 工作人员还是 Python 线程)都会无限期地停留在循环中。

如果我理解正确,服务器会在 30 秒后向客户端发送超时错误。但是 Python 工作者会发生什么?它会无限期地继续工作吗?听起来很危险!

想象一下,我有一台服务器,其中分配了 10 个工作人员。我让它运行,在某个时候,客户端尝试使用无限循环访问视图。一个工人将被分配给它,并且在下一次服务器重新启动之前将有效地死亡。危险的是,一开始我不会注意到它,因为站点会慢得不知不觉,有 9 个工人而不是 10 个。但它可能会在很长一段时间内一次又一次地发生,可能是几个月。该站点会逐渐变慢,直到最终只有一名工人时它会变得非常慢。

服务器重启可以解决问题,但我不想让我的网站的功能依赖于服务器重启。

这是一个真正的问题吗?有没有办法避免它?

更新:我也非常感谢一种方法来获取陷入无限循环的线程/工作者的堆栈跟踪,所以我可以通过电子邮件将其通过电子邮件发送给我,这样我就会意识到这个问题。(我不知道该怎么做,因为没有引发异常。)

更新人们所说的“避免编写具有无限循环的代码”的内容:如果不是很明显,我不会在空闲时间故意将无限循环放入我的代码中。当这些事情发生时,它们就是错误,错误可以被最小化,但永远不能完全避免。我想知道,即使我犯了错误,也会有一个安全网通知我并让我解决问题。

4

3 回答 3

5

这是一个真正的问题。在 gevent 的情况下,由于上下文切换,它甚至可以立即阻止您的网站响应。

一切都取决于您的环境。例如,当通过 uwsgi 在生产环境中运行 django 时,您可以设置harakiri- 以秒为单位的时间,在此之后处理请求的线程如果没有完成处理响应将被终止。强烈建议设置这样的值,以处理一些错误的请求或错误的代码。此类事件在 uwsgi 日志中报告。我相信在生产中运行 Django 的其他解决方案也有类似的选择。

否则,由于网络架构的原因,客户端断开连接不会停止无限循环,默认情况下根本没有响应——只是无限加载。各种超时选项(其中之一harakiri)可能最终显示连接超时 - 例如,php(据我记得)默认超时为 30 秒,它将返回 504 网关超时。套接字断开超时取决于 http 服务器设置,它不会停止应用程序线程,它只会关闭客户端套接字。

如果不使用 gevent(或任何其他绿色线程),无限循环往往会占用 100% 的可用 CPU 功率(仅限于一个核心),可能会占用越来越多的内存,因此您的网站运行速度会很慢和/或超时真的很快。Django 本身不知道请求时间,所以——如前所述——你的生产环境堆栈是防止这种情况发生的方法。在 uwsgi 的情况下,http ://uwsgi-docs.readthedocs.org/en/latest/Options.html#harakiri-verbose是要走的路。

Harakiri 确实打印被杀死进程的堆栈跟踪:(https://uwsgi-docs.readthedocs.org/en/latest/Tracebacker.html?highlight=harakiri)直接到 uwsgi 日志,并且由于警报系统,您可以通过电子邮件(http://uwsgi-docs.readthedocs.org/en/latest/AlarmSubsystem.html

于 2013-04-28T12:12:23.253 回答
2

我刚刚在 Django 的开发服务器上对此进行了测试。

结果:

  • 30 秒后不超时。(这可能是因为它不是生产服务器)
  • 一直在加载,直到我关闭页面。

我想避免它的一种方法是使用线程来控制超时并能够停止线程,而实际上只是避免这样的代码。

也许是这样的:

import threading
from django.http import HttpResponse

class MyThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
    def run(self):
        print "your possible infinite loop code here"

def possible_loop_view(request):
    thread = MyThread()
    thread.start()
    return HttpResponse("html response")
于 2013-04-27T13:33:48.823 回答
0

是的,你的分析是正确的。工作线程/进程将继续运行。此外,如果循环中没有等待/睡眠,它将占用 CPU。其他线程/进程将获得非常少的 cpu,导致您的整个站点响应缓慢。

另外,我认为服务器不会显式地向客户端发送任何超时错误。如果设置了 TCP 超时,则 TCP 连接将被关闭。

客户端也可能有一些超时设置来获得响应,这可能会出现。

避免此类代码是避免此类代码的最佳方法。您还可以在服务器上安装一些监控工具来查找 CPU/内存使用情况并通知异常活动,以便您采取措施。

于 2013-04-27T13:25:23.913 回答