前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版

Nginx中常用的模块整理与选型清单

首页2018-11-27 10:40:24Back-End
Nginx模块运维

Nginx 配置文件在线生成: https://nginxconfig.io/

Nginx 让人头疼的地方不在于指令难,而在于指令太多,而且不告诉你它属于哪个模块。你想做个限速,查到 limit_rate;想做个健康检查,查到 health_check,兴冲冲配上去 reload,报 unknown directive。原因是它压根不在你编译进来的模块里,或者干脆是商业版才有的。

这篇把 Nginx 里我实际用过的模块按能力分门别类过一遍,每个模块回答三个问题,它能干什么、什么场景下你会需要它、参数里哪几个是真正要调的。清单里的配置片段全部保留原样,我在每段前后补上了它在解决什么问题,以及自己踩过的坑。写于 2018 年,涉及 SSL、HTTP/2 这类会过时的部分,我把当年的写法留着,另起小段说明现在的情况。

在本篇文章中,我们将从浅入深,和大家一起学习以下知识:

  • 进程与事件层的性能参数,worker_processes 到底该写几
  • ngx_http_core_module 里那批高频指令,从 listen 到 limit_except
  • 访问控制、用户认证、状态查看这三个「运维刚需」模块
  • 日志、压缩、SSL 三个和线上表现直接相关的模块怎么调
  • rewrite 和 referer 的常见用法与陷阱
  • 反向代理模块的缓存体系,proxy_cache_path 那一长串参数分别管什么
  • upstream 的调度算法选型,以及哪些参数只在商业版生效
  • stream 模块做四层代理,什么时候它比 HAProxy 更合适
  • 配套的内核参数调优,以及这批参数在今天还成不成立

先说明一点,下面这些模块里,标准发行版默认编译进来的只是一部分。stub_status、ssl、stream 这几个都需要在 ./configure 阶段显式打开。装完之后敲一句 nginx -V,把输出里的 configure arguments 看一遍,你手上这个二进制有什么能力,那一行说得清清楚楚。这一步能省掉大量「配了没生效」的排查时间。

# 一、性能相关配置

这一组指令都写在配置文件的最外层,也就是 main 上下文,它们决定 Nginx 起几个干活的进程、每个进程能扛多少连接。调错了的表现不是报错,而是压测时怎么都上不去。

worker_processes number | auto;
@前端进阶之旅: 代码已经复制到剪贴板

worker进程的数量;通常应该为当前主机的cpu的物理核心数。多于8个的话建议写8,超过8个性能不会提升,稳定性降低

原文这句「多于 8 个建议写 8」是当年多数机器只有四核八核的经验值,现在服务器动辄三四十核,直接写 auto 让 Nginx 自己读 CPU 核心数就行。有一个场景要留神,在容器里跑的时候 auto 读到的是宿主机的核心数,而不是你给容器限的那点配额。给容器限了 2 核却起了 32 个 worker,进程之间抢 CPU 反而更慢。这种情况下就得按配额写死。

worker_cpu_affinity auto [cpumask] #将work进程绑定在固定cpu上提高缓存命中率 
# 例:
worker_cpu_affinity 0001 0010 0100 1000;
worker_cpu_affinity 0101 1010;
@前端进阶之旅: 代码已经复制到剪贴板

worker_cpu_affinity 是把每个 worker 钉死在指定的 CPU 核心上,减少进程在核心之间来回迁移带来的缓存失效。掩码是二进制位,0001 表示第一个核,0010 表示第二个核,一行写几组就是几个 worker 各自绑一个核。这个参数只在 Nginx 是这台机器上的主力进程时才划算,机器上还跑着数据库或者别的服务,绑核反而会让调度器没法腾挪。日常我基本不动它。

worker_priority number
# 指定worker进程的nice值,设定worker进程优先级: [-20,20]
@前端进阶之旅: 代码已经复制到剪贴板

这里原文写的取值区间不准,Linux 的 nice 值范围是 -20 到 19,越小优先级越高。想让 Nginx 在混部机器上抢到更多 CPU,可以往负值调,但改之前先确认这台机器上没有比它更重要的服务。

worker_rlimit_nofile number
worker # 进程所能够打开的文件数量上限,默认较小,生产中需要调大如65535。系统资源通过配置修改/etc/security/limits.conf 例:root soft nofile 65535,或命令修改ulimit -n,修改后需重启服务或系统生效。
@前端进阶之旅: 代码已经复制到剪贴板

这个参数是我认为整组里最容易被忽略、也最容易背锅的一个。Nginx 每接一个连接就要占一个文件描述符,反向代理场景下还要再占一个连回后端的。系统默认的 ulimit -n 通常是 1024,你把 worker_connections 配成 10240 是没用的,连接数到一千出头就开始报 too many open files。

改这个参数得两头一起改,配置里的 worker_rlimit_nofile 和系统的 /etc/security/limits.conf 缺一不可。

# 二、事件驱动events相关的配置

events 块管的是「怎么收连接」。它只有三四个指令,但每一个都直接决定并发上限。

  • 每个worker进程所能够打开的最大并发连接数数量,如10240
  • 总最大并发数: worker_processes * worker_connections
worker_connections number
@前端进阶之旅: 代码已经复制到剪贴板

这里的算法要注意,worker_processes * worker_connections 算出来的是「连接数」不是「并发请求数」。做反向代理的时候,一个客户端请求要占两个连接(客户端来的一个,转发到后端的一个),所以能撑的实际并发请求数要再除以 2。这个换算我一开始也是漏掉的,按 10240 去估容量,实测只有一半。

  • 指明并发连接请求的处理方法,默认自动选择最优方法不用调整
use method
# 如:use epoll;
@前端进阶之旅: 代码已经复制到剪贴板

use 这个指令基本不用手动写。Linux 上 Nginx 会自动选 epoll,FreeBSD 上选 kqueue,都是当前平台最优的那个。手写它唯一的用处是排查问题时确认它到底选了谁,nginx -V 和启动日志里都能看到。

  • on指由各个worker轮流处理新请求
  • Off指每个新请求的到达都会通知(唤醒)所有的worker进程,但只有一个进程可获得连接,造成「惊群」,影响性能,默认on
# 处理新的连接请求的方法
accept_mutex on | off # 互斥;
@前端进阶之旅: 代码已经复制到剪贴板

accept_mutex 是历史遗留问题的解法。早年内核没有解决惊群,多个 worker 同时被唤醒去抢一个连接,抢不到的白白唤醒一次,CPU 就浪费在这上面。加个互斥锁让 worker 轮流去 accept,惊群没了,但代价是新连接进来要等锁,高并发下反而增加延迟。

现在的情况反过来了。较新的 Nginx 版本里 accept_mutex 默认是 off,因为内核层面已经有 EPOLLEXCLUSIVE 和 SO_REUSEPORT 来处理惊群,比应用层加锁高效得多。真正推荐的做法是在 listen 上加 reuseport,让内核直接把连接分发到各个 worker,连锁都不用。原文写的默认值 on 是老版本的行为,具体默认值随版本变过,改之前对着你手上那个版本的官方文档确认一下。

# 三、http核心模块相关配置ngx_http_core_module

ngx_http_core_module 是唯一一个不用编译开关、不用额外声明就一定在的模块。你在 nginx.conf 里写的 server、location、root、listen,全部由它提供。所以它不像别的模块那样有一个明确的「功能边界」,它更像是 Nginx 的语法本身。

这一节的指令数量最多,我按用途分成了几块,实际配置时会反复回来查的也就是下面这十来个。

# 3.1web服务模板

一个虚拟主机的最小骨架就三行,监听哪个端口、认哪个域名、文件在哪。

server { ... }
# 配置一个虚拟主机
server {
    listen address[:PORT]|PORT;
    server_name SERVER_NAME; # 指令指向不同的主机名
    root /PATH/TO/DOCUMENT_ROOT;
} 
@前端进阶之旅: 代码已经复制到剪贴板

这个骨架有个容易忽略的点,root 写在 server 层还是 location 层结果不一样。写在 server 层是所有 location 的默认值,写在某个 location 里就只对那一段生效并且覆盖外层。混着写的时候,找不到文件的 404 往往就出在这儿。

# 3.2套接字相关配置

listen 决定这个 server 块从哪个地址、哪个端口收请求,后面那一串可选参数平时用到的不多,但每一个都是在特定场景下救过命的。

listen address[:port] [default_server] [ssl] [http2 | spdy] [backlog=number] [rcvbuf=size] [sndbuf=size]
@前端进阶之旅: 代码已经复制到剪贴板
  • default_server 设定为默认虚拟主机
  • ssl 限制仅能够通过ssl连接提供服务
  • backlog=number 超过并发连接数后,新请求进入后援队列的长度
  • rcvbuf=size 接收缓冲区大小
  • sndbuf=size 发送缓冲区大小

default_server 管的是「域名对不上时给谁」。有人拿 IP 直接访问你的服务器,或者把自己的域名解析到你的 IP 上,这类请求匹配不到任何 server_name,Nginx 就交给 default_server。不显式指定的话,同端口第一个 server 块自动当默认。生产环境我一般会专门写一个只返回 444 的默认块,把这类野请求直接掐掉。

backlog 是内核层面的等待队列长度,短时间涌进来大量新连接、worker 一时来不及 accept 的时候,多出来的连接排在这个队列里。队列满了内核就直接丢,客户端表现为连接超时而不是 502。这个值同时受 net.core.somaxconn 限制,只调 Nginx 不调内核是没用的,这一点和后面那份 sysctl 调优是配套的。

spdy 现在已经不用看了,它是 HTTP/2 标准化之前的过渡协议,早就从 Nginx 里移除。至于 listen 443 ssl http2 这个写法,新版本改成了独立的 http2 on; 指令,老写法一段时间内还兼容但会有 deprecated 提醒。你手上是哪种,以 nginx -V 的版本号对着官方文档看,别照抄博客。

# 3.3 server_name

  • 支持*通配任意长度的任意字符
server_name *.magedu.com www.magedu.*
@前端进阶之旅: 代码已经复制到剪贴板
  • 支持~起始的字符做正则表达式模式匹配,性能原因慎用
server_name ~^www\d+\.magedu\.com$   #\d 表示 [0-9]
@前端进阶之旅: 代码已经复制到剪贴板

匹配优先级机制从高到低:

  • 首先是字符串精确匹配 如: www.magedu.com
  • 左侧*通配符 如: *.magedu.com
  • 右侧*通配符 如: www.magedu.*
  • 正则表达式 如: ~^.*\.magedu\.com$
  • default_server
fe
  • 一、性能相关配置
  • 二、事件驱动events相关的配置
  • 三、http核心模块相关配置ngx_http_core_module
    • 3.1web服务模板
    • 3.2套接字相关配置
    • 3.3 server_name
    • 3.4 延迟发送选项
    • 3.5 sendfile
    • 3.6 隐藏版本信息
    • 3.7 location匹配
    • 3.8 错误页面显示
    • 3.9 长连接相关配置
    • 3.10 请求报文缓存
    • 3.11 对客户端进行限制相关配置
  • 四、访问控制模块ngx_http_access_module
  • 五、用户认证模块ngx_http_auth_basic_module
  • 六、状态查看模块ngx_http_stub_status_module
  • 七、日志记录模块ngx_http_log_module
  • 八、压缩相关选项ngx_http_gzip_module
  • 九、https模块ngx_http_ssl_module模块:
  • 十、重定向模块ngx_http_rewrite_module
  • 十一、引用模块ngx_http_referer_module
  • 十二、反向代理模块ngx_http_proxy_module
    • 12.1 proxy_pass URL
    • 12.2 proxy_set_header field value
    • 12.3 proxy_cache_path
    • 12.4 调用缓存
    • 12.5 proxy_cache_key string
    • 12.6 proxy_cache_valid [code …] time;
    • 12.7 proxy_cache_use_stale
    • 12.8 proxy_cache_methods GET | HEAD | POST
    • 12.9 proxy_hide_header field;
    • 12.10 proxy_connect_timeout time;
    • 12.11 proxy_send_timeout time
    • 12.12 proxy_read_timeout time;
  • 十三、首部信息
  • 十四、php 相关模块ngx_http_fastcgi_module
  • 十五、代理模块ngx_http_upstream_module模块
    • 15.1 upstream name { … }
    • 15.2 server address [parameters];
    • 15.3 ip_hash 源地址hash调度方法
    • 15.4 least_conn
    • 15.5 hash key [consistent]
    • 15.6 keepalive
    • 15.7 health_check [parameters]
    • 15.8 match name { … }
  • 十六、ngx_stream_core_module模块
  • 十七、ngx_stream_proxy_module模块
  • 十八、proxy_pass 路径拼接的四种情况
  • 十九、rewrite 与正则速查
  • 二十、log_format 与日志字段
  • 二十一、ssl证书加密配置
  • 二十二、sendfile
  • 二十三、keepalive_timeout
  • 二十四、gzip
  • 二十五、客户端上传文件限制
  • 二十六、worker_processes和worker_connections
  • 二十七、stream模块
  • 总结
  • 参考

← babel升级7.xx总结Taro原理总结 →