Nginx进阶
# worker抢占机制
master:一次性fork多个worker进程
worker:基于互斥锁进行抢占client的请求,然后开始进行处理
# 传统服务器事件处理
客户端阻塞时,master进程通过fork进程来处理进程,大量的连接进来会耗尽服务器资源

# Nginx事件处理
Nginx通过使用epoll模型,使用异步非阻塞的形式监听客户端连接,当阻塞的时候,会自动切换到另一个客户端连接上。
一个worker进程处理的最大连接数受限于nginx的worker_connections配置

# 同步阻塞与异步阻塞
方式 | 说明 |
---|---|
同步阻塞 | 客户端阻塞等待服务器处理完成 |
同步非阻塞 | 客户端阻塞等待服务器处理,服务器可以异步处理其他任务 |
异步阻塞 | 客户端异步发送请求到服务器,服务器处理完回调客户端 |
异步非阻塞 | 客户端与服务端都是异步处理任务,处理完成回调给客户端 |
同步与异步的区别在于客户端是否阻塞等待,阻塞与非阻塞的区别在于服务器是否阻塞等待
# Nginx常用命令及指令
常用命令
命令 | 说明 |
---|---|
nginx -s stop | 强制停止nginx |
nginx -s quit | 等待nginx处理完请求再退出 |
nginx -c nginx.conf | 指定nginx配置文件,可以解决invalid nginx pid的问题 |
指令
指令 | 说明 |
---|---|
root | location中会追加到root后面 |
alias | location中会以alias的路径为主 |
# 日志切割
该方式会将现有的access.log和error.log的内容copy到新的文件中,新的请求进来内容依然会写到access.log
#!/bin/bash
# 指定日志目录
LOG_PATH="/var/log/nginx/"
# 指定切割的日志格式
RECORD_TIME=$(date -d "yesterday"+%Y-%m-%d)
PID=/var/run/nginx/nginx.pid
# 将默认的access_log和error_log重命名为拆分后的格式
mv ${LOG-PATH}/access.log ${LOG-PATH}/access.${RECORD_TIME).log
mv ${LOG-PATH}/error.log ${LOG-PATH}/error.${RECORD_TIME}.Log
# 向Nginx主进程发送信号,用于重新打开日志文件
kill -USR1 `cat $PID`
# 记得修改权限 chmod +x cut_log.sh
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
也可以通过定时任务去实现自动切割,这种方式相对比较老,更新的日志分割可以结合nginx变量实现区分
# Nginx实现跨域请求
server {
listen 90;
server_name localhost;
# 允许跨域请求的域, *代表所有
add_header 'Access-Control-Allow-Origin' *;
# 允许带上cookie请求
add header 'Access-Control-Allow-Credentials' 'true';
# 允许请求的方法,比如GET/POST/PUT/DELETE
add header 'Access-control-Allow-Methods' *;
# 允许请求的header
add_header 'Access-Control-Allow-Headers' *;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
跨域是浏览器的一种同源策略的限制,解决方法本质都是通过header头部的设置,除此之外还可以发送jsonp请求来解决跨域问题
# Nginx配置静态资源防盗链
server {
listen 90;
server_name localhost;
# 通过验证refer头部来校验是否合法资源请求
valid_referers *.imooc.com;
# 非法引入会进入下方判断
if ($invalid_referer) {
return 404;
}
}
2
3
4
5
6
7
8
9
10
11
# upstream指令参数
upstream主要用于配置nginx的负载均衡,下面是对常用的指令的整理
# 负载均衡配置
upstream tomcats {
# max_conns表示该server支持的最大连接数
server 192.168.1.173:8080 max_conns=1;
# weight表示权重值,请求大概率会打到该服务器上
server 192.168.1.174:8080 weight=6;
# 1、通过server指令的slow_start参数来让其权重从0缓慢的恢复到正常值,避免大流量直接打进来再次压垮服务
# 2、商业版使用,该参数不能用在hash、randomloadbalancing中,如果只有一台服务器会失效
# 3、注意如果一个组里面只有一个server,那么max_fails,fail_timeout和slow_start参数都会被忽略。并且这个服务器永远都不会被认为是不可用的
server 192.168.1.175:8080 slow_start=60s;
# down用于标记服务节点不可用
server 192.168.1.173:8080 down;
# backup表示当前服务器节点是备用机,只有在其他的服务器都宕机以后,自己才会加入到集群中,被用户访问到,参数不能使用在hash和randomloadbalancing中
server 192.168.1.173:8080 down;
# 表示在15秒内请求某一server失败达到2次后,则认为该server已经挂了或者宕机了,随后再过15秒,这15秒内不会有新的请求到达刚刚挂掉的节点上,而是会运作的server,15秒后会再有新请求尝试连接挂掉的server,如果还是失败,重复上一过程
server 192.168.1.173:8080 max_fails=2 fail_timeout=15s;
# 保持的活跃的链接,避免频繁的创建连接,带来的性能损耗
keepalive 32;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# keepalive
主要是保持与后端的连接数,避免请求nginx的时候,不断的与后端建立连接带来的性能损耗。
详细的可以参考keepalive的说明
upstream tomcats {
server 192.168.1.174:8080 weight=6;
# 通过保持与客户端的长连接,来提高吞吐量,32为长连接的个数
keepalive 32;
}
server {
location /http/ {
proxy_pass http://tomcats;
# 设置长连接使用的版本号
proxy_http_version 1.1;
# 设置cookie头的connection为空
proxy_set_header Connection "";
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Ip_hash
ip_hash可以保证用户访问可以请求到上游服务中的固定的服务器,前提是用户ip没有发生更改。 使用ip_hash的注意点:不能把后台服务器直接移除,只能标记为down
upstream tomcats {
ip_hash ;
server 192.168.1.174:808;
server 192.168.1.174:8080 down;
}
server {
location /http/ {
proxy_pass http://tomcats;
}
}
2
3
4
5
6
7
8
9
10
11
hash算法:通过对ip进行hash计算,对节点个数进行求模,最后决定落到哪个节点

计算方式
参数 | 描述 |
---|---|
node_counts | 服务器的节点个数 |
index | 服务器对应的索引 |
主要是通过hash(ip) % node_counts = index
最后计算得到index,根据index来匹配对应的服务器节点
算法是根据ip的前3段来进行计算的,所以,同一段落的ip会落在同一台服务器上。
# 一致性hash算法
hash算法存在节点个数的变更,导致命中的服务器的index发生变化,为了解决该问题,出现了一致性hash算法
# 是什么?
一致性hash算法本质上是一个从0-2的32次方的线,最终形成的圆

# 基本原理
- 通过对服务器的节点(ip或者主机)、用户的ip进行hash后,最终确认服务器节点的位置和用户所在的位置。
- 按照顺时针的方向,选择最近的节点作为访问的节点
# 解决的问题
传统的hash算法,节点个数的变更,会导致全部的用户的请求发生变化。
一致性hash算法通过将服务器节点和用户的ip进行hash后,用户顺时针访问就近的节点,这样增加会移除节点影响的只是少部分用户。
# url_hash
根据url来路由到服务器的节点,计算方式:

具体的配置
upstream tomcats {
# 根据url进行hash,计算得到index作为服务器的索引
url hash;
# 路由请求到后端最少连接数的服务器上
# least_conn;
server 192.168.1.174:808;
server 192.168.1.174:8080 down;
}
server {
location /http/ {
proxy_pass http://tomcats;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
通过hash(url) % node_counts计算得到
index`如果url中带有/,计算得到的hash结果是不一样的,会落到不同的服务节点上的。
# Nginx缓存
主要是缓存后端server的请求到服务器上,来缓解服务器本身的压力

# 控制浏览器的缓存
location /html {
alias /html;
# 10s后失效
expires 10s;
# 到达指定的时间后失效
# expires @22h30m;
# 1小时前失效
# expires -1h;
# 不进行缓存
# expires epoch;
# 关闭,与epoch的区别在于off后浏览器保留默认的缓存机制
# expires off;
# 永不过期
# expires max;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
如果文件内容发生了变化,会重新请求浏览器,max-age表示缓存内容的有效期
# 反向代理缓存
# 设置缓存保存的路径
# key_zone:设置共享空间和占用的空间大小
# max_size:设置缓存大小
# inactive:设置缓存的有效期,超过此时间缓存自动清理
# use_temp_path:关闭临时目录
# nginx会把请求服务器的内容缓存到该目录下,8h后会自动清理
proxy_cache_path /usr/local/nginx/upsteam_cache keys_zone=mycache:5m max_size=1g inactive=8h use_temp_path=off;
server {
# 启用缓存,和keys_zone一致
proxy_cache mycache;
# 针对200、304的状态码保留8h的有效期
proxy_cache_valid 200 304 8h;
location /http/ {
proxy_pass http://tomcats;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Keepalived双机主备原理
keepalived具有以下特点:
- 解决slb单点故障
- 组件免费
- 可以实现高可用的HA机制
- 基于VRRP协议
通过主备节点争抢ip的方式来保证负载均衡节点的高可用
# master
通过在192.168.1.171、192.168.1.172两台物理机上安装keepalived,来实现双机主备
在机器192.168.1.171上配置msater节点
global_defs {
# 路由id:当前安装keepalived的节点主机标识符,保证全局唯一
router_id keep_171
}
vrrp_instance VI_1 {
# 表示状态是master主机还是backup备用机
state MASTER
# 该实例绑定的网卡
interface ens33
# 保证主备节点一致即可
virtual_router_id 51
# 权重, master权重一般高于backup,如果有多个,那就是选举,谁的权重高,谁就当选
priority 100
# 主备之间同步检查时间间隔,单位秒
adver_int 2
# 认证权限密码,防止非法节点进入
authentication {
auth_type PASS
auth_pass 1111
}
# 虚拟出来的ip,可以有多个vip
virtual_ipaddress {
192.168.1.161
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
服务启动后观察ip addr,发现192.168.1.161绑定到了网卡上了

# backup
在192.168.1.172上配置backup节点
global_defs {
# 路由id:当前安装keepalived的节点主机标识符,保证全局唯一
router_id keep_172
}
vrrp_instance VI_1 {
# 表示状态是master主机还是backup备用机
state BACKUP
# 该实例绑定的网卡,当master节点宕机后,备用节点会替代master,会看到ens33的网卡下绑定了虚拟ip
interface ens33
# 保证主备节点一致即可
virtual_router_id 51
# 权重, 权重低于master节点
priority 80
# 主备之间同步检查时间间隔,单位秒
adver_int 2
# 认证权限密码,防止非法节点进入
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
# 主备节点绑定的是同一个vip
192.168.1.161
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
为支持syetemctl的使用,注册keepalived为系统服务
# 切换到keepalived的源目录下
cd /usr/local/software/keepalived-2.0.20/keepalived/etc
# 将init.d目录中的keepalived文件拷贝到/etc/init.d目录中
cp init.d/keepalived /etc/init.d/
# 将sysconfig目录中的keepalived文件拷贝到/etc/sysconfig目录中
cp sysconfig/keepalived /etc/sysconfig/
# 重新加载服务的配置文件
systemctl daemon-reload
2
3
4
5
6
7
8
启动keepalived
# 启动keepalived
syetemctl start keepalived
# 停止keepalived
syetemctl stop keepalived
# 重启keepalived
syetemctl restart keepalived
# 查看进程是否存在
ps-ef|grepkeepalived
2
3
4
5
6
7
8
使用keepalived使nginx进程常驻
# 脚本存放到keepalived的配置目录下
vim /etc/keepalived/check_nginx_alive_or_not.sh
2
# 进程常驻
新增检查nginx进程脚本
# !bin/bash
nginx_process_total = `ps -c nginx --no-header | wc -l`
if [$nginx_process_total -eq 0]:then
/usr/local/sbin/nginx
# 等待一小会再次检查nginx,如果没有启动成功,则停止keepalived,使其启动
sleep 3
# 保证nginx进程常驻,如果没有正常拉起,则杀死keepalived,保证backup节点工作
if [`ps -c nginx --no-header | wc -l` -eq 0]:then
killall keepalived
fi
fi
2
3
4
5
6
7
8
9
10
11
12
13
新增脚本执行权限
chmod +x /etc/keepalived/check_nginx_alive_or_not.sh
配置keepalived监听nginx脚本
global_defs {
router_id keep_172
}
vrrp_script check_nginx_alive {
script "/etc/keepalived/check_nginx_alive_or_not.sh"
interval 2 # 每搁两秒运行一次脚本
weight 10 # 脚本执行失败,则权重+10
}
vrrp_instance VI_1 {
# vrrp_instance 中新增监听的脚本
track_script {
check_nginx_alive # 追踪nginx脚本
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
重启keepalived脚本
systemctl restart keepalived