驽马十驾 驽马十驾

驽马十驾,功在不舍

目录
Nginx配置不当导致大流量下 Websocket 连接异常问题分析和处理
/  

Nginx配置不当导致大流量下 Websocket 连接异常问题分析和处理

开篇

项目使用到了基于Netty的长连接,最近有一次活动,线上存在大流量,活动开始后的一段时间,各个指标正常,但是一段时间后就出现了部分用户无法连接上 WebSocket,需要重试多次才能连接。

首先来看看项目背景:

  • Netty作为Websocket的底层,Netty的性能不需要质疑。
  • Nginx作为代理,将Websocket升级到wssNginx的性能也不需要质疑。

所以整体来说就是:流量先打到了Nginx再通过他转发到了NettyWebsocket

正文

第一步查看了Java应用的内存占用和CPU占用,未发现异常。再查看 JVMGC情况,发现也是正常的,没有任何疑点。

所以我暂时排除了Java 应用导致的问题,也没有采用没有重启服务的万金油方案。

此时移动端和前端都提供了一个信息:建立Websocket长连接的时候,服务端返回了500或者50X

50X该问题通常是由于连接被客户端或者服务端主动断开导致的。在当时情况下,移动端和前端都应该是没有问题的,那么问题就应该后端,后端关键组件是NginxJava应用,排除了Java应用,那么就剩下Nginx了。

通过如下指令查看Nginx的日志

tail -f /log/access.log

发现确实存在GET请求就出现了502的错误。

结合当时情况来看,流量确实是有些大,但是我不信久经沙场的Nginx这么脆弱,所以估计是配置问题。

打开 Nginx配置,发现有如下关键配置

worker_processes 1;
events {
    worker_connections 1024;
}
http {
    include mime.types;
		....
}

可以发现这个 worker_connections1024,这个配置代表的含义的:单个进程能够建立的最大连接数。很明显,在大流量下1024肯定是不够的,所以该参数完全可以修改的更大。

该参数也并随便多大,受限于单个进程能够打开的最大文件数和系统内存:

  • Linux所有的资源都是文件,单个进程能够打开的最大文件数受制于系统的设置,可以通过ulimit -n获取,该参数通常是65535
  • 每个连接都是需要消耗内存资源的,大概是一个连接消耗328字节,所以可以计算下:65535*328/1024/1024=20.5MB

综上,经过修改后的 Nginx 配置如下:

# 2 个 进程
worker_processes 2;

# 能够打开的最大文件数
worker_rlimit_nofile 65535;

events {
    # 单个进程允许的客户端最大连接数
    worker_connections 65535;
}

然后重新或者重新加载 Nginx 配置文件后,通过如下指令观察了一段Nginx在处理Websocket升级的日志后,发现一切正常了。

tail -f xxx/accees.log

补充

这里在记录下这个过程中用到的一些命令:

  1. 查看Nginx进程可以打开的最大文件句柄数
# 该指令会有 2 个输出
ps -ef | grep nginx
# 获取文件句柄数 
cat /proc/$pId/limits 
# 然后查看`Max open files` 的数量
  1. 查看Nginx进程当前打开的文件数
lsof -p $pId |wc -l
  1. 假如Nginx部署在docker中,如何进入docker
docker exec -it nginx bash
  1. 配置系统和系统的最大文件数
# 查看进程能够打开的最大进程数
ulimit -n
# 查看系统能够打开的最大文件数
cat /proc/sys/fs/file-max

#设置进程
vim /etc/security/limits.conf
# 加入配置
* soft nofile 65535 
* hard nofile 65535

# 设置系统能够打开的最大文件数
vim /etc/sysctl.conf
# 加入配置
fs.file-max=6553560

# 最后重启
reboot now

结语

解决问题,一定要学会分析问题的源头到底在哪里,不要遇到问题就只会傻傻的重启服务来解决。

不积跬步,无以至千里。不积小流,无以成江海。