在具有三个 docker 实例的设置中,一个运行 haproxy,另外两个通过 uWsgi 运行基于 Flask 的 python 应用程序,我们在大约一天后遇到一种情况,一个或两个实例上不接受新连接。
uWsgi 设置为接受最多 100 个积压连接。这小于 中配置的默认 128 /proc/sys/net/core/somaxconn
。 uWsgi 放弃第 101 个连接。
ss
确认积压数量为 101。
root@ad9380a94c50:/# ss -nlpt
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 101 100 *:8080 *:* users:(("uwsgi",pid=25,fd=3),("uwsgi",pid=19,fd=3))
LISTEN 0 128 127.0.0.11:38230 *:*
运行时没有对应的连接,例如netstat -npt
。
uwsgi的源码显示,backlog队列长度是通过调用getsockopt
abd检索tcpi_unacked
字段得到的。换句话说,这似乎不是 uwsgi 中的错误,Linux 内核和/或 docker 似乎认为存在实际上并不存在的连接。我怀疑它们曾经存在过,以 haproxy 进行的健康检查的形式存在。
不会出现积压日志缓慢增加的情况。虽然实例运行良好,但积压仍为零。好像出了什么问题,之后积压的订单很快就达到了 100,事情就挂了。
我们在 Amazon 虚拟机上运行 docker。
答案1
该进程在互斥体(或 Linux 中的 futex)上阻塞。所以积压是合法的,我们实际上被困在系统调用后面,尽管连接消失了,但没有其他更新。
为了将来给发现这个问题的其他人提供参考,这是突破性的命令:
# strace -p 5340
Process 5340 attached
futex(0x223cee0, FUTEX_WAIT_PRIVATE, 0, NULL
所以存在某种死锁,我现在只需弄清楚哪个进程正在使用互斥体。gdb
最终给了我这些信息:
(gdb) bt
#0 sem_wait () at ../nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S:85
#1 0x00007f0ecc982068 in PyThread_acquire_lock () from /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0
#2 0x00007f0ecd037b29 in gil_real_get () from /usr/lib/uwsgi/plugins/python_plugin.so
#3 0x00007f0ecd030167 in uwsgi_python_master_fixup () from /usr/lib/uwsgi/plugins/python_plugin.so
#4 0x000000000042cb66 in uwsgi_respawn_worker ()
#5 0x000000000042b38f in master_loop ()
#6 0x000000000046741e in uwsgi_run ()
#7 0x000000000041698e in main ()
因此,在尝试获取全局解释器锁时会出现某种死锁。
编辑2: 情节变厚了。几乎完全相同的问题这家伙,只不过我们使用的是 RabbitMQ 而不是 MongoDB。运行第二个线程会导致重新加载期间出现问题,有时会导致 GIL 无法释放,然后在尝试重新获取它时挂起。
基本上,我们正在做一些不应该做的事情,只需要重新思考整个事情。