uWSGI socket 队列被占满的问题

国庆之后第一天,同事在 uWSGI 的日志发现这样的东西:

真有意思,看日志的表面意思是 socket 的队列被占满了。

介绍一下我们的业务场景吧,这个 uWSGI 服务负责处理的 HTTP 请求大多数一个前端的应用发过来的,请求耗时会很长,最长可能到 2 分钟,最短 ms 级别。处理请求的耗时不稳定,请求的频率也不稳定,比如可能突然发过来很多耗时长的请求。

我们的 uWSGI 基本没有配置,大多都是默认的参数,所以出现这种日志几乎是必然的。在网上搜索了一下,看到几篇 CSDN “互相参考” 风格的解决方案:加大 socket queue 的 size。主要操作分成两步:

  1. 加大内核的 socket queue
  2. 加大 uWSGI 的 queue

uWSGI 有一个 stat server,因为我们使用的默认的参数,查看 uWSGI 的 stats 可以看到 socket 的队列最大为 100:

开始修改,首先使用 sysctl 加大 kernel 的 socket queue.  执行 sudo echo "net.core.somaxconn = 1024" >> /etc/sysctl.conf; sysctl -p。然后在 uWSGI 启动参数添加 listen = 2014

要注意的是,如果只修改了 uWSGI 的 listen 参数但是不修改系统参数,将会碰到下面这个错误。

修改之后可以重新看 stats 发现确实修改成了 1024:

看起来大功告成了,但是突然,我眉头一皱,发现事情并没有这么简单。如果 uWSGI 并发能力不够,那么加大队列并没有什么意义啊,早晚是会满的,无论改成多大,占满队列只是时间问题。所以同样的 warning 不加思索的照抄网上的方法是不可取的,要思考根本原因。根本原因就是有些请求处理时间太长了,而且都是 IO 耗时,这个时候最合理的方案是加大线程数量,增加并发能力。

uWSGI 默认是单进程单线程启动的,并发能力当然低了。一般来说进程数与 CPU 数相等。但是我们这个应用处理请求是高 IO 的,所以我每个进程又开了 32 个线程。在 uWSGI 中添加的配置如下:

 

推荐一个 debug 的工具,简直是神器:uwsgitop。uWSGI 自身提供一个 stats 服务器,可以是 socket 的,也可以是 http 的。这个工具可以自动帮你刷新 uWSGI 的实时状态,像 top 那样展示出来。关键是代码竟然只有 300 行左右,惊为天人。

uwsgitop 显示效果

Leave a comment

电子邮件地址不会被公开。 必填项已用*标注