nginx进阶
nginx开源版本下载地址:http://nginx.org/en/download.html
# 1. nginx安装
get http://nginx.org/download/nginx-1.14.0.tar.gz
tar xf nginx-1.14.0.tar.gz
源码目录/root/nginx-1.14.0/contrib/vim 拷贝到~/.vim/目录下实现配置文件语法高亮(.vim目录需要手动创建)
./configure --help 查看编译参数帮助
nginx 在make编译后的源码文件会存放在/root/nginx-1.14.0/objs
make install
nginx access日志分析工具:goaccess
# 2. nginx TLS加密过程
HTTPS 采用混合加密算法,即共享秘钥加密(对称加密)和公开秘钥加密(非对称加密)。
通信前准备工作:
- 数字证书认证机构的公开秘钥(CA公钥)已事先植入到浏览器里;
- 数字证书认证机构用自己的私有密钥对服务器的公开秘钥做数字签名,生成公钥证书,并颁发给服务器。
加密过程:
- 第一步:rclient hello
握手第一步是客户端向服务端发送 Client Hello 消息,这个消息里包含了一个客户端生成的随机数 Random1、客户端支持的加密套件(Support Ciphers)和 SSL Version 等信息。
- 第二步:server hello
服务端向客户端发送 Server Hello 消息,这个消息会从 Client Hello 传过来的 Support Ciphers 里确定一份加密套件,这个套件决定了后续加密和生成摘要时具体使用哪些算法,另外还会生成一份随机数 Random2。注意,至此客户端和服务端都拥有了两个随机数(Random1+ Random2),这两个随机数会在后续生成对称秘钥时用到。
- 第三步:Certificate
这一步是服务端将自己的公钥证书下发给客户端。
- 第四步:Server Hello Done
Server Hello Done 通知客户端 Server Hello 过程结束。
- 第五步:Certificate Verify
客户端收到服务端传来的公钥证书后,先从 CA 验证该证书的合法性(CA公钥去解密公钥证书),验证通过后取出证书中的服务端公钥,再生成一个随机数 Random3,再用服务端公钥非对称加密 Random3生成 PreMaster Key。
- 第六步:Client Key Exchange
上面客户端根据服务器传来的公钥生成了PreMaster Key,Client Key Exchange就是将这个key 传给服务端,服务端再用自己的私钥解出这个PreMaster Key得到客户端生成的Random3。至此,客户端和服务端都拥有Random1+Random2+Random3,两边再根据同样的算法就可以生成一份秘钥,握手结束后的应用层数据都是使用这个秘钥进行对称加密。为什么要使用三个随机数呢?这是因为SSL/TLS握手过程的数据都是明文传输的,并且多个随机数种子来生成秘钥不容易被破解出来。
大文件 对称算法 aes 小文件 非对称算法 rsa
# 3. 安装openresty
下载openresty
openresty官网下载源码包:http://openresty.org/cn/download.html
wget https://openresty.org/download/openresty-1.13.6.2.tar.gz
编译安装
tar xf openresty-1.13.6.2.tar.gz
cd openresty-1.13.6.2
./configure
make && make install
2
3
4
基于openresty用lua语言实现简单服务
在nginx.conf配置文件中server端增加location匹配项:
location /lua {
default_type text/html;
content_by_lua 'ngx.say("User-Agent: ", ngx.req.get_headers()["User-Agent"])';
}
2
3
4
# 4. Nginx进程管理信号
master主进程支持的信号:
CHLD:监控worker进程
TERM, INT: 立刻退出
QUIT: 等待工作进程结束后再退出
KILL: 强制终止进程
HUP: 重新加载配置文件,使用新的配置启动工作进程,并逐步关闭旧进程。
USR1: 重新打开日志文件
USR2: 启动新的主进程,实现热升级
WINCH: 逐步关闭工作进程
worker工作进程支持的信号:
- TERM, INT: 立刻退出
- QUIT: 等待请求处理结束后再退出
- USR1: 重新打开日志文件
- WINCH: 逐步关闭工作进程
nginx命令行:
- reload HUP
- reopen USR1
- stop TERM
- quit QUIT
reload流程:
- 1.向master进程发送HUP信号(reload命令)
- 2.master进程检验配置语法
- 3.master进程打开新的监听端口
- 4.master进程用新配置启动新的worker子进程
- 5.master进程向老worker子进程发送QUIT信号
- 6.老worker子进程关闭监听句柄,处理完当前连接后结束进程
热升级流程:
- 1.将旧nginx二进制文件换成新的nginx文件(注意备份)
- 2.向master进程发送USR2信号
- 3.master进程修改pid文件名,加后缀.oldbin
- 4.master进程用新nginx二进制文件启动新master进程
- 5.向老master进程发送QUIT信号,关闭老master
- 6.回滚:向老master发送HUP,向新master发送QUIT
worker进程:(优雅关闭)
- 1.设置定时器:worker_shutdown_timeout
- 2.关闭监听句柄
- 3.关闭空闲连接
- 4.在循环中等待全部连接关闭
- 5.退出进程(满足1或4其中一个条件即可)
# 5. nginx进程之间的通讯方式
基础同步工具:
信号
共享内存
高级通讯方式:
锁
slab内存管理器
共享内存:跨worker进程通讯
使用共享内存的官方nginx模块有:
Ngx_http_lua_api
rbtree:
- Ngx_stream_limit_conn_module
- Ngx_http_limit_conn_module
- Ngx_stream_limit_req_module
- http cache:
Ngx_http_file_cache
Ngx_http_proxy_module
Ngx_http_scgi_module
Ngx_http_uwsgi_module
Ngx_http_fastcgi_module
- ssl:
Ngx_http_ssl_modul Ngx_mail_ssl_module Ngx_stream_ssl_module
- 单链表:
Ngx_http_upstream_zone_module
Ngx_stream_upstream_zone_module
slab内存管理:使用Bestfit方式,适合小对象、避免碎片、避免重复初始化
ngx_slab_stat:统计slab使用状态的模块
nginx容器:
- 数组
- 链表
- 队列
- 哈希表
- 红黑树
- 基数树
哈希表:
1.只为静态的不变的内容服务
2.bucket_size需要考虑对齐问题
红黑树:自平衡二叉查找树
nginx动态模块:
- 1.configure进入动态模块
- 2.编译进binary
- 3.启动时初始化模块数组
- 4.读取load_module配置
- 5.打开动态库并加入模块数组
- 6.基于模块数组开始初始化
nginx配置指令:
- 值指令:存储配置项的值,可以合并,向上覆盖
- 动作类指令:指定行为,不可以合并
# 6. HTTP请求处理时的11个阶段
序号 | 阶段 | 模块 |
---|---|---|
1 | post_read | realip |
2 | server_rewrite | rewrite |
3 | find_config | |
4 | rewrite | rewrite |
5 | post_rewrite | |
6 | preaccess | limit_conn,limit_req |
7 | access | auth_basic,access,auth_requet |
8 | post_access | |
9 | precontent | try_files |
10 | content | index,autoindex,concat |
11 | log | access_log |
# 6.1 postread阶段
使用realip模块
如何拿到真实的用户IP地址:
- 1.TCP连接四元组(src ip,src port,dst ip,dst port)
- 2.HTTP头部X-Forwarded-For用于传递IP
- 3.HTTP头部 X-Real-IP用于传递用户IP
- 4.网络中存在许多反向代理
拿到真实用户IP后如何使用:基于变量
realip模块:修改客户端地址
指令:set_real_ip_from、real_ip_header、real_ip_recursive
# 6.2 rewrite阶段
使用rewrite模块
return指令,返回状态码:
nginx自定义:
- 444 关闭连接
http 1.0标准:
301:永久重定向
302:临时重定向,禁止被缓存
http 1.1标准:
- 303:临时重定向,允许改变方法,禁止被缓存
- 307:临时重定向,不允许改变方法,禁止被缓存
- 308:永久重定向,不允许改变方法
rewrite指令:
- flag标志位:
- last : 相当于Apache的[L]标记,表示完成rewrite
- break : 本条规则匹配完成后,终止匹配,不再匹配后面的规则
- redirect : 返回302临时重定向,浏览器地址栏会显示跳转后的URL地址
- permanent : 返回301永久重定向,浏览器地址栏会显示跳转后的URL地址
- 打开rewrite日志:rewrite_log on|off;
if指令:
- 检查变量为空或者值是否为0,直接使用
- 将变量与字符串做匹配,=或者!=
- 将变量与正则表达式做匹配,大小写敏感,~或者!~,大小写不敏感,~或者!~
- 文件是否存在,-f或者!-f
- 目录是否存在,-d或者!-d
- 文件、目录、软链接是否存在,-e或者!-e
- 检查是否为可执行文件,-x或者!-x
# 6.3 find_config阶段
location指令:
- 匹配规则:仅匹配URI,忽略参数
- 合并连续的/符号:merge_slashes on
- 前缀字符串:
- 常规
- =:精确匹配
- ^~:匹配上后则不再进行正则表达式匹配
- 用于内部跳转的命名location:@
- 常规
- 正则表达式:
- ~:大小写敏感的正则匹配
- ~*:忽略大小写的正则匹配
# 6.4 preaccess阶段
**limit_conn指令:**限制每个客户端的并发连接数:ngx_http_limit_conn_module模块
- limit_conn_zone:定义共享内存(包括大小)以及key关键字
- limit_conn:限制并发连接数
- limit_conn_log_level:限制发生时的日志级别
- limit_conn_status:限制发生时向客户端返回的错误码
**limit_req指令:**限制每个客户端的每秒处理请求数:ngx_http_limit_req_module模块
- limit_req_zone:定义共享内存(包括大小)以及key关键字和限制速率
- limit_req:限制并发连接数
- limit_req_log_level:限制发生时的日志级别
- limit_req_status:限制发生时向客户端返回的错误码
# 6.5 access阶段
**ngx_http_access_module模块:**限制某些IP地址的访问权限
allow指令:允许访问
deny指令:拒绝访问
**auth_basic模块:**基于HTTP Basic Authutication协议进行用户名密码的认证
auth_basic指令:对话框Tetil
auth_basic_user_file指令:指定用户名密码文件
扩展:
密码生成工具:安装依赖包httpd-tools
执行命令:htpasswd -c file -b user pass
文件格式:
name1:password1 name2:password2:comment name3:password3
**auth_request模块:**统一的用户权限验证系统
auth_request指令:
auth_request_set指令:限制所有access阶段模块的satisfy指令
# 6.6 precontent阶段
**ngx_http_try_files_module模块:**处理依次试图访问多个url对应的文件
- try_files指令
**ngx_http_mirror_module模块:**实时拷贝流量
- mirror指令
- mirror_request_body指令
# 6.7 content阶段
root 和 alias 指令:
功能:将url映射为文件路径,以返回静态文件内容
差别:root会将完整url映射进文件路径中,alias只会将location后的url映射到文件路径
三个变量:
- request_filename 待访问文件的完整路径
- document_root 由URI和root/alias规则生成的文件夹路径
- realpath 将document_root中的软链接等换成真实路径
**ngx_http_index_module模块:**指定/访问时返回index文件内容
- index指令
- autoindex模块指令:
- random_index:随机index.html文件
- autoindex
- autoindex_exact_size
- autoindex_format
- autoindex_localtime
**concat模块:**ngx_http_concat_module模块,提升性能
功能:当页面需要访问多个小文件是,把它们的内容合并到一次http响应中返回,提升性能。
使用:在uri后加上??,后通过多个逗号分隔文件。如果还有参数,则在最后通过?添加参数
指令:
concat:on|off 模块开关
concat_types:MIME types 合并哪些文件类型
concat_unique:on | off 对一种还是多种文件进行合并
concat_max_files:numberp 最多合并文件数,默认10
concat_delimiter:string 返回多个文件内容时的分隔符
concat_ignore_file_error:on | off 忽略错误文件
# 6.8 log阶段
ngx_http_log_module模块:记录请求的访问日志
指令:
log_format:设置日志格式
对日志文件名包含变量时的优化:
open_log_file_cache指令:
- max 缓存内的最大文件句柄数,超出后用LRU算法淘汰
- inactive 文件访问完后在这段时间不会被关闭,默认10秒
- min_uses 在inactive时间内使用次数超过min_uses才会继续存在内存中,默认1
- valid 超出valid时间后,将对缓存的日志文件检查是否存在,默认60秒
- off 关闭缓存功能
# 7. 常用模块
**sub模块:**ngx_http_sub_filter_module模块,替换响应中的字符串
指令:
sub_filter:string replacement 匹配string替换为replacement(忽略大小写)
sub_filter_last_modified:on|off 是否给用户返回原先的响应头部
sub_filter_once:on|off 替换一次
sub_filter_types:mime-type 替换文件类型
2
3
4
**addition模块:**ngx_http_addition_filter_module模块,在响应的前后添加内容
功能:在响应前或者响应后增加内容,而增加内容的方式是通过新url响应完成
指令:
add_before_body:uri
add_after_body:uri
addition_types:mime-type
2
3
**nginx变量:**惰性求值。变量值可以时刻变化,其值2为使用的那一时刻的值
存放变量的哈希表:
variables_hash_bucket_size 64;
variables_hash_max_size 1024;
HTTP请求相关的变量:
arg_参数名:URL中某个具体参数的值
query_string:与arg变量完全相同
args:全部URL参数
is_args:如果请求URL中有参数则返回?否则返回空
content_length:HTTP请求中标识包体长度的Content_Length头部的值
content_type:标识请求包体类型的Content_Type头部的值
uri:请求的URI(不同于URL,不包括?后的参数)
document_uri:与uri完全相同
request_uri:请求的URL(包括URI以及完整的参数)
scheme:协议名,例如HTTP或者HTTPS
request_method:请求方法,例如GET或者POST
request_length:所有请求内容的大小,包括请求行、头部、包体等
remote_user:由HTTP Basic Authentication协议传入的用户名
request_body_file:临时存放请求包体的文件
request_body:请求中的包体,这个变量当且仅当使用反向代理,且设定用内存暂存包体是才有效
request:原始的url请求,含有方法与协议版本
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
tcp连接相关的变量:
binary_remote_addr:客户端地址的整型格式,对于ipv4是4字节,ipv6是16字节
remote_addr:客户端地址
remote_port:客户端端口
connection:递增的连接序号
connection_requests:当前连接上执行过的请求数,对于keepalive连接有意义
proxy_protocol_addr:若使用了proxy_protocol协议则返回协议中的地址,否则返回空
proxy_protocol_port:若使用了proxy_protocol协议则返回协议中的端口,否则返回空
server_addr:服务端地址
server_port:服务端端口
TCP_INFO:tcp内核层参数,包括$tcpinfo_rtt,$tcpinfo_rttvar,$tcpinfo_snd_cwnd,$tcpinfo_rcv_space
server_protocol:服务器端协议,例如HTTP/1.1
2
3
4
5
6
7
8
9
10
11
nginx处理请求过程中产生的变量:
reques_time:请求处理到现在的耗时,单位为秒,精确到毫秒
server_name:匹配上请求的server_name值
https:如果开启了TLS/SSL,则返回on,否则返回空
request_completion:若请求处理完则返回ok,否则返回空
request_id:以16进制输出的请求标识id,该id共含有16个字节,是随机生成的
request_filename:待访问文件的完整路径
document_root:由URI和root/alias规则生成的文件夹路径
realpath_root:将document_root中的软链接等转换成真实路径
limit_rate:返回客户端响应时的速度上限,单位为每秒字节数。可以通过set指令修改对请求产生效果
2
3
4
5
6
7
8
9
发送HTTP响应时相关的变量:
body_bytes_sent:响应中body包体的长度
bytes_sent:全部http响应的长度
status:http响应中的返回码
sent_trailer_名字:把响应结尾内容里值返回
2
3
4
nginx系统变量
time_local:以本地时间标准输出的当前时间
time_iso8601:使用ISO 8601标准输出的当前时间
nginx_version:Nginx版本号
pid:所属worker进程的进程id
pipe:使用了管道则返回p,否则返回.
hostname:所在服务器的主机名,与hostname命令输出一致
msec:1970年1月1日到现在的时间,单位为秒,小数点后精确到毫秒
2
3
4
5
6
7
**referer模块:**简单有效的防盗链手段
指令:
- valid_referers:可同时携带多个参数值,表示多个referer头部都生效
- none:允许缺失referer头部的请求访问
- blocked:允许referer头部没有对应的值的请求访问
- server_names:若referer中站点域名与server_name中本机域名某个匹配,则允许访问,若referer头部的值匹配字符串后,则允许访问;
- referer_hash_bucket_size:64;
- referer_hash_max_size:2048;
**secure_link模块:**另一种防盗链解决方案,ngx_http_secure_link_module模块
变量:secure_link、secure_link_expires
过程:通过验证url中哈希值的方式防盗链
- 1.由某服务器(也可以是nginx)生成加密后的安全链接url,返回给客户端
- 2.客户端使用安全url访问nginx,由nginx的secure_link变量判断是否验证通过
原理:
- 1.哈希算法是不可逆的
- 2.客户端只能拿到执行过哈希算法的URL
- 3.仅生成URL的服务器、验证URL是否安全的nginx才保存执行哈希算法前的原始字符串
- 4.原始字符串通常由以下部分有序组成:资源位置、用户信息、密钥
指令:
secure_link:参数
secure_link:
值为空字符串:验证不通过
值为0:URL过期
值为1:验证通过
secure_link_expires:时间戳的值
示例:
secure_link $arg_md5,$arg_expires;
secure_link_md5 "$secure_link_expires$uri$remote_addr secret";
仅对URI进行哈希的简单方法
1.将请求URL分为三个部分。/prefix/hash/link
2.hash生成方式。对link密钥做md5哈希求值
3.用secure_link_secret secret;配置密钥
2
3
4
map模块:通过映射新变量提供更多的可能性,ngx_http_map_module模块
功能:基于已有变量,使用类似switch{case:...default:...}的语法创建新变量,为其他基于变量值实现功能的模块提供更多的可能性
split_clients模块:实现AB测试,ngx_http_split_clients_module模块
功能:基于已有变量创建新变量,为其他AB测试提供更多的可能性
指令:split_clients string $variable {...}
示例:
split_clients "${http_testcli}" $variant {
0.51% .one;
20.0% .two;
50.5% .three;
* "";
}
2
3
4
5
6
geo模块:根据客户端地址创建新变量,ngx_http_geo_module模块
指令:geo [$address] $variable {...}
示例:
geo $country {
default ZZ;
#include conf/geo.conf;
proxy 116.62.160.193;
127.0.0.0/24 US;
127.0.0.1/32 RU;
10.1.0.0/16 RU;
192.168.1.0/24 UK;
}
2
3
4
5
6
7
8
9
geoip模块:基于MaxMind数据库从客户端地址获取变量,ngx_http_geoip_module模块
功能:根据IP地址创建新变量
流程:
- 1.安装MaxMind里geoip的C开发库( https://dev.maxmind.com/geoip/legacy/downloadable/)
- 2.编译nginx时带上--with-http_geoip_module参数
- 3.下载MaxMind中的二进制地址库
- 4.使用geoip_country或者geoip_city指令配置好nginx.conf
- 5.运行nginx
指令:
- geoip_country:file
提供的变量:
$geoip_country_code:两个字母的国家代码,比如CN或者US
$geoip_country_code3:三个字母的国家代码,比如CHN或者USA
$geoip_country_name:国家名称,例如China、United States
- geoip_city:file
提供的变量: $geoip_latitude:纬度
$geoip_longitude:经度
$geoip_city_continent_code:属于全球哪个洲
与geoip_country生成的变量重叠:
$geoip_city_country_code:两个字母的国家代码,比如CN或者US
$geoip_city_country_code3:三个字母的国家代码,比如CHN或者USA
$geoip_city_country_name:国家名称,例如China、United States
$geoip_region:洲或者省的编码
$geoip_region_name:洲或者省的名称
$geoip_city:城市名
$geoip_postal_code:邮编号
$geoip_area_code:仅美国使用的电话区号
$geoip_dma_code:仅美国使用的DMA编号
geoip_proxy:address|CIDR
# 8. 负载均衡
对客户端keepalive行为控制
功能:多个HTTP请求通过复用TCP连接,实现减少握手次数、减少并发连接数减少了服务器资源的消耗,降低TCP拥塞控制的影响
指令:
- keepalive_disable:none|brower
- keepalive_requests:number
- keepalive_timeout:timeout [header_timeout]
指定上游服务地址的upstream和server指令
功能:指定一组上游服务器地址
通用参数:
- backup 指定当前server为备份服务器,仅当非备份server不可用时才接收请求
- down:标识某台服务已经下线,不再服务
对上游服务使用keepalive长连接
模块:ngx_http_upstream_keeoalive_module模块
功能:通过复用连接,降低nginx与上游服务器建立、关闭连接的消耗,提升吞吐量的同事降低时延
对上游连接的http头部设定:
- proxy_http_version 1.1;
- proxy_set_header Connection "";
upstream_keepalive指令:
- keepalive:connections
- 1.15.3非稳定版本新增指令:
- keepalive_requests:number
- keepalive_timeout:timeout
指定上游服务域名解析的resolver指令
指令:
- resolver:address ... [valid=time] [ipv6=on|off];
- resolver_timeout:time;
调度算法
- 轮询:rr
默认算法:Round-Robin算法
- 加权轮询:wrr
功能:以加权轮询的方式访问server指令指定的上游服务 指令: weight:服务访问的权重,默认是1 max_conns:server的最大并发连接数,仅作用于单worker进程,默认是0,表示没有限制 max_fails:在fail_timeout时间内最大的失败次数,当达到最大失败时,会在fail_timeout时间内不再接收请求 fail_timeout:单位为秒,默认为10。指定多少时间内,最大的失败次数;到达最大失败数时,该server不能访问的时间
- hash算法
ip_hash模块:基于客户端IP地址的Hash算法实现负载均衡,ngx_http_upstream_ip_hash_module模块 功能:以客户端的ip地址做为hash算法的关键字,映射到特定的上游服务器中 指令:ip_hash
hash模块:基于任意关键字实现hash算法的负载均衡,ngx_http_upstream_hash_module模块 功能:通过指定关键字做为hash key,基于hash算法映射到特定的上游服务器中 指令:hash key 一致性hash算法:ngx_http_upstream_hash_module模块 功能:在宕机或者扩容时,不会引发大量路由变更,不会导致缓存大范围失效 指令:hash key [consistent] //添加consistent参数表示启用一致性hash算法
- 最小连接数:lc
ngx_http_upstream_ least_conn _module模块
功能:从所有上游服务器中,找出当前并发连接数最少的一个,将请求转到它 指令:least_conn
upstream_zone模块
策略跨worker进程生效,使用共享内存使负载均衡策略对所有的worker进程生效,ngx_http_upstream_ zone _module模块
功能:分配出共享内存,将其他upstream模块定义的负载均衡策略数据、运行时每个上游服务的状态数据存放在共享内存上以对所有nginx worker进程生效
指令:zone name [size]
upstream模块提供的变量
- upstream_addr:上游服务器的IP地址,格式为可读的字符串
- upstream_connect_time:与上游服务建立连接消耗的时间,单位为秒,精确到毫秒
- upstream_header_time:接收上游服务发回响应中http头部所消耗的时间,单位为秒,精确到毫秒
- upstream_response_time:接收完整的上游服务响应所消耗的时间,单位为秒,精确到毫秒
- upstream_http_名称:从上游服务返回的响应头部的值
- upstream_bytes_received:从上游服务接收到的响应长度,单位为字节
- upstream_response_length:从上游服务返回的响应包体长度,单位为字节
- upstream_status:上游服务返回的http响应中的状态码
- upstream_cookie_名称:从上游服务返回的响应头set-cookie中取出的cookie值
- upstream_trailer_名称:从上游服务的响应尾部取到的值
# 9. 反向代理
proxy模块:对http协议的反向代理,ngx_http_proxy_module模块
功能:对上游服务使用http/https协议进行反向代理
指令:proxy_pass:URL
接受客户端请求的包体:收完再转发还是边收边转发
指令:
- proxy_request_buffering
on:
- 1.客户端网速较慢
- 2.上游服务并发处理能力低
- 3.适应高吞吐场景
off:
- 1.更及时的响应
- 2.降低nginx读写磁盘的消耗
- 3.一旦开始发送内容,proxy_next_upstream功能失败