nginx系列(一)之基本介绍
nginx作为生产上的使用的非常广泛的一款web软件,从入行到现在一直也是经常用到的一款软件,好好记录一下。(文字介绍部分参考实战nginx和深入剖析NGINX)
一、nginx的基本介绍
常用的web服务器接触到的,有resin、tomcat、ruby on rails、apache、Microsoft IIS,当然最常用的还是nginx。
http://www.51niux.com/?id=39 #已经记录了nginx的基本安装,http://nginx.org/download/nginx-1.10.3.tar.gz 下载官网下载最新版已经1.10版本了。http://nginx.org/en/docs/ #官方在线文档
1.1 nginx启动、停止、平滑重启
nginx的信号控制:
TERN,INT:快速关闭
QUIT:从容关闭
HUP:平滑重启,重新加载配置文件
USR1:重新打开日志文件,在切割日志时用途较大
USR2:平滑升级可执行程序
WINCH:从容关闭工作进程
nginx的启动:
#/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf #参数"-c"指定了配置文件的路径,如果不加“-c”参数,nginx会默认加载其安装目的conf子目录中的nginx.conf文件
#/usr/local/nginx/sbin/nginx #所以我们一般这么启动
nginx的停止:
#ps -ef|grep nginx #下面是主进程号
root 3395 1 0 May04 ? 00:00:00 nginx: master process sbin/nginx
# kill - QUIT `/usr/local/nginx/logs/nginx.pid ` #从容停止nginx,或者直接kill - QUIT 主进程号(这里我们也就是3395),nginx.pid里面存放着nginx的主进程号
# kill - TERM nginx的主进程号 或者# kill - INT nginx的主进程号 #这是快速停止nginx
# pkill -9 nginx #强制停止所有nginx进程
nginx的平滑重启:
# /usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf #重启nginx之前先检查nginx的配置文件是否有问题
#kill -HUP nginx主进程号 或者 #kill -HUP `/usr/local/nginx/logs/nginx.pid ` #这两个命令都是平滑重启nginx
#当nginx接收到HUP信号时,它会尝试先解析配置文件(如果指定配置文件,就使用指定的,否则使用默认的),如果成功,就应用新的配置文件(例如,重新打开日志文件或监听的套接字)。之后,nginx运行新的工作进程并从容关闭旧的工作进程。通知工作进程关闭监听套接字,但是继续为当前连接的客户提供服务。所有客户端的服务完成后,旧的工作进程被关闭。如果新的配置文件应用失败,nginx将继续使用旧的配置进行工作。
# /usr/local/nginx/sbin/nginx -s reload #当然这是我们经常用的重新加载的命令
1.2 主要特性
作为轻量级HTTP服务的典型代表,nginx除了具备体积小、配置灵活、并发能力强、稳定等特点。
HTTP基本特性:
处理静态页面请求
处理index首页请求
对请求目录进行列表显示
支持多进程间的负载均衡
对打开文件描述符进行缓存(提高性能)
对反向代理进行缓存(加速)
支持FastCGI、uwsgi、SCGI和memcached多种后端服务器
支持gzip、ranges、chunked、XSLT、SSI以及图像缩放
支持SSL、TLS SNI
HTTP服务高级特性:
基于名称的虚拟主机
基于IP的虚拟主机
支持Keep-alive和pipelined连接
灵活和方便的配置
在更新配置和升级执行程序时提供不间断服务
可自定义客户端访问的日志格式
带缓存的日志写操作(提高性能)
支持快速的日志文件切换
支持对3xx-5xx错误代码进行重定向
URI重写支持正则表达式
根据客户端地址执行不同的功能
支持基于客户端IP地址的访问控制
支持基于HTTP基本认证机制的访问控制
支持HTTP referer验证
支持HTTP协议的PUT、DELETE、MKCOL、COPY及MOVE方法
支持FLV流和MP4流
支持限速机制
支持单客户端的并发控制
支持Perl脚本嵌入
邮件代理服务特性:
使用外部HTTP认证服务器将用户重定向到IMAP/POP3服务器
使用外部HTTP认证服务器将用户重定向内部SMTP服务器
支持的认证方式:
POP3:USER/PASS、APOP、AUTH LOGIN/PLAN/CRAM-MD5
IMAP:sLOGIN、AUTH LOGIN/PLAN/CRAM-MD5
SMTP : AUTH LOGIN/PLAIN/CRAM-MD5
支持SSL
支持STARTTLS和STLS
博文来自:www.51niux.com
二、 配置文件
nginx的配置文件格式是其作者lgor Sysoev自己定义的,采用一种近似于key-value对的形式。nginx配置文件可以认为是一种上下文相关的,高度可扩展的,有作用域以及可自定义变量等诸多高级语言特性的脚本语言。
nginx配置文件是由多个配置项组成的,每个配置项都有一个项目名和对应的项目值,项目名又称为指令(Directive),而项目值可能是简单的字符串和多个配置项组合而成配置块的复合结构(以大括号}结尾),我们可以将配置项归纳为两种:简单配置项(不带大括号)和复杂配置项(带大括号)。
nginx配置文件里的注释信息以井号(#)作为开头标记。
就http应用而言,nginx预定义的配置上下文主要包括main、http、server、location 4种(还有其他几种比如event、upstream、if、mail等)。
2.1 基础web配置:
# vim /usr/local/nginx/conf/nginx.conf
#user nobody;
#默认是nobody用户,一般可以指定我们特定的用户,如:user www www;指定启动后进程的属组属组为www。
worker_processes 1;
#指定工作衍生进程数(一般等于CPU的总核数或总核数的两倍,例如两个四核CPU,则总核数为8),如worker_processes 8;就是启动8个工作进程。
#error_log logs/error.log notice;
#指定错误日志存放的路径,如果是这种绝对路径的话,就是/usr/local/nginx/logs/error.log。错误日志级别一共有八级,等级从低到高分别为debug、info、notice、warn、error、crit、alert、emerg。如果设置为error,则表示nginx内等级为error、crit、alert和emerg的四种级别的日志将被输出到日志文件或标准终端。另外的debug、info、notice和warn这四种日志将被直接过滤掉而不会输出。如果只关注特别严重的信息,只需将日志等级设置为error就能减少错误输出了。
#pid logs/nginx.pid;
#指定pid存放路径
events {
use epoll;
#使用的网络I/O模型,新版本已经没这句话了。
worker_connections 1024;
#允许的连接数,如果服务器的性能好的话应该加大这里的连接。如(12核16G的机器):worker_connections 512000;
}
http {
include mime.types;
default_type application/octet-stream;
#charset gbk;
#设置使用的字符集,如果一个网站有多种字符集,应让程序员在HTML代码中通过Meta标签设置。
#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 logs/access.log main;
#上面是自定义日志输出格式,定义了一个main模板,然后我们的正常输出日志调用main,那就会以main模板里面定义的输出结构输出。
client_header_buffer_size 32k;
#客户端请求头缓存大小,默认值是1k,一般请求头不会超过1K。如果请求头信息大于1K时候,会报400报错。header中存放的信息非常多,比如request-line,cookie,还有各种key-value的特定header字段和值。有点时候,我们也会往header中添加一些自定义的属性。header的长度和URI的情况是一样的。协议中并没有显示限制header的大小。理论上在header中放多少属性都是可以的。但是实际上各个主流浏览器限制几十k~几百M不等的限制。client_header_buffer_size和下面的参数也会做限制。
large_client_header_buffers 4 32k;
#nginx默认会用client_header_buffer来读取header值,如果header过大,它会使用large_client_header_buffers来读取。如果一个请求的URI大小超过这个值,服务器将返回一个"Request URI too large" (414),同样,如果一个请求的头部字段大于这个值,服务器将返回"Bad request" (400)。
#client_header_buffer_size和large_client_header_buffers参数是为了解决get请求串长度超过了nginx默认的缓存大小或者请求串大小导致返回413、400、414等状态码等问题。
client_body_buffer_size 512k;
#如果把它设置为比较大的数值,例如256k,那么,无论使用firefox还是IE浏览器,来提交任意小于256k的图片,都很正常。如果注释该指令,使用默认的client_body_buffer_size设置,也就是操作系统页面大小的两倍,8k或者16k,问题就出现了。无论使用firefox4.0还是IE8.0,提交一个比较大,200k左右的图片,都返回500 Internal Server Error错误
client_max_body_size 100m;
#设置客户端能够上传的文件大小,默认是1m。指令指定允许客户端连接的最大请求实体大小,它出现在请求头部的Content-Length字段. 如果请求大于指定的值,客户端将收到一个"Request Entity Too Large" (413)错误. 记住,浏览器并不知道怎样显示这个错误.
client_body_in_single_buffer on;
#指示是否将请求体完整的存储在一块连续的内存中,默认为off,如果此指令被设置为on,则nginx会保证请求体在不大于client_body_buffer_size设置的值时,被存放在一块连续的内存中,但超过大小时会被整个写入一个临时文件;
#client_body_buffer_size和client_max_body_size(client_body_in_single_buffer)是为了解决超长的post请求出错的问题的。
sendfile on;
#开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。注意:如果图片显示不正常把这个改成off。
#tcp_nopush on;
#当使用sendfile函数时,tcp_nopush才起作用,nginx默认就是这种模式。和tcp_nodelay是互斥的。tcp_nopush = on 会设置调用tcp_cork方法,数据包不会马上传送出去,等到数据包最大时,一次性的传输出去,会最大化的利用网络资源,虽然有一点点延迟,这样有助于解决网络堵塞,www,ftp等大文件很有帮助.
tcp_nodelay on;
#禁止nagle算法,有需要发送的就立即发送,比较常见. 这个选项仅在将连接转变为长连接的时候才被启用。让任意小包可以快速传输,提高包的传输效率。
keepalive_timeout 65;
#默认是75s。每个http请求都要求打开一个tpc socket连接,并且使用一次之后就断开这个tcp连接。使用keep-alive可以改善这种状态,即在一次TCP连接中可以持续发送多份数据而不会断开连接。通过使用keep-alive机制,可以减少tcp连接建立次数,也意味着可以减少TIME_WAIT状态连接,以此提高性能和提高httpd服务器的吞吐率(更少的tcp连接意味着更少的系统内核调用,socket的accept()和close()调用)。但是长时间的tcp连接容易导致系统资源无效占用。
gzip on;
#默认这里是注释掉了,进行压缩会消耗CPU,看情况开启。经gzip压缩后的页面大小可以变为原来的30%甚至更小,因此很多网站使用gzip压缩以降低网站带宽消耗,同时提升访问速度,使访问者拥有更好的用户体验。gzip的压缩页面需要浏览器和服务器双方都支持,实际上就是服务器端压缩,传到浏览器后浏览器解压并解析。目前绝大多数浏览器都支持解析gzip压缩过的页面。
gzip_min_length 1k;
#默认值是0,不管页面多大都压缩。设置允许压缩的页面最小字节数,页面字节数从header头得content-length中进行获取。建议设置成大于1k的字节数,小于1k可能会越压越大。
gzip_buffers 4 16k;
#4 16k代表以16k为单位,安装原始数据大小以16k为单位的4倍申请内存。设置系统获取几个单位的缓存用于存储gzip的压缩结果数据流。
gzip_http_version 1.1;
# 识别http的协议版本(1.0/1.1)。 早期的浏览器不支持gzip压缩,用户会看到乱码,所以为了支持前期版本加了此选项,目前此项基本可以忽略。
gzip_comp_level 2;
#gzip压缩比,1压缩比最小处理速度最快,9压缩比最大但处理速度最慢(传输快但比较消耗cpu)。
gzip_types text/plain application/x-javascript text/css application/xml
#匹配mime类型进行压缩,无论是否指定,”text/html”类型总是会被压缩的。指定文本类型就好,不对图片、视频等已经是高压缩的文件再进行压缩
gzip_vary on;
#和http头有关系,加个vary头,给代理服务器用的,有的浏览器支持压缩,有的不支持。因此,为避免浪费不支持的也压缩,需要根据客户端的HTTP头来判断,是否需要压缩。
server {
listen 80;
#监听端口
server_name localhost;
#server_name指令主要用于配置基于名称的虚拟主机,server_name在接到请求后的匹配顺序分别为:准确的server_name匹配(如:server_name 51niux.com www.51niux.com;)以通配符开始的字符串(如:server_name *.51niux.com;)以通配符结束的字符串(如:server_name www.*;)匹配正则表达式(如:server_name ~^(?.+)\.51niux\.com$ ;),nginx会按照前面的四种顺序对server name进行批评,只要有一项匹配以后就会停止搜索。
location / {
#location指令是用来匹配URL进行配置。语法规则: location [=|~|~*|^~] /uri/ { … }
root html;
#location制定url,的文件路径位置,默认是html,也就是默认是nginx安装目录的html目录下面,也就是/usr/local/nginx/html。当然也可以指定其他的绝对路径,如:/home/www/html。
index index.html index.htm;
#默认显示的首页文件,index.html或者index.htm
}
error_page 500 502 503 504 /50x.html;
#指定 500 502 503 504这几个错误码所返回的页面为根目录下面的50x.html页面
location = /50x.html {
root html;
}
}
}
#另外:配置文件里面还有一种模式aio模式,不过一般用的比较少
aio on; #开启异步io功能 directio 512k;
#http://www.178linux.com/54790 这篇url说的比较详细 .
#https://segmentfault.com/a/1190000002924458 关于nginx线程池的
博文来自:www.51niux.com
2.2 nginx虚拟主机配置
虚拟主机使用的是特殊的软硬件技术,每台虚拟主机都可以是一个独立的网站,可以具有独立的域名,同一台主机上的虚拟主机之间是完全独立的。利用虚拟主机,可以在同一台服务器上面、同一组nginx进程上运行多个网站的功能。
nginx可以配置三种类型的虚拟主机:一种是基于IP的虚拟主机,二是基于域名的虚拟主机,三十基于端口的虚拟主机。
用一个简单例子演示一下:
http { #虚拟主机是定义在http内的 server { listen 192.168.1.103:80; #这里是80端口监听在了本地的对外IP上面 server_name 192.168.1.103; #此主机的IP地址,当然可以多搞几个IP地址,然后再浏览器上面打上IP地址就可以解析到对应的网页了. access_log logs/test1.access.log combined; #用access_log指定了nginx访问日志的位置,如果不希望输入可以用access_log off; location / { root /web/test1; #站点目录位置 index index.html index.htm; #默认首页从左至右查找,index.html存在就使用,不存在就看有没有index.htm,都没有返回404. } } server { listen 80; #这是一种常用的写法,监听地址是0.0.0.0 server_name aaa.51niux.com; #这是域名的形式,也是我们常用的一种形式,需要DNS辅助来使用。 access_log logs/test2.access.log combined; #因为默认的格式就是combined,所以也可以直接写access_log logs/test2.access.log; location / { root /web/test2; index index.html index.htm; } } server { listen 80; server_name www.51niux.com 51niux.com *.51niux.com; #这也是一种常用写法,这里就是www.51niux.com,51niux.com以及所有51niux.com的剩余域名除aaa.51niux.com外,因为上面已经定义了aaa.51niux.com。 access_log logs/test3.access.log combined; location / { root /web/test3; index index.html index.htm; } } }
#需要注意的是如果你的服务器只有一个对外IP的话,那么IP虚拟主机和域名虚拟主机一起使用。因为你域名解析出来的是对应的IP,然后IP又是一个虚拟主机,又会跑到IP虚拟主机对应的根目录下面去,不过一般也不会这么玩,IP虚拟主机一般可能是测试环境,不需要配DNS了,测试起来方便一点。
2.3 nginx的日志格式
http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_length #权威的参照官网
一般线上生产环节都是利用log_format指令来自定义日志输出格式的。
参数:
$remote_addr #客户端IP地址
$remote_user #客户端用户名称
$time_local #通用格式下的本地时间,访问时间和时区
$request #请求的URL和HTTP协议
$http_host #请求地址,即浏览器中输入的地址(IP或域名)
$http_referer #记录从哪个页面链接访问过来的
$status #HTTP请求状态码
$body_bytes_sent #发送给客户端的字节数,单位是byte,不包括响应头大小
$connection #连接的序列号。
$connection_requests #当前通过一个连接获得的请求数量。
$http_user_agent #用户终端浏览器等信息
$http_x_forwarded_for #客户端的真实ip,通常web服务器放在反向代理的后面,这样就不能获取到客户的IP地址了,通过$remote_add拿到的IP地址是反向代理服务器的iP地址。反向代理服务器在转发请求的http头信息中,可以增加x_forwarded_for信息,用以记录原有客户端的IP地址和原来客户端的请求的服务器地址。
$ssl_protocol #SSL协议版本
$ssl_cipher #交换数据中的算法
$upstream_addr #后台upstream的地址,即真正提供服务的主机地址,这是nginx反向代理商的配置
$request_time #整个请求的总时间,单位为秒,精度毫秒;从读入客户端的第一个字节开始,直到把最后一个字符发送给客户端后进行日志写入为止。
$request_length #请求的长度(包括请求行,请求头和请求正文)。
$upstream_response_time #请求过程中,upstream响应时间
定义示例:
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" $http_range $request_time';
#因为log日志是实时写入到磁盘上面的,所以输出信息尽量少,只输出我们必须要的一些信息就可以了。格式就是log_format 日志模板名称 日志格式;
下面写了一个参数比较多的日志,然后又日志输出正好对比一下参数对应的值:
log_format main '$remote_addr - $remote_user [$time_local] "$request" "$http_host" '
'$status $body_bytes_sent $connection $connection_requests "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" "$http_range" $request_time $request_length $upstream_response_time $upstream_addr';
url访问地址:http://192.168.1.103/jdk-8u102-linux-x64.rpm和http://192.168.1.103/session.log,jdk-8u102-linux-x64.rpm大小是159MB,session.log大小是734KB
192.168.1.115 - - [12/Jun/2017:12:33:22 +0800] "GET /session.log HTTP/1.1" "192.168.1.103" 206 109500 63 1 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0)" "-" "bytes=7300-" 0.009 417 - - 192.168.1.115 - - [12/Jun/2017:12:33:22 +0800] "GET /session.log HTTP/1.1" "192.168.1.103" 200 751285 62 1 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0)" "-" "-" 0.316 317 - - 192.168.1.102 - - [12/Jun/2017:12:50:59 +0800] "GET /session.log HTTP/1.0" "192.168.1.103" 200 751285 115 1 "-" "Wget/1.12 (linux-gnu)" "-" "-" 0.015 122 - - 192.168.1.115 - - [12/Jun/2017:12:51:17 +0800] "GET /session.log HTTP/1.1" "192.168.1.103" 304 0 114 1 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0)" "-" "-" 0.000 509 - -
$remote_addr - : 192.168.1.115 - (客户端的来源IP地址,因为我们定义了 -,也就是空格加个-位分隔符,一般每个参数之间以空格隔开)
$remote_user: - (如果没有什么内容输出就显示-)
[$time_local]:[12/Jun/2017:12:33:22 +0800](括号里面左边是当地的时间右边是时区)
"$request":"GET /session.log HTTP/1.1"(这个比较简单,就是下载根下面的session.log,也就是执行GET访问链接http://92.168.1.103/session.log,然后用的是HTTP/1.1协议)
"$http_host":"192.168.1.103"(好理解请求的IP地址或域名)
$status:http的状态码,第一行是一个请求这里有两个一个是206一个是200,是用猎豹浏览器发送的。第三行是用Linux主机wget发起的,第四个是用ie浏览器发起的。看状态码是200的,表示成功。
$body_bytes_sent :751285 (751285/1024=733KB)
$connection:63,62,115,114都是连接的序号,一般也不加这个参数
$connection_requests:1(当前连接的请求数量,一般也是1也没啥用也不加这个参数)
"$http_referer":-(因为我们这里是直接访问的根下面的内容所以不是从页面跳转过来的,正常这里应该是一个页面的url)
"$http_user_agent":“Mozilla/4.0...... ”这一看就是浏览器,当然linux wget curl也会在这里显示,收集浏览器访问也会在这里显示,用的啥app访问的也是在这里显示。
"$http_x_forwarded_for":如果nginx做web服务器前面有反向代理,就要加上这句话,不然获取的就是反向代理的IP。当然如果反向代理层级有点多就需要$http_x_real_ip了。http://www.sohu.com/a/122989120_494947说的很详细,http_x_forwarded_for、http_x_real_ip和remote_addr之间的关系。
"$http_range":- (这里要开启了nginx_cache设置才会有数据显示。这里显示的一般也是请求链接的IP地址。Nginx的ngx_http_slice_module模块是用来支持Range回源的。ngx_http_slice_module从Nginx的1.9.8版本开始有的。缓存、源站、 用户向缓存请求URL,缓存进行Range回源。Range回源是指客户端通知源站服务器只返回部分内容,以及部分内容的范围。这对于较大文件的分发加速有很大帮助,开启Range回源功能,可以减少回源流量消耗,并且提升资源响应时间。需要源站支持range请求,即对于http请求头中包含 Range 字段,源站能够响应正确的206文件分片。下面是介绍链接:http://blog.csdn.net/ai2000ai/article/details/55098768)
$request_time : 0.015(此次链接请求总时长用了0.015秒)
$request_length:317(请求长度,一般也不记录这个参数)
$upstream_response_time:- (这是nginx反向代理上面的设置,后台web服务器的响应时间)
$upstream_addr:- (这个也是nginx反向代理上面的设置,一般是后面哪个web响应了请求,这里显示其IP地址。)
$upstream_cache_status:一般是HTI或者MISS。nginx cache里面查看命中状态的(MISS 未命中,请求被传送到后端。HIT 缓存命中。EXPIRED 缓存已经过期请求被传送到后端。UPDATING 正在更新缓存,将使用旧的应答。STALE 后端将得到过期的应答)
#当然现在一般手机都会装app电脑上面也会装相关的软件,所以我们也可以同app里面获取一些我们想要的信息,如手机的型号啊等等,也是可以加到这里的。
博文来自:www.51niux.com
2.4 关于断点续传
所谓断点续传,也就是要从文件已经下载的地方开始继续下载。在以前版本的 HTTP 协议是不支持断点的,HTTP/1.1 开始就支持了。一般断点下载时才用到 Range 和 Content-Range 实体头。
Range
用于请求头中,指定第一个字节的位置和最后一个字节的位置,一般格式:
Range:(unit=first byte pos)-[last byte pos]
Content-Range
用于响应头,指定整个实体中的一部分的插入位置,他也指示了整个实体的长度。在服务器向客户返回一个部分响应,它必须描述响应覆盖的范围和整个实体长度。一般格式:
Content-Range: bytes (unit first byte pos) - [last byte pos]/[entity legth]
#如我们查看下载一个170MB左右的jdk文件,会发现日志中都会有"bytes=138671534-147464920" 这就是我们记录的range请求,记录了字节的起始位置和结束为止,也就是我们这次连接需要的字节范围。
192.168.1.115 - - [12/Jun/2017:15:29:09 +0800] "GET /jdk-8u102-linux-x64.rpm HTTP/1.1" "192.168.1.103" 206 109500 217 2 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0)" "-" "bytes=8192-" 0.041 542 - - 192.168.1.115 - - [12/Jun/2017:15:30:19 +0800] "GET /jdk-8u102-linux-x64.rpm HTTP/1.1" "192.168.1.103" 200 6180180 218 1 "http://192.168.1.103" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)" "-" "-" 69.561 305 - - 192.168.1.115 - - [12/Jun/2017:15:30:19 +0800] "GET /jdk-8u102-linux-x64.rpm HTTP/1.1" "192.168.1.103" 206 9435980 219 1 "http://192.168.1.103" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)" "-" "bytes=62780-166044031" 69.505 335 - - 192.168.1.115 - - [12/Jun/2017:15:30:19 +0800] "GET /jdk-8u102-linux-x64.rpm HTTP/1.1" "192.168.1.103" 206 8405220 222 1 "http://192.168.1.103" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)" "-" "bytes=55389866-92274587" 69.504 337 - - 192.168.1.115 - - [12/Jun/2017:15:30:19 +0800] "GET /jdk-8u102-linux-x64.rpm HTTP/1.1" "192.168.1.103" 206 3245580 221 1 "http://192.168.1.103" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)" "-" "bytes=129159310-166044031" 69.505 339 - - 192.168.1.115 - - [12/Jun/2017:15:30:19 +0800] "GET /jdk-8u102-linux-x64.rpm HTTP/1.1" "192.168.1.103" 206 11044900 223 1 "http://192.168.1.103" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)" "-" "bytes=36947505-55389865" 69.503 337 - - 192.168.1.115 - - [12/Jun/2017:15:30:19 +0800] "GET /jdk-8u102-linux-x64.rpm HTTP/1.1" "192.168.1.103" 206 8232940 220 1 "http://192.168.1.103" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)" "-" "bytes=92274588-166044031" 69.506 338 - - 192.168.1.115 - - [12/Jun/2017:15:30:19 +0800] "GET /jdk-8u102-linux-x64.rpm HTTP/1.1" "192.168.1.103" 206 8974620 226 1 "http://192.168.1.103" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)" "-" "bytes=110716949-129159309" 69.501 339 - - 192.168.1.115 - - [12/Jun/2017:15:30:19 +0800] "GET /jdk-8u102-linux-x64.rpm HTTP/1.1" "192.168.1.103" 206 10665300 225 1 "http://192.168.1.103" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)" "-" "bytes=18505144-36947504" 69.503 337 - - 192.168.1.115 - - [12/Jun/2017:15:30:19 +0800] "GET /jdk-8u102-linux-x64.rpm HTTP/1.1" "192.168.1.103" 206 10019980 224 1 "http://192.168.1.103" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)" "-" "bytes=73832227-92274587" 69.503 337 - - 192.168.1.115 - - [12/Jun/2017:15:30:19 +0800] "GET /jdk-8u102-linux-x64.rpm HTTP/1.1" "192.168.1.103" 206 9440360 227 1 "http://192.168.1.103" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)" "-" "bytes=147601671-166044031" 69.501 339 - -
# curl -I 192.168.1.103/session.log #使用curl命令可以查看任意资源的HTTP头,使用下面的curl命令可以发送一个HEAD请求,来知道文件大小以及远程服务器是否支持HTTP206请求.
HTTP/1.1 200 OK Server: nginx/1.10.3 #web版本是nginx的1.10.3版本 Date: Mon, 12 Jun 2017 07:34:12 GMT #加时区差才是本地时间。所以是07+8,大概是15点多。 Content-Type: application/octet-stream #文件类型,访问不通的资源显示的不一样,如访问主站就返回的是text/html Content-Length: 751285 #文件的大小,单位是字节 Last-Modified: Wed, 03 May 2017 12:05:04 GMT #文件最近一次的更改时间 Connection: keep-alive #启用了keep-alive模式 ETag: "5909c770-b76b5" #这里就是一个资源的标识类似于md5,如果文件没修改就不会改变,然后客户端第一次肯定是完全下载过去的,如页面图片什么的,节省带宽一些不会经常变化的资源我们一般都开启缓存,这时候第二次再来访问发现还是这个值就不会重新下载了,如果值变了就会重新下载。默认就是开启ETag,http{ etag off;}可关闭。另外有的版本如果设置了gzip on也有可能让ETag失效,这就需要简单的修改下源码。 Accept-Ranges: bytes #该响应头表明服务器支持Range请求,以及服务器所支持的单位是字节(这也是唯一可用的单位).Accept-Ranges: none 响应头表示服务器不支持范围请求.
其中Last-Modified、Expires和Etag是标记页面缓存标识: 1、Last-Modified 在浏览器第一次请求某一个URL时,服务器端的返回状态会是200,内容是你请求的资源,同时有一个Last-Modified的属性标记(Http Reponse Header)此文件在服务期端最后被修改的时间,格式类似这样: Last-Modified: Tue, 24 Feb 2009 08:01:04 GMT 客户端第二次请求此URL时,根据 HTTP 协议的规定,浏览器会向服务器传送 If-Modified-Since 报头(Http Request Header),询问该时间之后文件是否有被修改过: If-Modified-Since: Tue, 24 Feb 2009 08:01:04 GMT 如果服务器端的资源没有变化,则自动返回 HTTP 304 (NotChanged.)状态码,内容为空,这样就节省了传输数据量。当服务器端代码发生改变或者重启服务器时,则重新发出资源,返回和第一次请求时类似。从而保证不向客户端重复发出资源,也保证当服务器有变化时,客户端能够得到最新的资源。 注:如果If-Modified-Since的时间比服务器当前时间(当前的请求时间request_time)还晚,会认为是个非法请求 2、Etag工作原理 HTTP 协议规格说明定义ETag为"被请求变量的实体标记" (参见14.19)。简单点即服务器响应时给请求URL标记,并在HTTP响应头中将其传送到客户端,类似服务器端返回的格式: Etag: "5d8c72a5edda8d6a:3239″ 客户端的查询更新格式是这样的: If-None-Match: "5d8c72a5edda8d6a:3239″ 如果ETag没改变,则返回状态304。 即:在客户端发出请求后,Http Reponse Header中包含 Etag: "5d8c72a5edda8d6a:3239″ 标识,等于告诉Client端,你拿到的这个的资源有表示ID:5d8c72a5edda8d6a:3239。当下次需要发Request索要同一个URI的时候,浏览器同时发出一个If-None-Match报头( Http RequestHeader)此时包头中信息包含上次访问得到的Etag: "5d8c72a5edda8d6a:3239″标识。 If-None-Match: "5d8c72a5edda8d6a:3239" ,这样,Client端等于Cache了两份,服务器端就会比对2者的etag。如果If-None-Match为False,不返回200,返回304 (Not Modified) Response。 3、Expires 给出的日期/时间后,被响应认为是过时。如Expires: Thu, 02 Apr 2009 05:14:08 GMT 需和Last-Modified结合使用。用于控制请求文件的有效时间,当请求数据在有效期内时客户端浏览器从缓存请求数据而不是服务器端. 当缓存中数据失效或过期,才决定从服务器更新数据。 4、Last-Modified和Expires Last-Modified标识能够节省一点带宽,但是还是逃不掉发一个HTTP请求出去,而且要和Expires一起用。而Expires标识却使得浏览器干脆连HTTP请求都不用发,比如当用户F5或者点击Refresh按钮的时候就算对于有Expires的URI,一样也会发一个HTTP请求出去,所以,Last-Modified还是要用的,而 且要和Expires一起用。 5、Etag和Expires 如果服务器端同时设置了Etag和Expires时,Etag原理同样,即与Last-Modified/Etag对应的HttpRequest Header:If-Modified-Since和If-None-Match。我们可以看到这两个Header的值和WebServer发出的Last-Modified,Etag值完全一样;在完全匹配If-Modified-Since和If-None-Match即检查完修改时间和Etag之后,服务器才能返回304. 6、Last-Modified和Etag Last-Modified 和ETags请求的http报头一起使用,服务器首先产生 Last-Modified/Etag标记,服务器可在稍后使用它来判断页面是否已经被修改,来决定文件是否继续缓存 过程如下: 1. 客户端请求一个页面(A)。 2. 服务器返回页面A,并在给A加上一个Last-Modified/ETag。 3. 客户端展现该页面,并将页面连同Last-Modified/ETag一起缓存。 4. 客户再次请求页面A,并将上次请求时服务器返回的Last-Modified/ETag一起传递给服务器。 5. 服务器检查该Last-Modified或ETag,并判断出该页面自上次客户端请求之后还未被修改,直接返回响应304和一个空的响应体。 注: 1、Last-Modified和Etag头都是由Web Server发出的Http Reponse Header,Web Server应该同时支持这两种头。 2、Web Server发送完Last-Modified/Etag头给客户端后,客户端会缓存这些头; 3、客户端再次发起相同页面的请求时,将分别发送与Last-Modified/Etag对应的HttpRequestHeader:If-Modified-Since和If-None-Match。我们可以看到这两个Header的值和WebServer发出的Last-Modified,Etag值完全一样; 4、通过上述值到服务器端检查,判断文件是否继续缓存;
#注:这个206的状态在视频音频等大文件的传输过程中是经常会遇到的,小图片啊jss啥的一般是200.当然一般也要我们客户端支持断点续传,像linux的wget和ie浏览器就不支持,不过现在一般下载东西都是客户端下载。
2.5 关于日志的轮询
生产环节中的服务器,日志文件增长是非常快的,一天大几百MB几个G都算少的,日志太大会影响服务器效率,比较常见的是按天切割,0点切割,不过不支持像apache一样使用cronolog来轮转日志。
#crontab -l #一般是定时任务来进行0点的执行切割脚本工作
00 00 * * * /usr/local/nginx/nginx_cut.sh &>/dev/null
#cat /usr/local/nginx/nginx_cut.sh
#!/bin/sh logs_path="/usr/local/nginx/logs" backdir="/usr/local/nginx/logs" yesterday=`date -d -1day +%Y%m%d` rmdays=`date -d '7 days ago' +%Y%m%d` mkdir ${backdir}/${yesterday} mv ${logs_path}/*.log ${backdir}/${yesterday}/ kill -USR1 `cat /usr/local/nginx/logs/nginx.pid` rm -Rf ${backdir}/${rmdays}
还有一种方式(再配置文件中定义):
if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})T(\d{2})") { set $year $1; set $month $2; set $day $3; set $hour $4; } access_log /mnt/logs/nginx/access-$year-$month-$day.log main;
#上面的方式可以实现日志的轮询但是不利于日志采集,因为日志目录都写在了一个目录下面最后还是需要写个定时任务清理一下呢。
2.6 nginx自动列目录配置
gzip功能上面的配置已经记录了这里就不写了。nginx的目录功能在一些镜像下载啊,资源下载啊是经常会用到的,如:http://nginx.org/download/
下面是简单的配置(这种直接指定到根下面的方法不能又Index.html文件了):
location / { root /web/test1; autoindex on; #开启自动列目录的功能,默认是不开启的。一般的web站点都不会罗列,也就是下载站针对某个一些url做罗列。 autoindex_exact_size off; #默认就是关闭状态,是让页面显示文件的以KB,GB等形式显示文件的大小,如果不显示单位就说明数字的单位是字节,如果开启了,就是统一显示为字节的形式。 autoindex_localtime on; #默认也是关闭,是以GTM的形式显示。这里我们开启后,就是以文件自身在linux系统上面显示的本地时间来显示。 }
2.7 expires功能
默认是关闭此功能的,语法格式:expires [time|epoch|max|off],作用域:http,server,location。
用途:使用本指令可以控制HTTP应答中的“Expires”和"Cache-Control"的Header头信息(起到控制页面缓存的作用)。time可以使用正数或负数,一般是正数,单位是s(秒)、m(分钟)、h(小时)、d(天)、M(月)、y(年)。
如:https://www.baidu.com/img/bd_logo1.png百度的login就缓存到了2027年,就是那些经常不会变动的静态资源一般都会缓存到浏览器上,既节省公司带宽也提升用户体验。
location ~* \.(gif|jpg|jpeg)$ { root /web/test1/; #如果在server下面已经定义了默认的站点目录位置,这里可以不用加,会直接去server下面定义的那个全局的root所指定的站点目录下面去找资源。 expires 10d; #这里还有一个expires max;大概是20.5年 }
192.168.1.115 - - [13/Jun/2017:10:55:37 +0800] "GET /login/3.jpg HTTP/1.1" "192.168.1.103" 304 0 2927 1 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0" "-" "-" 0.001 457 0.001 192.168.1.103:80 #通过日志查看的话会发现304状态码后面的发送字节大小那里是0,也就是只是验证了下文件是否变化,因为没变化所以告知浏览器使用本地缓存便可,并没有文件发送而消耗带宽。
然后你再把3.jpg这个图片换成别的图片,链接不变,会发现刷新出来的页面已经发生变化了,这里就不截图了挺浪费流量的。如果你关心后台nginx的访问日志的话,你会发现每次请求都会先发送到nginx,然后检查文件是否发送了变化,如果Etag值啊,Last-Modified都没变化,nginx端就会通知客户端的浏览器,图片没变化你就用自己本地的缓存就可以了。如果发送了变化,就会让浏览器重新下载一次图片,这个请求就是200状态码了而非304状态码了。所以不用担心资源缓存到本地,文件发送更改,而客户端那里还使用未更改的旧资源。