Nginx调优别急着改参数,先把这三处瓶颈定位清楚
一台4核8G的机器,Nginx跑静态文件,理论上一秒钟处理几千个请求不难。但真到线上压测,requests per second经常只有两三百,CPU占用还不到30%。这种时候多数人第一反应是去翻配置文件,把worker_connections从1024改到65535,把worker_processes改成auto,重启一遍,发现数字几乎没动。问题不在参数,在于没搞清楚瓶颈在哪一层。
调优这件事,顺序比参数重要。先定位,再改配置,改完再压一遍对比。跳过定位直接抄参数,等于闭着眼睛换零件。
先压出真实数字,别用感觉判断快慢
没有基线就没法判断优化有没有效果。我一般会先用wrk或ab跑一轮,拿到两个数:每秒请求数,以及平均延迟。这两个数要一起看。requests per second高但延迟也高,说明并发上去了但每个请求都慢;requests per second低而延迟很低,说明压力根本没打上来,可能是压测机自己成了瓶颈。
压测机的网卡和CPU要留够余量。用一台2核的小机器去压一台8核的Nginx,测出来的数字是压测机的上限,不是服务器的上限。我见过不少这样的配置,测了半天其实在测自己。
压测命令里把连接数从10逐步加到500,观察requests per second的变化曲线。曲线在某个点开始走平甚至下降,那个点就是当前配置的实际容量。这个容量值才是后面调参的参照。
连接打满还是单请求慢,两种病要用两种药
容量上不去,无非两类原因。一类是连接数不够用,表现为大量请求在排队,Nginx的error log里出现worker_connections are not enough。另一类是单个请求处理太慢,连接数没满,但每个请求都要等很久。
区分方法很直接。看Nginx的stub_status或者access log里的request_time。request_time普遍在几十毫秒以上,那是后端或者磁盘的问题,加连接数没用。
worker_connections要配合worker_processes一起调。worker_processes设成CPU核心数,4核就写4。worker_connections乘以worker_processes就是理论最大并发连接。但真正卡住并发的往往是系统层面的文件描述符限制,ulimit -n和nginx.conf里的worker_rlimit_nofile都要放开,通常设到65535。
- 连接数不够:error log报worker_connections不足,调worker_connections和worker_rlimit_nofile
- 单请求慢:request_time偏高,去查后端响应、磁盘IO或DNS解析
keepalive_timeout这个参数值得单独说。默认65秒,长连接能减少TCP握手开销,但连接一直占着不放会吃内存。静态资源多的站点,设成15到30秒通常够用。
静态文件和反向代理,优化重点完全不同
如果Nginx主要发静态文件,瓶颈多半在磁盘IO和系统调用上。sendfile on打开之后,数据从磁盘到网卡走内核直接搬运,不用在用户态和内核态之间来回拷。这个参数对静态站点提升明显,通常能省掉一半以上的CPU开销。搭配tcp_nopush on,把多个小包合并成一个大包发出去,减少网络上的包数量。
如果Nginx做反向代理,重点就换了。上游服务器的响应时间直接决定整体延迟,Nginx这边能做的有限。proxy_buffering打开可以让Nginx先把上游的响应缓存下来再发给客户端,慢客户端不会拖住上游连接。proxy_connect_timeout和proxy_read_timeout设短一点,比如10秒,避免上游卡死时连接一直挂着。
CPU中断这块容易被忽略。网卡中断如果全压在CPU0上,其他核心再空也没用。多队列网卡配合irqbalance或者手动绑核,能把中断分散到多个核心。这个改动对高pps的场景提升不小,但配置起来比改nginx.conf麻烦,要不要做取决于你的瓶颈是不是真的在中断上。
改完一轮参数,重新压一遍,和之前的基线数字对比。requests per second涨了,说明改对了;没涨,退回去换下一个方向。调优是个排除法,不是一次性配好就完事。
最后说服务器选型这一层。Nginx调优能榨出多少性能,和底层硬件关系很大。CPU主频高、单核性能强的机器,单请求处理就快;内存带宽足,反向代理缓存大对象时不容易卡。如果是高并发的静态分发场景,香港大带宽物理服务器 X 配的是E5-2660双路、64G内存、250M带宽,月付1683.17美元,适合流量已经跑起来、需要靠带宽和CPU一起扛的站点。流量还没到那个量级之前,先把参数调明白,比换机器划算。