【问题标题】:Why do Gunicorn sync workers hang when spawning threads?为什么 Gunicorn 同步工作者在生成线程时会挂起?
【发布时间】:2015-04-17 14:15:36
【问题描述】:

我有一个spawns a new thread for each log entry 的 Python 日志处理程序,并且在新线程中,日志被发送到另一台服务器。但是,我发现请求间歇性地超时。如果我禁用处理程序,问题就会消失。

我尝试过其他 WSGI 服务器(WSGIUtils、WSGIRef),但无法重现此问题。

有什么想法吗?

我在 Debian 上运行 Gunicorn 19.3 和同步工作者和 Django 1.6。

【问题讨论】:

  • 这是在请求周期内记录吗?您确定在等待将日志推送到套接字时没有阻塞线程吗?
  • 我不确定新线程如何干扰 gunicorn,但为每个日志消息创建一个新线程非常昂贵。尝试创建一个队列和一个处理队列中日志条目的工作线程。然后日志系统的其余部分可以推入队列,这应该非常快。
  • @andrefsp:是的,线程中的函数很可能需要很长时间才能完成,但是为什么这会影响完成请求所需的时间?
  • @AaronDigulla 我同意它会更贵,但我们这样做是因为它需要更少的代码(与拥有队列相比)并且性能税在测试中并不重要。但是,这怎么会导致工作人员响应请求的时间过长?

标签: python gunicorn


【解决方案1】:

我认为这是 GIL - Global Interpreter Lock 的另一种情况。假设发生这种情况:

  • 请求进来
  • 工人启动
  • 工作日志 -> 线程已启动
  • 工人完成
  • 已发送响应
  • 线程日志事件

看起来不错,对。但是如果线程的工作速度更快呢?然后你得到:

  • 请求进来
  • 工人启动
  • 工作日志 -> 线程已启动
  • 工人完成
  • 线程日志事件
  • 已发送响应

根据线程持有的锁或它调用的操作系统函数,线程可能在一段时间内不会释放 GIL,这会阻塞工作线程或至少阻止响应完全传递。

查看代码时,我发现您正在为每条日志消息创建 SSL 连接。 SSL 非常、非常、非常昂贵。不要那样做。相反,创建一个工作线程,它打开 SSL 套接字一次并保持打开状态。当您写入套接字时,python 库应该释放 GIL,以便其他代码可以工作。但我不确定 Python 是否会在您打开套接字时释放锁。

【讨论】:

  • 谢谢!但是使用队列的单个长时间运行的线程不会出现同样的问题吗?既然您说“取决于线程持有的锁或它调用的操作系统函数,线程可能在一段时间内不会释放 GIL”。长时间运行的线程可能也会发生同样的情况,对吧?
  • 我也忘了问:如果是 GIL,为什么其他 WSGI 服务器不会发生这种情况?我试过 WSGIUtils 和 WSGIRef 都没有问题。
  • 您可以尝试只创建一次 SSL 连接吗?如果可行,我知道为什么会出现问题。
猜你喜欢
  • 2015-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-20
  • 1970-01-01
  • 1970-01-01
  • 2018-07-29
  • 1970-01-01
相关资源
最近更新 更多