【发布时间】:2018-03-31 21:19:09
【问题描述】:
在与各种 Web 服务通信的 Django 项目上运行 Python,我们遇到了一个问题,即偶尔请求需要大约 5 秒而不是通常的
我已将其缩小到 socket.getaddrinfo 函数所花费的时间 - 当我们连接到外部服务时,requests 会调用它,但它似乎也会影响到 Postgres 数据库框中的默认 Django 连接集群。当我们在部署后重新启动uwsgi 时,第一个进来的请求将需要 5 秒来发送响应。我也相信我们的 celery 任务通常需要 5 秒,但我还没有向它们添加 statsd 计时器跟踪。
我已经写了一些代码来重现这个问题:
import socket
import timeit
def single_dns_lookup():
start = timeit.default_timer()
socket.getaddrinfo('stackoverflow.com', 443)
end = timeit.default_timer()
return int(end - start)
timings = {}
for _ in range(0, 10000):
time = single_dns_lookup()
try:
timings[time] += 1
except KeyError:
timings[time] = 1
print timings
典型结果为{0: 9921, 5: 79}
我的同事已经指出了有关 ipv6 查找时间的潜在问题,并将其添加到 /etc/gai.conf:
precedence ::ffff:0:0/96 100
这无疑改善了非 Python 程序的查找,例如我们使用的 curl,但不是来自 Python 本身。服务器运行的是 Ubuntu 16.04.3 LTS,我可以在带有 Python 2 的 vanilla VM 上重现它。
我可以采取哪些步骤来提高所有 Python 查找的性能,以便它们可以花费
【问题讨论】:
-
你的dns解析器好像很慢,试试ncsd?
-
@georgexsh 我不确定 nscd 将如何提供帮助 - 第一个未缓存的请求仍需要 5 秒。在缓存值过期后,通过解析器的第一个请求将再次花费 5 秒。这只会减少慢请求的百分比,而不是完全删除它们,对吗?
-
您是否尝试过使用
sysctl net.ipv6.conf.all.disable_ipv6=1完全禁用 IPv6 堆栈,并检查是否能解决您的问题?如果是,那么很可能您的python链接到不尊重 gai.conf 的 glibc 版本(或静态编译的)。 -
无法在 vagrant ubuntu/xenial64 本地复制
-
考虑使用
collections.Counter,而不是自己使用KeyError
标签: python sockets dns python-requests