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编码嵌入;如下:
<!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>
[root@tnt-1 ~]# vim /etc/nginx/nginx.conf
# error_page 500 502 503 504 /50x.html;
# location = /50x.html {
# root html;
# }
#
error_page 402 403 404 500 502 503 504 /404.html;
location = /404.html {
root /usr/local/nginx/html;
}
#进主配置文件,找到原先默认的错误页面配置内容,注释掉或者修改掉.
#加入新的配置内容.写好路径.内容意思是只要出现402 403 500 502 503 504这些代码的,就会返回/404.html页面,并且去root /usr/local/nginx/html这个位置里面找这个页面.
[root@tnt-1 ~]# vim /usr/local/nginx/html/404.html
[root@tnt-1 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@tnt-1 ~]# nginx -s reload
# 然后自己定义的路径里创建一个404的页面.
# 页面代码上面有一个,复制粘贴就可以.
# 在vim创建的时候要用这个,因为这个页面代码内容特殊,可以预防复制粘贴不一致.
# :set paste 回车 然后按A 插入
# 然后查看配置文件代码是否正常.
# 重新加载配置文件.
# 然后浏览器访问测试
求的数量。请求,可以是一个简单网站首页的GET请求,也可以是登录表单的 POST 请求。流量限制可以用作安全目的,比如可以减慢暴力密码破解的速率。通过将传入请求的速率限制为真实用户的典型值,并标识目标URL地址(通过日志),还可以用来抵御 DDOS 攻击。更常见的情况,该功能被用来保护上游应用服务器不被同时太多用户请求所压垮。
以下将会介绍Nginx的 流量限制 的基础知识和高级配置,”流量限制”在Nginx Plus中也适用。
Nginx的”流量限制”使用漏桶算法(leaky bucket algorithm),该算法在通讯和分组交换计算机网络中广泛使用,用以处理带宽有限时的突发情况。就好比,一个桶口在倒水,桶底在漏水的水桶。如果桶口倒水的速率大于桶底的漏水速率,桶里面的水将会溢出;同样,在请求处理方面,水代表来自客户端的请求,水桶代表根据”先进先出调度算法”(FIFO)等待被处理的请求队列,桶底漏出的水代表离开缓冲区被服务器处理的请求,桶口溢出的水代表被丢弃和不被处理的请求。
“流量限制”配置两个主要的指令,limit_req_zone
和limit_req
,如下所示:
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/s;
server {
location /login/ {
limit_req zone=mylimit;
proxy_pass http://my_upstream;
}
}
limit_req_zone
指令定义了流量限制相关的参数,而limit_req
指令在出现的上下文中启用流量限制(示例中,对于”/login/”的所有请求)。
limit_req_zone
指令通常在HTTP块中定义,使其可在多个上下文中使用,它需要以下三个参数:
$binary_remote_addr
,保存客户端IP地址的二进制形式。这意味着,我们可以将每个不同的IP地址限制到,通过第三个参数设置的请求速率。(使用该变量是因为比字符串形式的客户端IP地址$remote_addr
,占用更少的空间)zone=keyword
标识区域的名字,以及冒号后面跟区域大小。16000个IP地址的状态信息,大约需要1MB,所以示例中区域可以存储160000个IP地址。当Nginx需要添加新条目时存储空间不足,将会删除旧条目。如果释放的空间仍不够容纳新记录,Nginx将会返回 503状态码(Service Temporarily Unavailable)。另外,为了防止内存被耗尽,Nginx每次创建新条目时,最多删除两条60秒内未使用的条目。
limit_req_zone
指令设置流量限制和共享内存区域的参数,但实际上并不限制请求速率。所以需要通过添加
limit_req
指令,将流量限制应用在特定的location
或者server
块。在上面示例中,我们对/login/
请求进行流量限制。
现在每个IP地址被限制为每秒只能请求10次/login/
,更准确地说,在前一个请求的100毫秒内不能请求该URL。
[root@tnt-1 ~]# vim /etc/nginx/nginx.conf
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s;
location / {
root html;
index index.html index.htm;
limit_req zone=mylimit;
}
#打开配置文件
#定义加入一个模块用来做限制.
#模块意思是,$binary_remote_addr zone 用二进制的方式去记录客户端的IP地址,并且定义一个名字叫做mylimit的地址用来存储所有来访问的客户端的IP地址,最后限制每个IP地址rate=1r/s,允许1秒钟不超过1个请求.内存共享区大小是10m.
#这个模块要写在server级别之外.为了便于测试,我们把rate=1r/s改成1秒1次.
#然后再在你需要引用这个模块的地方加上limit_req zone=mylimit;
#相当于先定义变量,然后引用变量.
[root@tnt-1 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@tnt-1 ~]# nginx -s reload
#测试配置文件
#重新加载
[root@tnt-2 ~]# curl -I http://120.25.2xx.2xx
HTTP/1.1 200 OK
Server: nginx/1.14.2
Date: Tue, 09 Jun 2020 09:20:41 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Mon, 01 Jun 2020 17:17:58 GMT
Connection: keep-alive
ETag: "5ed53846-264"
Accept-Ranges: bytes
[root@tnt-2 ~]# curl -I http://120.25.2xx.2xx
HTTP/1.1 503 Service Temporarily Unavailable
Server: nginx/1.14.2
Date: Tue, 09 Jun 2020 09:20:41 GMT
Content-Type: text/html
Content-Length: 9616
Connection: keep-alive
ETag: "5edf30fe-2590"
#然后浏览器或者curl测试.会发现第一次访问正常,快速访问的话就会被限制了.
#换一台服务器进行curl
如果我们在100毫秒内接收到2个请求,怎么办?对于第二个请求,Nginx将给客户端返回状态码503。这可能并不是我们想要的结果,因为应用本质上趋向于突发性。相反地,我们希望缓冲任何超额的请求,然后及时地处理它们。我们更新下配置,在limit_req
中使用burst
参数:
location /login/ {
limit_req zone=mylimit burst=20;
proxy_pass http://my_upstream;
}
burst
参数定义了超出zone指定速率的情况下(示例中的mylimit
区域,速率限制在每秒10个请求,或每100毫秒一个请求),客户端还能发起多少请求。上一个请求100毫秒内到达的请求将会被放入队列,我们将队列大小设置为20。
这意味着,如果从一个给定IP地址发送21个请求,Nginx会立即将第一个请求发送到上游服务器群,然后将余下20个请求放在队列中。然后每100毫秒转发一个排队的请求,只有当传入请求使队列中排队的请求数超过20时,Nginx才会向客户端返回503。
[root@tnt-1 ~]# vim /etc/nginx/nginx.conf
location / {
root html;
index index.html index.htm;
limit_req zone=mylimit burst=20;
}
#打开配置文件.
#加上一个参数burst=20.
#这个参数理解为用来定义如果一定时间内超过了之前定义的速率1r/s以外的请求,会让第一个请求以外的其它请求去排队.超过了20个,才会丢弃掉返回503报错.就是最多让20个请求进行排队,最大延迟请求数量不大于20,在等待处理.
[root@tnt-1 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@tnt-1 ~]# nginx -s reload
#测配置文件.
#重新加载.
#然后测试
和上面一个测试例子对比,这里快速访问两次的话不会返回503.会发现会有一个稍微的卡顿,这里就可以理解为第二个请求在排队.最后返回的还是200.
配置burst
参数将会使通讯更流畅,但是可能会不太实用,因为该配置会使站点看起来很慢。在上面的示例中,队列中的第20个包需要等待2秒才能被转发,此时返回给客户端的响应可能不再有用。要解决这个情况,可以在burst
参数后添加nodelay
参数:
location /login/ {
limit_req zone=mylimit burst=20 nodelay;
proxy_pass http://my_upstream;
}
使用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
参数是很实用的。
注意: 对于大部分部署,我们建议使用burst
和nodelay
参数来配置limit_req
指令。
通过将基本的“流量限制”与其他Nginx功能配合使用,我们可以实现更细粒度的流量限制。
下面这个例子将展示,如何对任何不在白名单内的请求强制执行“流量限制”:
geo $limit {
default 1;
10.0.0.0/8 0;
192.168.0.0/64 0;
}
map $limit $limit_key {
0 "";
1 $binary_remote_addr;
}
limit_req_zone $limit_key zone=req_zone:10m rate=5r/s;
server {
location / {
limit_req zone=req_zone burst=10 nodelay;
# ...
}
}
这个例子同时使用了geo
和map
指令。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/8和192.168.0.0/24 网段内)不会被限制。其它所有IP地址都会被限制到每秒5个请求。
limit_req
指令将限制应用到**/**的location块,允许在配置的限制上最多超过10个数据包的突发,并且不会延迟转发。
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个请求。
默认情况下,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"
日志条目中包含的字段:
默认情况下,Nginx以error
级别来记录被拒绝的请求,如上面示例中的[error]
所示(Ngin以较低级别记录延时请求,一般是info
级别)。如要更改Nginx的日志记录级别,需要使用limit_req_log_level
指令。这里,我们将被拒绝请求的日志记录级别设置为warn
:
location /login/ {
limit_req zone=mylimit burst=20 nodelay;
limit_req_log_level warn;
proxy_pass http://my_upstream;
}
一般情况下,客户端超过配置的流量限制时,Nginx响应状态码为503(Service Temporarily Unavailable)。可以使用limit_req_status
指令来设置为其它状态码(例如下面的444状态码):
location /login/ {
limit_req zone=mylimit burst=20 nodelay;
limit_req_status 444;
}
location
拒绝所有请求如果你想拒绝某个指定URL地址的所有请求,而不是仅仅对其限速,只需要在location
块中配置deny
all指令:
location /foo.php {
deny all;
}
以上已经涵盖了Nginx和Nginx Plus提供的“流量限制”的很多功能,包括为HTTP请求的不同loation设置请求速率,给“流量限制”配置burst
和nodelay
参数。还涵盖了针对客户端IP地址的白名单和黑名单应用不同“流量限制”的高级配置,阐述了如何去日志记录被拒绝和延时的请求。
(1)基于IP的访问控制:http_access_module
(2)基于用户的信任登录:http_auth_basic_module
Syntax:allow address | CIDR | unix: | all;
default:默认无
Context:http,server,location,limit_except
Syntax:deny address | CIDR | unix: | all;
default:默认无
Context:http,server,location,limit_except
修改/etc/nginx/conf.d/access_mod.conf
内容如下:
location ~ ^/admin.html {
root /opt/app/code;
deny 192.168.174.1;
allow all;
index index.html index.htm;
}
虚拟机宿主机IP为192.168.174.1
,虚拟机IP为192.168.174.132
,故这里禁止宿主机访问,允许其他所有IP访问。
宿主机访问http://192.168.174.132/admin.html
,显示403 Forbidden
。
当然也可以反向配置,同时也可以使用IP网段的配置方式,如allow 192.168.174.0/24;
,表示满足此网段的IP都可以访问。
remote_addr
只能记录上一层与服务器直接建立连接的IP地址,若中间有代理,则记录的是代理的IP地址。
http_x_forwarded_for
可以记录每一层级的IP。
(1)采用别的HTTP头信息控制访问,如HTTP_X_FORWARD_FOR(无法避免被改写)
(2)结合geo模块
(3)通过HTTP自定义变量传递
Syntax:auth_basic string | off;
default:auth_basic off;
Context:http,server,location,limit_except
Syntax:auth_basic_user_file file;
default:默认无
Context:http,server,location,limit_except
file:存储用户名密码信息的文件。
改名access_mod.conf
为auth_mod.conf
,内容如下:
location ~ ^/admin.html {
root /opt/app/code;
auth_basic "Auth access test!";
auth_basic_user_file /etc/nginx/auth_conf;
index index.html index.htm;
}
auth_basic
不为off
,开启登录验证功能,auth_basic_user_file
加载账号密码文件。
[root@web ~]# htpasswd -cm /etc/nginx/auth_conf user10
[root@web ~]# htpasswd -m /etc/nginx/auth_conf user20
[root@web ~]# cat /etc/nginx/auth_conf
user10:$apr1$Cw6eF/..$MNBh6rvkvsfH9gDZ/kEhg/
user20:$apr1$tb6B8...$y28sfvudhfb4V8xPlvvi//
(1)用户信息依赖文件方式
(2)操作管理机械,效率低下
(1)Nginx结合LUA实现高效验证
(2)Nginx和LDAP打通,利用nginx-auth-ldap模块
(3)Nginx只做中间代理,具体认证交给应用。
Nginx 同 Apache 和 Lighttpd 等其他 Web 服务器的配置记法不太相同,Nginx的配置文件使用语法的就是一门微型的编程语言。可以类似写程序一般编写配置文件,可操作性很大。既然是编程语言,一般也就少不了“变量”这种东西。
所有的 Nginx变量在 Nginx 配置文件中引用时都须带上 $ 前缀
在 Nginx 配置中,变量只能存放一种类型的值,有且也只存在一种类型,那就是字符串类型
nginx可以使用变量简化配置与提高配置的灵活性,所有的变量值都可以通过这种方式引用:
$变量名
nginx中的变量分为两种,自定义变量与内置预定义变量
可以在sever,http,location等标签中使用set命令(非唯一)声明变量,语法如下
set $变量名 变量值
注意:
nginx 中的变量必须都以$开头
nginx 的配置文件中所有使用的变量都必须是声明过的,否则 nginx 会无法启动并打印相关异常日志
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块中的所有子块可见
server {
listen 8080;
server_name localhost;
location /test {
set $foo hello;
echo "foo: $foo";
}
}
输出
[root@localhost html]# nginx -s reload
[root@localhost html]# curl localhost/test
foo: hello
如果我们想通过 echo 指令直接输出含有“美元符”($)的字符串,那么有没有办法把特殊的 $ 字符给转义掉呢?答案是否定的。不过幸运的是,我们可以绕过这个限制,比如通过不支持“变量插值”的模块配置指令专门构造出取值为 $ 的 Nginx 变量,然后再在 echo 中使用这个变量。看下面这个例子:
http {
...
geo $dollar {
default "$";
}
server {
...
location /test-dollar {
echo "This is a dollar sign: $dollar";
}
}
}
输出
[root@localhost html]# nginx -s reload
[root@localhost html]# curl localhost/test-dollar
This is a dollar sign: \$
这里用到了标准模块 ngx_geo 提供的配置指令 geo 来为变量 $dollar 赋予字符串 “$”,这样我们在下面需要使用美元符的地方,就直接引用我们的 $dollar 变量就可以了。
在“变量插值”的上下文中,还有一种特殊情况,即当引用的变量名之后紧跟着变量名的构成字符时(比如后跟字母、数字以及下划线),我们就需要使用特别的记法来消除歧义,例如:
server {
...
location /test-brace {
set $first "hello ";
echo "${first}world";
}
}
输出
[root@localhost html]# nginx -s reload
[root@localhost html]# curl localhost/test-brace
hello world
这里,我们在 echo 配置指令的参数值中引用变量 first 的时候,后面紧跟着 world 这个单词,所以如果直接写作 “firstworld” 则 Nginx “变量插值”计算引擎会将之识别为引用了变量 firstworld. 为了解决这个难题,Nginx 的字符串记法支持使用花括号在 之后把变量名围起来,比如这里的 ${first}。
set 指令(以及前面提到的 geo 指令)不仅有赋值的功能,它还有创建 Nginx 变量的副作用,即当作为赋值对象的变量尚不存在时,它会自动创建该变量。比如在上面这个例子中,如果 $a 这个变量尚未创建,则 set 指令会自动创建 $a 这个用户变量。如果我们不创建就直接使用它的值,则会报错。
例如
server {
...
location /bad {
echo $foo;
}
}
此时 Nginx 服务器会拒绝加载配置:
[emerg] unknown "foo" variable
Nginx 变量的创建和赋值操作发生在全然不同的时间阶段,Nginx 变量的创建只能发生在 Nginx 配置加载的时候,或者说 Nginx 启动的时候,而赋值操作则只会发生在请求实际处理的时候。
这意味着不创建而直接使用变量会导致启动失败,同时也意味着我们无法在请求处理时动态地创建新的 Nginx 变量。
Nginx 变量一旦创建,其变量名的可见范围就是整个 Nginx 配置,甚至可以跨越不同虚拟主机的 server 配置块。我们来看一个例子:
server {
listen 8080;
location /foo {
echo "foo = [$foo]";
}
location /bar {
set $foo 32;
echo "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 新手来说,最常见的错误之一,就是将 Nginx 变量理解成某种在请求之间全局共享的东西,或者说“全局变量”。而事实上,Nginx 变量的生命期是不可能跨越请求边界的。
关于 Nginx 变量的另一个常见误区是认为变量容器的生命期,是与 location 配置块绑定的。其实不然。我们来看一个涉及“内部跳转”的例子:
server {
listen 8080;
location /foo {
set $a hello;
echo_exec /bar;
}
location /bar {
echo "a = [$a]";
}
}
输出
[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 无关。
内置预定义变量即无需声明就可以使用的变量,通常包括一个http请求或响应中一部分内容的值,以下为一些常用的内置预定义变量
变量名 | 定义 |
---|---|
$arg_PARAMETER | GET请求中变量名PARAMETER参数的值。 |
$args | 这个变量等于GET请求中的参数。例如,foo=123&bar=blahblah;这个变量只可以被修改 |
$binary_remote_addr | 二进制码形式的客户端地址。 |
$body_bytes_sent | 传送页面的字节数 |
$content_length | 请求头中的Content-length字段。 |
$content_type | 请求头中的Content-Type字段。 |
$cookie_COOKIE | cookie COOKIE的值。 |
$document_root | 当前请求在root指令中指定的值。 |
$document_uri | 与$uri相同。 |
$host | 请求中的主机头(Host)字段,如果请求中的主机头不可用或者空,则为处理请求的server名称(处理请求的server的server_name指令的值)。值为小写,不包含端口。 |
$hostname | 机器名使用 gethostname系统调用的值 |
$http_HEADER | HTTP请求头中的内容,HEADER为HTTP请求中的内容转为小写,-变为_(破折号变为下划线),例如:$http_user_agent(Uaer-Agent的值); |
$sent_http_HEADER | HTTP响应头中的内容,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 内建变量最常见的用途就是获取关于请求或响应的各种信息。
由 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
另一个特别常用的内建变量其实并不是单独一个变量,而是有无限多变种的一群变量,即名字以 arg_ 开头的所有变量,我们估且称之为 arg_XXX 变量群。
一个例子是 arg_name,这个变量的值是当前请求中名为 name 的参数的值,而且还是未解码的原始形式的值。
location /test-arg {
echo "name: $arg_name";
echo "class: $arg_class";
}
输出
[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
其实 $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:
如果你想对 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 模块的官方文档。
进程监控
端口监控
注意: 这两个是必须要加在zabbix监控,加触发器有问题及时告警。
web 服务器 nginx 以其高性能与抗并发能力越来越多的被用户使用
作为一款服务器产品,其运行状态是运维密切关注的,因此,对 nginx 的实时监控就必须要关注的了
nginx 提供了 ngx_http_stub_status_module,ngx_http_reqstat_module模块,这个模块提供了基本的监控功能
作为官方企业版的 nginx plus 通过 ngx_http_status_module 提供了更加完善的监控功能: http://demo.nginx.com/status.html
我们需要对以下主要的指标进行监控:
Accepts(接受)、Handled(已处理)、Requests(请求数)是一直在增加的计数器。Active(活跃)、Waiting(等待)、Reading(读)、Writing(写)随着请求量而增减。
名称 | 描述 | 指标类型 |
---|---|---|
Accepts(接受) | NGINX 所接受的客户端连接数 | 资源: 功能 |
Handled(已处理) | 成功的客户端连接数 | 资源: 功能 |
Dropped(已丢弃,计算得出) | 丢弃的连接数(接受 - 已处理) | 工作:错误* |
Requests(请求数) | 客户端请求数 | 工作:吞吐量 |
NGINX worker 进程接受 OS 的连接请求时 Accepts 计数器增加,而Handled 是当实际的请求得到连接时(通过建立一个新的连接或重新使用一个空闲的)。这两个计数器的值通常都是相同的,如果它们有差别则表明连接被Dropped,往往这是由于资源限制,比如已经达到 NGINX 的worker_connections的限制。
按照固定时间间隔采样请求数据,计算出单位时间的请求量可以看到你的 web 服务器的请求情况
通过持续的 QPS 监控,可以立刻发现是否被恶意攻击或对服务的可用性进行评估
虽然当问题发生时,通过 QPS 不能定位到确切问题的位置,但是他却可以在第一时间提醒你环境可能出问题了
通过监控固定时间间隔内的错误代码(4XX代码表示客户端错误,5XX代码表示服务器端错误),可以了解到客户端收到的结果是否是正确的错误率突然的飙升很可能是你的网站漏洞发出的信号
如果你希望通过 access log 分析错误率,那么你需要配置 nginx 的日志模块,让 nginx 将响应码写入访问日志
请求处理时间也可以被记录在 access log 中,通过分析 access log,统计请求的平均响应时间,通过持续观察,可以发现上游服务器的问题
介绍了这么多的监控指标,事实上,上面介绍的仅仅是基本的监控指标,针对实际的情况,还有很多指标十分具有监控的必要
那么,怎么去收集这些指标进行监控呢?
通过在编译时加入 nginx
的 ngx_http_stub_status_module
模块我们可以实时监控以下基本的指标:
先使用命令查看是否已经安装这个模块:
# -V大写会显示版本号和模块等信息、v小写仅显示版本信息
[root@nginx]#./nginx -V
# 或用此使用看:
[root@nginx]#nginx -V 2>&1 | grep -o with-http_stub_status_module
如果已经安装,会在显示的信息中包含 --with-http_stub_status_module
信息。如果没有此模块,需要重新安装,编译命令如下:
./configure –with-http_stub_status_module
具体的使用方法是在执行 ./configure 时,指定 --with-http_stub_status_module,然后通过配置:
location /nginx-status {
stub_status on;
access_log on;
allow 127.0.0.1;
deny all;
#auth_basic "nginxstatus";
#auth_basic_user_file conf/nginxstaus;
}
此处默认只有本地访问,如果远程查看需要加相关的IP或者干脆去掉Deny all即可。加密文件可以使用#htpasswd -c /usr/nginx/conf hxb 命令来创建。配置完成后需要重启Nginx服务。状态配置只能是针对某个Nginx服务。目前Nginx还无法做到针对单个站点进行监控。
配置完成后在浏览器中输入http://127.0.0.1/nginx-status 查看(或者用 curl localhost/nginx_status
),显示信息如下:
Active connections: 100
server accepts handled requests
1075 1064 6253
Reading: 0 Writing: 5 Waiting: 95
Accepts(接受)、Handled(已处理)、Requests(请求数)是一直在增加的计数器。Active(活跃)、Waiting(等待)、Reading(读)、Writing(写)随着请求量而增减。
名称 | 描述 | 指标类型 |
---|---|---|
Accepts(接受) | NGINX 所接受的客户端连接数 | 资源: 功能 |
Handled(已处理) | 成功的客户端连接数 | 资源: 功能 |
Dropped(已丢弃,计算得出) | 丢弃的连接数(接受 - 已处理) | 工作:错误* |
Requests(请求数) | 客户端请求数 | 工作:吞吐量 |
active connections – 活跃的连接数量
server accepts handled requests — 总共处理了1075个连接 , 成功创建1064次握手, 总共处理了6253个请求
每个连接有三种状态waiting、reading、writing
reading —读取客户端的Header信息数.这个操作只是读取头部信息,读取完后马上进入writing状态,因此时间很短。
writing — 响应数据到客户端的Header信息数.这个操作不仅读取头部,还要等待服务响应,因此时间比较长。
waiting — 开启keep-alive后等候下一次请求指令的驻留连接.
正常情况下waiting数量是比较多的,并不能说明性能差。反而如果reading+writing数量比较多说明服务并发有问题。
名称 | 描述 | 是否累加历史数据 |
---|---|---|
Accepts(接受) | NGINX 接受的客户端连接数(包括 Handled + Dropped + Waiting) | 是 |
Handled(已处理) | 成功处理的客户端连接数(包含 Waiting 状态连接) | 是 |
Active(活跃) | 当前活跃的客户端连接数 | 否 |
Dropped(已丢弃) | 已丢弃连接数(出错) | 是 |
Requests(请求数) | 客户端请求数 | 是 |
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 在运行时的参考数据。
nginx折线图
描述
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"来确认
例子
http {
req_status_zone server "$host,$server_addr:$server_port" 10M;
req_status_zone_add_indicator server $limit;
server {
location /us {
req_status_show;
req_status_show_field req_total $limit;
}
set $limit 0;
if ($arg_limit = '1') {
set $limit 1;
}
req_status server;
}
}
kv,bytes_in,bytes_out,conn_total,req_total,http_2xx,http_3xx,http_4xx,http_5xx,http_other_status,rt,ups_req,ups_rt,ups_tries,http_200,http_206,http_302,http_304,http_403,http_404,http_416,http_499,http_500,http_502,http_503,http_504,http_508,http_other_detail_status,http_ups_4xx,http_ups_5xx
指令
Syntax: req_status_zone zone_name value size
Default: none
Context: main
创建统计使用的共享内存。zone_name是共享内存的名称,value用于定义key,支持变量。size是共享内存的大小。
例子:
req_status_zone server "$host,$server_addr:$server_port" 10M;
创建名为“server”的共享内存,大小10M,使用“$host,$server_addr:$server_port”计算key。
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 v a r 1 [ var1 [ var1[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引入第三方模块解决该问题
1. 安装
# cd /usr/local/src/
# wget "http://nginx.org/download/nginx-1.4.2.tar.gz"
# tar -xzvf nginx-1.4.2.tar.gz
# wget https://github.com/zls0424/ngx_req_status/archive/master.zip -O ngx_req_status.zip
# unzip ngx_req_status.zip
# cd nginx-1.4.2/
# patch -p1 < ../ngx_req_status-master/write_filter.patch
# yum -y install pcre pcre-devel openssl openssl-devel gcc gcc-c++ zlib zlib-devel
# ./configure --prefix=/usr/local/nginx-1.4.2 --add-module=../ngx_req_status-master
# make -j2
# make install
# useradd nginx passwd nginx
2. 配置
http {
req_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 www.1000status.com;
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
./configure --prefix=/usr/local/nginx-1.4.2 --add-module=../ngx_req_status-master --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/tmp/nginx/client_body --http-proxy-temp-path=/tmp/nginx/proxy --http-fastcgi-temp-path=/tmp/nginx/fastcgi --pid-path=/var/run/nginx.pid --lock-path=/var/lock/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_gzip_static_module --with-pcre --group=nginx --user=nginx
查看Nginx并发进程数:ps -ef | grep nginx | wc -l
查看Web服务器TCP连接状态:netstat -n | awk ‘/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}’
商业版的 nginx plus 通过他的 ngx_http_status_module 提供了比 nginx 更多的监控指标,可以参看 http://demo.nginx.com/status.html
nginx 的 access log 中可以记录很多有价值的信息,通过分析 access log,可以收集到很多指标
python 编写的 linux 工具 ngxtop 就实现了对 access log 的分析功能
HTTPS(全称:HyperText Transfer Protocol over Secure Socket Layer),其实 HTTPS 并不是一个新鲜协议,Google 很早就开始启用了,初衷是为了保证数据安全。 近些年,Google、Baidu、Facebook 等这样的互联网巨头,不谋而合地开始大力推行 HTTPS, 国内外的大型互联网公司很多也都已经启用了全站 HTTPS,这也是未来互联网发展的趋势。
为鼓励全球网站的 HTTPS 实现,一些互联网公司都提出了自己的要求:
等等,因此想必在不久的将来,全网 HTTPS 势在必行。
HTTP 协议(HyperText Transfer Protocol,超文本传输协议):是客户端浏览器或其他程序与Web服务器之间的应用层通信协议 。
HTTPS 协议(HyperText Transfer Protocol over Secure Socket Layer):可以理解为HTTP+SSL/TLS, 即 HTTP 下加入 SSL 层,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL,用于安全的 HTTP 数据传输。
如上图所示 HTTPS 相比 HTTP 多了一层 SSL/TLS
据记载,公元前400年,古希腊人就发明了置换密码;在第二次世界大战期间,德国军方启用了“恩尼格玛”密码机,所以密码学在社会发展中有着广泛的用途。
对称加密
有流式、分组两种,加密和解密都是使用的同一个密钥。
例如:DES、AES-GCM、ChaCha20-Poly1305等
非对称加密
加密使用的密钥和解密使用的密钥是不相同的,分别称为:公钥、私钥,公钥和算法都是公开的,私钥是保密的。非对称加密算法性能较低,但是安全性超强,由于其加密特性,非对称加密算法能加密的数据长度也是有限的。
例如:RSA、DSA、ECDSA、 DH、ECDHE
哈希算法
将任意长度的信息转换为较短的固定长度的值,通常其长度要比信息小得多,且算法不可逆。
例如:MD5、SHA-1、SHA-2、SHA-256 等
数字签名
签名就是在信息的后面再加上一段内容(信息经过hash后的值),可以证明信息没有被修改过。hash值一般都会加密后(也就是签名)再和信息一起发送,以保证这个hash值不被修改。
抓包如下:
如上图所示,HTTP请求过程中,客户端与服务器之间没有任何身份确认的过程,数据全部明文传输,“裸奔”在互联网上,所以很容易遭到黑客的攻击,如下:
可以看到,客户端发出的请求很容易被黑客截获,如果此时黑客冒充服务器,则其可返回任意信息给客户端,而不被客户端察觉,所以我们经常会听到一词“劫持”,现象如下:
下面两图中,浏览器中填入的是相同的URL,左边是正确响应,而右边则是被劫持后的响应(从貌美如花变成如花。。。)
所以 HTTP 传输面临的风险有:
第一步:为了防止上述现象的发生,人们想到一个办法:对传输的信息加密(即使黑客截获,也无法破解)
如上图所示,此种方式属于对称加密,双方拥有相同的密钥,信息得到安全传输,但此种方式的缺点是:
(1)不同的客户端、服务器数量庞大,所以双方都需要维护大量的密钥,维护成本很高
(2)因每个客户端、服务器的安全级别不同,密钥极易泄露
第二步:既然使用对称加密时,密钥维护这么繁琐,那我们就用非对称加密试试
如上图所示,客户端用公钥对请求内容加密,服务器使用私钥对内容解密,反之亦然,但上述过程也存在缺点:
(1)公钥是公开的(也就是黑客也会有公钥),所以第 ④ 步私钥加密的信息,如果被黑客截获,其可以使用公钥进行解密,获取其中的内容
第三步:非对称加密既然也有缺陷,那我们就将对称加密,非对称加密两者结合起来,取其精华、去其糟粕,发挥两者的各自的优势
如上图所示
(1)第 ③ 步时,客户端说:(咱们后续回话采用对称加密吧,这是对称加密的算法和对称密钥)这段话用公钥进行加密,然后传给服务器
(2)服务器收到信息后,用私钥解密,提取出对称加密算法和对称密钥后,服务器说:(好的)对称密钥加密
(3)后续两者之间信息的传输就可以使用对称加密的方式了
遇到的问题:
(1)客户端如何获得公钥
(2)如何确认服务器是真实的而不是黑客
(1)提供一个下载公钥的地址,回话前让客户端去下载。(缺点:下载地址有可能是假的;客户端每次在回话前都先去下载公钥也很麻烦)
(2)回话开始时,服务器把公钥发给客户端(缺点:黑客冒充服务器,发送给客户端假的公钥)
2、那有木有一种方式既可以安全的获取公钥,又能防止黑客冒充呢? 那就需要用到终极武器了:SSL 证书(申购)
如上图所示,在第 ② 步时服务器发送了一个SSL证书给客户端,SSL 证书中包含的具体内容有:
(1)证书的发布机构CA
(2)证书的有效期
(3)公钥
(4)证书所有者
(5)签名
………
3、客户端在接受到服务端发来的SSL证书时,会对证书的真伪进行校验,以浏览器为例说明如下:
(1)首先浏览器读取证书中的证书所有者、有效期等信息进行一一校验
(2)浏览器开始查找操作系统中已内置的受信任的证书发布机构CA,与服务器发来的证书中的颁发者CA比对,用于校验证书是否为合法机构颁发
(3)如果找不到,浏览器就会报错,说明服务器发来的证书是不可信任的。
(4)如果找到,那么浏览器就会从操作系统中取出 颁发者CA 的公钥,然后对服务器发来的证书里面的签名进行解密
(5)浏览器使用相同的hash算法计算出服务器发来的证书的hash值,将这个计算的hash值与证书中签名做对比
(6)对比结果一致,则证明服务器发来的证书合法,没有被冒充
(7)此时浏览器就可以读取证书中的公钥,用于后续加密了
4、所以通过发送SSL证书的形式,既解决了公钥获取问题,又解决了黑客冒充问题,一箭双雕,HTTPS加密过程也就此形成
所以相比HTTP,HTTPS 传输更加安全
(1) 所有信息都是加密传播,黑客无法窃听。
(2) 具有校验机制,一旦被篡改,通信双方会立刻发现。
(3) 配备身份证书,防止身份被冒充。
综上所述,相比 HTTP 协议,HTTPS 协议增加了很多握手、加密解密等流程,虽然过程很复杂,但其可以保证数据传输的安全。所以在这个互联网膨胀的时代,其中隐藏着各种看不见的危机,为了保证数据的安全,维护网络稳定,建议大家多多推广HTTPS。
HTTPS 缺点:
CA(Certificate Authority)证书颁发机构主要负责证书的颁发、管理以及归档和吊销。证书内包含了拥有证书者的姓名、地址、电子邮件帐号、公钥、证书有效期、发放证书的CA、CA的数字签名等信息。证书主要有三大功能:加密、签名、身份验证。
rpm -qa openssl
如果未安装,安装 openssl
yum install openssl openssl-devel
openssl 配置/etc/pki/tls/openssl.cnf
有关CA的配置。如果服务器为证书签署者的身份那么就会用到此配置文件,此配置文件对于证书申请者是无作用的。
####################################################################
[ ca ]
default_ca = CA_default # 默认的CA配置;CA_default指向下面配置块
####################################################################
[ CA_default ]
dir = /etc/pki/CA # CA的默认工作目录
certs = $dir/certs # 认证证书的目录
crl_dir = $dir/crl # 证书吊销列表的路径
database = $dir/index.txt # 数据库的索引文件
new_certs_dir = $dir/newcerts # 新颁发证书的默认路径
certificate = $dir/cacert.pem # 此服务认证证书,如果此服务器为根CA那么这里为自颁发证书
serial = $dir/serial # 下一个证书的证书编号
crlnumber = $dir/crlnumber # 下一个吊销的证书编号
crl = $dir/crl.pem # The current CRL
private_key = $dir/private/cakey.pem# CA的私钥
RANDFILE = $dir/private/.rand # 随机数文件
x509_extensions = usr_cert # The extentions to add to the cert
name_opt = ca_default # 命名方式,以ca_default定义为准
cert_opt = ca_default # 证书参数,以ca_default定义为准
default_days = 365 # 证书默认有效期
default_crl_days= 30 # CRl的有效期
default_md = sha256 # 加密算法
preserve = no # keep passed DN ordering
policy = policy_match #policy_match策略生效
# For the CA policy
[ policy_match ]
countryName = match #国家;match表示申请者的申请信息必须与此一致
stateOrProvinceName = match #州、省
organizationName = match #组织名、公司名
organizationalUnitName = optional #部门名称;optional表示申请者可以的信息与此可以不一致
commonName = supplied
emailAddress = optional
# For the 'anything' policy
# At this point in time, you must list all acceptable 'object'
# types.
[ policy_anything ] #由于定义了policy_match策略生效,所以此策略暂未生效
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
根CA服务器:因为只有 CA 服务器的角色,所以用到的目录只有/etc/pki/CA
网站服务器:只是证书申请者的角色,所以用到的目录只有/etc/pki/tls
[root@server ~]# cd /etc/pki/CA/
[root@server CA]# ls
certs crl newcerts private
[root@server CA]# touch index.txt #生成证书索引数据库文件
[root@server CA]# ls
certs crl index.txt newcerts private
[root@server CA]# echo 01 > serial #指定第一个颁发证书的序列号
[root@server CA]# ls
certs crl index.txt newcerts private serial
在根CA服务器上创建密钥,密钥的位置必须为/etc/pki/CA/private/cakey.pem
,这个是openssl.cnf中中指定的路径,只要与配置文件中指定的匹配即可。
[root@server CA]# (umask 066; openssl genrsa -out private/cakey.pem 2048)
Generating RSA private key, 2048 bit long modulus
........................................................+++
.........................+++
e is 65537 (0x10001)
根CA自签名证书,根CA是最顶级的认证机构,没有人能够认证他,所以只能自己认证自己生成自签名证书。
[root@server CA]# openssl req -new -x509 -key /etc/pki/CA/private/cakey.pem -days 7300 -out /etc/pki/CA/cacert.pem -days 7300
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:BEIJING
Locality Name (eg, city) [Default City]:BEIJING
Organization Name (eg, company) [Default Company Ltd]:CA
Organizational Unit Name (eg, section) []:OPT
Common Name (eg, your name or your server's hostname) []:ca.qf.com
Email Address []:
[root@server CA]# ls
cacert.pem certs crl index.txt newcerts private serial
-new: 生成新证书签署请求
-x509: 专用于CA生成自签证书
-key: 生成请求时用到的私钥文件
-days n: 证书的有效期限
-out /PATH/TO/SOMECERTFILE: 证书的保存路径
/etc/pki/CA/cacert.pem
就是生成的自签名证书文件,使用 SZ/xftp
工具将他导出到窗口机器中。然后双击安装此证书到受信任的根证书颁发机构
rpm -qa openssl
如果未安装,安装 openssl
yum install openssl openssl-devel
[root@node1 ~]# (umask 066; openssl genrsa -out /etc/pki/tls/private/www.qf.com.key 2048)
Generating RSA private key, 2048 bit long modulus
......................+++
....................................................................................+++
e is 65537 (0x10001)
[root@node1 ~]# cd /etc/pki/tls/private
[root@node1 private]# ls
www.qf.com.key
[root@node1 private]# ls ../
cert.pem certs misc openssl.cnf private
[root@node1 private]# openssl req -new -key /etc/pki/tls/private/www.qf.com.key -days 365 -out /etc/pki/tls/www.qf.com.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:BEIJING
Locality Name (eg, city) [Default City]:BEIJING
Organization Name (eg, company) [Default Company Ltd]:QF
Organizational Unit Name (eg, section) []:OPT
Common Name (eg, your name or your server's hostname) []:www.qf.com
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
[root@node1 private]# cd ../
[root@node1 tls]# ls
cert.pem certs misc openssl.cnf private www.qf.com.csr
CSR(Certificate Signing Request)包含了公钥和名字信息。通常以.csr为后缀,是网站向CA发起认证请求的文件,是中间文件。
在这一命令执行的过程中,系统会要求填写如下信息:
要求添写的内容 | |
---|---|
Country Name (2 letter code) | 使用国际标准组织(ISO)国码格式,填写2个字母的国家代号。中国请填写CN |
State or Province Name (full name) | 省份,比如填写BeiJing |
Locality Name (eg, city) | 城市,比如填写BeiJing |
Organization Name (eg, company) | 组织单位,比如填写公司名称的拼音 |
Organizational Unit Name (eg, section) | 比如填写IT Dept |
Common Name (eg, your websites domain name) | 城市,比如填写BeiJing |
Email Address | 邮件地址,可以不填 |
A challenge password | 可以不填 |
An optional company name | 可以不填 |
最后把生成的请求文件(/etc/pki/tls/www.qf.com.csr
)传输给CA ,这里我使用scp命令,通过ssh协议,将该文件传输到CA下的/etc/pki/CA/private/
目录
root@node1 tls]# scp www.qf.com.csr 192.168.95.134:/etc/pki/CA/private/
[email protected]'s password:
www.qf.com.csr 100% 997 777.2KB/s 00:00
[root@server ~]# openssl ca -in /etc/pki/CA/private/www.qf.com.csr -out /etc/pki/CA/certs/www.qf.com.ctr -days 365
Using configuration from /etc/pki/tls/openssl.cnf
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number: 1 (0x1)
Validity
Not Before: Mar 14 13:45:02 2019 GMT
Not After : Mar 13 13:45:02 2020 GMT
Subject:
countryName = CN
stateOrProvinceName = BEIJING
organizationName = QF
organizationalUnitName = OPT
commonName = www.qf.com
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Comment:
OpenSSL Generated Certificate
X509v3 Subject Key Identifier:
08:65:70:98:2B:0B:15:D0:74:FE:69:58:05:B8:02:BC:45:D8:23:9B
X509v3 Authority Key Identifier:
keyid:60:6B:BC:F1:A1:01:BF:72:FD:7D:02:A8:BD:15:BE:9C:3B:3E:03:30
Certificate is to be certified until Mar 13 13:45:02 2020 GMT (365 days)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
证书通常以.crt为后缀,表示证书文件
[root@server ~]# openssl openssl ca -in /etc/pki/CA/private/www.qf.com.csr -out /etc/pki/CA/certs/www.qf.com.ctr -days 365
Using configuration from /etc/pki/tls/openssl.cnf
Check that the request matches the signature
Signature ok
The organizationName field needed to be the same in the
CA certificate (CA) and the request (QF)
因为默认使用/etc/pki/tls/openssl.cnf,里面要求其一致,修改organizationName=supplied
修改 /etc/pki/tls/openssl.cnf
# For the CA policy
[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = supplied
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[root@server ~]# openssl x509 -in /etc/pki/CA/certs/www.qf.com.ctr -noout -subject
subject= /C=CN/ST=BEIJING/O=QF/OU=OPT/CN=www.qf.com
[root@server ~]# scp www.qf.com.ctr [email protected]:/etc/pki/CA/certs/
root@192.168.95.135's password:
www.qf.com.ctr 100% 4422 1.3MB/s 00:00
[root@server ~]#openssl x509 -in /PATH/FROM/CERT_FILE -noout -serial -subject
先根据客户提交的serial与subject信息,对比检验是否与index.txt文件中的信息一致;然后
[root@server ~]#openssl ca -revoke /etc/pki/CA/newcerts/SERIAL.pem
第一次吊销一个证书时才需要执行
[root@server ~]#echo 01 > /etc/pki/CA/crlnumber
[root@server ~]#openssl ca -gencrl -out thisca.crl
[root@server ~]#openssl crl -in /PATH/FROM/CRL_FILE.crl -noout -text
要搭建https服务首先需有SSL证书,证书通常是在第三方申请,在阿里云的安全服务中有SSL证书这一项,可以在里面申请免费的证书;
也可以在自己电脑中生成,虽然也能完成加密,但是浏览器是不认可的,因此最好还是去第三方申请
阿里云提供免费的证书,不需要人工审核,用来做测试是非常不错的选择,申请地址如下URL。
https://common-buy.aliyun.com/?spm=5176.2020520163.cas.1.1aa12b7aWWn20O&commodityCode=cas#/buy
免费型的证书隐藏的比较深,想要申请免费证书需要先选择 1个域名->Symantec->免费型 ,所以读者这里需要注意一下,如下图参考。
选择之后,一直点击下一步,便可购买完成,免费购买证书之后笔者需要回到证书控制台,在控制台有一个补全信息的链接地址,需要通过此地址补充申请人的联系信息,参考下图填写
补全个人信息之后,还需要给阿里云验证当前域名是属于本人的,验证方式有两种,第一种是通过dns解析认证,第二种是通过上传验证文件认证,这里采用的是验证文件认证,首先需要下载文件,如下图
在下载验证文件完成之后,笔者需要把文件放到服务器中去,这里提供一条复制命令
[root@web ~]#scp ~/Downloads/fileauth.txt [email protected]:~/
将验证文件复制到服务器之后,还需要将验证文件放到站点对应目录,参考命令如下:
[root@web ~]#mkdir -p /website/.well-known/pki-validation && cp fileauth.txt /website/.well-known/pki-validation/
现在要验证文件放置的位置是否正确,通过两种方式进行了验证,分别是手动验证,和阿里云验证。
手动验证的目的是首先确保文件位置放置是否正确,可以通过访问站点的url是否成功进行判断,比如笔者可以访问如下URL,如果返回如果页面能够正常打开,并且可以看到某些值,则代表配置成功。
http://www.qf.com/.well-known/pki-validation/fileauth.txt
在确保文件放置正确之后,关键的是能让阿里云能访问到,阿里云这里提供了一个检查配置的功能,在下载验证文件页面,有一个检测配置的链接,单击之后便可进行检查,如下图。
当点击 检查配置 之后,如果阿里云能够正常访问,则会在左侧给出提示,现在可以返回证书列表,在列表中可以看到当前状态为审核中,如下图
审核因为不需要人为干预,所以很快就能下发证书,下发证书的时间大约是2分钟左右。
证书签发之后,可以在列表中可以看到状态栏中为 已签发 ,同时操作栏可以下载以及查看详情等,如下图所示
点击下载后,会跳转到下载详情页面,在下载详情页可以选择自己相对应的web服务,比如使用nginx,当选择nginx之后,下方还会很贴心的提示如何配置,下载nginx配置文件。
下载配置文件之后,需要将其解压,解压之后可以看见里面包含了两个证书文件
xxx.key
xxx.pem
接着需要把这两个证书文件给复制到服务器当中去,首先需要在服务器创建对应的文件夹,参考命令如下
[root@web ~]#cd /usr/local/nginx/conf/ && mkdir cert #此命令在服务器执行
在服务器创建完成对应文件夹之后,执行命令将证书文件复制到服务器中,参考命令如下:
[root@web ~]#scp ~/Downloads/214905423420461/* [email protected]:/usr/local/nginx/conf/cert
证书复制完成之后,可以对nginx配置文件进行更改,使用vim命令编辑nginx配置文件,参考命令如下:
[root@web ~]#vim /usr/local/nginx/conf/nginx.conf
在vim界面把之前http的配置部分复制一份,复制之后修改监听的端口(listen)为443,并在其后面添加ssl的信息,参考配置如下:
listen 443;
ssl on;
ssl_certificate cert/214905423420461.pem;
ssl_certificate_key cert/214905423420461.key;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
修改配置文件之后,需要测试nginx配置文件是否正确
[root@web ~]#nginx -t
当nginx如果没有出现error相关信息,基本配置没有问题,下面是我的nginx返回结果:
nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful
nginx 配置没有问题之后,笔者需要重启nginx让其生效,参考命令如下
[root@web ~]#nginx -s reload
现在所有该做的工作都做好了,笔者可以通过浏览器来访问可以正常访问,打开如下URL。
https://www.xxx.com
浏览器地址栏显示如下图所示
如果看到浏览器,展示安全,并且显示绿色就说明大功告成了
当我需要进行性能优化时,说明我们服务器无法满足日益增长的业务。性能优化是一个比较大的课题,需要从以下几个方面进行探讨
首先需要了解的是当前系统瓶颈,用的是什么,跑的是什么业务。里面的服务是什么样子,每个服务最大支持多少并发。比如针对nginx而言,我们处理静态资源效率最高的瓶颈是多大?能支持多少qps访问请求?怎么得出系统当前的结构瓶颈?
可以通过查看当前cpu负荷,内存使用率,进程使用率来做简单判断。还可以通过操作系统的一些工具来判断当前系统性能瓶颈,如分析对应的日志,查看请求数量。也可以通过nginx http_stub_status_module模块来查看对应的连接数,总握手次数,总请求数。也可以对线上进行压力测试,来了解当前的系统能性能,并发数,做好性能评估。
虽然我们是在做性能优化,但还是要熟悉业务,最终目的都是为业务服务的。我们要了解每一个接口业务类型是什么样的业务,比如电子商务抢购模式,这种情况平时流量会很小,但是到了抢购时间,流量一下子就会猛涨。也要了解系统层级结构,每一层在中间层做的是代理还是动静分离,还是后台进行直接服务。需要我们对业务接入层和系统层次要有一个梳理
性能与安全也是一个需要考虑的因素,往往大家注重性能忽略安全或注重安全又忽略性能。比如说我们在设计防火墙时,如果规则过于全面肯定会对性能方面有影响。如果对性能过于注重在安全方面肯定会留下很大隐患。所以大家要评估好两者的关系,把握好两者的孰重孰轻,以及整体的相关性。权衡好对应的点。
大家对相关的系统瓶颈及现状有了一定的了解之后,就可以根据影响性能方面做一个全体的评估和优化。
上面列举出来每一级都会有关联,也会影响整体性能,这里主要关注的是nginx服务这一层。
在linux/unix操作系统中一切皆文件,我们的设备是文件,文件是文件,文件夹也是文件。当我们用户每发起一次请求,就会产生一个文件句柄。文件句柄可以简单的理解为文件句柄就是一个索引
。文件句柄就会随着请求量的增多,进程调用频繁增加,那么产生的文件句柄也就会越多。
系统默认对文件句柄是有限制的,不可能会让一个进程无限制的调用句柄。因为系统资源是有限的,所以我们需要限制每一个服务能够使用多大的文件句柄。操作系统默认使用的文件句柄是1024个句柄。
[root@server ~]#vim /etc/security/limits.conf
在文件最下面找到
#* soft core 0
#* hard rss 10000
#@student hard nproc 20
#@faculty soft nproc 20
#@faculty hard nproc 50
#ftp hard nproc 0
#@student - maxlogins 4
#root只是针对root这个用户来限制,soft只是发提醒,操作系统不会强制限制,一般的站点设置为一万左右就ok了
root soft nofile 65535
root hard nofile 65535
# *代表通配符 所有的用户
* soft nofile 25535
* hard nofile 25535
可以看到root
和*
,root代表是root用户,*代表的是所有用户,后面的数字就是文件句柄大小。大家可以根据个人业务来进行设置。
[root@server ~]#vim /etc/nginx/nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
worker_rlimit_nofile 65535; #进程限制
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$http_user_agent' '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'"$args" "$request_uri"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
worker_rlimit_nofile
是在进程上面进行限制。
cpu的亲和能够使nginx对于不同的work工作进程绑定到不同的cpu上面去。就能够减少在work间不断切换cpu,把进程通常不会在处理器之间频繁迁移,进程迁移的频率小,来减少性能损耗。[nginx 亲和配置](
查看物理cpu
[root@server ~]#cat /proc/cpuinfo|grep "physical id"|sort |uniq|wc -l
查看cpu核心数
[root@server ~]#cat /proc/cpuinfo|grep "cpu cores"|uniq
查看cpu使用率
[root@server ~]#top 回车后按 1
[root@server ~]#vim /etc/nginx/nginx.conf
将刚才查看到自己cpu * cpu核心就是worker_processes
worker_processes 2; #根据自己cpu核心数配置
假如小菜的配置是2cpu,每个cpu是8核。配置如下
worker_processes 16;
1010101010101010 0101010101010101;
配置完成后可以通过下面命令查看nginx进程配置在哪个核上
[root@server ~]#ps -eo pid,args,psr |grep [n]ginx
在nginx 1.9版本之后,就帮我们自动绑定了cpu;
worker_cpu_affinity auto;
[root@server ~]#vim /etc/nginx/nginx.conf
#将nginx进程设置为普通用户,为了安全考虑
user nginx;
#当前启动的worker进程,官方建议是与系统核心数一直
worker_processes 2;
#方式一, 第一个work进程绑定第一个cpu核心,第二个work进程绑定到第二个cpu核心,依次内推 直到弟16个
#wokrer_cpu_affinity 0000000000000000 0000000000000001 0000000000000010 0000000000000100 ... 1000000000000000
#方式二,当 worker_processes 2 时,表明 第一work进程可以绑定第 2 4 6 8 10 12 14 16 核心,那么第二work进程就绑定 奇数核心
#worker_cpu_affinity 1010101010101010 0101010101010101;
#方式三,就是自动分配绑定
worker_cpu_affinity auto;
#日志配置成warn
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
#针对 nginx 句柄的文件限制
worker_rlimit_nofile 35535;
#事件模型
events {
#使用epoll内核模型
user epoll;
#每一个进程可以处理多少个连接,如果是多核可以将连接数调高 worker_processes * 1024
worker_connections 10240;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
charset utf-8; #设置字符集
#设置日志输出格式,根据自己的情况设置
log_format main '$http_user_agent' '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'"$args" "$request_uri"';
access_log /var/log/nginx/access.log main;
sendfile on; #对静态资源的处理比较有效
#tcp_nopush on; #如果做静态资源服务器可以打开
#tcp_nodeny on; #当nginx做动态的服务时可以选择打开
keepalive_timeout 65;
########
#Gzip module
gzip on; #文件压缩默认可以打开
gzip_disable "MSIE [1-6]\."; #对于有些浏览器不能识别压缩,需要过滤如ie6
gzip_http_version 1.1;
include /etc/nginx/conf.d/*.conf;
}
#查看 核心绑定的nginx work进程
[root@server ~]#ps -eo pid,args,psr | grep [n]ginx
ab是Apache超文本传输协议(HTTP)的性能测试工具。其设计意图是描绘当前所安装的Apache的执行性能,主要是显示你安装的Apache每秒可以处理多少个请求。
# 安装工具
[root@server ~]#yum install httpd-tools
# 使用
[root@server ~]#ab -n 2000 -c 2 http://127.0.0.1/index.html
-n 总的请求数
-c 并发数
-k 是否开启长连接
-n:即requests,用于指定压力测试总共的执行次数
-c:即concurrency,用于指定的并发数
-t:即timelimit,等待响应的最大时间(单位:秒)
-b:即windowsize,TCP发送/接收的缓冲大小(单位:字节)
-p:即postfile,发送POST请求时需要上传的文件,此外还必须设置-T参数
-u:即putfile,发送PUT请求时需要上传的文件,此外还必须设置-T参数
-T:即content-type,用于设置Content-Type请求头信息,例如:application/x-www-form-urlencoded,默认值为text/plain
-v:即verbosity,指定打印帮助信息的冗余级别
-w:以HTML表格形式打印结果
-i:使用HEAD请求代替GET请求
-x:插入字符串作为table标签的属性
-y:插入字符串作为tr标签的属性
-z:插入字符串作为td标签的属性
-C:添加cookie信息,例如:"Apache=1234"(可以重复该参数选项以添加多个)
-H:添加任意的请求头,例如:"Accept-Encoding: gzip",请求头将会添加在现有的多个请求头之后(可以重复该参数选项以添加多个)
-A:添加一个基本的网络认证信息,用户名和密码之间用英文冒号隔开
-P:添加一个基本的代理认证信息,用户名和密码之间用英文冒号隔开
-X:指定使用的和端口号,例如:"126.10.10.3:88"
-V:打印版本号并退出
-k:使用HTTP的KeepAlive特性
-d:不显示百分比
-S:不显示预估和警告信息
-g:输出结果信息到gnuplot格式的文件中
-e:输出结果信息到CSV格式的文件中
-r:指定接收到错误信息时不退出程序
-H:显示用法信息,其实就是ab -help
Server Software: nginx/1.10.2 (服务器软件名称及版本信息)
Server Hostname: 192.168.1.106(服务器主机名)
Server Port: 80 (服务器端口)
Document Path: /index1.html. (供测试的URL路径)
Document Length: 3721 bytes (供测试的URL返回的文档大小)
Concurrency Level: 1000 (并发数)
Time taken for tests: 2.327 seconds (压力测试消耗的总时间)
Complete requests: 5000 (的总次数)
Failed requests: 688 (失败的请求数)
Write errors: 0 (网络连接写入错误数)
Total transferred: 17402975 bytes (传输的总数据量)
HTML transferred: 16275725 bytes (HTML文档的总数据量)
Requests per second: 2148.98 [#/sec] (mean) (平均每秒的请求数) 这个是非常重要的参数数值,服务器的吞吐量
Time per request: 465.338 [ms] (mean) (所有并发用户(这里是1000)都请求一次的平均时间)
Time request: 0.247 [ms] (mean, across all concurrent requests) (单个用户请求一次的平均时间)
Transfer rate: 7304.41 [Kbytes/sec] received 每秒获取的数据长度 (传输速率,单位:KB/s)
...
Percentage of the requests served within a certain time (ms)
50% 347 ## 50%的请求在347ms内返回
66% 401 ## 60%的请求在401ms内返回
75% 431
80% 516
90% 600
95% 846
98% 1571
99% 1593
100% 1619 (longest request)
[root@server ~]#ab -n 50 -c 20 http://walidream.com/sub_module
输出内容
Server Software: nginx/1.14.1
Server Hostname: walidream.com
Server Port: 80
Document Path: /sub_module
Document Length: 169 bytes
Concurrency Level: 20
Time taken for tests: 0.005 seconds
Complete requests: 50
Failed requests: 0
Write errors: 0
Non-2xx responses: 50
Total transferred: 14900 bytes
HTML transferred: 8450 bytes
Requests per second: 9746.59 [#/sec] (mean)
Time per request: 2.052 [ms] (mean)
Time per request: 0.103 [ms] (mean, across all concurrent requests)
Transfer rate: 2836.41 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.1 0 1
Processing: 1 1 0.3 1 2
Waiting: 0 1 0.2 1 1
Total: 1 2 0.3 2 2
Percentage of the requests served within a certain time (ms)
50% 2
66% 2
75% 2
80% 2
90% 2
95% 2
98% 2
99% 2
100% 2 (longest request)
● 测试机与被测试机要分开
● 不要对线上的服务器做压力测试
● 观察测试工具ab所在机器,以及被测试的前端机的CPU、内存、网络等都不超过最高限度的75%
服务器并发处理能力的量化描述,单位是reqs/s,指的是在某个并发用户数下单位时间内处理的请求数。某个并发用户数下单位时间内能处理的最大请求数,称之为最大吞吐率。记住:吞吐率是基于并发用户数的。这句话代表了两个含义:
● 吞吐率和并发用户数相关
● 不同的并发用户数下,吞吐率一般是不同的
计算公式:总请求数/处理完成这些请求数所花费的时间,即
Request per second=Complete requests/Time taken for tests
必须要说明的是,这个数值表示当前机器的整体性能,值越大越好
必须要说明的是,这个数值表示当前机器的整体性能,值越大越好
并发连接数指的是某个时刻服务器所接受的请求数目,简单的讲,就是一个会话。
要注意区分这个概念和并发连接数之间的区别,一个用户可能同时会产生多个会话,也即连接数。在HTTP/1.1下,IE7支持两个并发连接,IE8支持6个并发连接,FireFox3支持4个并发连接,所以相应的,我们的并发用户数就得除以这个基数。
计算公式:处理完成所有请求数所花费的时间/(总请求数/并发用户数),即:
Time per request=Time taken for tests/(Complete requests/Concurrency Level)
计算公式:处理完成所有请求数所花费的时间/总请求数,即:
Time taken for/testsComplete requests
可以看到,它是吞吐率的倒数。同时,它也等于用户平均请求等待时间/并发用户数,即
Time per request/Concurrency Level
[root@server ~]#wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
[root@server ~]#chmod +x cfssl_linux-amd64
[root@server ~]#sudo mv cfssl_linux-amd64 /root/local/bin/cfssl
[root@server ~]#wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
[root@server ~]#chmod +x cfssljson_linux-amd64
[root@server ~]#sudo mv cfssljson_linux-amd64 /root/local/bin/cfssljson
[root@server ~]#wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
[root@server ~]#chmod +x cfssl-certinfo_linux-amd64
[root@server ~]#sudo mv cfssl-certinfo_linux-amd64 /root/local/bin/cfssl-certinfo
[root@server ~]#export PATH=/root/local/bin:$PATH
[root@server ~]#cfssl print-defaults config > ca-config.json
[root@server ~]#cfssl print-defaults csr > ca-csr.json
[root@server ~]#cat ca-config.json
{
"signing": {
"default": {
"expiry": "9999h"
},
"profiles": {
"www": {
"expiry": "9999h",
"usages": [
"signing",
"key encipherment",
"server auth"
]
},
"client": {
"expiry": "9999h",
"usages": [
"signing",
"key encipherment",
"client auth"
]
}
}
}
}
ca-config.json
:可以定义多个 profiles,分别指定不同的过期时间、使用场景等参数;后续在签名证书时使用某个 profile;
signing
:表示该证书可用于签名其它证书;生成的 ca.pem 证书中 CA=TRUE
;
server auth
:表示 client 可以用该 CA 对 server 提供的证书进行验证;
client auth
:表示 server 可以用该 CA 对 client 提供的证书进行验证;
{
"CN": "registry.test.com",
"hosts": [
"127.0.0.1",
"172.16.160.38",
"registry.test.com"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "k8s",
"OU": "System"
}
]
}
“CN”:Common Name
,kube-apiserver 从证书中提取该字段作为请求的用户名 (User Name);浏览器使用该字段验证网站是否合法;
“O”:Organization
,kube-apiserver 从证书中提取该字段作为请求用户所属的组 (Group);
[root@server ~]#cfssl gencert -initca ca-csr.json | cfssljson -bare ca #重新执行
[root@server ~]#ls ca*
ca-config.json ca.csr ca-csr.json ca-key.pem ca.pem
openssl
命令校验证书[root@server ~]#openssl x509 -noout -text -in kubernetes.pem
...
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=CN, ST=BeiJing, L=BeiJing, O=k8s, OU=System, CN=Kubernetes
Validity
Not Before: Apr 5 05:36:00 2017 GMT
Not After : Apr 5 05:36:00 2018 GMT
Subject: C=CN, ST=BeiJing, L=BeiJing, O=k8s, OU=System, CN=kubernetes
...
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Subject Key Identifier:
DD:52:04:43:10:13:A9:29:24:17:3A:0E:D7:14:DB:36:F8:6C:E0:E0
X509v3 Authority Key Identifier:
keyid:44:04:3B:60:BD:69:78:14:68:AF:A0:41:13:F6:17:07:13:63:58:CD
X509v3 Subject Alternative Name:
DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc, DNS:kubernetes.default.svc.cluster, DNS:kubernetes.default.svc.cluster.local, IP Address:127.0.0.1, IP Address:10.64.3.7, IP Address:10.254.0.1
...
+ 确认 `Issuer` 字段的内容和 `ca-csr.json` 一致;
+ 确认 `Subject` 字段的内容和 `kubernetes-csr.json` 一致;
+ 确认 `X509v3 Subject Alternative Name` 字段的内容和 `kubernetes-csr.json` 一致;
+ 确认 `X509v3 Key Usage、Extended Key Usage` 字段的内容和 `ca-config.json` 中 `kubernetes` profile 一致;
cfssl-certinfo
命令校验证书[root@server ~]#cfssl-certinfo -cert kubernetes.pem
...
{
"subject": {
"common_name": "kubernetes",
"country": "CN",
"organization": "k8s",
"organizational_unit": "System",
"locality": "BeiJing",
"province": "BeiJing",
"names": [
"CN",
"BeiJing",
"BeiJing",
"k8s",
"System",
"kubernetes"
]
},
"issuer": {
"common_name": "Kubernetes",
"country": "CN",
"organization": "k8s",
"organizational_unit": "System",
"locality": "BeiJing",
"province": "BeiJing",
"names": [
"CN",
"BeiJing",
"BeiJing",
"k8s",
"System",
"Kubernetes"
]
},
"serial_number": "174360492872423263473151971632292895707129022309",
"sans": [
"kubernetes",
"kubernetes.default",
"kubernetes.default.svc",
"kubernetes.default.svc.cluster",
"kubernetes.default.svc.cluster.local",
"127.0.0.1",
"10.64.3.7",
"10.64.3.8",
"10.66.3.86",
"10.254.0.1"
],
"not_before": "2017-04-05T05:36:00Z",
"not_after": "2018-04-05T05:36:00Z",
"sigalg": "SHA256WithRSA",
...
导入证书
ca.pem改名为ca.crt。将正式导入浏览器。
构建https服务
[root@server ~]#cd /root/ssl_test
[root@server ~]#cat > http-server.js <
var https = require('https');
var fs = require('fs');
var options = {
key: fs.readFileSync('./keys/app-key.pem'),
cert: fs.readFileSync('./keys/app.pem')
};
https.createServer(options, function (req, res) {
res.writeHead(200);
res.end('hello world');
}).listen(8000);
EOF
[root@server ~]#yum install nodejs -y
[root@server ~]#npm install https -g
[root@server ~]#node http-server.js
修改hosts文件添加
172.16.160.28 www.test.com
在浏览器访问https://www.test.com:8000 发现网站显示为安全
数字证书中主题(Subject)中字段的含义
字段名 | 字段值 |
---|---|
公用名称 (Common Name) | 简称:CN 字段,对于 SSL 证书,一般为网站域名;而对于代码签名证书则为申请单位名称;而对于客户端证书则为证书申请者的姓名; |
单位名称 (Organization Name) | 简称:O 字段,对于 SSL 证书,一般为网站域名;而对于代码签名证书则为申请单位名称;而对于客户端单位证书则为证书申请者所在单位名称; |
字段名 | 字段值 |
---|---|
所在城市 (Locality) | 简称:L 字段 |
所在省份 (State/Provice) | 简称:S 字段 |
所在国家 (Country) | 简称:C 字段,只能是国家字母缩写,如中国:CN |
字段名 | 字段值 |
---|---|
电子邮件 (Email) | 简称:E 字段 |
多个姓名字段 | 简称:G 字段 |
介绍 | Description 字段 |
电话号码: | Phone 字段,格式要求 + 国家区号 城市区号 电话号码,如: +86 732 88888888 |
地址: | STREET 字段 |
邮政编码: | PostalCode 字段 |
显示其他内容 | 简称:OU 字段 |
例子:
[root@server ca]#cat ca-config.json
{
"signing": {
"default": {
"expiry": "9999h"
},
"profiles": {
"www": {
"expiry": "9999h",
"usages": [
"signing",
"key encipherment",
"server auth"
]
},
"client": {
"expiry": "9999h",
"usages": [
"signing",
"key encipherment",
"client auth"
]
}
}
}
}
[root@server ca]#cat ca-csr.json
{
"CN": "registry.test.com",
"hosts": [
"127.0.0.1",
"172.16.160.38",
"registry.test.com"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "k8s",
"OU": "System"
}
]
}
[root@server ca]#ll
总用量 8
-rw-r--r-- 1 root root 568 11月 14 15:59 ca-config.json
-rw-r--r-- 1 root root 289 11月 14 16:02 ca-csr.json
[root@dev ca]# cfssl gencert -initca ca-csr.json | cfssljson -bare ca
2018/11/14 16:05:01 [INFO] generating a new CA key and certificate from CSR
2018/11/14 16:05:01 [INFO] generate received request
2018/11/14 16:05:01 [INFO] received CSR
2018/11/14 16:05:01 [INFO] generating key: rsa-2048
2018/11/14 16:05:01 [INFO] encoded CSR
2018/11/14 16:05:01 [INFO] signed certificate with serial number 303515642193399207794287652931621857332460556169
[root@server ca]#ll
总用量 20
-rw-r--r-- 1 root root 568 11月 14 15:59 ca-config.json
-rw-r--r-- 1 root root 1082 11月 14 16:05 ca.csr
-rw-r--r-- 1 root root 289 11月 14 16:02 ca-csr.json
-rw------- 1 root root 1679 11月 14 16:05 ca-key.pem
-rw-r--r-- 1 root root 1379 11月 14 16:05 ca.pem
[root@server ~]#openssl x509 -noout -text -in ca.pem
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
35:2a:1c:b2:f6:1a:f3:82:38:50:05:8c:fb:65:ef:9e:89:74:8f:89
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=CN, ST=BeiJing, L=BeiJing, O=k8s, OU=System, CN=harbor
Validity
Not Before: Nov 14 08:00:00 2018 GMT
Not After : Nov 13 08:00:00 2023 GMT
Subject: C=CN, ST=BeiJing, L=BeiJing, O=k8s, OU=System, CN=harbor
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:b7:2e:6a:52:f4:d2:34:8b:5e:3f:95:5d:c8:b0:
85:9a:1b:ef:c5:0f:1b:94:b9:94:12:fe:fa:66:0d:
8c:67:b8:9e:82:30:fc:e1:42:94:6e:00:fb:c0:fd:
84:be:65:2c:e4:8f:f1:f1:93:e5:ae:8e:5b:74:7a:
d5:94:25:9c:01:76:f9:96:4e:02:b9:27:a2:44:e0:
da:b3:f3:09:82:5c:9f:26:a6:26:54:35:15:e6:a6:
7a:4b:14:99:07:9d:e3:c3:b8:bd:3f:b6:76:53:05:
82:02:bb:e2:61:21:23:5b:3b:23:4c:08:eb:a7:51:
00:fb:01:5f:b7:f8:b9:67:5b:a1:99:19:23:42:7a:
d2:22:0a:11:01:1d:75:34:9e:25:9c:c8:9f:31:d7:
f5:f3:98:14:b8:c4:07:f3:5a:a1:fa:96:bd:0f:b3:
dc:13:5b:8e:03:e8:66:3b:b5:bd:8d:08:ee:61:c2:
4f:78:dc:9a:ee:37:f8:87:6b:5f:e3:87:ae:91:b0:
8c:c9:40:51:44:cb:57:47:23:f1:2d:34:af:0f:5f:
42:89:14:ac:de:73:d4:32:54:c2:de:99:38:96:d4:
b8:de:f3:df:5c:a5:55:54:8f:a1:b7:fa:42:8b:d9:
fe:2d:14:1f:d5:62:d9:c7:c1:4d:55:41:3b:a9:d3:
0d:2d
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:2
X509v3 Subject Key Identifier:
15:1F:81:A2:AC:41:18:DA:DD:19:36:03:61:18:7B:EF:3D:94:10:AE
X509v3 Authority Key Identifier:
keyid:15:1F:81:A2:AC:41:18:DA:DD:19:36:03:61:18:7B:EF:3D:94:10:AE
X509v3 Subject Alternative Name:
IP Address:127.0.0.1, IP Address:172.16.160.38
Signature Algorithm: sha256WithRSAEncryption
62:41:3c:40:6d:91:29:d2:0b:6d:ce:08:a1:e4:47:64:0a:66:
0e:c0:55:eb:c4:6b:30:6d:79:51:b4:97:8c:02:1e:15:ba:0f:
84:ce:2a:3c:c7:86:29:3c:1f:55:35:a1:da:df:70:5d:58:93:
45:24:c4:20:4d:c1:c7:bb:83:8d:52:0c:7d:43:e2:7c:5b:00:
5d:57:5a:b5:bf:d0:56:5a:57:32:ca:fc:29:59:23:ab:5e:1e:
0e:9b:f9:f6:8d:e8:e4:c6:cb:e6:fe:9f:e3:cd:55:2e:7b:35:
1e:bc:80:0f:ba:d8:66:ae:43:19:bf:d1:bb:81:17:d6:4a:3b:
01:ba:d4:28:da:3f:19:63:82:72:6f:df:7a:b4:bc:d4:cf:a9:
b1:fc:a6:c7:c1:5d:9b:09:2e:72:2a:d4:18:ed:f4:3d:97:1e:
e6:43:81:5c:eb:40:2c:f9:aa:6f:90:16:70:46:77:52:09:64:
43:83:00:0c:44:59:de:17:65:7b:7e:3d:51:df:54:6e:bb:80:
cb:22:13:e2:20:80:91:f8:3f:5e:83:70:32:68:ad:ad:7e:4a:
15:32:45:a7:a5:c4:ed:1c:d4:e4:cc:38:ac:8a:9d:d1:bb:4e:
1c:21:17:56:a2:a0:f9:39:f3:73:e4:96:00:ac:98:93:f3:80:
96:9d:b5:97
[root@dev ca]#
如果出现
[root@server ~]#docker login registry.test.com
Username (admin): admin
Password:
Error response from daemon: Get https://registry.mayocase.com/v1/users/: x509: certificate signed by unknown authority
检查下目录/etc/docker/certs.d/registry.test.com下是否有ca.crt文件,可能需要重启docker
[root@server ~]#cp ca.pem /etc/docker/certs.d/registry.test.com/ca.crt
[root@server ~]#systemctl restart docker
修改harbor证书后操作:
[root@server ~]#cd /data/harbor #一定要在此目录下运行以下命令。
[root@server ~]#ll
总用量 878344
drwxr-xr-x 4 root root 35 7月 31 2017 common
-rw-r--r-- 1 root root 1988 7月 31 2017 docker-compose.notary.yml
-rw-r--r-- 1 root root 3155 7月 31 2017 docker-compose.yml
-rw-r--r-- 1 root root 4304 7月 31 2017 harbor_1_1_0_template
-rw-r--r-- 1 root root 4178 7月 31 2017 harbor.cfg
-rw-r--r-- 1 root root 1082 7月 31 2017 harbor.csr
-rw-r--r-- 1 root root 288 7月 31 2017 harbor-csr.json
-rw-r--r-- 1 root root 448963966 7月 31 2017 harbor.v1.1.1.tar.gz
-rw-r--r-- 1 root root 450041094 7月 31 2017 harbor.v1.1.2.tar.gz
-rwxr-xr-x 1 root root 5169 7月 31 2017 install.sh
-rw-r--r-- 1 root root 337600 7月 31 2017 LICENSE
-rw-r--r-- 1 root root 472 7月 31 2017 NOTICE
-rwxr-xr-x 1 root root 16522 7月 31 2017 prepare
-rwxr-xr-x 1 root root 4550 7月 31 2017 upgrade
# 停止 harbor
[root@server harbor]# docker-compose down -v #多运行几次直到所有docker都删除
# 修改配置
[root@server harbor]# vim harbor.cfg
# 更修改的配置更新到 docker-compose.yml 文件
[root@server harbor]# ./prepare
# 启动 harbor
[root@server harbor]# docker-compose up -d
Intel QAT 助力 Nginx 压缩处理
Intel® QuickAssist Technology是Intel®公司提供的一种高性能数据安全和压缩的加速方案。该方案利用QAT芯片分担对称/非对称加密计算,DEFLATE无损压缩等大计算量的任务,来降低CPU使用率并提高整体平台性能。该方案可以主板芯片,独立的PCI-E加速卡或者SOC三种方式部署。
QAT支持硬件加速Deflate无损压缩算法,在处理海量数据时,QAT在不增加CPU开销的前提下,通过压缩来减少需要传输和存盘的数据量,从而减少了网络带宽和磁盘读写的开销,最终提高了整体的系统性能。 例如,在Web Serer上使用QAT硬件加速压缩处理,可将CPU从繁重的压缩计算中解放出来,以处理更多的连接请求。
Nginx(发音同engine x)是一款使用异步框架的高性能Web服务器,相较于Apache、lighttpd等其他Web Server,Nginx具有占有内存少,稳定性高等优势。根据Netcraft 2018年一月的Web Server市场调查报告, Nginx的装机率达25.39%,位列Web Server市场第三,并在持续增长中[1]。
Nginx中的GZIP模块实现了对HTTP压缩的支持,该模块通过调用Zlib库实现对网页内容进行Deflate压缩。由于使用软件实现无损压缩,需要消耗大量CPU运算时间进行压缩运算。
然而,在大并发流量的网站接入层的Nginx需要处理相当多的业务,包括https连接建立,安防攻击,流量镜像,链路追踪等等。使得CPU进行HTTP压缩处理成为Web Server最主要的CPU开销,进而限制了网站支持最大并发连接数。根据客户提供的接入层流量模型分析来看, GZIP 单个模块 CPU 消耗占比达到 15%-20% 左右,且占比呈上升趋势。所以,若能使用加速Nginx的网页压缩处理,可以极大的提高网站性能。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iBGF86Oi-1592399674118)(assets/1-1.jpg)]
Zlib作为广泛部署的软件压缩库,提供Deflate压缩的软件实现,被包括Nginx在内的广大应用程序所采用。Intel® QuickAssist Technology提供了与Zlib类似接口的Zlib-SHIM 软件库来适配上层应用,减少了应用迁移的开发量。该库提供了与Zlib一致的Deflate API,只需对源代码做少量修改,并将原有应用与Zlib-SHIM编译链接,就能使用QuickAssit提供的硬件加速功能。
Zlib-SHIM库实现了DeflateInit,DeflateInit2,Deflate,DeflateEnd等常用API并支持Stateful和Stateless压缩,可以替代Zlib的绝大部分功能。
Zlib-SHIM提供了Deflate API同步模式接口(调用程序阻塞在Deflate API上,直到压缩任务完成),而其内部实现调用了异步模式API,即在CPU上运行的QAT驱动程序向QAT协处理器提交了一个数据压缩请求后即返回,期间使用Polling 接口定期检查压缩请求是否完成,等到QAT硬件完成压缩处理后通过回调函数通知CPU端的应用程序进行下一步操作。这样的设计, 在不影响上层应用程序原有设计的前提下,实现了高并发场景中CPU和QAT的协同工作:CPU专注于网络链接处理而QAT处理复杂的压缩计算, 各司其职,最终提高了系统整体性能。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jaDbTTHK-1592399674126)(assets/2-1552557277602.png)]Zlib-SHIM 层次图
采用这种异步模式API实现对外的同步接口,在实现上有三种方法:Direct Polling,Indirect Polling Spinning和Indirect Polling Semaphore模式。
使用Direct Polling模式时,Deflate调用者会在当前线程直接调用Polling接口,若压缩结果还没有返回则休眠一段时间后再检查,直到压缩成功后Deflate 调用才返回。Direct Polling模式下CPU开销小,但是单个Request从发出到返回结果延迟较长,只有在多进程多线程高并发模式下才能充分发挥QAT的压缩性能。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yh8xtUpC-1592399674126)(assets/3.png)]Direct polling 模式流程图
Indirect Polling模式,是通过创建一个轮询线程定期调用Polling接口来检查压缩请求在QAT 协处理器中的执行状态,轮询线程一旦发现有请求执行完毕就通过回调函数(Callback Function)通知CPU端程序进行后续处理。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XkwCXwdA-1592399674128)(assets/4-1.png)]
Indirect pooling模式时序图
根据回调通知方式的不同,Indirect Polling模式又可细分为Spinning模式和Semaphore模式:
Spinning模式中,Deflate函数调用线程定期轮询与回调函数共享的任务完成标志,若尚未完成则主动休眠,若已完成则进行后续处理。
Semaphore模式中,Deflate调用线程通过互斥锁来隔离与轮询线程共享的任务完成标志的访问操作,若任务尚未完成则Deflate调用线程休眠,一旦任务完成,轮询线程中的回调函数会通过信号量唤醒调用线程进行后续处理。
采用Indirect Polling模式无论Deflate调用数目多少都需要启动轮询线程,在压缩请求数不大的情况下增加了CPU的Polling开销,但是当压缩任务作为CPU的主要任务时可以减少不必要的Polling调用,提高CPU的使用率。
Nginx为了实现高性能的高并发处理能采用了单进程单线程异步工作模式,如果使用Indirect Polling模式,就需要在每个Nginx Worker进程中创建一个轮询线程 (Polling Thread), 从而增加了线程间切换的开销和共享数据的互斥的操作, 所以在Nginx和Zlib-SHIM集成中,我们使用了Direct Polling Mode。
USDM是QAT为了优化内存使用效率而提供的用户态内存管理工具。由于QAT和CPU之前需要频繁高速的交换数据,使用传统的Memory Copy方式不仅效率低而且消耗CPU资源,所以QAT支持DMA方式进行数据传输,CPU只需分配好拥有物理连续内存的输入地址和输出地址,QAT会自动完成的从该地址的输入读取或输出写回的操作。QAT Driver中的USDM模块,利用了Linux 内核提供的Huge-Page特性来获得物理地址连续内存并使用SLAB算法进行内存管理。
对于每一个新分配的Huge-Page,USDM会对应地在Devfs中新建一个临时文件,并通过mmap将临时文件描述符与新申请到的Huge-Page关联上,当USDM发现该Huge-Page上所有内存块均已释放,并不需将其留作缓存时,就关闭该临时文件以释放Huge-Page。当Zlib-SHIM运行过程中需要使用连续的内存时,就使用USDM Alloc接口从内存池中申请连续物理地址的内存, 并在发送压缩请求时将申请到的连续内存地址作为参数传递给QAT。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ihKd2D5t-1592399674129)(assets/5-1.jpg)]USDM DMA传输
基于以上设计的Zlib-SHIM可以很方便的替换原有Zlib库,使得调用者可以方便的利用QAT进行压缩加速。 在实际应用中, 客户就是将Zlib-SHIM与基于Nginx定制的Web Server进行集成,在接入层的性能优化上取得了理想的效果。
客户的Web Server运行在Intel® Xeon® CPU上(CPU型号:Intel® Xeon® CPU E5-2650 v2 @ 2.60GHz 32核 内核:2.6.32 Zlib版本:zlib-1.2.8 QAT驱动版本:intel-qatOOT40052 ),在相同网络流量条件下,未开启QAT加速的CPU平均使用率为48%左右,而开启QAT加速后CPU平均使用率为41%左右。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vDsJsoHO-1592399674130)(assets/6-1.jpg)]CPU使用率对比[2]
相同条件下,开启QAT加速后系统load平均值为12.09,关闭QAT加速时系统load平均值为14.22,如下图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XlpD74vD-1592399674130)(assets/7-1.jpg)]系统load对比[2]
综合以上数据,Web Server在QPS 10K的压力下,使用QAT加速后可以节省CPU 15%左右,且Gzip基本上完全卸载、随着其占比变高,优化效果将越好。
拥有和Zlib相同API接口的Zlib-SHIM可以很方便的与上层应用集成,利用QAT的硬件加速性能。此外,为了最大限度的发挥QAT的新能,Intel还提供了使用专有API的QATzip软件库,相应的Nginx module也在开发中,相信不久的将来集成QATzip的Web Server能够提供更好的性能。
性能测试中使用的软件和工作负荷可能仅在英特尔微处理器上进行了性能优化。诸如SYSmark和MobileMark等测试均系基于特定计算机系统、硬件、软件、操作系统及功能。上述任何要素的变动都有可能导致测试结果的变化。请参考其他信息及性能测试(包括结合其他产品使用时的运行性能)以对目标产品进行全面评估。