多个Python进程变慢

dan*_*360 4 python unix performance http task

我有一个python脚本,它会向各个域发出大量的HTTP和urllib请求.

我们有大量的域进程,需要尽快完成.由于HTTP请求很慢(即它们可能超出域上没有网站),我会在任何时候运行一些脚本,从数据库中的域列表中提取它们.

我看到的问题是在一段时间内(几小时到24小时)脚本都开始变慢,ps -al显示它们正在睡觉.

服务器功能非常强大(8核,72GB RAM,6TB Raid 6等80MB 2:1连接)并且永远不会超出,即Free -m显示

-/+ buffers/cache:      61157      11337
Swap:         4510        195       4315
Run Code Online (Sandbox Code Playgroud)

顶部显示80-90%闲置

sar -d显示平均5.3%的效用

更有趣的是,iptraf以大约50-60MB/s的速度开始,大约4小时后最终达到8-10MB/s.

我目前在每台服务器(2台服务器)上运行大约500个版本的脚本,它们都显示相同的问题.

ps -al 显示大多数python脚本正在睡觉,我不明白为什么例如:

0 S 0 28668  2987  0  80   0 - 71003 sk_wai pts/2 00:00:03 python
0 S 0 28669  2987  0  80   0 - 71619 inet_s pts/2 00:00:31 python
0 S 0 28670  2987  0  80   0 - 70947 sk_wai pts/2 00:00:07 python
0 S 0 28671  2987  0  80   0 - 71609 poll_s pts/2 00:00:29 python
0 S 0 28672  2987  0  80   0 - 71944 poll_s pts/2 00:00:31 python
0 S 0 28673  2987  0  80   0 - 71606 poll_s pts/2 00:00:26 python
0 S 0 28674  2987  0  80   0 - 71425 poll_s pts/2 00:00:20 python
0 S 0 28675  2987  0  80   0 - 70964 sk_wai pts/2 00:00:01 python
0 S 0 28676  2987  0  80   0 - 71205 inet_s pts/2 00:00:19 python
0 S 0 28677  2987  0  80   0 - 71610 inet_s pts/2 00:00:21 python
0 S 0 28678  2987  0  80   0 - 71491 inet_s pts/2 00:00:22 python
Run Code Online (Sandbox Code Playgroud)

脚本中没有睡眠状态被执行,所以我无法理解为什么ps -al显示大多数睡眠状态以及为什么当CPU,内存,磁盘访问和带宽为时,它们应该越来越慢,从而减少IP请求的时间.所有可用的丰富.

如果有人可以提供帮助,我将非常感激.

编辑:

代码是巨大的,因为我通过它使用异常来捕获有关域的诊断,即我无法连接的原因.如果需要,可以在某处发布代码,但是通过HTTPLib和URLLib的基本调用是直接的python示例.

更多信息:

quota -u mysql quota -u root

一无所获

nlimit -n返回1024有更改limit.conf允许mysql允许16000软和硬连接,并且能够运行超过2000脚本到目前为止,但仍然是问题.

一些进展

好吧,所以我已经改变了用户的所有限制,确保所有套接字都关闭(它们没有),虽然情况比较好,但我仍然慢下来虽然没有那么糟糕.

有趣的是,我也注意到了一些内存泄漏 - 脚本运行的时间越长,内存越多,但我不确定是什么导致这种情况.我将输出数据存储在一个字符串中,然后在每次迭代后将其打印到终端,我也在最后清除字符串,但是不断增加的内存可以降低到存储所有输出的终端吗?

编辑:似乎没有 - 跑出30个脚本而没有输出到终端,仍然是相同的泄漏.我没有使用任何聪明的东西(只是字符串,HTTPlib和URLLib) - 想知道python mysql连接器是否有任何问题......?

cho*_*own 7

检查ulimitquota选择框和运行脚本的用户. /etc/security/limits.conf也可能包含您可能想要修改的资源限制.

ulimit -n 将显示允许的最大打开文件描述符数.

  • 所有打开的插座都可能超过这个数量?
  • 脚本在完成后会关闭每个套接字吗?

您还可以检查fd,ls -l /proc/[PID]/fd/其中[PID]一个脚本的进程ID 在哪里.

需要看一些代码来说明真正发生的事情..


编辑(导入评论和更多故障排除想法):

你能显示打开关闭连接的代码吗?
刚运行一些脚本进程时,它们是否也会在一段时间后开始闲置?或者只有当有几百个+一次运行时才发生这种情况?
是否有单个父进程启动所有这些脚本?

如果您使用s = urllib2.urlopen(someURL),请确保s.close()完成后再使用它.Python 通常可以为你关闭事情(比如你做的事情x = urllib2.urlopen(someURL).read()),但如果你被告知(例如将变量赋值给返回值),它会留给.urlopen().仔细检查urllib调用的打开和关闭(或所有 I/O代码是否安全).如果每个脚本被设计为一次只有一个打开的套接字,并且/proc/PID/fd每个脚本进程显示多个活动/打开套接字,那么肯定有一个代码问题需要修复.

ulimit -n显示1024被给予限制开放的插座/ FD的是,MySQL的用户都可以有,你可以改变这个ulimit -S -n [LIMIT_#],但首先看看这篇文章:
用"的ulimit -n"更改的process.max-文件描述符会导致MySQL来改变table_open_cache值.

您可能需要注销并重新封装.和/或将其添加到/etc/bashrc(source /etc/bashrc如果您更改bashrc并且不想注销/中,请不要忘记).

磁盘空间是我发现的另一件事(困难的方式)会导致非常奇怪的问题.我的进程就像它们正在运行(没有被僵尸)但没有做到预期的,因为它们在没有磁盘空间的分区上有一个日志文件的打开句柄.

netstat -anpTee | grep -i mysql 还将显示这些插座是否已连接/建立/等待关闭/等待超时/等.

watch -n 0.1 'netstat -anpTee | grep -i mysql'在一个漂亮的表输出中实时查看套接字打开/关闭/更改状态/ etc (export GREP_OPTIONS=如果你将它设置为类似的话可能需要首先--color=always).

lsof -u mysql或者lsof -U还会显示你打开的FD(输出非常详细).


import urllib2
import socket

socket.settimeout(15) 
# or settimeout(0) for non-blocking:
#In non-blocking mode (blocking is the default), if a recv() call 
# doesn’t find any data, or if a send() call can’t
# immediately dispose of the data,
# a error exception is raised.

#......

try:
    s = urllib2.urlopen(some_url)
    # do stuff with s like s.read(), s.headers, etc..
except (HTTPError, etcError):
    # myLogger.exception("Error opening: %s!", some_url)
finally:
    try:
        s.close()
    # del s - although, I don't know if deleting s will help things any.
    except:
        pass
Run Code Online (Sandbox Code Playgroud)

一些手册页和参考链接: