总字符数: 17.17K
代码: 8.84K, 文本: 3.25K
预计阅读时间: 53 分钟
Nginx 实战
我始终认为,各种开发工具的配置还是结合实战来讲述,会让人更易理解.
Http 反向代理
我们先实现一个小目标:不考虑复杂的配置,仅仅是完成一个 http 反向代理.
nginx.conf
配置文件如下:
注:
conf/nginx.conf
是 nginx 的默认配置文件.你也可以使用 nginx -c 指定你的配置文件
1 | #运行用户 |
好了,让我们来试试吧:
- 启动 webapp,注意启动绑定的端口要和 nginx 中的
upstream
设置的端口保持一致. - 更改 host:在 C:\Windows\System32\drivers\etc 目录下的 host 文件中添加一条 DNS 记录
1 | 127.0.0.1 www.helloworld.com |
- 启动前文中 startup.bat 的命令
- 在浏览器中访问 www.helloworld.com,不出意外,已经可以访问了.
Https 反向代理
一些对安全性要求比较高的站点,可能会使用 HTTPS(一种使用 ssl 通信标准的安全 HTTP 协议).
这里不科普 HTTP 协议和 SSL 标准.但是,使用 nginx 配置 https 需要知道几点:
- HTTPS 的固定端口号是 443,不同于 HTTP 的 80 端口
- SSL 标准需要引入安全证书,所以在 nginx.conf 中你需要指定证书和它对应的 key
其他和 http 反向代理基本一样,只是在 Server
部分配置有些不同.
1 | #HTTP服务器 |
负载均衡
前面的例子中,代理仅仅指向一个服务器.
但是,网站在实际运营过程中,大部分都是以集群的方式运行,这时需要使用负载均衡来分流.
nginx 也可以实现简单的负载均衡功能.
假设这样一个应用场景:将应用部署在 192.168.1.11:80、192.168.1.12:80、192.168.1.13:80 三台 linux 环境的服务器上.网站域名叫 www.helloworld.com ,公网 IP 为 192.168.1.11.在公网 IP 所在的服务器上部署 nginx,对所有请求做负载均衡处理(下面例子中使用的是加权轮询策略).
nginx.conf 配置如下:
1 | http { |
负载均衡策略
Nginx 提供了多种负载均衡策略,让我们来一一了解一下:
负载均衡策略在各种分布式系统中基本上原理一致,对于原理有兴趣,不妨参考 负载均衡
轮询
1 | upstream bck_testing_01 { |
加权轮询
1 | upstream bck_testing_01 { |
最少连接
1 | upstream bck_testing_01 { |
加权最少连接
1 | upstream bck_testing_01 { |
IP Hash
1 | upstream bck_testing_01 { |
普通 Hash
1 | upstream bck_testing_01 { |
网站有多个 webapp 的配置
当一个网站功能越来越丰富时,往往需要将一些功能相对独立的模块剥离出来,独立维护.这样的话,通常,会有多个 webapp.
举个例子:假如 www.helloworld.com 站点有好几个 webapp,finance(金融)、product(产品)、admin(用户中心).访问这些应用的方式通过上下文(context)来进行区分:
我们知道,http 的默认端口号是 80,如果在一台服务器上同时启动这 3 个 webapp 应用,都用 80 端口,肯定是不成的.所以,这三个应用需要分别绑定不同的端口号.
那么,问题来了,用户在实际访问 www.helloworld.com 站点时,访问不同 webapp,总不会还带着对应的端口号去访问吧.所以,你再次需要用到反向代理来做处理.
配置也不难,来看看怎么做吧:
1 | http { |
搭建文件服务器
有时候,团队需要归档一些数据或资料,那么文件服务器必不可少.使用 Nginx 可以非常快速便捷的搭建一个简易的文件服务.
Nginx 中的配置要点:
- 将 autoindex 开启可以显示目录,默认不开启.
- 将 autoindex_exact_size 开启可以显示文件的大小.
- 将 autoindex_localtime 开启可以显示文件的修改时间.
- root 用来设置开放为文件服务的根路径.
- charset 设置为
charset utf-8,gbk;
,可以避免中文乱码问题(windows 服务器下设置后,依然乱码,本人暂时没有找到解决方法).
一个最简化的配置如下:
1 | autoindex on;# 显示目录 |
解决跨域
web 领域开发中,经常采用前后端分离模式.这种模式下,前端和后端分别是独立的 web 应用程序,例如:后端是 Java 程序,前端是 React 或 Vue 应用.
各自独立的 web app 在互相访问时,势必存在跨域问题.解决跨域问题一般有两种思路:
- CORS
在后端服务器设置 HTTP 响应头,把你需要允许访问的域名加入 Access-Control-Allow-Origin
中.
- jsonp
把后端根据请求,构造 json 数据,并返回,前端用 jsonp 跨域.
这两种思路,本文不展开讨论.
需要说明的是,nginx 根据第一种思路,也提供了一种解决跨域的解决方案.
举例:www.helloworld.com 网站是由一个前端 app ,一个后端 app 组成的.前端端口号为 9000, 后端端口号为 8080.
前端和后端如果使用 http 进行交互时,请求会被拒绝,因为存在跨域问题.来看看,nginx 是怎么解决的吧:
首先,在 enable-cors.conf 文件中设置 cors :
1 | # allow origin list |
接下来,在你的服务器中 include enable-cors.conf
来引入跨域配置:
1 | # ---------------------------------------------------- |
到此,就完成了.
Nginx问题集
Nginx 出现大量 TIME_WAIT
检测TIME_WAIT状态的语句
1 | $ netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' |
状态解析:
CLOSED
- 无连接是活动的或正在进行LISTEN
- 服务器在等待进入呼叫SYN_RECV
- 一个连接请求已经到达,等待确认SYN_SENT
- 应用已经开始,打开一个连接ESTABLISHED
- 正常数据传输状态FIN_WAIT1
- 应用说它已经完成FIN_WAIT2
- 另一边已同意释放ITMED_WAIT
- 等待所有分组死掉CLOSING
- 两边同时尝试关闭TIME_WAIT
- 另一边已初始化一个释放LAST_ACK
- 等待所有分组死掉
解决方法
执行 vim /etc/sysctl.conf
,并添加下面字段
1 | net.ipv4.tcp_syncookies = 1 |
执行 /sbin/sysctl -p
让修改生效.
上传文件大小限制
问题现象
显示错误信息:413 Request Entity Too Large.
意思是请求的内容过大,浏览器不能正确显示.常见的情况是发送 POST
请求来上传大文件.
解决方法
- 可以在
http
模块中设置:client_max_body_size 20m;
- 可以在
server
模块中设置:client_max_body_size 20m;
- 可以在
location
模块中设置:client_max_body_size 20m;
三者区别是:
- 如果文大小限制设置在
http
模块中,则对所有 Nginx 收到的请求. - 如果文大小限制设置在
server
模块中,则只对该server
收到的请求生效. - 如果文大小限制设置在
location
模块中,则只对匹配了location
路由规则的请求生效.
请求时间限制
问题现象
请求时间较长,链接被重置页面刷新.常见的情况是:上传、下载大文件.
解决方法
修改超时时间
Nginx编译参数详解
理论上来说 Nginx 没有必选参数,所有参数都是可选的,基本上只添加--prefix
参数即可,但不选任何参数就毫无意义了.
Nginx 的核心功能包括 HTTP 、 Mail 和 Stream ,本文将以核心功能为区分解析 Nginx 的编译参数.
可能仅介绍一些核心参数,对于非核心参数请查看 Nginx 官方文档.
基础路径类
参数 | 示例值 | 说明 |
---|---|---|
--prefix=<path> |
/etc/nginx |
Nginx 安装的根路径, 所有其它路径类参数都要依赖该选项 |
--sbin-path=<path> |
/usr/sbin/nginx |
Nginx 二进制文件路径, 不指定则使用<prefix>/sbin/nginx |
--conf-path=<path> |
/etc/nginx/nginx.conf |
配置文件默认路径, 不指定则需要在运行时附带-c 参数 |
--error-log-path=<path> |
/var/log/nginx/error.log |
错误日志路径, 可以被配置文件中的配置项覆盖掉 |
--pid-path=<path> |
/var/run/nginx.pid |
Nginx 主进程 PID 写入位置 |
--user=<user> |
nginx |
Worker 进程运行的用户 |
--group=<group> |
nginx |
Worker 进程运行的组 |
--modules-path=<path> |
/usr/lib/nginx/modules |
Nginx 模块路径 |
--lock-path=<path> |
/var/run/nginx.lock |
Lock文件位置 |
--http-log-path |
/var/log/nginx/access.log |
HTTP 访问日志位置 |
HTTP 功能类
参数 | 说明 |
---|---|
--with-http_ssl_module |
启用SSL支持 |
--with-http_v2_module |
启用HTTP2支持 |
--with-http_realip_module |
当Nginx服务器在反向代理后面的时候, 该模块可让 Nginx 知晓真正的用户IP |
--with-http_addition_module |
过滤相应前后的文本 |
--with-http_image_filter_module |
转换 JPEG、GIF、PNG 和 WebP 格式图像 该模块可被编译为动态模块 |
--with-http_sub_module |
可以替换指定的字符串来修改响应数据 |
--with-http_dav_module |
开启 WebDAV 协议 |
--with-http_flv_module |
对 Flash 启用服务端支持 |
--with-http_mp4_module |
对 MP4 文件启用服务端支持 |
--with-http_gunzip_module |
对不支持 gzip 编码方法的客户端解压缩 Content-Encoding:gzip 的响应. 可以存储压缩数据以节省空间并降低 I/O 成本 |
--with-http_gzip_static_module |
发送以 .gz 结尾的预压缩文件替代普通文件 |
--with-http_auth_request_module |
基于子请求结果实现客户端授权 |
--with-http_random_index_module |
随机选择目录中的文件作为索引文件展示 |
--with-http_secure_link_module |
用于检查请求链接的真实性, 保护资源免受未经授权的访问, 并限制链接有效时长. |
--with-http_degradation_module |
用于当主机剩余内存较低时,用户请求访问, Nginx会对某些请求返回204或444的响应码 |
--with-http_slice_module |
将请求切片并返回 |
--with-http_stub_status_module |
提供对基本状态信息的访问的支持 |
--without-http |
禁用 HTTP 功能 |
--without-http-cache |
禁用 HTTP 缓存功能 |
邮件类
参数 | 说明 |
---|---|
--with-mail |
启用邮件功能 该模块可被编译为动态模块 |
--with-mail_ssl_module |
对邮件功能启用SSL |
--without-mail_pop3_module |
禁用POP3 |
--without-mail_imap_module |
禁用IMAP |
--without-mail_smtp_module |
禁用SMTP |
其他参数
参数 | 说明 |
---|---|
--with-google_perftools_module |
可以使用 Google 性能工具 对 nginx 的 worker 进程进行分析 |
--with-compat |
启用动态模块兼容性 |
--with-file-aio |
启用异步IO |
--with-threads |
启用线程池功能 |
--with-cpu-opt=<cpu> |
为特定的CPU执行编译操作 有效的值:pentium,pentiumpro,pentium3,pentium4,athlon,opteron,sparc32,sparc64,ppc64. |
模块配置示例
http_random_index_module
1 | location / { |
http_stub_status_module
1 | location = /basic_status { |
其他附加模块
ngx_brotli
Brotli 是基于LZ77算法的一个现代变体、霍夫曼编码和二阶上下文建模.Google软件工程师在2015年9月发布了包含通用无损数据压缩的Brotli增强版本,特别侧重于HTTP压缩.其中的编码器被部分改写以提高压缩比,编码器和解码器都提高了速度,流式API已被改进,增加更多压缩质量级别.
与常见的通用压缩算法不同,Brotli使用一个预定义的120千字节字典.该字典包含超过13000个常用单词、短语和其他子字符串,这些来自一个文本和HTML文档的大型语料库.预定义的算法可以提升较小文件的压缩密度.
使用Brotli替换Deflate来对文本文件压缩通常可以增加20%的压缩密度,而压缩与解压缩速度则大致不变.
下载源码
1
2
3cd /usr/local/src/
git clone https://github.com/google/ngx_brotli
cd ngx_brotli && git submodule update --init重新编译 Nginx
编译时只需要在原有的编译参数后面添加
--add-module=/usr/local/src/ngx_brotli
.1
2# 示例如下:
./configure --prefix=/usr/share/nginx --with-http_ssl_module --add-module=/usr/local/src/ngx_brotli检查是否安装成功
1
nginx -V
输出中有
ngx_brotli
字样即为成功.修改配置文件
1
2
3
4#Brotli Compression
brotli on; # switch
brotli_comp_level 6; # level 1-11
brotli_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript image/svg+xml;
其中brotli_comp_level
值为压缩比,1 压缩比最小,处理速度最快,11 压缩比最大,传输速度快,但是处理慢,也比较消耗CPU资源.