Nginx (engine x) 是一个高性能的HTTP(解决C10k的问题)和反向代理服务器,也是一个IMAP/POP3/SMTP服务器。
理论方法
第一种方法:
最传统的多进程并发模型 (每进来一个新的I/O流会分配一个新的进程管理。)
第二种方法:
I/O多路复用 (单个线程,通过记录跟踪每个I/O流(sock)的状态,来同时管理多个I/O流 。)
发明它的原因,是尽量多的提高服务器的吞吐能力。
在同一个线程里面, 通过拨开关的方式,来同时传输多个I/O流
技术类型
$ pstree |grep nginx
|-+= 81666 root nginx: master process nginx
| |— 82500 nobody nginx: worker process
| — 82501 nobody nginx: worker process
1个master进程,2个work进程
每进来一个request,会有一个worker进程去处理。但不是全程的处理,处理到什么程度呢?处理到可能发生阻塞的地方,比如向上游(后端)服务器转发request,并等待请求返回。那么,这个处理的worker不会这么一直等着,他会在发送完请求后,注册一个事件:“如果upstream返回了,告诉我一声,我再接着干”。于是他就休息去了。这就是异步。此时,如果再有request 进来,他就可以很快再按这种方式处理。这就是非阻塞和IO多路复用。而一旦上游服务器返回了,就会触发这个事件,worker才会来接手,这个request才会接着往下走。这就是异步回调。
CPU时钟/中断设计
ADSL
HTTP–Hyper Text Transfer Protocol,超文本传输协议,是一种建立在TCP上的无状态连接,整个基本的工作流程是客户端发送一个HTTP请求,说明客户端想要访问的资源和请求的动作,服务端收到请求之后,服务端开始处理请求,并根据请求做出相应的动作访问服务器资源,最后通过发送HTTP响应把结果返回给客户端。其中一个请求的开始到一个响应的结束称为事务,当一个事物结束后还会在服务端添加一条日志条目。
官方链接: https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/Identifying_resources_on_the_Web.
简介:
统一资源标识符(Uniform Resource Identifier,或URI)
HTTP 请求的内容通称为"资源"。”资源“这一概念非常宽泛,它可以是你能够想到的格式。每个资源都由一个 (URI) 来进行标识。URL即统一资源定位符,它是 URI 的一种。一份文档,一张图片,或所有其他。URI包含URL,URN
URL
URL 用于定位,全称叫做:统一资源定位符(URL,英语Uniform Resource Locator的缩写)也被称为网页地址
示例:
URN
用于区分,URN仅用于命名,而不指定地址。用于标识唯一书目的ISBN系统是一个典型的URN使用范例。例如,ISBN 0486275574(urn:isbn:0-486-27557-4)无二义性地标识出莎士比亚的戏剧《罗密欧与朱丽叶》的某一特定版本。
URN 是另一种形式的 URI,它通过特定命名空间中的唯一名称来标识资源。
urn:isbn:9780141036144
urn:ietf:rfc:7230
上面两个 URN 标识了下面的资源:
• 乔治·奥威尔所著的《1984》
• IETF规范7230,超文本传输协议 (HTTP/1.1):Message Syntax and Routing.
三者关系图
通过下面的例子(源自 Wikipedia),我们可以很好地理解URN 和 URL之间的区别。如果是一个人,我们会想到他的姓名和住址。
URL类似于住址,它告诉你一种寻找目标的方式(在这个例子中,是通过街道地址找到一个人)。要知道,上述定义同时也是一个URI。
相对地,我们可以把一个人的名字看作是URN;因此可以用URN来唯一标识一个实体。由于可能存在同名(姓氏也相同)的情况,所以更准确地说,人名这个例子并不是十分恰当。更为恰当的是书籍的ISBN码和产品在系统内的序列号,尽管没有告诉你用什么方式或者到什么地方去找到目标,但是你有足够的信息来检索到它。
关于URL:
URL是URI的一种,不仅标识了Web 资源,还指定了操作或者获取方式,同时指出了主要访问机制和网络位置。
关于URN:
URN是URI的一种,用特定命名空间的名字标识资源。使用URN可以在不知道其网络位置及访问方式的情况下讨论资源。
现在,如果到Web上去看一下,你会找出很多例子,这比其他东西更容易让人困惑。我只展示一个例子,非常简单清楚地告诉你在互联网中URI 、URL和URN之间的不同。
我们一起来看下面这个虚构的例子。
这是一个URI:“http://bitpoetry.io/posts/hello.html#intro”
“http://”是定义如何访问资源的方式。
“bitpoetry.io/posts/hello.html”是资源存放的位置。
“#intro”是资源。
URL是URI的一个子集,告诉我们访问网络位置的方式。在我们的例子中,URL应该如下所示:
“http://bitpoetry.io/posts/hello.html”
URN是URI的子集,包括名字(给定的命名空间内),但是不包括访问方式,如下所示:
“bitpoetry.io/posts/hello.html#intro”
就是这样。现在你应该能够辨别出URL和URN之间的不同。
如果你忘记了这篇文章的内容,至少要记住一件事:URI可以被分为URL、URN或两者的组合。如果你一直使用URI这个术语,就不会有错。
统一资源标识符的语法 (URL)
协议
“http://” 告诉浏览器使用何种协议。对于大部分 Web 资源,通常使用 HTTP 协议或其安全版本,HTTPS 协议。
另外,浏览器也知道如何处理其他协议。例如, “mailto:” 协议指示浏览器打开邮件客户端;“ftp:”协议指示浏览
器处理文件传输。
常见的方案有:
主机
www.example.com 既是一个域名,也代表管理该域名的机构。它指示了需要向网络上的哪一台主机发起请
求。当然,也可以直接向主机的 IP address 地址发起请求。但直接使用 IP 地址的场景并不常见。
端口
:80 是端口。它表示用于访问 Web 服务器上资源的技术“门”。如果访问的该 Web 服务器使用HTTP协议的标准
端口(HTTP为80,HTTPS为443)授予对其资源的访问权限,则通常省略此部分。否则端口就是 URI 必须的部分。
路径
/path/to/myfile.html 是 Web 服务器上资源的路径。在 Web 的早期,类似这样的路径表示 Web 服务器上的物理文件位置。现在,它主要是由没有任何物理实体的 Web 服务器抽象处理而成的。
查询
?key1=value1&key2=value2 是提供给 Web 服务器的额外参数。这些参数是用 & 符号分隔的键/值对列表。Web 服务器可以在将资源返回给用户之前使用这些参数来执行额外的操作。每个 Web 服务器都有自己的参数规则,想知道特定 Web 服务器如何处理参数的唯一可靠方法是询问该 Web 服务器所有者。
片段
#SomewhereInTheDocument 是资源本身的某一部分的一个锚点。锚点代表资源内的一种“书签”,它给予浏览器显示位于该“加书签”点的内容的指示。 例如,在HTML文档上,浏览器将滚动到定义锚点的那个点上;在视频或音频文档上,浏览器将转到锚点代表的那个时间。值得注意的是 # 号后面的部分,也称为片段标识符,永远不会与请求一起发送到服务器。
示例
官方链接: https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Overview.
知识点
概览
HTTP是一种能够获取如 HTML 这样的网络资源的通讯协议。它是 Web 上数据交换的基础,是一种
client-server 协议,也就是说请求通常是由像浏览器这样的接受方发起的。一个完整的web文档是由不同的子文档重新组建而成的,像是文本、布局描述、图片、视频、脚本等等。
HTTP被设计于上20世纪90年代初期,是一种可扩展性的协议。它是应用层的协议,虽然理论上它
可以通过任何可靠的传输协议来发送,但是它还是通过TCP,或者是TLS-加密的TCP连接来发送。因为
它很好的扩展性,时至今日它不仅被用来传输超文本文档,还用来传输图片、视频或者向服务器发送如
HTML表单这样的信息。HTTP还可以根据网页需求,来获取部分web文档的内容来更新网页。
requests
客户端和服务端通过交换各自的消息来进行交互。通常由像浏览器这样的客户端发出的消息叫做
requests,那么被服务端回应的消息就叫做 responses。
HTTP是一个client-server协议:请求通过一个实体被发出,实体也就是用户代理。大多数情况下,这
个用户代理都是指浏览器,当然它也可能是任何东西,比如一个爬取网页来生成和维护搜索引擎索引的机器。
每一个发送到服务器的请求,都会被服务器处理并且返回一个消息,也就是response。在client与server之
间,还有许许多多的被称为proxies的实体,他们的作用与表现各不相同,比如有些是网关,还有些是caches等。
1. 客户端:user-agent
严格意义来说,user-agent就是任何能够为用户发起行为的工具。但实际上,这个角色通常都是由浏览器
来扮演。对于发起请求来说,浏览器总是作为发起一个请求的实体。
要渲染出一个网页,浏览器首先要发送第一个请求来获取这个页面的HTML文档,再解析它并根据文档中的
资源信息发送其他的请求来获取脚本信息,或者CSS来进行页面布局渲染,还有一些其它的页面资源(如图片
和视频等)。然后,它把这些资源结合到一起,展现出来一个完整的文档,也就是网页。打开一个网页后,浏
览器还可以根据脚本内容来获取更多的资源来更新网页。
一个网页就是一个超文本文档,也就是说有一部分显示的文本可能是链接,启动它(通常是鼠标的点击)就
可以获取一个新的网页。网页使得用户可以控制它的user-agent来导航Web。浏览器来负责翻译HTTP请求的命
令,并翻译HTTP的返回消息让用户能明白返回消息的内容。
2. Web服务端
在上述通信过程的另一端,就是一个Web Server来服务并提供客户端请求的文档。Server只是虚拟意义上:
它可以是许多共同分担负载(负载平衡)的一组服务器组成的计算机群,也可以是一种复杂的软件,通过向其他
计算机发起请求来获取部分或全部资源的软件。
3. Proxies
在浏览器和服务器之间,有许多计算机和其他设备转发了HTTP的消息。因为Web栈层次结构的原因,它们大多数都出现在传输层、网络层和物理层上,对于HTTP的应用层来说就是透明的(虽然它们可能会对应用层的性能有重要影响)。而还有一部分表现在应用层上的,就叫做proxies了。Proxies既可以表现得透明,又可以不透明(看请求是否通过它们),主要表现在这几个功能上:
回应
元素
• HTTP的版本号。
• 一个状态码(status code),来告知对应的请求发送成功或失败,以及失败的原因。
• 一个状态信息,这个信息是非权威的状态码描述信息,也就是说可以由服务端自行设定的。
• HTTP headers,与请求的很像。
• 可选的,但是比在请求报文中更加常见地包含获取资源的body。
HTTP headers
实验分析http报头信息
目的:wget下载一个源码包,分析HTTP头部的信息,通过wget -d选项,学习HTTP头部字段信息。
了解http通信原理,为后期优化打下基础。
wget -d http://nginx.org/download/nginx-1.12.1.tar.gz
DEBUG output created by Wget 1.14 on linux-gnu.
---request begin--- 请求开始
GET /download/nginx-1.12.1.tar.gz HTTP/1.1 动作下载 页面地址 HTTP版本
User-Agent: Wget/1.14 (linux-gnu) 代理程序:wget
Accept: */* 接收的类型:任何类型
Host: nginx.org 目标主机:nginxorg
Connection: Keep-Alive 链接类型:启动长连接
---request end--- 请求结束
HTTP request sent, awaiting response... 发送请求中
---response begin--- 响应开始
HTTP/1.1 200 OK 协议版本 状态码 结果
Server: nginx/1.13.3 服务器版本
Date: Fri, 06 Oct 2017 09:05:15 GMT 相应时间
Content-Type: application/octet-stream 接收应用类型:字节流(软件类)
Content-Length: 981093 文档大小
Last-Modified: Tue, 11 Jul 2017 15:45:09 GMT 资源最后修改的时间(stat文件即可查看)
Connection: keep-alive 长连接开启
Keep-Alive: timeout=15 长连接有效期
ETag: "5964f285-ef865" 校验值
Accept-Ranges: bytes 接收范围:字节的范围
---response end---
200 OK
Registered socket 3 for persistent reuse.
Length: 981093 (958K) [application/octet-stream]
Saving to: ‘nginx-1.12.1.tar.gz’
官网链接: http://www.nginx.org.
1.15
官方文档里的步骤如下:
RHEL/CentOS
Install the prerequisites:
sudo yum install yum-utils
vim /etc/yum.repos.d/nginx.repo 创建文件并把如下内容复制到文件里
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key
By default, the repository for stable nginx packages is used. If you would like to use mainline nginx packages, run the following command:
执行以下命令
sudo yum-config-manager --enable nginx-mainline
To install nginx, run the following command:
接下来就是安装了
sudo yum install nginx
When prompted to accept the GPG key, verify that the fingerprint matches 573B FD6B 3D8F BC64 1079 A6AB ABF5 BD82 7BD9 BF62, and if so, accept it.
环境问题注意关闭防火墙和selinux
setenforce 0
systemctl stop firewalld
yum -y install nginx
systemctl start nginx
systemctl enable nginx
nginx -V 查看安装附带的功能模块
到这里nginx就算是安装完成了,浏览器输入IP地址开始测试
所有文件
rpm -ql nginx
/etc/logrotate.d/nginx 日志轮转
/etc/nginx/nginx.conf 总配置文件
/etc/nginx/conf.d 子配置文件夹
/etc/nginx/conf.d/default.conf 默认的网站配置文件
/etc/nginx/fastcgi_params 动态网站模块文件-python,php所需的相关变量
/etc/nginx/scgi_params
/etc/nginx/uwsgi_params
/etc/nginx/koi-utf 字符集,文件编码
/etc/nginx/win-utf
/etc/nginx/koi-win
/etc/nginx/mime.types 文件关联程序 网站文件类型 和 相关处理程序
/etc/nginx/modules 模块文件夹。第三方模块
/etc/sysconfig/nginx
# Configuration file for the nginx service.
NGINX=/usr/sbin/nginx
CONFFILE=/etc/nginx/nginx.conf
/etc/sysconfig/nginx-debug
# Configuration file for the nginx-debug service.
NGINX=/usr/sbin/nginx-debug
CONFFILE=/etc/nginx/nginx.conf
LOCKFILE=/var/lock/subsys/nginx-debug
/usr/lib/systemd/system/nginx-debug.service nginx调试程序启动脚本
/usr/lib/systemd/system/nginx.service systemctl 服务脚本。
/usr/sbin/nginx 主程序
/usr/sbin/nginx-debug nginx调试程序
/usr/share/doc/nginx-1.12.1 文档
/usr/share/doc/nginx-1.12.1/COPYRIGHT
/usr/share/man/man8/nginx.8.gz man 手册
/usr/share/nginx
/usr/share/nginx/html
/usr/share/nginx/html/50x.html
/usr/share/nginx/html/index.html 默认主页
/var/cache/nginx
缓存各种
ls /var/cache/nginx/ client_temp fastcgi_temp proxy_temp scgi_temp uwsgi_temp
/var/log/nginx 日志文件夹
ls /var/log/nginx/ access.log error.log
/usr/lib64/nginx Nginx模块目录
观察主配置文件
分类
全局/核心块:配置影响nginx全局的指令。一般有运行nginx服务器的用户组,nginx进程pid存放路径,日志存放路径,配置文件引入,允许生成worker process数等。
events块:配置影响nginx服务器或与用户的网络连接。有每个进程的最大连接数,选取哪种事件驱动模型处理连接请求,是否允许同时接受多个网路连接,开启多个网络连接序列化等。
http块:可以嵌套多个server,配置代理,缓存,日志定义等绝大多数功能和第三方模块的配置。如文件引入,mime-type定义,日志自定义,是否使用sendfile传输文件,连接超时时间,单连接请求数等。
server块:配置虚拟主机的相关参数,一个http中可以有多个server。
代码: vim /etc/nginx/nginx.conf
user nginx; 运行nginx程序的独立账号
worker_processes 1; 启动的worker进程数量(CPU数量一致或auto)
error_log /var/log/nginx/error.log warn; 错误日志存放位置
pid /var/run/nginx.pid;
events { 事件
use epoll; 事件驱动模型epoll【默认】
事件驱动模型分类,select|poll|kqueue|epoll|resig|/dev/poll|eventport
worker_connections 10240; //每个worker进程允许处理的最大连接数,例如10240,65535
}
http {
include /etc/nginx/mime.types; 文档和程序的关联记录
default_type application/octet-stream; 字节流处理方式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'; 日志格式,讲日志回来看
access_log /var/log/nginx/access.log main;
sendfile on; 优化参数
高效传输文件的模式 Nginx高级篇sendfile配置
sendfile: 设置为on表示启动高效传输文件的模式。sendfile可以让Nginx在传输文件时直接在磁盘和tcp socket之间传输数据。如果这个参数不开启,会先在用户空间(Nginx进程空间)申请一个buffer,用read函数把数据从磁盘读到cache,再从cache读取到用户空间的buffer,再用write函数把数据从用户空间的buffer写入到内核的buffer,最后到tcp socket。开启这个参数后可以让数据不用经过用户buffer。
#tcp_nopush on; 优化参数 也就是说tcp_nopush = on 会设置调用tcp_cork方法,这个也是默认的,结果就是数据包不会马上传送出去,等到数据包最大时,一次性的传输出去,这样有助于解决网络堵塞。
keepalive_timeout 65; 优化参数
长连接
#gzip on; 压缩参数
include /etc/nginx/conf.d/*.conf; 包含子配置文件夹
观察默认虚拟主机配置文件
vim /etc/nginx/conf.d/default.conf
server { 默认网站配置文件
listen 80; 监听端口
server_name localhost; FQDN
#charset koi8-r; 网页字符类型
#access_log /var/log/nginx/host.access.log main; 日志
location / {
root /usr/share/nginx/html; 主目录
index index.html index.htm; 默认主页名
}
#error_page 404 /404.html; 错误页面
# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html; 错误页面
location = /50x.html { 错误页面
root /usr/share/nginx/html; 错误页面主目录
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80 代理设置
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 动态网站设置
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root 访问控制部分
# concurs with nginx's one
#location ~ /\.ht {
# deny all;
#}
}
启动一个新的虚拟主机
vim /etc/nginx/conf.d/xuleilinux.conf
server {
listen 80;
server_name xuleilinux.com;
location / {
root /xuleilinux;
index index.html ;
}
}
server 虚拟主机
listen 监听端口
server_name 服务器名称
location 网站目录设置
root 网站主目录在本地的路径
index 主页文件名
http{} 是整个服务器,所有虚拟主机的设置。
server{}是某一个虚拟主机的设置
location{} 是某一个页面的设置。
mkdir /xuleilinux
echo 我爱你 > /xuleilinux/index.html
1.日志模块
官方文档: http://nginx.org/en/docs/http/ngx_http_log_module.html.
日志模块的名称:ngx_http_log_module
2.相关指令
- log_format 日志格式
- access_log 访问日志
- error_log 错误日志
- open_log_file_cache 日志缓存
3.日志的格式和命令
log_format
简介:
Nginx有非常灵活的日志记录模式。每个级别的配置可以有各自独立的访问日志。日志格式通过log_format命令定义。
定义位置设置
主配置文件里日志的部分配置
vim /etc/nginx/nginx.conf
> log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
日志格式允许包含的变量
- $remote_addr, 远程地址: 记录客户端IP地址
- $remote_user 远程用户:记录客户端用户名称
- [$time_local] 本地时间:服务器自身时间
- $request 请求:记录请求的URL和HTTP协议
"GET /1.html HTTP/1.1" 和 "GET /index.html HTTP/1.1"
- $status 状态:记录请求状态
如:200 404 503 100 301
- $body_bytes_sent 发送给客户端的字节数,不包括响应头的大小
- $http_referer 记录从哪个页面链接访问过来的 (超链接)
- $http_user_agent 记录客户端浏览器相关信息,如火狐、IE
- $http_x_forwarded_for 代理IP
4.访问日志和错误日志
access_log 和 error_log
access_log
某条日志记录
> 192.168.100.254 - - [17/Dec/2017:14:45:59 +0800] "GET /nginx-logo.png HTTP/1.1" 200 368 "http://192.168.100.10/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:57.0) Gecko/20100101 Firefox/57.0" "-"
某条日志记录含义
- 192.远程主机IP
- — — 用户
- 【2017】时间
- get获得,下载,还有post提交。
- /nginx-logo.png 下载图片
- http版本
- 状态码 什么结果。对,还是错
- 368 字节大小
- 引用自哪个连接,主页http://192.168.100.10/
- Mozilla 5.0浏览器的版本
- Windows NT 客户端系统类型
- -远程客户端主机地址 (请看注释)
Nginx安装,会默认启动日志轮转。
rpm -ql nginx| grep log
此命令查看本机日志轮转配置文件和日志存放文件
如下两个文件:
/etc/logrotate.d/nginx
/var/log/nginx
观察日志轮转配置文件
vim /etc/logrotate.d/nginx
- /var/log/nginx/*log { 待切割的日志
- create 0644 nginx nginx 创建新的日志文件,属主
- daily 天
- rotate 10 10份
- missingok 丢失不提示
- notifempty 空文件的话,不转储
- compress 压缩
- sharedscripts 轮转后脚本
> postrotate
> /bin/kill -USR1 `cat /run/nginx.pid 2>/dev/null` 2>/dev/null || true
> endscript
USR1亦通常被用来告知应用程序重载配置文件;例如,向Apache HTTP服务器发送一个USR1信号将导致以下步骤的发生:停止接受新的连接,等待当前连接停止,重新载入配置文件,重新打开日志文件,重启服务器,从而实现相对平滑的不关机的更改。
- }
轮转语句
指令 /usr/sbin/logrotate -s /var/lib/logrotate/logrotate.status /etc/logrotate.conf
常用字段
> $remote_addr $1 远程客户端地址
> $time_local $4 本机时间
> $request $7 请求URL
> $status $9 状态码
> $body_bytes_sent $10 请求体积
案例:
链接: https://pan.baidu.com/s/1RWxGI2N0ekfCG72Hbt7PIA.
提取码:zlzl
里面有一些统计的日志文件,用于学习使用。
grep '05/Sep/2017' cd.mobiletrain.org.log |wc -l 1260条
8点-9点间
grep '05/Sep/2017:08' sz.mobiletrain.org.log |wc -l
或者
awk '$4>="[05/Sep/2017:08:00:00" && $4<="[05/Sep/2017:09:00:00" {print $0}' sz.mobiletrain.org.log | wc -l
grep '05/Sep/2017' cd.mobiletrain.org.log | awk '{ ips[$1]++ } END{for(i in ips){print i,ips[i]} } '| sort -k2 -rn | head -n10
grep '05/Sep/2017' cd.mobiletrain.org.log | awk '{ ips[$1]++ } END{for(i in ips){ if(ips[i]>100) {print i,ips[i]}} } '| sort -k2 -rn | head -n10
grep '05/Sep/2017' cd.mobiletrain.org.log |awk '{urls[$7]++} END{for(i in urls){print urls[i],i}}' |sort -k1 -rn |head -n10
grep '05/Sep/2017' sz.mobiletrain.org.log |
awk '{ urls[$7]++; size[$7]+=$10}
END{for(i in urls){print urls[i],size[i],i}}'|
sort -k1 -rn | head -n10
grep '05/Sep/2017' cd.mobiletrain.org.log |
awk '{ ip_code[$1" "$9]++}
END{ for(i in ip_code){print i,ip_code[i]} }' |
sort -k1 -rn | head -n10
grep '05/Sep/2017' cd.mobiletrain.org.log |
awk '$9=="404"{ccc[$1" "$9]++}
END{for(i in ccc){print i,ccc[i]}}' |
sort -k3 -rn
或者
grep '05/Sep/2017' sz.mobiletrain.org.log |
awk '{if($9=="404"){ip_code[$1" "$9]++}}
END{for(i in ip_code){print i,ip_code[i]}}'
date=$(date -d '-1 minute' +%d/%b/%Y:%H:%M);awk -v date=$date '$0 ~ date {i++} END{print i}' sz.mobiletrain.org.log
shell中的变量在awk程序中无法使用,因为在执行AWK时,
是一个新的进程去处理的,因此就需要-v 来向awk程序中传参数了,
你比如在shell程序中有一个变量a=15,你在awk程序中直接使用变
量a是不行的,而你用awk -v b=a, 这样在AWK程序中就可以
使用变量b了!也就相当于使用a了!
# date=$(date -d '-1 minute' +%Y:%H:%M); awk -v date=$date '$0 ~ date{i++}END{print i}' /var/log/nginx/xuleilinux.access.log
awk '$4>="[05/Sep/2017:08:30:00" &&
$4<="[05/Sep/2017:09:00:00"
{if($9=="404"){ip_code[$1" "$9]++}}
END{for(i in ip_code){print i,ip_code[i]}}'
sz.mobiletrain.org.log
grep '05/Sep/2017' sz.mobiletrain.org.log | awk '{code[$9]++} END{for(i in code){print i,code[i]}}'
百分比
grep '05/Sep/2017' sz.mobiletrain.org.log | awk '{code[$9]++;total++} END{for(i in code){printf i" ";printf code[i]"\t";printf "%.2f",code[i]/total*100;print "%"}}'
nginx -V 2>&1 | grep stub_status
2 配置状态模块
进入虚拟主机配置文件
vim /etc/nginx/conf.d/default.conf
请写在server内
server {
location /nginx_status {
stub_status;
allow all;
}
}
3 重启服务再次访问
systemctl restart nginx
- Active connections: 22 当前活动的连接数
- server accepts handled requests 服务器接受处理请求
17 17 24
17 总连接数connection(TCP)
17 成功的连接数connection (TCP) 失败连接=(总连接数-成功连接数)
24 总共处理的请求数requests(HTTP)
connection 连接数,tcp连接
request http请求GET/POST/DELETE/UPLOAD
Reading: 2 读取客户端Header的信息数 请求头
Writing: 1 返回给客户端的header的信息数 响应头
Waiting: 19 等待的请求数,开启了keepalive
TCP机制
四大计时器:
重传计时器(Retransmession)
为了防止数据报丢失,当TCP发送一个报文时,就启动重传计时器,有2种情况:
1.若在计时器超时之前收到了特定报文的确认,则撤消这个计时器;
2.特定数据报在计时器超时前没有收到确认,则重传该数据报,并把计时器复位
持久计时器(Persistance)
前面在流量控制篇提到死锁现象
要解开死锁,TCP为每一个连接使用一个持久计时器
当发送端TCP接收到rwnd=0的确认时,就启动持久计时器,当计时器截止时间到时,发送端TCP需要发送一个特殊的报文,叫做探测报文
当发送端TCP接收到rwnd=0的确认时,就启动持久计时器,当计时器截止时间到时,发送端TCP需要发送一个特殊的报文,叫做探测报文
该报文只有1字节,有序号,但无需确认
探测报文提醒接收端TCP:确认已丢失,必须重传
持久计时器截止时间设置为重传时间的数值,但是,如果没有收到从接收端回来的响应,则需要发送另外一个探测报文,并将持久计时器的值加倍和复位
持久计时器截止时间设置为重传时间的数值,但是,如果没有收到从接收端回来的响应,则需要发送另外一个探测报文,并将持久计时器的值加倍和复位
如果结果和上面一样,发送端继续发送探测报文,直到其截止时间增大到阈值(通常为60s)为止
在这以后,发送端每60s发送一个探测报文,直到窗口重新打开
保活计时器(keep-alive)
在某些实现中要使用keeplive timer来防止两个TCP之间出现长时间的空闲
比如客户端打开了服务器端的连接,传送了一些数据,然后就保持静默了
也许该客户端除了故障,在这种情况下,这个连接就永远处于打开状态
保活计时器的解决方法为,当服务器端收到客户端的信息时,就把计时器复位,超时通常设置2小时
若服务器2小时还没有收到客户的信息,就发送探测报文
若发送10个同样的报文(每个相隔75s)还没有收到响应,就认为客户端出了故障,终止这个连接
时间等待(time-wait)
如果最后一个ACK报文丢失了,那么服务器TCP(它为最后的FIN设置了计时器)以为它的FIN丢失了,因而重传
TCP流控/拥塞管理
原理:
接收端处理数据的速度是有限的,如果发送方的速度太快,就会把缓冲区u打满。这个时候如果继续发送数据,就会导致丢包等一系列连锁反应。
所以TCP支持根据接收端能力来决定发送端的发送速度。这个机制叫做流控制。
窗口大小:
(接收端向发送端主机通知自己可以接受数据的大小,这个大小限制就叫做窗口大小)
什么是请求
一次HTTP查询
keepalived
长连接设置
Httpd守护进程,一般都提供了keep-alive timeout时间设置参数。比如nginx的keepalive_timeout,和Apache的KeepAliveTimeout。这个 keepalive_timout时间值意味着:一个http产生的tcp连接在传送完最后一个响应后,还需要hold住 keepalive_timeout秒后,才开始关闭这个连接。当httpd守护进程发送完一个响应后,理应马上主动关闭相应的tcp连接,设置 keepalive_timeout后,httpd守护进程会想说:”再等等吧,看看浏览器还有没有请求过来”,这一等,便是 keepalive_timeout时间。如果守护进程在这个等待的时间里,一直没有收到浏览发过来http请求,则关闭这个http连接。
systemctl restart nginx
random_index_module
目的:将主页设置成随机页面,是一种微调更新机制
启动随机主页
1 创建主页目录
mkdir /app
2 创建多个主页
touch /app/{blue.html,green.html,red.html,.yellow.html}
在不同的页面书写不同的内容,例如
green color</title>
</head>
"background-color:green">
green color!</h1>
</body>
</html>
vim /etc/nginx/conf.d/default.conf 进入虚拟主机配置文件
server{
location / {
#root /usr/share/nginx/html;
#index index.html index.htm;
root /app;
random_index on;
}
}
完成该试验后,请注释掉该功能。
避免影响其他实验。
重启服务
systemctl restart nginx
刷新主页,观察变化
4 请注意隐藏文件并不会被随机选取
sub_module
目的:网页内容替换。
如果我们用模板生成网站的时候,因为疏漏或者别的原因造成代码不如意,但是此时因为文件数量巨大,不方便全部重新生成,那么这个时候我们就可以用此模块来暂时实现纠错。另一方面,我们也可以利用这个实现服务器端文字过滤的效果。
vim /etc/nginx/conf.d/default.conf 启动nginx默认页面
server { 在server{下面插入
sub_filter nginx 'I love you';
sub_filter_once on;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
替换模块 将nginx 替换成 I love you
单次替换 开启
}
重启服务,测试页面
只替换了一处。
将单次替换关闭,再次刷新页面,即可看见全文替换。
模块 ngx_http_core_module
语法
Syntax: sendfile on | off;
Default: sendfile on;
Context: http, server, location, if in location
Syntax: tcp_nopush on | off;
Default: tcp_nopush off;
Context: http, server, location
Syntax: tcp_nodelay on | off;
Default: tcp_nodelay on;
Context: http, server, location
原理介绍
硬盘 >> kernel buffer >> user buffer>> kernel socket buffer >>协议栈
硬盘 >> kernel buffer (快速拷贝到kernelsocket buffer) >>协议栈
sendfile() 不但能减少切换次数而且还能减少拷贝次数。
未使用tcp_nopush()网络资源浪费
应用程序每产生一次操作就会发送一个包,而典型情况下一个包会拥有一个字节的数据以及40个字节长的包头,于是产生4000%的过载,很轻易地就能令网络发生拥塞。同时也浪费资源
使用tcp_nopush()网络传输效率提升
当包累计到一定大小后再发送。
开启或关闭nginx使用TCP_NODELAY选项的功能。 这个选项仅在将连接转变为长连接的时候才被启用。
TCP_NODELAY是禁用Nagle算法,即数据包立即发送出去。
由于Nagle和DelayedACK的原因,数据包的确认信息需要积攒到两个时才发送,长连接情况下,奇数包会造成延时40ms,所以tcp_nodelay会将ack立刻发出去。 如果不在长连接时,可以关闭此模块,因为ack会被立刻发出去。
启用模块
location /video/ {
sendfile on;
tcp_nopush on;
}
默认启动,无需验证
原理介绍
启动该模块,使文件传输前进行压缩,提升传输效率。
模块: ngx_http_gzip_module
语法:
Syntax: gzip on | off;
Default: gzip off;
Context: http, server, location, if in location
Syntax: gzip_comp_level level;
Default: gzip_comp_level 1;(1~9)
Context: http, server, location
Syntax: gzip_http_version 1.0 | 1.1;
Default: gzip_http_version 1.1;
Context: http, server, location
启用模块
http {
gzip on;
gzip_http_version 1.1;
gzip_comp_level 2;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
gzip_static on;
## gzip_static on; # nginx对于静态文件的处理模块
systemctl restart nginx 重启
模块 : ngx_http_headers_module
expires起到控制页面缓存的作用,合理的配置expires可以减少很多服务器的请求要配置expires,可以在http段中或者server段中或者location段中加入。
Nginx(expires 缓存减轻服务端压力),
语法:
Syntax: expires [modified] time;
expires epoch | max | off;
Default: expires off;
Context: http, server, location, if in location
原理介绍
无缓存,每次访问服务器,均是全文传输。
开启缓存可以加速浏览网站。
启用缓存
观察浏览器缓存
1 开启浏览器缓存,浏览页面。(默认)
第一次返回状态码200.页面对象全文传输
第二次返回状态304.页面对象部分传输。
2 禁用缓存。浏览页面
返回码200.全文传输
理解浏览器缓存作用。
理解nginx服务器缓存
4 开启服务器缓存模块
vim /etc/nginx/nginx.conf
location / {
root /usr/share/nginx/html
index index.html index.htm;
expires 24h;
}
5 再次浏览页面,观察响应头中出现服务器回复的缓存时间
6 理解nginx服务器启动缓存时间,加速浏览。
模块: ngx_http_referer_module
语法:
Syntax: valid_referers none | blocked | server_names | string ...;
Default: —
Context: server, location
日志原理介绍
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
日志格式中的http_referer是记录,访问点引用的URL。也就是超链接的上一级地址。
通过这段地址,可以发现一种网络行为——盗链。非法盗链会影响站点的正常访问。
通过http_referer模块可以控制这一点。防止非法盗链现象。
启动防盗链
展现盗链现象,启动防盗链
1 搭建一个a.com网站,在主页中插入图片
vim index.html
'1.jpg' />
注意要将1.jpg图片拷贝至网站主目录。
2 搭建一个b.com网站,在主页中盗链A网站的图片
vim index.html
'http://A网站的域名或者地址/1.jpg' /> 盗用链接
注意网站主目录中,根本没有图片。
3 访问两个网站页面。均能正常显示图片。
4 注意b.com网站的日志
日志正常。
192.168.100.254 - - [20/Sep/2017:15:10:27 +0800] "GET / HTTP/1.1" 200 42 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:57.0) Gecko/20100101 Firefox/57.0" "-"
5 注意a.com网站的日志
日志不正常。日志莫名其妙的产生了。
观察referer字段,发现被盗链了。
192.168.100.254 - - [20/Sep/2017:15:10:27 +0800] "GET /1.jpg HTTP/1.1" 200 1635350 "http://192.168.100.20/" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:57.0) Gecko/20100101 Firefox/57.0"
6 启动a.com防盗链功能
location / {
root /a.com;
index index.html index.htm;
valid_referers none blocked *.a.com;
if ($invalid_referer) {
return 403;
}
}
重启服务
7 再次访问b.com网站,盗链失败。
8 如果希望某些网站能够使用(盗链)资源:
location ~* \.(gif|jpg|png|bmp)$ {
root /a.com
valid_referers none blocked *.qfcloud.top server_names ~tianyun ~\.google\. ~\.baidu\.;
if ($invalid_referer) {
return 403;
#rewrite .* http://qfcloud.top/403.jpg;
}
}
location / {
root /a.com;
index index.html index.htm;
valid_referers none blocked *.a.com server_name 192.168.100.* ~tianyun ~\.google\. ~\.baidu\. b.com;
if ($invalid_referer) {
return 403;
}
}
9 再次盗链,合法盗链成功。
ngx_http_limit_req_module
启动请求频率限制
测试未限制情况下的访问 yum install -y httpd-tools
ab -n 100 -c 10 http://tianyun.me/
vim /etc/nginx/nginx.conf
定义: limit_req_zone $binary_remote_addr zone=req_zone:10m rate=1r/s;
限制请求 二进制地址 限制策略的名称 占用10M空间 允许每秒1次请求
引用: limit_req zone=req_zone;
引用 限制策略的名称
配置
http {
limit_req_zone $binary_remote_addr zone=req_zone:10m rate=1r/s; 定义
server {
location / {
root /usr/share/nginx/html;
index index.html index.htm;
limit_req zone=req_zone; 引用
#limit_req zone=req_zone burst=5;
#limit_req zone=req_zone burst=5 nodelay;
}
}
}
引用限制
引用限制,但是令牌桶有5个。有延迟。速度慢
引用限制,但是令牌桶有5个。无延迟。速度快
burst=5 表示最大延迟请求数量不大于5。 如果太过多的请求被限制延迟是不需要的 ,这时需要使用nodelay参数,服务器会立刻返回503状态码。
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Benchmarking localhost (be patient).....done
Server Software: nginx/1.12.1
Server Hostname: tianyun.me
Server Port: 80
Document Path: /
Document Length: 671 bytes
Concurrency Level: 10
Time taken for tests: 0.006 seconds
Complete requests: 100
Failed requests: 99 失败的请求
(Connect: 0, Receive: 0, Length: 99, Exceptions: 0)
Write errors: 0
Non-2xx responses: 99 有问题的相应。
Total transferred: 73273 bytes
HTML transferred: 53834 bytes
Requests per second: 16131.63 [#/sec] (mean)
Time per request: 0.620 [ms] (mean)
Time per request: 0.062 [ms] (mean, across all concurrent requests)
Transfer rate: 11543.10 [Kbytes/sec] received
tail -f /var/log/nginx/error.log
2017/10/08 01:05:08 [error] 23287#23287: *720 limiting requests, excess: 5.109 by zone "req_zone",
client: 27.216.240.201, server: localhost, request: "GET / HTTP/1.0", host: "tianyun.me"
limiting requests
由于限制请求导致。
ngx_http_limit_conn_module
目的:通过IP地址,限制链接(TCP)。但是实验环境无法测试
启动连接频率限制
启动连接频率限制
http {
limit_conn_zone $binary_remote_addr zone=conn_zone:10m;
}
server {
location / {
...
limit_conn conn_zone 1;
}
}
limit_conn_zone:全局定义限制对象(IP),存储区限制空间(10M)字节
limit_conn:该指令指定每个给定键值的最大同时连接数,当超过这个数字时返回503(Service )错误。如(同一IP同一时间只允许有2个连接):
客户端的IP地址作为键。注意,这里使用的是 binary_remote_addr 变量,而不是 remote_addr 变量。
remote_addr变量的长度为7字节到15字节,而存储状态在32位平台中占用32字节或64字节,在64位平台中占用64字节。
binary_remote_addr变量的长度是固定的4字节,存储状态在32位平台中占用32字节或64字节,在64位平台中占用64字节。
1M共享空间可以保存3.2万个32位的状态,1.6万个64位的状态。
如果共享内存空间被耗尽,服务器将会对后续所有的请求返回 503 (Service Temporarily Unavailable) 错误。
limit_conn_zone $binary_remote_addr zone=conn_zone:10m模块开启对单个ip、单个会话同时存在的连接数的限制。这里定义一个记录区conn_zone,conn_zone的总容量是10m,该记录区针对于变量 $binary_remote_add生效,这里是针对单个IP生效。该模块只是一个定义,配置在http配置段,需要配合limit_conn指令使用才生效, limit_conn conn_zone 1表示该location段使用conn_zone定义的 limit_conn_zone ,对单个IP限制同时存在一个连接。
单个IP,同时只允许有一个tcp连接
ab -n 100 -c 10 http://服务器IP地址/
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Benchmarking localhost (be patient).....done
Server Software: nginx/1.12.1
Server Hostname: tianyun.me
Server Port: 80
Document Path: /
Document Length: 671 bytes 文档长度
Concurrency Level: 10 当前并发数
Time taken for tests: 0.006 seconds 消耗总时间
Complete requests: 100 完成请求数
Failed requests: 0 失败请求数
Write errors: 0
Total transferred: 90400 bytes 总的传输大小
HTML transferred: 67100 bytes http传输大小
Requests per second: 15873.02 [#/sec] (mean) 每秒钟处理多少个请求。
基于主机(ip)
module
ngx_http_access_module
Directives
allow 允许某些主机
deny 拒绝某些主机
Syntax:
Syntax: allow address | CIDR | unix: | all;
Context: http, server, location, limit_except
启用控制
1 限制主机访问
vim /etc/nginx/conf.d/default.conf
server {
allow 10.18.45.65;
allow 10.18.45.181;
deny all;
}
2 测试
服务器无法访问