就业班 第三阶段(nginx) 2401--4.25 day4 nginx4 流量控制+访问

16、nginx 错误页面配置

nginx错误页面包括404 403 500 502 503 504等页面,只需要在server中增加以下配置即可:

#error_page  404 403 500 502 503 504  /404.html;location = /404.html {root   /usr/local/nginx/html;}

注意:

/usr/local/nginx/html/ 路径下必须有404.html这个文件!!!

404.html上如果引用其他文件的png或css就会有问题,显示不出来,因为其他文件的访问也要做配置;
为了简单,可以将css嵌入文件中,图片用base编码嵌入;如下:

[root@localhost html]# vim 404.html
<!DOCTYPE html>
<html><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" /><title>404</title><style>.layout-table{display:table;height:100%;width:100%;vertical-align: middle;margin-top:150px}.layout-table-cell{display: table-cell;vertical-align: middle;text-align:center}.layout-tip{font-size:28px;color:#373737;margin: 0 auto;margin-top:16px;border-bottom: 1px solid #eee;padding-bottom: 20px;width: 360px;}#tips{font-size:18px;color:#666666;margin-top:16px;}</style></head><body class="layui-layout-body"><div class="layui-layout layui-layout-admin"><div class="layui-body"><div class="layout-table"><div class="layout-table-cell"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAV4AAACMCAYAAAA0qsGKAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkIwRDQ0ODRFMzMyODExRThBQ0Q5Q0UyNkNCMkE4MDk0IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkIwRDQ0ODRGMzMyODExRThBQ0Q5Q0UyNkNCMkE4MDk0Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QjBENDQ4NEMzMzI4MTFFOEFDRDlDRTI2Q0IyQTgwOTQiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QjBENDQ4NEQzMzI4MTFFOEFDRDlDRTI2Q0IyQTgwOTQiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4Qz6opAAAU5klEQVR42uxd3XXjthKe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" class="layout-img"><p class="layout-tip">哎呀,找不到该页面啦!</p><p id="tips">请检查您的网络连接是否正常或者输入的网址是否正确</p></div></div></div></div></body>
</html>

展示效果;

17、nginx 流量控制

流量限制 (rate-limiting),是Nginx中一个非常实用,却经常被错误理解和错误配置的功能。我们可以用来限制用户在给定时间内HTTP请求的数量。请求,可以是一个简单网站首页的GET请求,也可以是登录表单的 POST 请求。流量限制可以用作安全目的,比如可以减慢暴力密码破解的速率。通过将传入请求的速率限制为真实用户的典型值,并标识目标URL地址(通过日志),还可以用来抵御 DDOS 攻击。更常见的情况,该功能被用来保护上游应用服务器不被同时太多用户请求所压垮。

以下将会介绍Nginx的 流量限制 的基础知识和高级配置,”流量限制”在Nginx Plus中也适用。

1、Nginx如何限流

Nginx的”流量限制”使用漏桶算法(leaky bucket algorithm),该算法在通讯和分组交换计算机网络中广泛使用,用以处理带宽有限时的突发情况。就好比,一个桶口在倒水,桶底在漏水的水桶。如果桶口倒水的速率大于桶底的漏水速率,桶里面的水将会溢出;同样,在请求处理方面,水代表来自客户端的请求,水桶代表根据”先进先出调度算法”(FIFO)等待被处理的请求队列,桶底漏出的水代表离开缓冲区被服务器处理的请求,桶口溢出的水代表被丢弃和不被处理的请求。

2、配置基本的限流

“流量限制”配置两个主要的指令,limit_req_zonelimit_req,如下所示:

limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;upstream myweb {server 10.0.105.196:80 weight=1 max_fails=1 fail_timeout=1;}server {listen 80;server_name localhost;location /login {limit_req zone=mylimit;proxy_pass http://myweb;proxy_set_header Host $host:$server_port;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}}
10.0.105.196配置:
server {listen 80;server_name localhost;location /login {root    /usr/share/nginx/html;index   index.html index.html;}
}

limit_req_zone指令定义了流量限制相关的参数,而limit_req指令在出现的上下文中启用流量限制(示例中,对于”/login/”的所有请求)。

limit_req_zone指令通常在HTTP块中定义,使其可在多个上下文中使用,它需要以下三个参数:

  • Key - 定义应用限制的请求特性。示例中的 Nginx 变量$binary_remote_addr,保存客户端IP地址的二进制形式。这意味着,我们可以将每个不同的IP地址限制到,通过第三个参数设置的请求速率。(使用该变量是因为比字符串形式的客户端IP地址$remote_addr,占用更少的空间)
  • Zone - 定义用于存储每个IP地址状态以及被限制请求URL访问频率的共享内存区域。保存在内存共享区域的信息,意味着可以在Nginx的worker进程之间共享。定义分为两个部分:通过zone=keyword标识区域的名字,以及冒号后面跟区域大小。16000个IP地址的状态信息,大约需要1MB,所以示例中区域可以存储160000个IP地址。
  • Rate - 定义最大请求速率。在示例中,速率不能超过每秒10个请求。Nginx实际上以毫秒的粒度来跟踪请求,所以速率限制相当于每100毫秒1个请求。因为不允许”突发情况”(见下一章节),这意味着在前一个请求100毫秒内到达的请求将被拒绝。

当Nginx需要添加新条目时存储空间不足,将会删除旧条目。如果释放的空间仍不够容纳新记录,Nginx将会返回 503状态码(Service Temporarily Unavailable)。另外,为了防止内存被耗尽,Nginx每次创建新条目时,最多删除两条60秒内未使用的条目。

limit_req_zone指令设置流量限制和共享内存区域的参数,但实际上并不限制请求速率。所以需要通过添加

limit_req指令,将流量限制应用在特定的location或者server块。在上面示例中,我们对/login/请求进行流量限制。

现在每个IP地址被限制为每秒只能请求10次/login/,更准确地说,在前一个请求的100毫秒内不能请求该URL。

3、处理突发

如果我们在100毫秒内接收到2个请求,怎么办?对于第二个请求,Nginx将给客户端返回状态码503。这可能并不是我们想要的结果,因为应用本质上趋向于突发性。相反地,我们希望缓冲任何超额的请求,然后及时地处理它们。我们更新下配置,在limit_req中使用burst参数:

limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;upstream myweb {server 10.0.105.196:80 weight=1 max_fails=1 fail_timeout=1;}server {listen 80;server_name localhost;location /login {limit_req zone=mylimit burst=20;proxy_pass http://myweb;proxy_set_header Host $host:$server_port;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}}

burst参数定义了超出zone指定速率的情况下(示例中的mylimit区域,速率限制在每秒10个请求,或每100毫秒一个请求),客户端还能发起多少请求。上一个请求100毫秒内到达的请求将会被放入队列,我们将队列大小设置为20。
如果你设置了每秒只允许 10 个请求,并且 burst 为 5,那么在短时间内可能会有 15 个请求被接收,但只有 10 个会立即被处理,剩下的 5 个会在“缓冲区”中等待。

4、无延迟的排队

配置burst参数将会使通讯更流畅,但是可能会不太实用,因为该配置会使站点看起来很慢。在上面的示例中,队列中的第20个包需要等待2秒才能被转发,此时返回给客户端的响应可能不再有用。要解决这个情况,可以在burst参数后添加nodelay参数:

limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;upstream myweb {server 10.0.105.196:80 weight=1 max_fails=1 fail_timeout=1;}server {listen 80;server_name localhost;location /login {limit_req zone=mylimit burst=20 nodelay;proxy_pass http://myweb;proxy_set_header Host $host:$server_port;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}}

使用nodelay参数,Nginx仍将根据burst参数分配队列中的位置,并应用已配置的速率限制,而不是清理队列中等待转发的请求。相反地,当一个请求到达“太早”时,只要在队列中能分配位置,Nginx将立即转发这个请求。将队列中的该位置标记为”taken”(占据),并且不会被释放以供另一个请求使用,直到一段时间后才会被释放(在这个示例中是,100毫秒后)。

假设如前所述,队列中有20个空位,从给定的IP地址发出的21个请求同时到达。Nginx会立即转发这个21个请求,并且标记队列中占据的20个位置,然后每100毫秒释放一个位置。如果是25个请求同时到达,Nginx将会立即转发其中的21个请求,标记队列中占据的20个位置,并且返回503状态码来拒绝剩下的4个请求。

现在假设,第一组请求被转发后101毫秒,另20个请求同时到达。队列中只会有一个位置被释放,所以Nginx转发一个请求并返回503状态码来拒绝其他19个请求。如果在20个新请求到达之前已经过去了501毫秒,5个位置被释放,所以Nginx立即转发5个请求并拒绝另外15个。

效果相当于每秒10个请求的“流量限制”。如果希望不限制两个请求间允许间隔的情况下实施“流量限制”,nodelay参数是很实用的。

注意: 对于大部分部署,我们建议使用burstnodelay参数来配置limit_req指令。

5、高级配置示例

通过将基本的“流量限制”与其他Nginx功能配合使用,我们可以实现更细粒度的流量限制。

1、白名单

下面这个例子将展示,如何对任何不在白名单内的请求强制执行“流量限制”:

http {include       /etc/nginx/mime.types;default_type  application/octet-stream;log_format  main  '$remote_addr - $remote_user [$time_local] "$request" ''$status $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"';access_log  /var/log/nginx/access.log  main;geo $limit {default 		1;10.0.0.0/24 		0;192.168.0.0/24 		0;}map $limit $limit_key {0 "";1 $binary_remote_addr;}limit_req_zone $limit_key zone=req_zone:10m rate=5r/s;server {listen 80;server_name localhost;location / {limit_req zone=req_zone burst=10 nodelay;root /usr/share/nginx/html;index index.html index.hml;}
}include /etc/nginx/conf.d/*.conf;
}

这个例子同时使用了geomap指令。geo块将给在白名单中的IP地址对应的$limit变量分配一个值0,给其它不在白名单中的分配一个值1。然后我们使用一个映射将这些值转为key,如下:

  • 如果$limit变量的值是0,$limit_key变量将被赋值为空字符串
  • 如果$limit变量的值是1,$limit_key变量将被赋值为客户端二进制形式的IP地址

两个指令配合使用,白名单内IP地址的$limit_key变量被赋值为空字符串,不在白名单内的被赋值为客户端的IP地址。当limit_req_zone后的第一个参数是空字符串时,不会应用“流量限制”,所以白名单内的IP地址(10.0.0.0/24和192.168.0.0/24 网段内)不会被限制。其它所有IP地址都会被限制到每秒5个请求。

limit_req指令将限制应用到**/**的location块,允许在配置的限制上最多超过10个数据包的突发,并且不会延迟转发。

2、location 包含多limit_req指令

我们可以在一个location块中配置多个limit_req指令。符合给定请求的所有限制都被应用时,意味着将采用最严格的那个限制。例如,多个指令都制定了延迟,将采用最长的那个延迟。同样,请求受部分指令影响被拒绝,即使其他指令允许通过也无济于事。

扩展前面将“流量限制”应用到白名单内IP地址的例子:

http {# ...limit_req_zone $limit_key zone=req_zone:10m rate=5r/s;limit_req_zone $binary_remote_addr zone=req_zone_wl:10m rate=15r/s;server {# ...location / {limit_req zone=req_zone burst=10 nodelay;limit_req zone=req_zone_wl burst=20 nodelay;# ...}}
}

白名单内的IP地址不会匹配到第一个“流量限制”,而是会匹配到第二个req_zone_wl,并且被限制到每秒15个请求。不在白名单内的IP地址两个限制能匹配到,所以应用限制更强的那个:每秒5个请求。

6、配置流量控制相关功能
1、配置日志记录

默认情况下,Nginx会在日志中记录由于流量限制而延迟或丢弃的请求,如下所示:

2019/02/13 04:20:00 [error] 120315#0: *32086 limiting requests, excess: 1.000 by zone "mylimit", client: 192.168.1.2, server: nginx.com, request: "GET / HTTP/1.0", host: "nginx.com"

日志条目中包含的字段:

  • limiting requests - 表明日志条目记录的是被“流量限制”请求
  • excess - 每毫秒超过对应“流量限制”配置的请求数量
  • zone - 定义实施“流量限制”的区域
  • client - 发起请求的客户端IP地址
  • server - 服务器IP地址或主机名
  • request - 客户端发起的实际HTTP请求
  • host - HTTP报头中host的值

默认情况下,Nginx以error级别来记录被拒绝的请求,如上面示例中的[error]所示(Ngin以较低级别记录延时请求,一般是info级别)。如要更改Nginx的日志记录级别,需要使用limit_req_log_level指令。这里,我们将被拒绝请求的日志记录级别设置为warn

limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;upstream myweb {server 10.0.105.196:80 weight=1 max_fails=1 fail_timeout=1;}server {listen 80;server_name localhost;location /login {limit_req zone=mylimit burst=20 nodelay;limit_req_log_level warn;proxy_pass http://myweb;proxy_set_header Host $host:$server_port;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}}
2、发送到客户端的错误代码

一般情况下,客户端超过配置的流量限制时,Nginx响应状态码为503(Service Temporarily Unavailable)。可以使用limit_req_status指令来设置为其它状态码(例如下面的444状态码):

limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;upstream myweb {server 10.0.105.196:80 weight=1 max_fails=1 fail_timeout=1;}server {listen 80;server_name localhost;location /login {limit_req zone=mylimit burst=20 nodelay;limit_req_log_level warn;limit_req_status 444;proxy_pass http://myweb;proxy_set_header Host $host:$server_port;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}}

7、nginx 流量控制总结

以上已经涵盖了Nginx和Nginx Plus提供的“流量限制”的很多功能,包括为HTTP请求的不同loation设置请求速率,给“流量限制”配置burstnodelay参数。还涵盖了针对客户端IP地址的白名单和黑名单应用不同“流量限制”的高级配置,阐述了如何去日志记录被拒绝和延时的请求。

18、nginx 访问控制

1、nginx 访问控制模块

(1)基于IP的访问控制:http_access_module
(2)基于用户的信任登录:http_auth_basic_module

2、基于IP的访问控制
1、配置语法
Syntax:allow address | CIDR | unix: | all;
default:默认无
Context:http,server,location,limit_exceptSyntax:deny address | CIDR | unix: | all;
default:默认无
Context:http,server,location,limit_except
2、配置测试

修改/etc/nginx/conf.d/access_mod.conf内容如下:

server {listen 80;server_name localhost;location ~ ^/admin {#/home/www/html/admin/index.htmlroot /home/www/html;index index.html index.hml;deny 192.168.1.8;allow all;#deny 192.168.1.8;}
}
#需要注意:
如果先允许访问,在定义拒绝访问。那么拒绝访问不生效。
先写范围小的

虚拟机宿主机IP为192.168.1.8,虚拟机IP为192.168.1.11,故这里禁止宿主机访问,允许其他所有IP访问。
宿主机访问http://192.168.1.11/admin,显示403 Forbidden
当然也可以反向配置,同时也可以使用IP网段的配置方式,如allow 192.168.1.0/24;,表示满足此网段的IP都可以访问。

3、指定location拒绝所有请求

如果你想拒绝某个指定URL地址的所有请求,而不是仅仅对其限速,只需要在location块中配置deny all指令:

server {listen 80;server_name localhost;location /foo.html {root /home/www/html;deny all;}
}
4、局限性

remote_addr只能记录上一层与服务器直接建立连接的IP地址,若中间有代理,则记录的是代理的IP地址。
http_x_forwarded_for可以记录每一层级的IP。

5、解决方法

(1)采用别的HTTP头信息控制访问,如HTTP_X_FORWARD_FOR(无法避免被改写)
(2)结合geo模块
(3)通过HTTP自定义变量传递

3、基于用户的信任登录
1、配置语法
Syntax:auth_basic string | off;
default:auth_basic off;
Context:http,server,location,limit_exceptSyntax:auth_basic_user_file file;
default:默认无
Context:http,server,location,limit_except
file:存储用户名密码信息的文件。
2、配置示例

改名access_mod.confauth_mod.conf,内容如下:

server {listen 80;server_name localhost;location ~ ^/admin {root /home/www/html;index index.html index.hml;auth_basic "Auth access test!";auth_basic_user_file /etc/nginx/auth.conf;}
}

auth_basic不为off,开启登录验证功能,auth_basic_user_file加载账号密码文件。

3、建立口令文件
[root@192 ~]# yum install -y httpd-tools #htpasswd 是开源 http 服务器 apache httpd 的一个命令工具,用于生成 http 基本认证的密码文件
[root@192 ~]# htpasswd -cm /etc/nginx/auth_conf user10
[root@192 ~]# htpasswd -m /etc/nginx/auth_conf user20
[root@192 ~]# cat /etc/nginx/auth_conf 
user10:$apr1$MOa9UVqF$RlYRMk7eprViEpNtDV0n40
user20:$apr1$biHJhW03$xboNUJgHME6yDd17gkQNb0
4、访问测试

5、局限性

(1)用户信息依赖文件方式
(2)操作管理机械,效率低下

6、解决方法

(1)Nginx结合LUA实现高效验证
(2)Nginx和LDAP打通,利用nginx-auth-ldap模块
(3)Nginx只做中间代理,具体认证交给应用。

19、nginx 变量(了解)

Nginx 同 Apache 和 Lighttpd 等其他 Web 服务器的配置方法不太相同,Nginx的配置文件使用语法的就是一门微型的编程语言。可以类似写程序一般编写配置文件,可操作性很大。既然是编程语言,一般也就少不了“变量”这种东西。

1、nginx变量简介
  • 所有的 Nginx变量在 Nginx 配置文件中引用时都须带上 $ 前缀
  • 在 Nginx 配置中,变量只能存放一种类型的值,有且也只存在一种类型,那就是字符串类型
  • nginx可以使用变量简化配置与提高配置的灵活性,所有的变量值都可以通过这种方式引用:
$变量名
2、nginx 变量的定义和使用

nginx中的变量分为两种,自定义变量与内置预定义变量

1、自定义变量

1、声明变量
可以在sever,http,location等标签中使用set命令(非唯一)声明变量,语法如下

set $变量名 变量值

注意:

  • nginx 中的变量必须都以$开头
  • nginx 的配置文件中所有使用的变量都必须是声明过的,否则 nginx 会无法启动并打印相关异常日志

2、变量的可见性

nginx 变量的一个有趣的特性就是nginx中每一个变量都是全局可见的,而他们又不是全局变量。如下例子

location /a/ {return 200 $a;
}location /b/ {set $a "hello nginx";return 200 $a;
}

由于变量是全局可见的所以nginx启动不会报错,而第一个location中并不知道$a的具体值因此返回的响应结果为一个空字符串。

在不同层级的标签中声明的变量性的可见性规则如下:

  • location标签中声明的变量中对这个location块可见
  • server标签中声明的变量对server块以及server块中的所有子块可见
  • http标签中声明的变量对http块以及http块中的所有子块可见

**3、配置 $foo=hello **?

server {listen 8080;server_name  localhost;location /test {set $foo hello;return 200 "foo: $foo";}
}

输出

[root@localhost html]# nginx -s reload
[root@localhost html]# curl localhost/test
hello \$

这里用到了标准模块 ngx_geo 提供的配置指令 geo 来为变量 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传",这样我们在下面需要使用美元符的地方,就直接引用我们的 $dollar 变量就可以了。

4、 使用大括号插值

在“变量插值”的上下文中,还有一种特殊情况,即当引用的变量名之后紧跟着变量名的构成字符时(比如后跟字母、数字以及下划线),我们就需要使用特别的记法来消除歧义,例如:

server {...location /test-brace {set $first "hello ";return 200 ${foo}world;}
}

输出

[root@localhost html]# nginx -s reload
[root@localhost html]# curl localhost/test-brace
hello world

这里,我们在 echo 配置指令的参数值中引用变量 first 的时候,后面紧跟着 world 这个单词,所以如果直接写作 “firstworld” 则 Nginx “变量插值”计算引擎会将之识别为引用了变量 firstworld. 为了解决这个难题,Nginx 的字符串记法支持使用花括号在 之后把变量名围起来,比如这里的 ${first}。

5、变量作用域

set 指令(以及前面提到的 geo 指令)不仅有赋值的功能,它还有创建 Nginx 变量的副作用,即当作为赋值对象的变量尚不存在时,它会自动创建该变量。比如在上面这个例子中,如果 $a 这个变量尚未创建,则 set 指令会自动创建 $a 这个用户变量。如果我们不创建就直接使用它的值,则会报错。
例如

server {...location /bad {return 200 $foo;}
}

此时 Nginx 服务器会拒绝加载配置:

[emerg] unknown "foo" variable

Nginx 变量的创建和赋值操作发生在全然不同的时间阶段,Nginx 变量的创建只能发生在 Nginx 配置加载的时候,或者说 Nginx 启动的时候,而赋值操作则只会发生在请求实际处理的时候。
这意味着不创建而直接使用变量会导致启动失败,同时也意味着我们无法在请求处理时动态地创建新的 Nginx 变量。

Nginx 变量一旦创建,其变量名的可见范围就是整个 Nginx 配置,甚至可以跨越不同虚拟主机的 server 配置块。我们来看一个例子:

server {listen 8080;location /foo {return 200 "foo = [$foo]";}location /bar {set $foo 32;return 200 "foo = [$foo]";}
}

输出

[root@localhost html]# curl 'http://localhost/foo'
foo = [][root@localhost html]# curl 'http://localhost/bar'
foo = [32][root@localhost html]# curl 'http://localhost/foo'
foo = []

这里我们在 location /bar 中用 set 指令创建了变量 foo,于是在整个配置文件中这个变量都是可见的,因此我们可以在 location /foo 中直接引用这个变量而不用担心 Nginx 会报错。
从这个例子我们可以看到,set 指令因为是在 location /bar 中使用的,所以赋值操作只会在访问 /bar 的请求中执行。而请求 /foo 接口时,我们总是得到空的 foo值,因为用户变量未赋值就输出的话,得到的便是空字符串。

从这个例子我们可以窥见的另一个重要特性是,Nginx 变量名的可见范围虽然是整个配置,但每个请求都有所有变量的独立副本,或者说都有各变量用来存放值的容器的独立副本,彼此互不干扰。比如前面我们请求了 /bar 接口后,foo 变量被赋予了值 32,但它丝毫不会影响后续对 /foo 接口的请求所对应的 foo 值(它仍然是空的!),因为各个请求都有自己独立的 $foo 变量的副本。

对于 Nginx 新手来说,最常见的错误之一,就是将 Nginxee 变量理解成某种在请求之间全局共享的东西,或者说“全局变量”。而事实上,Nginx 变量的生命期是不可能跨越请求边界的。

关于 Nginx 变量的另一个常见误区是认为变量容器的生命期,是与 location 配置块绑定的。其实不然。我们来看一个涉及“内部跳转”的例子:

server {listen 8080;location /foo {set $a hello;echo_exec /bar;}location /bar {echo "a = [$a]";}xxx
}

输出

[root@localhost html]# curl localhost/foo
a = [hello]

这 里我们在 location /foo 中,使用第三方模块 ngx_echo 提供的 echo_exec 配置指令,发起到 location /bar 的“内部跳转”。所谓“内部跳转”,就是在处理请求的过程中,于服务器内部,从一个 location 跳转到另一个 location 的过程。这不同于利用 HTTP 状态码 301 和 302 所进行的“外部跳转”,因为后者是由 HTTP 客户端配合进行跳转的,而且在客户端,用户可以通过浏览器地址栏这样的界面,看到请求的 URL 地址发生了变化。内部跳转和 Bourne Shell(或 Bash)中的 exec 命令很像,都是“有去无回”。另一个相近的例子是 C 语言中的 goto 语句。

既然是内部跳转,当前正在处理的请求就还是原来那个,只是当前的 location 发生了变化,所以还是原来的那一套 Nginx 变量的容器副本。对应到上例,如果我们请求的是 /foo 这个接口,那么整个工作流程是这样的:先在 location /foo 中通过 set 指令将 a 变量的值赋为字符串 hello,然后通过 echo_exec 指令发起内部跳转,又进入到 location /bar 中,再输出 a 变量的值。因为 a 还是原来的 a,所以我们可以期望得到 hello 这行输出。测试证实了这一点:

但如果我们从客户端直接访问 /bar 接口,就会得到空的 a 变量的值,因为它依赖于 location /foo 来对 a 进行初始化。

从上面这个例子我们看到,一个请求在其处理过程中,即使经历多个不同的 location 配置块,它使用的还是同一套 Nginx 变量的副本。这里,我们也首次涉及到了“内部跳转”这个概念。值得一提的是,标准 ngx_rewrite 模块的 rewrite 配置指令其实也可以发起“内部跳转”,例如上面那个例子用 rewrite 配置指令可以改写成下面这样的形式:

server {listen 8080;location /foo {set $a hello;rewrite ^ /bar;}location /bar {echo "a = [$a]";}
}

从上面这个例子我们看到,Nginx 变量值容器的生命期是与当前正在处理的请求绑定的,而与 location 无关。

2、内置预定义变量

内置预定义变量即无需声明就可以使用的变量,通常包括一个http请求或响应中一部分内容的值,以下为一些常用的内置预定义变量

变量名定义
$arg_PARAMETERGET请求中变量名PARAMETER参数的值。
$args这个变量等于GET请求中的参数。例如,foo=123&bar=blahblah;这个变量只可以被修改
$binary_remote_addr二进制码形式的客户端地址。
$body_bytes_sent传送页面的字节数
$content_length请求头中的Content-length字段。
$content_type请求头中的Content-Type字段。
$cookie_COOKIEcookie COOKIE的值。
$document_root当前请求在root指令中指定的值。
$document_uri与$uri相同。
$host请求中的主机头(Host)字段,如果请求中的主机头不可用或者空,则为处理请求的server名称(处理请求的server的server_name指令的值)。值为小写,不包含端口。
$hostname机器名使用 gethostname系统调用的值
$http_HEADERHTTP请求头中的内容,HEADER为HTTP请求中的内容转为小写,-变为_(破折号变为下划线),例如:$http_user_agent(Uaer-Agent的值);
$sent_http_HEADERHTTP响应头中的内容,HEADER为HTTP响应中的内容转为小写,-变为_(破折号变为下划线),例如: $sent_http_cache_control, $sent_http_content_type…;
$is_args如果$args设置,值为"?“,否则为”"。
$limit_rate这个变量可以限制连接速率。
$nginx_version当前运行的nginx版本号。
$query_string与$args相同。
$remote_addr客户端的IP地址。
$remote_port客户端的端口。
$remote_user已经经过Auth Basic Module验证的用户名。
$request_filename当前连接请求的文件路径,由root或alias指令与URI请求生成。
$request_body这个变量(0.7.58+)包含请求的主要信息。在使用proxy_pass或fastcgi_pass指令的location中比较有意义。
$request_body_file客户端请求主体信息的临时文件名。
$request_completion如果请求成功,设为"OK";如果请求未完成或者不是一系列请求中最后一部分则设为空。
$request_method这个变量是客户端请求的动作,通常为GET或POST。包括0.8.20及之前的版本中,这个变量总为main request中的动作,如果当前请求是一个子请求,并不使用这个当前请求的动作。
$request_uri这个变量等于包含一些客户端请求参数的原始URI,它无法修改,请查看$uri更改或重写URI。
$scheme所用的协议,比如http或者是https,比如rewrite ^(.+)$ $scheme://example.com$1 redirect;
$server_addr服务器地址,在完成一次系统调用后可以确定这个值,如果要绕开系统调用,则必须在listen中指定地址并且使用bind参数。
$server_name服务器名称。
$server_port请求到达服务器的端口号。
$server_protocol请求使用的协议,通常是HTTP/1.0或HTTP/1.1。
$uri请求中的当前URI(不带请求参数,参数位于args),不同于浏览器传递的args),不同于浏览器传递的args),不同于浏览器传递的request_uri的值,它可以通过内部重定向,或者使用index指令进行修改。不包括协议和主机名,例如/foo/bar.html

Nginx 内建变量最常见的用途就是获取关于请求或响应的各种信息。

1、uri vs request_uri

由 ngx_http_core 模块提供的内建变量 uri,可以用来获取当前请求的 URI(经过解码,并且不含请求参数),
而 request_uri 则用来获取请求最原始的 URI (未经解码,并且包含请求参数)。

location /test-uri {echo "uri = $uri";echo "request_uri = $request_uri";
}

输出

[root@localhost html]# nginx -s reload
[root@localhost html]# curl localhost/test-uri
uri = /test-uri
request_uri = /test-uri[root@localhost html]# curl "localhost/test-uri?a=3&b=4"
uri = /test-uri
request_uri = /test-uri?a=3&b=4[root@localhost html]# curl "localhost/test-uri/hello%20world?a=3&b=4"
uri = /test-uri/hello world
request_uri = /test-uri/hello%20world?a=3&b=4

2、$arg_XXX

另一个特别常用的内建变量其实并不是单独一个变量,而是有无限多变种的一群变量,即名字以 arg_ 开头的所有变量,我们估且称之为 arg_XXX 变量群。
一个例子是 arg_name,这个变量的值是当前请求中名为 name 的参数的值,而且还是未解码的原始形式的值。

location /test-arg {return 200 "name = $arg_name \n age = $arg_age";
}

输出

[root@localhost html]# nginx -s reload
[root@localhost html]# curl localhost/test-arg
name: 
class:[root@localhost html]# curl "localhost/test-arg?name=Tom&class=3"
name: Tom
class: 3[root@localhost html]# curl "localhost/test-arg?name=hello%20world&class=9"
name: hello%20world
class: 9

3、$arg_XXX 不区分大小写

其实 $arg_name 不仅可以匹配 name 参数,也可以匹配 NAME 参数,抑或是 Name,Nginx 会在匹配参数名之前,自动把原始请求中的参数名调整为全部小写的形式。

[root@localhost html]# curl "localhost/test-arg?NAME=Marry"
name: Marry
class:[root@localhost html]# curl "localhost/test-arg?Name=Jimmy"
name: Jimmy
class:

4、对 uri 解码

如果你想对 URI 参数值中的 %XX 这样的编码序列进行解码,可以使用第三方 ngx_set_misc 模块提供的

location /test-unescape-uri {set_unescape_uri $name $arg_name;set_unescape_uri $class $arg_class;echo "name: $name";echo "class: $class";
}

现在我们再看一下效果:

[root@localhost html]# curl "localhost/test-arg?name=hello%20world&class=9"
name: hello world
class: 9

从这个例子我们同时可以看到,这个 set_unescape_uri 指令也像 set 指令那样,拥有自动创建 Nginx 变量的功能。后面我们还会专门介绍到 ngx_set_misc 模块。

像 $arg_XXX 这种类型的变量拥有无穷无尽种可能的名字,所以它们并不对应任何存放值的容器。而且这种变量在 Nginx 核心中是经过特别处理的,第三方 Nginx 模块是不能提供这样充满魔法的内建变量的。

类 似 arg_XXX 的内建变量还有不少,比如用来取 cookie 值的 cookie_XXX 变量群,用来取请求头的 http_XXX 变量群,以及用来取响应头的 sent_http_XXX 变量群。这里就不一一介绍了,感兴趣的读者可以参考 ngx_http_core 模块的官方文档。

补充:添加echo指令
wget http://nginx.org/download/nginx-1.16.0.tar.gz
tar xf nginx-1.16.0.tar.gz
cd nginx-1.16.0
wget https://github.com/openresty/echo-nginx-module/archive/v0.61.tar.gz
tar xf v0.61.tar.gz
在nginx原有编译参数中添加 --add-module=解压后的目录名,然后重新编译即可

20、nginx 监控(了解)

1、nginx的基础监控
  • 进程监控
  • 端口监控

注意: 这两个是必须要加在zabbix监控,加触发器有问题及时告警。

web 服务器 nginx 以其高性能与抗并发能力越来越多的被用户使用

作为一款服务器产品,其运行状态是运维密切关注的,因此,对 nginx 的实时监控就必须要关注的了

nginx 提供了 ngx_http_stub_status_modulengx_http_reqstat_module模块,这个模块提供了基本的监控功能

作为官方企业版的 nginx plus 通过 ngx_http_status_module 提供了更加完善的监控功能: http://demo.nginx.com/status.html

2、监控的主要指标

我们需要对以下主要的指标进行监控:

1、基本活跃指标

Accepts(接受)、Handled(已处理)、Requests(请求数)是一直在增加的计数器。Active(活跃)、Waiting(等待)、Reading(读)、Writing(写)随着请求量而增减。

名称描述指标类型
Accepts(接受)NGINX 所接受的客户端连接数资源: 功能
Handled(已处理)成功的客户端连接数资源: 功能
Dropped(已丢弃,计算得出)丢弃的连接数(接受 - 已处理)工作:错误*
Requests(请求数)客户端请求数工作:吞吐量

NGINX worker 进程接受 OS 的连接请求时 Accepts 计数器增加,而Handled 是当实际的请求得到连接时(通过建立一个新的连接或重新使用一个空闲的)。这两个计数器的值通常都是相同的,如果它们有差别则表明连接被Dropped,往往这是由于资源限制,比如已经达到 NGINX 的worker_connections的限制。

2、每秒请求数 – QPS

按照固定时间间隔采样请求数据,计算出单位时间的请求量可以看到你的 web 服务器的请求情况

通过持续的 QPS 监控,可以立刻发现是否被恶意攻击或对服务的可用性进行评估

虽然当问题发生时,通过 QPS 不能定位到确切问题的位置,但是他却可以在第一时间提醒你环境可能出问题了

3、服务器错误率

通过监控固定时间间隔内的错误代码(4XX代码表示客户端错误,5XX代码表示服务器端错误),可以了解到客户端收到的结果是否是正确的错误率突然的飙升很可能是你的网站漏洞发出的信号

如果你希望通过 access log 分析错误率,那么你需要配置 nginx 的日志模块,让 nginx 将响应码写入访问日志

4、请求处理时间

请求处理时间也可以被记录在 access log 中,通过分析 access log,统计请求的平均响应时间,通过持续观察,可以发现上游服务器的问题

3、指标的收集

介绍了这么多的监控指标,事实上,上面介绍的仅仅是基本的监控指标,针对实际的情况,还有很多指标十分具有监控的必要

那么,怎么去收集这些指标进行监控呢?

通过在编译时加入 nginxngx_http_stub_status_module 模块我们可以实时监控以下基本的指标:

1、nginx Stub Status 监控模块安装

先使用命令查看是否已经安装这个模块:

# -V大写会显示版本号和模块等信息、v小写仅显示版本信息
[root@localhost ~]# nginx -V

如果没有此模块,需要重新安装,编译命令如下:

./configure –with-http_stub_status_module

具体的使用方法是在执行 ./configure 时,指定 --with-http_stub_status_module,然后通过配置:

server {listen 80;server_name localhost;location /nginx-status {stub_status     on;access_log  /var/log/nginx/access.log;allow   10.0.105.207; #允许本地电脑访问deny    all;}
}

此处默认只有本地访问,如果远程查看需要加相关的IP或者干脆去掉Deny all即可。加密文件可以使用#htpasswd -c /usr/nginx/conf hxb 命令来创建。配置完成后需要重启Nginx服务。状态配置只能是针对某个Nginx服务。目前Nginx还无法做到针对单个站点进行监控。

2、nginx 状态查看

配置完成后在浏览器中输入http://10.0.105.207/nginx-status 查看(或者用 curl localhost/nginx_status),显示信息如下:

Active connections: 2 
server accepts handled requests26 26 48 
Reading: 0 Writing: 1 Waiting: 1

Accepts(接受)、Handled(已处理)、Requests(请求数)是一直在增加的计数器。Active(活跃)、Waiting(等待)、Reading(读)、Writing(写)随着请求量而增减

3、Stub Status 参数说明

active connections – 活跃的连接数量

server accepts handled requests — 总共处理了1075个连接 , 成功创建1064次握手, 总共处理了6253个请求

每个连接有三种状态waiting、reading、writing

reading —读取客户端的Header信息数.这个操作只是读取头部信息,读取完后马上进入writing状态,因此时间很短。

writing — 响应数据到客户端的Header信息数.这个操作不仅读取头部,还要等待服务响应,因此时间比较长。

waiting — 开启keep-alive后等候下一次请求指令的驻留连接.

正常情况下waiting数量是比较多的,并不能说明性能差。反而如果reading+writing数量比较多说明服务并发有问题。

当用户请求连接Nginx服务器时,accepts计数器会加一。且当服务器处理该连接请求时,handled计数器同样会加一。一般而言,两者的值是相等的,除非达到了某些资源极限(如worker_connection的限制)。

用户连接请求被处理,就会进入 active 状态。如果该连接没有其他 request,则进入 waiting 的子状态;如果有 request,nginx 会读取 request 的 header,计数器 request 加一,进入 reading 的子状态。 reading 状态持续时间非常短,header 被读取后就会进入 writing 状态。事实上,直到服务器将响应结果返回给用户之前,该连接会一直保持 writing 状态。所以说,writing 状态一般会被长时间占用。

一旦 NGINX 成功处理一个连接时,连接会移动到Active状态,在这里对客户端请求进行处理:

Active状态

Waiting: 活跃的连接也可以处于 Waiting 子状态,如果有在此刻没有活跃请求的话。新连接可以绕过这个状态并直接变为到 Reading 状态,最常见的是在使用“accept filter(接受过滤器)” 和 “deferred accept(延迟接受)”时,在这种情况下,NGINX 不会接收 worker 进程的通知,直到它具有足够的数据才开始响应。如果连接设置为 keep-alive ,那么它在发送响应后将处于等待状态。
Reading: 当接收到请求时,连接离开 Waiting 状态,并且该请求本身使 Reading 状态计数增加。在这种状态下 NGINX 会读取客户端请求首部。请求首部是比较小的,因此这通常是一个快速的操作。
Writing: 请求被读取之后,其使 Writing 状态计数增加,并保持在该状态,直到响应返回给客户端。这意味着,该请求在 Writing 状态时, 一方面 NGINX 等待来自上游系统的结果(系统放在 NGINX “后面”),另外一方面,NGINX 也在同时响应。请求往往会在 Writing 状态花费大量的时间。

通常,一个连接在同一时间只接受一个请求。在这种情况下,Active 连接的数目 == Waiting 的连接 + Reading 请求 + Writing 。

怎么利用这些参数?

开源的 Nginx 提供的原始参数中,实时性的会比较有用,如 Active connections、Reading、Writing 以及 Waiting。这些数据能够反映当前 Nginx 的负载情况,方便在服务器出现问题时及时发现问题。而另一些数据由于不是状态量,Nginx 无法计算当前的量值而改做其统计数,如 accepts、handled 和 requests。

对于维护网站人员,accepts、handled 和 requests 的统计值用处是不大的,值得参考的是短时间内这三者数值的增量。这个短时间可以是一秒,如 accepts_per_second、handled_per_second 和 requests_per_second。一个简单的做法就是每秒都去读取这些参数,返回一个和上一秒的差值就行。当然,handled_per_second 替换成 dropped_per_second=accepts_per_second-handled_per_second 就更完美了。

通过这七个参数,就可以从连接到请求全方位的监控起 Nginx 的运行状态。为了方便检测,对每次获取的参数保留下来,然后按时间展现出来。下图展示了 Nginx 在运行时的参考数据。

4、Reqstat 模块监控

描述

  • ngx_http_reqstat_module 模块
  • 这个模块计算定义的变量,根据变量值分别统计 nginx 的运行状况。
  • 可以监视的运行状况有:连接数、请求数、各种响应码范围的请求数、输入输出流量、rt、upstream访问等。
  • 可以指定获取所有监控结果或者一部分监控结果。
  • 利用变量添加自定义监控状态。总的监控状态最大个数为50个。
  • 回收过期的监控数据。
  • 设置输出格式
  • 跟踪请求,不受内部跳转的影响
  • 不要使用与响应相关的变量作为条件,比如"$status"

编译

默认编入Tengine,可通过 --without-http_reqstat_module 编译此模块,或通过–with-http_reqstat_module=shared 编译为so模块。

使用so模块加载的话,请确保其顺序在"ngx_http_lua_module"之后。可以借助"nginx -m"来确认。


Syntax: req_status zone_name1 [zone_name2 [zone_name3 […]]]
Default: none
Context: http、srv、loc

开启统计,可以指定同时统计多个目标,每一个zone_name对应一个目标。


Syntax: req_status_show [zone_name1 [zone_name2 […]]]
Default: 所有建立的共享内存目标
Context: loc

按格式返回统计结果。可指定返回部分目标的统计结果。


Syntax: req_status_show_field field_name1 [field_name2 [field_name3 […]]]
Default: all the fields, including user defined fields
Context: loc

定义输出格式。可以使用的字段:内置字段,以上面的名字来表示;自定义字段,用变量表示。
'kv’总是每行的第一个字段。


Syntax: _req_status_zone_add_indecator zone_name _外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传var2 […]]
Default: none
Context: http

通过变量增加自定义字段,新增加的字段目前会展现在每行的末尾。


Syntax: req_status_zone_key_length zone_name length
Default: none
Context: http

定义某个共享内存块中key的最大长度,默认值104。key中超出的部分会被截断。


Syntax: req_status_zone_recycle zone_name times seconds
Default: none
Context: http

定义某个共享内存块过期数据的回收。回收在共享内存耗尽时自动开启。只会回收访问频率低于设置值的监控数据。
频率定义为 times / seconds,默认值为10r/min,即

req_status_zone_recycle demo_zone 10 60;

安装模块:

tengine官方说req-statu模块默认安装。但是并没有。而且tengine的req-status模块不能分upstream监控,从github引入第三方模块解决该问题
yum与编译安装的nginx扩展模块安装:
[root@nginx-server ~]# yum install -y unzip
1. 安装,先查看一下当前编译安装nginx的版本
[root@localhost nginx-1.16.0]# nginx -V  
下载或者上传一个和当前的nginx版本一样的nginx的tar包。
[root@nginx-server ~]# tar xzf nginx-1.16.0.tar.gz -C /usr/local/
2.下载ngx_req_status_module 模块, 这是第三方模块需要添加
[root@nginx-server ~]# wget https://github.com/zls0424/ngx_req_status/archive/master.zip -O ngx_req_status.zip
[root@nginx-server ~]# unzip ngx_req_status.zip
[root@nginx-server ~]# cp -r ngx_req_status-master/ /usr/local/ #与解压的nginx在同一级目录下
[root@nginx-server ~]# cd /usr/local/nginx-1.16.0/
[root@nginx-server nginx-1.16.0]# yum -y install pcre pcre-devel openssl openssl-devel gcc gcc-c++   zlib zlib-devel
[root@nginx-server nginx-1.16.0]# yum -y install patch.x86_64
[root@nginx-server nginx-1.16.0]# patch -p1 < ../ngx_req_status-master/write_filter-1.7.11.patch
[root@localhost nginx-1.16.0]# ./configure 添加上原来的参数 --add-module=/usr/local/ngx_req_status-master
[root@localhost nginx-1.16.0]# make -j2
由于原先已有nginx,所以不能执行make install,否则会覆盖掉以前的配置文件及内容
[root@localhost nginx-1.16.0]# mv /usr/sbin/nginx /usr/sbin/nginx_bak
[root@localhost nginx-1.16.0]# cp objs/nginx /usr/sbin/
[root@localhost nginx-1.16.0]# systemctl restart nginx 
[root@localhost nginx-1.16.0]# nginx -V   
如果发现编译的配置文件有变化就成功了!
配置如下: 需要在http里面配置。
!!注意,添加了此配置,只有重启nginx才能生效。
[root@localhost ~]# vim /etc/nginx/nginx.confreq_status_zone server_name $server_name 256k;req_status_zone server_addr $server_addr 256k;req_status_zone server_url  $server_name$uri 256k;req_status server_name server_addr server_url;server {server_name localhost;location /req-status {req_status_show on;}}指令介绍req_status_zone
语法: req_status_zone name string size
默认值: None
配置块: http
定义请求状态ZONE,请求按照string分组来排列,例如:
req_status_zone server_url  $server_name$uri 256k;
域名+uri将会形成一条数据,可以看到所有url的带宽,流量,访问数req_status
语法: req_status zone1[ zone2]
默认值: None
配置块: http, server, location
在location中启用请求状态,你可以指定更多zones。req_status_show
语法: req_status_show on
默认值: None
配置块: location
在当前位置启用请求状态处理程序

请求状态信息包括以下字段:

  • zone_name - 利用req_status_zone定义的分组标准。例如,按照服务器名称对请求进行分组后;
  • key - 请求按分组标准分组后的分组标识(即组名)。例如按服务器名称分组时,组名可能是10.0.105.196;
  • max_active - 该组的最大并发连接数;
  • max_bw - 该组的最大带宽;
  • traffic - 该组的总流量;
  • requests - 该组的总请求数;
  • active - 该组当前的并发连接数;
  • bandwidth - 该组当前带宽。
5、补充:

查看Nginx并发进程数:ps -ef | grep nginx | wc -l

查看Web服务器TCP连接状态:netstat -n | awk ‘/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}’

LISTEN:侦听来自远方的TCPport的连接请求

SYN-SENT:再发送连接请求后等待匹配的连接请求

SYN-RECEIVED:再收到和发送一个连接请求后等待对方对连接请求的确认

ESTABLISHED:代表一个打开的连接

FIN-WAIT-1:等待远程TCP连接中断请求,或先前的连接中断请求的确认

FIN-WAIT-2:从远程TCP等待连接中断请求

CLOSE-WAIT:等待从本地用户发来的连接中断请求

CLOSING:等待远程TCP对连接中断的确认

LAST-ACK:等待原来的发向远程TCP的连接中断请求的确认

TIME-WAIT:等待足够的时间以确保远程TCP接收到连接中断请求的确认

CLOSED:没有不论什么连接状态

商业版的 nginx plus 通过他的 ngx_http_status_module 提供了比 nginx 更多的监控指标,可以参看 http://demo.nginx.com/status.html

4、nginx access log 分析

nginx 的 access log 中可以记录很多有价值的信息,通过分析 access log,可以收集到很多指标

python 编写的 linux 工具 ngxtop 就实现了对 access log 的分析功能

1.制作nginx的日志切割,每天凌晨切割并压缩。

PV:PV(访问量): 即Page View, 即页面浏览量或点击量,用户每次刷新即被计算一次。

UV:UV(独立访客):即Unique Visitor,访问您网站的一台电脑客户端为一个访客。00:00-24:00内相同的客户端只被计算一次。

面试:

1.根据访问IP统计UV

awk ‘{print $1}’ access.log|sort | uniq -c |wc -l

2.统计访问URL统计PV

awk ‘{print $7}’ access.log|wc -l

3.查询访问最频繁的URL

awk ‘{print $7}’ access.log|sort | uniq -c |sort -n -k 1 -r|more

4.查询访问最频繁的IP

awk ‘{print $1}’ access.log|sort | uniq -c |sort -n -k 1 -r|more

5.查询访问最频繁的前10的IP

awk ‘{print $1}’ access.log|sort | uniq -c |sort -n -k 1 -r|head -n 10

总结

理解今天所学

nginx如何限流

使用的是漏桶算法,一个桶口在倒水,桶底在漏水,如果是涓涓细流,水漏出来了那么nginx可以给你处理,如果水流过大,那么nginx只能处理漏出来的水,其余的在缓存区等待。

image-20240425173251580

image-20240425114259352

nginx 流量控制

一秒钟十次,一千毫秒十次,一百毫秒一次

image-20240425172015802

然后再准备限制的地方加上limit_req zone=mylimit;

image-20240425172151470

处理突发

比如说burst=20

如果你设置了每秒只允许 10 个请求,并且 burst 为 5,那么在短时间内可能会有 15 个请求被接收,但只有 10 个会立即被处理,剩下的 5 个会在“缓冲区”中等待。现有的先处理。人多了就会增加服务器的负载,然后我们就应该无延迟排队。

无延迟排队

让突发的20个先被处理,速度就会很快,因为第一个不需要排队,所以是21个状态码是200,其他都是503

又让用户的体验增加了,也让黑客不会有可乘之机。

白名单

image-20240425190546805

limit_req_status 503;

访问

1、一棒子把人打死了

image-20240425200841996

2、建立口令文件比如htpasswd,容易被攻击

image-20240425201113953

平滑升级

yum安装的不能平滑升级

需要编译安装

课件在nginx3.md文件中。

变量

nginx变量的全局可见的

image-20240425204106815

如果没有rewrite ,他也会重新查找到,但是找不到变量,rewrite之后,就会直接找到并赋值

背诵:

pv 点击量 上车下车 两次

uv 游客数量 算的人头数

qps

image-20240425210502544

这就是pv、

uv:

awk ’ {print $1}’ access.log | sort -n | uniq -c | sort -r

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/661649.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

github托管静态页面

免费在线上空间&#xff0c;不用简直就是浪费&#xff0c;关键还不限流量赶紧去折腾一下 这是搭建的GitHub托管网页&#xff0c;由于是GitHub的服务器&#xff0c;国内访问会非常&#xff01;慢 下载 Watt Toolkit 这里我建议下载一个软件 Watt Toolkit 它是一个开源跨…

用大模型生成带文字的海报

本文代码讲整合在&#xff1a; GitHub - liangwq/Chatglm_lora_multi-gpu: chatglm多gpu用deepspeed和 这篇文章介绍如何利用VLMdiffusion模型来搭建一条文本生成海报的链路。搭建这条链路有两个应用&#xff1a;1.实际的业务中需要批量生产文字图海报可以用&#xff0c;2.可以…

Progress Kemp LoadMaster 远程命令执行漏洞复现(CVE-2024-1212)

0x01 产品简介 Progress Kemp LoadMaster是一款负载均衡和应用交付控制器,由Progress Software Corporation(前身为Kemp Technologies)开发和提供。该产品旨在提供高可用性、可靠性和性能优化的应用交付解决方案,帮助组织管理和优化其应用程序交付流量。 0x02 漏洞概述 …

短信测压APP(新增Python跑接口)

新增Python跑接口测压&#xff0c;手机电脑都可跑

Python 深度学习(二)

原文&#xff1a;zh.annas-archive.org/md5/98cfb0b9095f1cf64732abfaa40d7b3a 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 第五章&#xff1a;图像识别 视觉可以说是人类最重要的感官之一。我们依赖视觉来识别食物&#xff0c;逃离危险&#xff0c;认出朋友和家人…

C++笔试练习笔记 【2】: 数字统计 BC153 两个数组的交集 NC313 点击消除 AB5

文章目录 数字统计分析题目代码部分 两个数组的交集题目分析代码部分 点击消除题目解析代码部分 数字统计 分析题目 这个题涉及到两个知识点&#xff0c;就是枚举和数字的拆分 那么我的思路是进行遍历&#xff0c;拆分数字判断二的个数&#xff0c;枚举进行计数 那么数字的拆分…

Python中的类(Class)详解——新手指南

在Python编程中&#xff0c;类&#xff08;Class&#xff09;是一个非常重要的概念&#xff0c;它允许程序员创建自己的对象类型。这些对象类型可以包含数据&#xff08;称为属性&#xff09;和函数&#xff08;称为方法&#xff09;&#xff0c;它们定义了这些对象的行为。本文…

数据结构:实验七:数据查找

一、 实验目的 &#xff08;1&#xff09;领会各种查找算法的过程和算法设计。 &#xff08;2&#xff09;掌握查找算法解决实际问题。 二、 实验要求 &#xff08;1&#xff09;编写一个程序exp8-1.cpp, 按提示输入10个任意的整形数据&#xff08;无序&#xff09;&…

283. 移动零 11. 盛最多水的容器

283. 移动零 把非零的数全交换到前面去 11. 盛最多水的容器 双指针&#xff1a; 双指针一个在头 一个在尾部 计算两个边的盛水量并更新数值 左右两边 哪边矮就移动哪边

【大模型学习】Transformer(学习笔记)

Transformer介绍 word2vec Word2Vec是一种用于将词语映射到连续向量空间的技术&#xff0c;它是由Google的Tomas Mikolov等人开发的。Word2Vec模型通过学习大量文本数据中的词语上下文信息&#xff0c;将每个词语表示为高维空间中的向量。在这个向量空间中&#xff0c;具有相似…

C++ | Leetcode C++题解之第59题螺旋矩阵II

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<vector<int>> generateMatrix(int n) {int num 1;vector<vector<int>> matrix(n, vector<int>(n));int left 0, right n - 1, top 0, bottom n - 1;while (left < r…

YOLOV8 pycharm

1 下载pycharm 社区版 https://www.jetbrains.com/zh-cn/pycharm/download/?sectionwindows 2 安装 3 新建 4 选择 文件-> setting 配置环境变量 5 添加conda 环境