IO模型
前言
- 对于一些公共的底层的资源,都是由linux内核来管控的。比如磁盘IO,网络IO等。
- 用户空间内的程序如果需要调用这些IO,需要向内核发起申请。也叫系统调用
- 对于程序来说,它内部必定有相对应的函数来进行系统调用。那么在进行交互时,程序和内核的交互消息是怎么通知的?
- 既然它们有交互,那么程序在等待内核消息的时候它的状态都有哪些?
消息通知
以磁盘IO为例。
同步: 程序在申请磁盘IO的操作时,程序就一直等待,直到内核将申请的磁盘IO功能完整的结束并响应给程序
异步:还是程序申请调用磁盘IO,程序不在傻傻等待内核完成操作的信息,而是先让内核接着工作。程序去做别的事情。但是程序会专门给内核留一个方法,以便内核完成工作的时候可以找到程序。
IO模型
还是以磁盘IO为例,注意:IO不止有磁盘,还有网络IO,但是它们基本没有区别。
对于一次完整的文件IO来说,由两阶段组成:
- 等待数据,由磁盘将数据复制到内核内存
- 复制数据,由内核内存复制到进程内存
这两步操作是因为程序无法直接操作底层硬件。都得去向内核发起系统调用。
上边已经说了消息通知,同步是等待,问题是怎么等待?这就有了IO模型,用来关注程序(也就是调用者)在结果返回之前的状态。
- 同步阻塞:在结果返回来之前,调用者会被挂起。意思是操作没完成,调用者会睡去,什么都不干。而这个睡眠态是无法唤醒的。谁来都不好使。上图就是同步阻塞,进程通过recvfrom函数向应用进程发送请求访问,应用进程向内核申请调用磁盘数据,在拿不到内核返回的磁盘数据之前,进程将会被阻塞在recvfrom函数调用,直到结果返回。
- 同步非阻塞:结果返回来之前,调用者不会被挂起,但是它仍然什么事情都不能干。它的等待方式就是一遍遍的去问内核,完成操作了么?直到内核结束操作。只有第一步是非阻塞的,第二步仍然是阻塞的。上图为同步非阻塞
- 复用器IO模型:如果调用者申请的不止磁盘IO,还有键盘IO,还有鼠标IO等等。它就会将自己阻塞在的内核一个复用器上,然后告知内核我就在这个复用器上等你消息,你完成一项就通知我一项好了。对于IO复用的实现:select函数以及poll函数。httpd的prefork工作模式就是采用select函数,它的意思是一个主控进程只能监听1024路个请求,也就是所谓的最大并发数量是1024个。而poll没有限制。 上图为复用器io模型
- even模型:事件驱动模型。 调用者在发起请求后,不再等待第一步的完成,而是去想干嘛就干嘛。直到结果返回过来说第一步已经完成,这时调用者回来接着完成第二步。对一步来说只是异步的,第二步仍然是阻塞的。事件驱动型的IO实现:epoll函数。
- 异步非阻塞:完全异步,不参与io的任何操作,直接拿到内核完成两步的结果即可。
关于io模型的文章发现一篇不错:https://www.cnblogs.com/dongguacai/p/5770287.html
nginx
Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。根据上图简单介绍下nginx的工作方式。
- 一个master主控进程,主要功能:负责加载和分析配置文件。管理work进程。平滑升级(例如你的web服务需要从0.8升级到0.9,先将master升级,然后生成新的worker进程处理0.9版本。老的worker进程等处理完请求之后再升级为0.9版本即可。)
- worker:可以有一个或多个进程。用来处理并响应用户的请求。worker中的小方块就是nginx自带的模块。master监控work的进程,当有worker进程发生异常退出时,会立马创建一个worker进程。
- cache loader:载入缓存对象。cache manager:管理缓存对象。当一个用户访问磁盘上的内容时,nginx会把它缓存下来,这样当第二个用户访问同样内容,nginx会将缓存直接响应给第二个用户。
- nginx采用异步非阻塞、事件驱动模型来保证自己可以拥有高并发、高性能的能力。通过epoll()和select()函数来让自己处理并发更高一筹。
- IO方面采用sendfile、AIO(异步IO)等,加速磁盘的IO性能。
nginx模块
nginx是高度模块化的,在早期版本中不支持DSO机制,也就是在编译的时候编译进去了什么模块就只有什么模块,不能动态装卸模块。在1.0 版本之后,有了动态装卸模块的功能,但也仅对个别模块有效。
- nginx模块的分类
- core_module:核心模块
- HTTP_modules:web模块
- Standard HTTP modules:标准模块
- Optional HTTP modules:可选模块
- mail module:邮件模块
- Stream module:流模块
下面主要讲解core模块和web模块的使用
安装nginx
官方提供了官方安装的版本,centos上在epel仓库中也提供了安装版本。两者有略微不同,功能都是一样的。下面以epel仓库安装的为示例。
yum install epel-release
yum install nginx
程序环境:
- 主配置文件:nginx.conf
- 主程序文件:/usr/sbin/nginx
- Unit File:nginx.service
nginx命令的用法:
[root@ydong2 ~]# nginx -h
nginx version: nginx/1.12.2
Usage: nginx [-?hvVtTq] [-s signal] [-c filename] [-p prefix] [-g directives]
Options:
-?,-h : this help
-v : show version and exit #输出版本号
-V : show version and configure options then exit # 输出编译默认添加的模块以及安装路径
-t : test configuration and exit #测试nginx.conf文件中的语法是否正确
-T : test configuration, dump it and exit
-q : suppress non-error messages during configuration testing
-s signal : send signal to a master process: stop, quit, reopen, reload #可以给nginx发送信号,停止,退出,重启,重载
-p prefix : set prefix path (default: /usr/share/nginx/) #重新设置安装路径
-c filename : set configuration file (default: /etc/nginx/nginx.conf) # 重新设置配置文件路径
-g directives : set global directives out of configuration file
运行nginx:systemctl start nginx.service
和httpd一样,运行完成之后监听在80端口,可直接在网页访问本地地址。
nginx.conf的配置
(1)主配置文件的配置指令:directive value [value2 ...];
注意:
- 配置文件中的指令要以;号结尾
- 可以使用nginx中的变量
- 内建变量:由nginx模块提供, 可以直接引用。但是有的变量被某些模块所依赖,所以只能使用编译安装模块的内建变量。有的变量没有指明模块,则可以直接使用。
- 自定义变量:由用户自定义设置变量,
set variable_name value;
(2)主配置文件的架构:
配置段 | 解释 |
---|---|
main block | 主配置段,也就是全局配置 |
event | 事件驱动类型的相关配置,比如并发数量等 |
http | HTTP的相关配置 |
mail的相关配置 | |
stream | stream的相关配置 |
main段相关指令
main配置段常见的配置指令: 相关配置可查看官方文档里的Core functionality
- 正常运行必备的配置
- 优化性能相关的配置
- 用于调试及定位问题相关的配置
- 事件驱动相关的配置
以上图为例:
1、正常运行必备的配置
(1)user
:定义启动worker进程的用户,安装nginx之后,默认为nginx。
nginx 8050 0.0 0.3 127476 3576 ? S 23:20 0:00 nginx: worker process
nginx 8051 0.0 0.3 127476 3776 ? S 23:20 0:00 nginx: worker process
nginx 8052 0.0 0.3 127476 3796 ? S 23:20 0:00 nginx: worker process
nginx 8053 0.0 0.3 127476 3568 ? S 23:20 0:00 nginx: worker process
(2)pid /run/nginx.pid
:指明存储nginx主进程号码的文件路径
(3)include /usr/share/nginx/modules/*.conf
:指明要装载的模块
(4)include /PATH/TO/*.conf
:指明包含进来的其他配置的片段
2、性能优化相关的配置
(1) worker_processes auto | number
:决定worker进程的数量。它是由你的CPU物理核心决定的,比如你是4核的,auto就自动启动为4个进程。当然也可以指定你要启动的进程数Number。通常要设置成小于等于你的物理核心。如果你设置超过了你的核心数,只会增加nginx的负担。epel包安装完成之后,默认auto。
示例:将worker进程数设置为2
nginx 8273 0.0 0.4 128176 4188 ? S 23:39 0:00 nginx: worker process
nginx 8274 0.0 0.4 128176 4188 ? S 23:39 0:00 nginx: worker process
(2)worker_cpu_affinity auto [cpumask]
:绑定进程到指定的cpu物理核心上
假如你的CPU上有2个核心,每个核心上处理一个进程。这两个进程可能在某一时刻会互换CPU核心。大家知道每个cpu核心上都有缓存功能。如果进程来回互换位置,那么进程换一次就要重新缓存。这样极大的浪费了CPU时钟周期。所以我们要把进程进行绑定到CPU核心上,让它们不再互换位置。
示例:
将worker_cpu_affinity设置成auto,自动绑定进程和cpu。也可以使用mask来指定要绑定的cpu核心。例如你的cpu核心数为4个,那它的从0-3的表示方法就是:0001,0010,0100,1000。就是你有几个核心数,就有几个0。
示例:
[root@ydong2 ~]# ps axo user,psr,comm | grep nginx
root 1 nginx
nginx 3 nginx
nginx 2 nginx
nginx 1 nginx
nginx 0 nginx
#再次进行压测,cpu就不会改变了。
(3) worker_priority number
:用来设置worker进程的优先级,默认为0
[root@ydong2 ~]# ps axo user,comm,ni | grep nginx
root nginx 0
nginx nginx 0
nginx nginx 0
nginx nginx 0
nginx nginx 0
[root@ydong2 ~]# ps axo user,comm,ni | grep nginx
root nginx 0
nginx nginx -10
nginx nginx -10
nginx nginx -10
nginx nginx -10
(4)worker_rlimit_nofile number
:worker进程能够打开文件的数量上限。主要用于并发访问时请求打开文件的数量。
当并发数量超过打开文件上限,会有一些用户会得不到响应。配置的太小也会影响并发访问的性能。当然设置这么高,也不一定就会打开这么多的文件。
3、调试,定位问题的配置
(1)daemon on|off
:是否以守护进程运行nginx。主要用于开发过程中。
(2)master_process on|off
:是否以master/worker架构来运行nginx,默认为on。off表示只以master来进程处理。off也只适用于开发人员。
(3)error_log file [level]
:管理错误日志,这是自我管理,而非rsyslog管理。因为nginx产生的日志量太大了。所以要专门放置一个文件来存放它自己的日志。
level
的级别有:debug, info, notice, warn, error, crit, alert, or emerg.
默认级别: error, crit, alert, and emerg
示例:
4、事件驱动类型配置 events{...}
(1)worker_connections
:每个worker进程能够打开的并发最大响应数量,默认为1024路。所以4个进程能够打开的是4*1024
(2)use method
:指明并发连接请求的处理方法。
官方解释:nginx支持各种连接处理方法。特定方法的可用性取决于所使用的平台。在支持多种方法的平台上,nginx通常会自动选择最有效的方法。如果要使用:可以选择select
、poll
、kqueue
、epoll
官方文档的解释
(3)accept_mutex on | off
:处理新的连接的请求方法。on
意味着每个worker进程轮流处理心情求。off
表示每个新请求的到达都会通知所有的worker进程。
解释:例如10个请求进来之后,分给了4个进程。on的意思就是在重新进来1个请求之后,还是分给第一个进程,无论它是否还在处理别的进程。off的意思就是重新进来一个请求之后,4个进程谁先抢到就给谁处理。off的话再请求进来之后会将所有的进程唤醒,反而会影响机器的
示例:
HTTP模块配置
与套接字相关的配置
1、server{…}
用来配置虚拟主机,每一个server就是一个虚拟主机。
2、listen指令
语句格式:listen address[:port] [default_server] [ssl] [http2 | spdy] [backlog=number] [rcvbuf=size] [sndbuf=size]
值 | 解释 |
---|---|
address | IP地址 |
port | 监听端口 |
default_server | 默认主机 |
ssl | 限制仅能够通过ssl连接提供服务 |
backlog=number | 后援队列长度 |
rcvbuf=size | 接收缓冲区大小 |
sndbuf=size | 发送缓冲区大小 |
3、server_name name
指明虚拟主机的主机名称。由以下几种方式:
- 支持*号通配任意长度的任意字符;
- 支持~号起始的字符做正则表达式模式匹配
对于有多个虚拟主机的匹配机制:
- 字符串精确匹配;
- 左侧*通配符;
- 右侧*通配符;
- 正则表达式;
- \d表示0-9
4、tcp_nodelay on | off
在keepalived模式下的连接是否启用TCP_NODELAY选项。
delay:延迟发送,当报文从应用层向下传输封装的时候,外部的封装已经大于报文本身的大小。这时候发送就会很浪费带宽。所以就攒着一块儿发送。这就是delay。用户在接收报文的时候,小的的报文会延迟收到。大大的影响了用户体验。只有nodelay,有多大发多大。不延迟,用户体验才好。
5、tcp_nopush on|off
它与nodelay差不多,也是将包攒起来 一起发送。只不过它可以设置一次发送包的大小。它只能和sendfile搭配使用。
6、sendfile on|off
当请求报文进来之后,由内核转交给用户空间进程,然后用户空间进程向内核发起系统调用。内核从硬盘读取数据复制到自己的内存中。再将数据由内核空间复制到用户空间的内存中去。用户空间响应时再次将处理的数据发送至内核中,然后由内核转发给用户响应报文。sendfile去除了由内核空间和用户空间之间的转换。直接由内核进行硬盘的数据处理,发送给用户响应报文。
7、types_hash_max_size number
设置hash表的最大值,当一个资源请求发过来时,nginx为了加速内部的运行,将访问资源的hash值保存在内存中。当另一个同样的资源请求发过来时,nginx就可以使用已经保存的hash值来快速响应给客户。epel包安装完成之后默认为2048
8、隐藏nginx版本
为了不显示当前服务器使用的nginx的版本,需要server_tokens off
即可
[root@localhost ~]# curl -I www.a.com
HTTP/1.1 200 OK
Server: nginx #就不会再显示版本号了
与路径相关的配置
1、root path
设置web资源路径映射,相当于httpd的DocumentRoot
。它的配置范围区域:http,server,location,if in location。
http配置段内的root和server中root不一样,server中的root会覆盖掉http中的root。同样,location内的root也是如此。
2、location [ = | ~ | ~ | ^~ ] uri { … }*
主要用于在server中实现从uri到文件路径的实现。nginx会根据用户请求的URI来检查定义的所有location,并找出一个最佳匹配,而后应用其配置。
符号 | 解释 |
---|---|
= | 做精确匹配,优先级最高 |
^~ | 对URI的左半部分做匹配检查。不区分大小写,优先级次之 |
~ | 对URI做正则表达式匹配,区分大小写,优先级第三 |
~* | 对URI做正则表达式匹配,不区分大小写,优先级与~一样 |
不带符号 | 匹配始于此URI的所有的URL |
示例:
1 server {
2 listen 80;
3 server_name www1.ydong.com;
4 root /data/;
5 location = / { #1
6 root /data/nginx/;
7 }
8
9 location /pictures/ { #2
10 root /data/nginx/;
11 }
12
13 location ~* \.(jpg|png)$ { #3
14 root /data/nginx/;
15 }
16
17
18 location / { #4
19 root /data/nginx/;
20 }
21
22 location ^~ /images/ { #5
23 root /data/nginx/;
24 }
25 }
(1)当访问www1.ydong.com的时候,匹配1,4,但是优先级最高的是第一个。用location精确定位主页访问,可以加速网页的访问。
(2)访问www1.ydong.com/pictures/fish.jpg, 匹配2,3,4,优先级最高的为3。
(3)访问www1.ydong.com/images/book.jpg,匹配3,5 , 优先级最高为5。
注意:location中定义的root会自动覆盖掉server中定义的root。
3、 alias path
定义路径别名,文档映射的另一种机制,只能用于location的上下文中。
location中的root和alias的区别:
- root,给定的路径对应于location中/uri/左侧的/。
例如/images/ root /data/nginx/ images前面的/号是nginx后面的/号
- alias ,与root相反,是位于右侧。
例如:/images/ alias /data/nginx/ nginx后面的/是images右侧的/,简单理解就是访问images时,访问的内容是/data/nginx/下的index.html
官方解释:location /i/ {
alias /data/w3/images/;
}
on request of “/i/top.gif”, the file /data/w3/images/top.gif will be sent.
访问/i/top.gif,/data/w3/images/top.gif会发送出去。
示例:
server {
2 listen 80;
3 server_name www1.ydong.com;
4 root /data/;
5 location = / {
6 root /data/nginx/;
7 }
8
9 location /pictures/ {
10 root /data/nginx/;
11 }
22 location ^~ /images {
23 alias /data/nginx/;
24 }
25 }
[root@ydong2 nginx]# ls
fish.jpg flower.jpg index.html pictures www2 #data/nginx/下的图片文件。
访问www1.ydong.com/images/fish.jpg
路径下并没有images的文件夹,但是通过alias可以将data/nginx/fish.jpg发送出去。
4、error_page code … [=[response]] uri
定义自定义的错误页以及响应码。
示例:
server {
listen 80;
server_name www1.ydong.com;
root /data/;
location = / {
root /data/nginx/;
}
location ^~ /images {
alias /data/nginx/;
}
error_page 404 =200 /error.html;#此处是将404错误码改为200的正常响应码。 可以防止某些恶意劫持错误页。后面是错误网页
location = /error.html { #定义错误网页地址
root /data/nginx/error_page;
}
}
[root@ydong2 nginx]# cat /data/nginx/error_page/error.html
<h1>error 1111</h1>
5、try_files file … uri; try_files file … =code;
按顺序检查文件是否存在,返回第一个找到的文件或文件夹(结尾加斜线表示为文件夹),如果所有的文件或文件夹都找不到,会进行一个内部重定向到最后一个参数。只有最后一个参数可以引起一个内部重定向,之前的参数只设置内部URI的指向。最后一个参数是回退URI且必须存在,否则会出现内部500错误
[root@localhost ~]# cat /etc/nginx/conf.d/a.com.conf
server{
listen 80;
server_name www.a.com;
root /data/a;
location /images/ {
try_files $uri /images/day.jpg;
}
}
# 用户在请求页面时,服务器会先查找用户请求images下的资源,如果images没有,则重定向到/images/day.jpg
所以我们将访问不到的资源直接重定向到一个提示页面。
[root@localhost a]# cat /etc/nginx/conf.d/a.com.conf
server{
listen 80;
server_name www.a.com;
root /data/a;
error_page 404 /error.html;
location / {
try_files $uri $uri/index.html $uri.html =404;
}
location /error.html {
root /data/a;
}
}
#用户在访问根下的目录,如果请求的uri无资源,先查找请求的资源是否有index.html,如果没有就跳转到404页面。
定义客户端请求的相关配置
1、keepalive_timeout timeout [header_timeout]
设定持续连接的超时时长,0表示禁止长连接,默认为75秒。epel安装包改为了65秒。
2、keepalive_requests number
在一次长连接上所允许请求资源的最大数量,默认为100。
3、keepalive_disable none | brower
对哪种浏览器禁止使用长连接。
4、send_timeout time
向客户端发送响应报文的超时时长,仅在两个连续的写操作之间设置超时,而不是为整个响应的传输。如果客户端在此时间内未收到任何内容,则会关闭连接。
5、client_body_buffer_size size
用于接收客户端请求报文的body部分的缓冲区大小,64位的默认为16K。32位的默认8K。超出此大小时,将被临时存储在磁盘上由client_body_temp_path指令所定义的位置。一般用于博客等需要上传的时候使用。
6、clien_body_temp_path path [leve1 [level2] [level3] ]
设定用于存储客户端请求报文的body部分的临时存储路径及子目录结构和数量;
最多可以使用3级子目录层级结构。、
需要找寻目录3下,子目录2中的文件时,如果能直接定位到目录3,然后在定位到子目录2下。会大大的节省时间。上述指令就是实现该功能,只不过它是使用了16进制的数字目录结构。
示例:
[root@localhost ~]# sha1sum anaconda-ks.cfg
f34da9b6f9d93e37a88ebe8bc30bda2aac3d64ac anaconda-ks.cfg
#一级子目录以结尾创建,16进制就有16个1级子目录,2级子目录使用4a来创建,两个16进制的数组成的数目就是256, 同样3级子目录也是两位,也是256。
所以这样进行创建之后,1级目录下有16个子目录, 16个子目录里,每个目录有256个二级子目录。 256个二级子目录的子目录里又有256个三级子目录。
对客户端进行限制的相关配置
1、limit_rate rate
限制响应给客户端的传输速率,单位是bytes/second 默认是0,无限制
2、limit_except method … {…}
限制对指定的请求方法之外的其他方法的使用客户端。该method参数可以是下列之一: GET, HEAD, POST, PUT, DELETE, MKCOL, COPY, MOVE, OPTIONS, PROPFIND, PROPPATCH, LOCK, UNLOCK,或 PATCH。
limit_except GET {
allow 192.168.1.0/32;
deny all;
}
#限制除GET以外的所有方法。
文件操作优化的配置
1、aio on | off | threads[=pool]
是否启动异步IO功能。
2、directio size | off;
在Linux主机启用O_DIRECT标记,此处意味文件大于等于给定的大小时使用,默认为4M。 可以参考此处文章。
3、 open_file_cache off | open_file_cache max=N [inactive=time]
nginx可以换缓存一下三种信息:
- 文件的描述符、文件大小和最近一次的修改时间
- 打开的目录结构
- 没有找到的或者没有权限访问的文件的相关信息
注意:此种缓存方式是缓存的元数据,并非数据内容。
max=N
:设置缓存的缓存项上限,达到上限后会启用LRU算法来进行管理。LRU:就是最近最少使用的缓存。
inactive=time
:缓存项的非活动时长,此处指定的时长内未被命中的或者命中的次数少于open_file_cache_min-users指令所指定的次数的缓存项即为非活动项
3、 open_file_cache_valid time
用来指明多长时间去检查一下缓存项。
4、open_file_cache_min_uses number
在inactive time设定的时长内,至少命中多少次缓存项才能被认为活动项。
5、 open_file_cache_errors on | off
是否缓存查找时发生错误的文件一类的缓存信息。
基于ip的访问控制功能,ngx_http_access_module
总共就两个指令:
allow address | CIDR | unix: | all
:允许哪些IP地址访问deny address | CIDR | unix: | all
:禁止哪些IP地址访问
示例:
1 server {
2 listen 80;
3 server_name www2.ydong.com;
4 root /data/;
5 keepalive_requests 1;
6 location = / {
7 index file.html;
8 keepalive_requests 1;
9 deny 192.168.199.146;
10 allow all;
11 }
12 }
#访问www2.ydong.com 时,允许除146客户端的所有客户端访问。
ngx_http_auth_basic_module模块
实现基于用户的访问控制,使用basic机制进行用户认证
1、auth_basic string | off
提示登录时的验证信息。
2、auth_basic_user_file file
设置用于存放帐号密码的文件。可以使用htpasswd
示例:
1 server {
2 listen 80;
3 server_name www2.ydong.com;
4 root /data/;
5 location /admin/ {
6 root /data/nginx/;
7 auth_basic "Enter your name and password";
8 auth_basic_user_file /data/nginx/.passwd;
9 }
10 }
~
ngx_http_stub_status_module模块
用户输出nginx模块的状态页面,相当于httpd的status。
示例:
1 server {
2 listen 80;
3 server_name www2.ydong.com;
4 root /data/;
5 location /admin/ {
6 root /data/nginx/;
7 auth_basic "Enter your name and password";
8 auth_basic_user_file /data/nginx/.passwd;
9 }
10
11 location /status {
12 auth_basic "import,be careful";
13 auth_basic_user_file /data/nginx/.passwd;
14 stub_status;
15 }
16 }
状态信息 | 解释 |
---|---|
Active connections | 活动状态的连接数 |
accepts | 已接受的客户端的请求的总数 |
handled | 已处理完成客户端的请求的总数 |
requests | 客户端发来请求的总数 |
Reading | 处于读取客户端请求报文首部的连接的连接数 |
Writing | 处于向客户端发送响应报文过程中的连接数 |
Waiting | 处于等待客户端发出请求的空闲连接数 |
ngx_http_log_module
用来定义日志格式的模块
1、log_format name [escape=default|json|none] string …
定义日志格式,string可以使用http核心模块以及其他模块的内嵌变量
2、access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]]
访问日志文件路径,格式及相关缓冲的配置。
access_log off
:用来关闭日志。
3、open_log_file_cache max=N [inactive=time] [min_uses=N] [valid=time]
缓存各日志文件相关的元数据信息
- max:缓存的最大文件描述符数量
- min_uses:在inactive指定的时长内访问大于等于此值方可被当作活动项
- inactive:非活动时长
- valid:验正缓存中各缓存项是否为活动项的时间间隔
ngx_http_gzip_module
将传输数据进行压缩,虽然会影响CPU的时钟周期,但是可以大大节约带宽。
1、gzip on | off
是否启用压缩功能
2、gzip_comp_level level {0-9}
指定压缩级别
3、 gzip_disable regex …
对具有与任何指定正则表达式匹配的“User-Agent”标头字段的请求禁用gzipping响应。
4、gzip_min_length length
启用压缩功能的响应报文大小阈值
5、gzip_buffers number size
支持实现压缩功能时为其配置的缓冲区数量及每个缓存区的大小
6、gzip_proxied off | expired | no-cache | no-store | private | no_last_modified | no_etag | auth | any …
nginx作为代理服务器接收到从被代理服务器发送的响应报文后,以何种条件下启用压缩功能。
off
:对代理的请求不启用no-cache, no-store,private
:表示从被代理服务器(后端真正的服务器)收到的响应报文首部的Cache-Control的值为此三者中任何一个,则启用压缩功能
7、gzip_types mime-type ….
压缩过滤器,仅对此处设定的MIME类型的内容启用压缩功能,查看mime-type:/etc/nginx/mime.types
示例:
1 server {
2 listen 80;
3 server_name www2.ydong.com;
4 root /data/;
5 gzip on;
6 gzip_comp_level 5;
7 gzip_proxied any;
8 gzip_types image/gif image/jpeg text/css text/xml;
9 gzip_min_length 60;
}
ngx_http_ssl_module
1、ssl on | off
是否启动ssl功能,在listen段用了ssl。就无需再显式指明这一项。
2、ssl_certificate file
当前虚拟机上使用PEM格式的证书文件
3、ssl_certificate_key file
当前虚拟机上与其证书匹配的私钥文件
4、ssl_protocols [SSLv2] [SSLv3] [TLSv1] [TLSv1.1] [TLSv1.2]
支持的协议版本
5、ssl_session_cache off | none | [builtin[:size]] [shared:name:size]
- [builtin[:size]]:使用openssl内建的缓存,此缓存为每worker进程私有
- [shared:name:size]:在各个worker之间共享的缓存。
6、ssl_session_timeout time
客户端一侧的连接可以复用ssl session cache中缓存的ssl参数的有效时长
示例:
ydong1主机为自建CA证书, ydong2为nginx服务机
[root@ydong1 CA]# (umask 077; openssl genrsa -out private/cakey.pem 2048)
Generating RSA private key, 2048 bit long modulus
....................+++
................+++
e is 65537 (0x10001)
[root@ydong1 CA]# openssl req -new -x509 -key private/cakey.pem -out cacert.pem -days 365
[root@ydong1 CA]# mkdir index.txt
[root@ydong1 CA]# echo 01 > serial
#上边为构建CA
[root@ydong2 ssl]# (umask 077; openssl genrsa -out nginx_ssl.key 2048)
Generating RSA private key, 2048 bit long modulus
....+++
.........+++
e is 65537 (0x10001)
[root@ydong2 ssl]# openssl req -new -key nginx_ssl.key -out ngx_ssl.csr -days 365
#ydong2创建签署证书请求
[root@ydong1 CA]# openssl ca -in /tmp/ngx_ssl.csr -out certs/ngx_ssl.crt -days 365
#ydong1签署请求。
将签好的证书以及CA自己的证书一并发过去。
主机设置
server {
listen 443 ssl; #注意,要使用ssl功能,一定要在监听的端口后面写上ssl
server_name www2.ydong.com;
root /data/;
ssl on;
ssl_certificate /etc/nginx/ssl/ngx_ssl.crt;
ssl_certificate_key /etc/nginx/ssl/nginx_ssl.key;
ssl_session_timeout 20m;
}
多个ssl虚拟主机实现
1)首先未站点a.com, b.com创建自签证书。
[root@www certs]# pwd
/etc/pki/tls/certs
[root@www certs]# ll
总用量 28
-rw------- 1 root root 1310 4月 16 15:42 a.com.crt
-rw------- 1 root root 1679 4月 16 15:42 a.com.key
-rw------- 1 root root 1310 4月 16 15:43 b.crt
-rw------- 1 root root 1679 4月 16 15:43 b.key
2)将它们放置在/etc/nignx/conf.d目录下。
[root@www certs]# mv a.com.* b.* /etc/nginx/conf.d/
3)为站点提供配置文件
[root@www conf.d]# cat a.com.conf
server{
listen 443 ssl;
server_name www.a.com;
root /data/a;
ssl_certificate /etc/nginx/conf.d/a.com.crt;
ssl_certificate_key /etc/nginx/conf.d/a.com.key;
ssl_session_timeout 10m;
ssl_session_cache shared:sslshare:20m;
}
[root@www conf.d]# cat b.com.conf
server{
listen 443 ssl;
server_name www.b.com;
root /data/b;
ssl_certificate /etc/nginx/conf.d/b.crt;
ssl_certificate_key /etc/nginx/conf.d/b.key;
ssl_session_timeout 10m;
ssl_session_cache shared:sslshare:20m;
}
4)测试
[root@localhost ~]# curl -k https://www.a.com
a.com
[root@localhost ~]# curl -k https://www.b.com
b.com
ngx_http_rewrite_module
将用户请求的URI基于regex所描述的模式进行检查,而后完成替换。
rewrite模块可以理解为httpd的重定向。
rewrite工作机制:
- 客户端发送请求时,服务端发现请求的页面为已经改变网址的页面,然后向客户端发送响应报文,带有location的首部报文,客户端根据location的指向重新访问。
- rewrite可以有多个,但是有隐藏的循环机制,它由上而下进行匹配,假如说总共有三条rewrite,请求进来后,发现第一条匹配,所以转换成了第一条的内容,然后走着发现第三条匹配,于是又转换成了第三条。但是它匹配完第三条之后,会自上而下再次进行匹配,直到最后谁也匹配不到为止。简而言之:就是匹配到一条,就自上而下重新匹配一遍。
1、rewrite regex replacement [flag]
- regex:查找的内容
- replacement:替换的内容,不支持正则表达式
示例:
[root@www conf.d]# cat a.com.conf
server{
listen 80 default_server;
server_name www.a.com;
root /data/a;
location /bbs {
rewrite ^/bbs/(.*)$ /blog/$1;
}
}
#访问bbs下内容时直接转换成blog下的资源
[flag]:
- last:重写完成之后停止对当前URI在当前location中后续的其他重写操作,而后对新的URI启动新一轮重写检查,提前重启新一轮循环
- break:重写完成后停止对当前URI在当前location中后续的其他操作,而后直接跳转至重写配置之后的配置。结束循环。
- redirect:重写完成后以临时重定向方式直接返回重写后生成的新URI给客户端,由客户端重新发起请求;不能以http或https开头。
- permanent:重写完成后以永久重定向方式直接返回重写后生成的新URI给客户端,由客户端重新发起请求。
- 上诉所有操作全由nginx内部自己完成,无需客户端参与。
- 注意:如果替换的字符串是以http,https开头的,直接将重定向返回给客户端。
示例:
[root@ydong2 nginx]# ls
admin error_page fish.jpg flower.jpg index.html pictures
#nginx的根目录下并没有.png文件。
[root@ydong2 pictures]# cat /etc/nginx/conf.d/www1.conf
server {
listen 80;
server_name www2.ydong.com;
root /data/;
location / {
rewrite /(.*).png$ /$1.jpg; #访问的png图片全部重定向至.jpg
}
}
对flag进行测试
last
[root@www conf.d]# cat a.com.conf
server{
listen 80 default_server;
server_name www.a.com;
root /data/a;
location / {
rewrite /(.*).html /$1.txt last;
rewrite /(.*).txt /$1.html;
}
}
[root@localhost ~]# curl -IL http://www.a.com/1.txt
HTTP/1.1 500 Internal Server Error
Server: nginx
Date: Thu, 16 Apr 2020 08:15:58 GMT
Content-Type: text/html
Content-Length: 170
Connection: close
# 造成死循环,导致内部出错
[root@www conf.d]# cat a.com.conf
server{
listen 80 default_server;
server_name www.a.com;
root /data/a;
location / {
rewrite /(.*).html /$1.txt break;
rewrite /(.*).txt /$1.html;
}
}
[root@localhost ~]# curl http://www.a.com/1.html
1.txt
[root@localhost ~]# curl http://www.a.com/2.html
2.txt
[root@localhost ~]# curl http://www.a.com/2.txt
2.txt
# break,直接停止处理,以第三个为例,首先2.txt转换成2.html,然后从第一行将2.html转换成2.txt。然后break终止替换
[root@www conf.d]# cat a.com.conf
server{
listen 80 default_server;
server_name www.a.com;
root /data/a;
location / {
rewrite /(.*).html /$1.txt redirect;
rewrite /(.*).txt /$1.html;
}
}
[root@localhost ~]# curl -IL http://www.a.com/1.txt
curl: (47) Maximum (50) redirects followed
# 死循环,导致curl命令退出。 permanent和redirect一样、
2、return
return code [text] | return code URL| return URL
停止处理并将指定的内容返回code给客户端
3、rewrite_log on | off
是否开启重写日志。
4、 if (condition) { … }
引入一个新的配置上下文 ;条件满足时,执行配置块中的配置指令
操作比较符 | 解释 |
---|---|
== 和!= | 运算比较符 |
~ | 模式匹配,区分字符大小写 |
~* | 模式匹配,不区分字符大小写 |
!~ | 模式不匹配,区分字符大小写 |
!~* | 模式不匹配,不区分字符大小写 |
-f、!-f | 检查文件是否存在 |
-d、!-d | 检查文件是否是目录 |
-e、!-e | 检查文件,目录或符号链接是否存在 |
-x、!-x | 检查文件是否为执行文件 |
将http跳转到https上。
[root@www conf.d]# cat a.com.conf
server{
listen 80 default_server;
server_name www.a.com;
root /data/a;
location / {
rewrite /(.*) https://www.a.com/$1 redirect;
}
}
server{
listen 443 ssl;
server_name www.a.com;
root /data/a;
ssl_certificate /etc/nginx/conf.d/a.com.crt;
ssl_certificate_key /etc/nginx/conf.d/a.com.key;
ssl_session_timeout 10m;
ssl_session_cache shared:sslshare:20m;
}
但是如果将https和http写在同一个server中,需要增加if条件
[root@www conf.d]# cat a.com.conf
server{
listen 80 default_server;
listen 443 ssl;
server_name www.a.com;
root /data/a;
ssl_certificate /etc/nginx/conf.d/a.com.crt;
ssl_certificate_key /etc/nginx/conf.d/a.com.key;
ssl_session_timeout 10m;
ssl_session_cache shared:sslshare:20m;
location / {
rewrite /(.*) https://www.a.com/$1 redirect;
}
}
#这样会导致死循环。
[root@www conf.d]# cat a.com.conf
server{
listen 80 default_server;
listen 443 ssl;
server_name www.a.com;
root /data/a;
ssl_certificate /etc/nginx/conf.d/a.com.crt;
ssl_certificate_key /etc/nginx/conf.d/a.com.key;
ssl_session_timeout 10m;
ssl_session_cache shared:sslshare:20m;
location / {
if ( $scheme = http ) {
rewrite /(.*) https://www.a.com/$1 redirect;
}
}
}
[root@localhost ~]# curl -kL http://www.a.com
a.com
ngx_http_referer_module
用于阻止对“Referer”头字段中具有无效值的请求访问站点。对于Referer来说,它是非常容易伪造的。所以该模块可以用于阻止大部分的非法请求。
1、valid_referers none | blocked | server_names | string …
名词 解释 | |
---|---|
none | 请求报文首部没有referer首部 |
block | 请求报文中的referer没有值 |
server_name | 可以有值作为主机或者主机名模式。 |
其中server_name有两种特别方式:
- *:用来表示通配符。
- ~:使用正则表达式,必须要写在需要正则表达式字符串的开头。例如 ~*..magedu.com
Referer主要用来表明是用户从哪个网站跳转过来的,当用户直接在地址栏里输入某网站的IP,它当前的主页是没有Referer首部的。就是上边none的意思。如果用户从一个网页跳转到别的网页之后,Referer后边没有值,那就无法判定用户是否从合法网页过来,所以都允许它们访问。也就是block。该指令被用作防盗链功能。
示例:
server {
listen 80;
server_name www2.ydong.com;
root /data/;
valid_referers none blocked server_names ~\.baidu\. *.magedu.com ~\.google\. ;
if ($invalid_referer){
return 403;
} #含有baiud和googlle的域名,以及magedu.com的网址可以跳转至本网站,别的不可以。
location / {
#rewrite /(.*)\.png$ http://www2.ydong.com/$1.jpg break;
rewrite /(.*).png$ /$1.jpg;
rewrite /(.*)$ https://www2.ydong.com/$1;
}
}