Python 的日志 SMTP 处理器会让我的线程冻结 2 分钟吗?

2 投票
2 回答
754 浏览
提问于 2025-04-15 22:04

根据我的日志文件,发生了一系列让我感到困惑的事情,我准备把很多责任推给Python的日志系统,这个说法有点大胆。我觉得我应该听听其他人的意见,看看我说的是否有道理。

我想解释一下,为什么在我的应用程序遇到压力、错过截止时间的时候,日志文件中会出现几个大空白(大约每次两分钟)。

我在一个远程服务器上使用Python的日志模块,并通过配置文件设置了所有严重性为ERROR或更高的日志会发邮件给我。通常情况下,一次只会发一条错误信息,但在持续出现问题的时候,我可能会在一分钟内收到十几条邮件——这虽然让人烦,但应该不会对SMTP造成太大压力。

我觉得,在短时间内收到这样的消息后,Python的日志系统(或者说它所依赖的SMTP系统)可能会遇到错误或拥堵。这样一来,调用Python日志的过程就会被“阻塞”两分钟,导致我的线程错过了截止时间。(我聪明地把日志记录放在了应用程序的关键路径之后——所以我不在乎日志记录花费几秒钟,但两分钟就太长了。)

这看起来像是一个相当尴尬的架构(既有可能让日志系统卡住,也有可能让SMTP系统(Ubuntu,sendmail)无法处理一分钟内几十封邮件),所以这让我感到惊讶,但这正好符合我遇到的问题。

有没有人有过类似的经历?能不能告诉我怎么解决这个阻塞的问题?

** 编辑 #2:我实际上数了一下。两小时内发了170封邮件。忘掉之前的编辑吧,我数错了。这里已经很晚了……

2 个回答

1

两分钟的暂停听起来像是超时了——很可能是在网络方面出现了问题。

试着在所有相关机器的:

*                -       nofile          64000

的 /etc/security/limits.conf 文件中添加这些内容,然后重启所有机器,以确保这些设置能应用到所有正在运行的服务上。

2

压力测试的结果很有启发性:

我的日志配置把重要信息发送到SMTPHandler,而调试信息则记录在本地日志文件里。

为了测试,我创建了大约50个线程,它们会等待一个触发信号,然后同时尝试记录一个重要信息或调试信息,具体取决于测试内容。

测试#1:所有线程发送重要信息:结果显示,第一个重要信息发送大约花了0.9秒。第二个重要信息发送大约花了1.9秒。第三个更长,时间迅速累加。看起来,发送到邮箱的消息在互相等待完成发送。

测试#2:所有线程发送调试信息:这些运行得相当快,从几百微秒到几千微秒不等。

测试#3:两者混合。结果显示,调试信息也在等待重要信息的邮件发送,导致被阻塞。

所以,2分钟并不是说超时,而是代表有很多线程在队列中被阻塞在等待。

为什么会有这么多重要信息同时发送呢?这就是讽刺了。在一个方法里有一个logging.debug()的调用,这个方法还包括了一个网络调用。我有一些代码在监控这个方法的速度(看看网络调用是否太慢)。如果太慢,它(当然)会记录一个重要错误并发送邮件。接下来的线程就被logging.debug()的调用阻塞了,导致它错过了截止时间,触发了另一个邮件,又导致另一个线程运行缓慢。

一个线程的2分钟延迟并不是网络超时,而是一个线程在等待另一个线程,而那个线程被阻塞了1分57秒,因为它在等待另一个被阻塞了1分55秒的线程,依此类推。

这不是SMTPHandler很好的表现。

撰写回答