Nginx (engine x) 是一个高性能的HTTP(解决C10k的问题)和反向代理服务器,也是一个IMAP/POP3/SMTP服务器。
Ⅰ.IO多路复用:
1.理论方法:
- 最传统的多进程并发模型(没进来一个新的I/O流会分配一个新的进程管理)
- I/O多路复用(单个线程,通过记录跟踪每个I/O流(sock)的状态,来同时管理多个I/O流。)能尽量多的提高服务器的吞吐能力。
- 在同一个线程里面,通过拨开关的方式,来同时传输多个I/O流。
2.技术类型:
- select:
• select是第一个实现 (1983 左右在BSD里面实现的)。
• select 被实现以后,很快就暴露出了很多问题。
• select 会修改传入的参数数组,这个对于一个需要调用很多次的函数,是非常不友好的。
• select 如果任何一个sock(I/O stream)出现了数据,select 仅仅会返回,但是并不会告诉你是那个sock上有数据,于是你只能自己一个一个的找,10几个sock可能还好,要是几万的sock每次都找一遍…
• select 只能监视1024个链接。
• select 不是线程安全的,如果你把一个sock加入到select, 然后突然另外一个线程发现,这个sock不用,要收回,这个select 不支持的,如果你丧心病狂的竟然关掉这个sock, select的标准行为是不可预测的
- poll:
• 于是14年以后(1997年)一帮人又实现了poll, poll 修复了select的很多问题,比如 poll 去掉了1024个链接的限制,于是要多少链接呢, 你开心就好。
• poll 从设计上来说,不再修改传入数组,不过这个要看你的平台了,所以行走江湖,还是小心为妙。
• 其实拖14年那么久也不是效率问题, 而是那个时代的硬件实在太弱,一台服务器处理1千多个链接简直就是神一样的存在了,select很长段时间已经满足需求。
• 但是poll仍然不是线程安全的, 这就意味着,不管服务器有多强悍,你也只能在一个线程里面处理一组I/O流。
你当然可以那多进程来配合了,不过然后你就有了多进程的各种问题。
- epoll:
• 于是5年以后, 在2002, 大神 Davide Libenzi 实现了epoll.
epoll 可以说是I/O 多路复用最新的一个实现,epoll 修复了poll 和select绝大部分问题, 比如:
• epoll 现在是线程安全的。
• epoll 现在不仅告诉你sock组里面数据,还会告诉你具体哪个sock有数据,你不用自己去找了。• 特点:异步、非阻塞
$ 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
Ⅱ.URI
- 简介:统一资源标识符(Uniform Resource Identifier,或URI)
HTTP 请求的内容通称为”资源“。”资源“这一概念非常宽泛,它可以是你能够想到的格式。每个资源都由一个 (URI) 来进行标识。URL即统一资源定位符,它是 URI 的一种。一份文档,一张图片,或所有其他。URI包含URL,URN。
- URL:统一资源定位符(Uniform Resource Locator,或URL)
URL用于定位,也被称为网页地址。
URL 由多个必须或可选的组件构成。下面给出了一个复杂的 URL:
http://www.example.com:80/path/to/myfile.html?key1=value1&key2=value2#SomewhereInTheDocument
- URN
URN 是另一种形式的 URI,它通过特定命名空间中的唯一名称来标识资源。
URN仅用于命名,而不指定地址。用于标识唯一书目的ISBN系统是一个典型的URN使用范例。
例如,ISBN 0486275574(urn:isbn:0-486-27557-4)无二义性地标识出莎士比亚的戏剧《罗密欧与朱丽叶》的某一特定版本。
Ⅲ.三者关系图
通过下面的例子(源自 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)
1.协议
“http://” 告诉浏览器使用何种协议。对于大部分 Web 资源,通常使用 HTTP 协议或其安全版本,HTTPS 协议。
另外,浏览器也知道如何处理其他协议。例如, “mailto:” 协议指示浏览器打开邮件客户端;“ftp:”协议指示浏览器处理文件传输。2.主机
www.example.com 既是一个域名,也代表管理该域名的机构。它指示了需要向网络上的哪一台主机发起请
求。当然,也可以直接向主机的 IP address 地址发起请求。但直接使用 IP 地址的场景并不常见。3.端口
:80 是端口。它表示用于访问 Web 服务器上资源的技术“门”。如果访问的该 Web 服务器使用HTTP协议的标准
端口(HTTP为80,HTTPS为443)授予对其资源的访问权限,则通常省略此部分。否则端口就是 URI 必须的部分。4.路径
/path/to/myfile.html 是 Web 服务器上资源的路径。在 Web 的早期,类似这样的路径表示 Web 服务器上的物理文件位置。现在,它主要是由没有任何物理实体的 Web 服务器抽象处理而成的。
5.查询
?key1=value1&key2=value2 是提供给 Web 服务器的额外参数。这些参数是用 & 符号分隔的键/值对列表。Web 服务器可以在将资源返回给用户之前使用这些参数来执行额外的操作。每个 Web 服务器都有自己的参数规则,想知道特定 Web 服务器如何处理参数的唯一可靠方法是询问该 Web 服务器所有者。
6.片段
#SomewhereInTheDocument 是资源本身的某一部分的一个锚点。锚点代表资源内的一种“书签”,它给予浏览器显示位于该“加书签”点的内容的指示。 例如,在HTML文档上,浏览器将滚动到定义锚点的那个点上;在视频或音频文档上,浏览器将转到锚点代表的那个时间。值得注意的是 # 号后面的部分,也称为片段标识符,永远不会与请求一起发送到服务器。
7.示例
https://developer.mozilla.org/en-US/docs/Learn
[email protected]:mdn/browser-compat-data.git
ftp://example.org/resource.txt
Ⅰ.官方链接
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Overview
Ⅱ.知识点
1.概述
- 图示
我们获得的图像,影音,广告都是由web服务器 get而来。
- 概览
HTTP是一种能够获取如 HTML 这样的网络资源的通讯协议。它是 Web 上数据交换的基础,是一种client-server 协议,也就是说请求通常是由像浏览器这样的接受方发起的。一个完整的web文档是由不同的子文档重新组建而成的,像是文本、布局描述、图片、视频、脚本等等。
HTTP被设计于上20世纪90年代初期,是一种可扩展性的协议。它是应用层的协议,虽然理论上它可以通过任何可靠的传输协议来发送,但是它还是通过TCP,或者是TLS-加密的TCP连接来发送。因为它很好的扩展性,时至今日它不仅被用来传输超文本文档,还用来传输图片、视频或者向服务器发送如HTML表单这样的信息。HTTP还可以根据网页需求,来获取部分web文档的内容来更新网页。
- requests
客户端和服务端通过交换各自的消息来进行交互。通常由像浏览器这样的客户端发出的消息叫做requests,那么被服务端回应的消息就叫做 responses。
2.组件系统
HTTP是一个client-server协议:请求通过一个实体被发出,实体也就是用户代理。大多数情况下,这个用户代理都是指浏览器,当然它也可能是任何东西,比如一个爬取网页来生成和维护搜索引擎索引的机器。
每一个发送到服务器的请求,都会被服务器处理并且返回一个消息,也就是response。在client与server之间,还有许许多多的被称为proxies的实体,他们的作用与表现各不相同,比如有些是网关,还有些是caches等。
- 客户端:user-agent
严格意义来说,user-agent就是任何能够为用户发起行为的工具。但实际上,这个角色通常都是由浏览器来扮演。对于发起请求来说,浏览器总是作为发起一个请求的实体。
要渲染出一个网页,浏览器首先要发送第一个请求来获取这个页面的HTML文档,再解析它并根据文档中的资源信息发送其他的请求来获取脚本信息,或者CSS来进行页面布局渲染,还有一些其它的页面资源(如图片和视频等)。然后,它把这些资源结合到一起,展现出来一个完整的文档,也就是网页。打开一个网页后,浏览器还可以根据脚本内容来获取更多的资源来更新网页。
一个网页就是一个超文本文档,也就是说有一部分显示的文本可能是链接,启动它(通常是鼠标的点击)就可以获取一个新的网页。网页使得用户可以控制它的user-agent来导航Web。浏览器来负责翻译HTTP请求的命令,并翻译HTTP的返回消息让用户能明白返回消息的内容。
- Web服务端
在上述通信过程的另一端,就是一个Web Server来服务并提供客户端请求的文档。Server只是虚拟意义上:它可以是许多共同分担负载(负载平衡)的一组服务器组成的计算机群,也可以是一种复杂的软件,通过向其他计算机发起请求来获取部分或全部资源的软件。
- Proxies
在浏览器和服务器之间,有许多计算机和其他设备转发了HTTP的消息。因为Web栈层次结构的原因,它们大多数都出现在传输层、网络层和物理层上,对于HTTP的应用层来说就是透明的(虽然它们可能会对应用层的性能有重要影响)。而还有一部分表现在应用层上的,就叫做proxies了。Proxies既可以表现得透明,又可以不透明(看请求是否通过它们)。
3.报文
- 请求
• 一个HTTP的method,经常是由一个动词像GET, POST 或者一个名词像OPTIONS,HEAD来定义客户端的动
作行为的。通常客户端的操作都是获取资源(用GET方法)或者发送一个HTML form表单的值(用POST方法),
虽然在一些情况下也会有其他的操作。
• 要获取的资源的路径,通常是上下文中就很明显的元素资源的URL,它没有protocol (http://),domain(developer.mozilla.org),或是TCP的port(HTTP是80端口)。
• HTTP协议的版本号。
• 为服务端表达其他信息的可选择性的headers。
- 回应
• HTTP的版本号。
• 一个状态码(status code),来告知对应的请求发送成功或失败,以及失败的原因。
• 一个状态信息,这个信息是非权威的状态码描述信息,也就是说可以由服务端自行设定的。
• HTTP headers,与请求的很像。
• 可选的,但是比在请求报文中更加常见地包含获取资源的body。
Ⅰ.实验分析http报头信息
Ⅱ.目的
- wget下载一个源码包,分析HTTP头部的信息。
- 通过wget -d选项,学习HTTP头部字段信息。
- 了解http通信原理,为后期优化打下基础。
Ⅲ.执行下载
[root@localhost ~]# wget -d http://nginx.org/download/nginx-1.12.1.tar.gz
Ⅳ.分析Debug信息
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 目标主机:nginx.org 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/1.1 HTTP协议版本1.1; 200 OK 响应的状态码是200,即正常返回数据,不同场景会有其它如2xx、3xx、4xx、5xx; Server 服务器软件是Nginx,版本是1.13.3; Date 从服务器获取该资源时间,时间差8小时,时区不同; Content-Type 响应的数据类型,这里的资源是文件,则是application/octet-stream了,其它还有图片, 视频、json、html、xml、css等; Content-Length response body的长度,也就是源码包的字节大小; Last-Modified 即下载的文件在服务器端最后修改的时间; Connection keep-alive Nginx开启了TCP长连接; ETag ETag HTTP响应头是资源的特定版本的标识符。 这可以让缓存更高效,并节省带宽,因为如果内容没有改变,Web服务器不需要发送完整的响应; Accept-Ranges 响应头 Accept-Range 标识自身支持范围请求,字段值用于定义范围请求的单位。 206 Partial Content Accept-Ranges 告诉我们服务器是否支持指定范围请求及哪种类型的分段请求,这里是byte Content-Range 告诉我们在整个返回体中本部分的字节位置,我们请求的是图片的前100字节
http://www.nginx.org
- Mainline version: 主线版,即开发版
- Stable version: 最新稳定版,生产环境上建议使用的版本
- Legacy versions: 遗留的老版本的稳定版
- 官网帮助手册教程
http://nginx.org/en/linux_packages.html#RHEL-CentOS
--- 安装前的环境问题,关闭firewalld和selinux ---
[root@ocalhost ~]# yum -y install nginx
[root@ocalhost ~]# systemctl start nginx
[root@ocalhost ~]# systemctl enable nginx
[root@ocalhost ~]# nginx -V
#查看安装附带的功能模块
- 测试
[root@ocalhost ~]# 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/ngin/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
服务脚本
/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模块目录
[root@localhost ~]# nginx -v
nginx version: nginx/1.14.1
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-28) (GCC)
built with OpenSSL 1.0.2k-fips 26 Jan 2017
TLS SNI support enabled
configure arguments:
配置参数./configure --help查询帮助
--prefix=/etc/nginx
安装路径
--sbin-path=/usr/sbin/nginx
程序文件
--modules-path=/usr/lib64/nginx/modules
模块路径
---conf-path=/etc/nginx/nginx.conf
主配置文件
--error-log-path=/var/log/nginx/error.log
错误日志
--http-log-path=/var/log/nginx/access.log
访问日志
--pid-path=/var/run/nginx.pid
程序id
--lock-path=/var/run/nginx.lock
所路径防止重复启动nginx
--httpd-client-body-temp-path=/var/cache/nginx/client_temp
缓存
--httpd-proxy-temp-path/var/cache/nginx/proxy_temp
代理缓存
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp
php缓存
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp
python缓存
--http-scgi-temp-path=/var/cache/nginx/scgi_temp
--with-compat
启动动态模块兼容性
--user=nginx
用户
--group=nginx
组
--with-file-aio
使用nginx的aio特性会大大提高性能,比如图片站的特点是大量的读io操作,nginx aio不用等待每次io的结果,有助于并发处理大量io和提高nginx处理效率。
aio的优点就是能够同时提交多个io请求给内核,然后直接由内核的io调度算法去处理这些请求(directio)。
这样的话,内核就有可能执行一些合并,节约了读取文件的处理时间。
就是异步非阻塞
--with-threads
多线程模块
----------------------------------------------------------
--with-http_addition_module
响应之前或者之后追加文本内容,比如想在站点底部追加一个js广告或者新增的css样式
nginx配置addition
配置nginx.conf
server {
listen 80;
server_name www.ttlsa.com;
root /data/site/www.ttlsa.com;
location / {
add_before_body /2013/10/header.html;
add_after_body /2013/10/footer.html;
}
}
测试
以下三个文件,对应请求的主体文件和add_before_body、add_after_body对应的内容
# cat /data/site/test.ttlsa.com/2013/10/20131001_add.html
I am title</title>
</head>
ngx_http_addition_module
</body>
</html>
# cat /data/site/test.ttlsa.com/2013/10/header.html
I am header!
# cat /data/site/test.ttlsa.com/2013/10/footer.html
footer - ttlsa
访问结果如下,可以看到20131001_add.html的顶部和底部分别嵌入了子请求header.html和footer的内容。
# curl test.ttlsa.com/2013/10/20131001_add.html
I am header!
I am title</title>
</head>
ngx_http_addition_module
</body>
</html>
footer - ttlsa
----------------------------------------------------------
--with-http_auth_request_module
认证模块
--with-http_dav_module
增加上传PUT,DELETE,MKCOL:创建集合,COPY和MOVE方法默认情况下为关闭
--with-http_flv_module
NGINX 添加MP4、FLV视频支持模块
--with-http_gunzip_module
压缩模块
--with-http_mp4_module
--with-http_random_index_module
mginx显示随机主页模块
--with-http_realip_module
mginx获取真实ip模块
--with-http_secure_link_module
nginx安全下载模块
--with-http_slice_module
nginx中文文档
--with-http_ssl_module
安全模块
--with-http_stub_status_module
访问状态
--with-http_sub_module
nginx替换网站响应内容
--with-http_v2_module
--with-mail
邮件客户端
--with-mail_ssl_module
--with-stream
负载均衡模块。nginx从1.9.0开始,新增加了一个stream模块,用来实现四层协议的转发、代理或者负载均衡等。
--with-stream_reaip_module
--with-stream_ssl_module
--with-stream_ssl_preread_module
-----------------------CPU优化参数--------------------------
--with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --
param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC'
--with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie'
----------------------------------------------------------
CoreModule 核心模块(进程数等)
EventsModule 事件驱动模块(工作模式等)
HttpCoreModule http内核模块(文档程序类型,配置文件等)
1、全局/核心块:配置影响nginx全局的指令。一般有运行nginx服务器的用户组,nginx进程pid存放路径,日志存放路径,配置文件引入,允许生成worker process数等。
2、events块:配置影响nginx服务器或与用户的网络连接。有每个进程的最大连接数,选取哪种事件驱动模型处理连接请求,是否允许同时接受多个网路连接,开启多个网络连接序列化等。
3、http块:可以嵌套多个server,配置代理,缓存,日志定义等绝大多数功能和第三方模块的配置。如文件引入,mime-type定义,日志自定义,是否使用sendfile传输文件,连接超时时间,单连接请求数等。
4、server块:配置虚拟主机的相关参数,一个http中可以有多个server。
5、location块:配置请求的路由,以及各种页面的处理情况。
user nginx
运行nginx程序的独立账号
worker_processes 1;
启动的worker进程数量(CPU数量一致或auto)
error_log /var/run/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 - $remove_user [$time_local] "$request"'
'$status $body_bytes_sent "$http_refer"'
'"$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
包含子配置文件夹
}
[root@localhost ~]# 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 = /50.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 tp FastCGI server listening on 127.0.0.1:9000
动态网站设置
#location ~ \.php${
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index ondex.php
# fastcgi_param SCRIPT_FILENAME /scrpts$fastcgi_script_name;
# incule fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
访问控制部分
#concurs with nginx's one
#location ~ /\.ht{
# deny all;
#}
}
[root@localhost ~]# vim /etc/nginx/conf.d/jslinux.conf
server{
listen 80;
server_name jslinux.com;
location / {
root /jslinux;
index index.html;
}
}
-----------------------------------------------------------
server 虚拟主机
listen 监听端口
server_name 服务器名称
location 网站目录设置
root 网站主目录在本地的路径
index 主页文件名
http{
} 是整个服务器,所有虚拟主机的设置。
server{
}是某一个虚拟主机的设置
location{
} 是某一个页面的设置。
-----------------------------------------------------------
[root@localhost ~]# mkdir /jslinux
[root@localhost ~]# vim /jslinux/index.html
2020zz-js
/>
cloud compting
[root@localhost ~]# systemctl restart nginx
Ⅰ.官方文档
http://nginx.org/en/docs/http/ngx_http_log_module.html
Ⅱ.日志模块名称
ngx_http_log_module
log_format
日志格式
access_log
访问日志
error_log
错误日志
open_log_file_cache
语法如下:
open_log_file_cache max=N [inactive=time] [mim_uses=N] [valid=time] | off
该指令默认是禁止的,等同于:
open_log_file_cache off;
open_log_file_cache 指令的各项参数说明如下:
max: 设置缓存中的最大文件描述符数量。如果超过设置的最大文件描述符数量,则采用LRU (Least Recently Used)算法清除"较不常使用的文件描述符"。
LRU (Least Recently Used)算法的基本概念是:当内存缓冲区剩余的可用空间不够时,缓冲区尽可能地先保留使用者最常使用的数据,将最近未使用的数据移出内存,腾出空间来加载另外的数据。
inactive:
设置一个时间,如果在设置的时间内没有使用此文件描述符,则自动删除此描述符。此参数为可选参数,默认的时间为10秒钟。
min_uses:
在参数 inactive 指定的时间范围内,如果日志文件超过被使用的次数,则将该日志文件的描述符记入缓存。默认次数为1。
valid:
设置多长时间检查一次,看一看变量指定的日志文件路径与文件名是否仍然存在。默认时间为60秒。
off:
禁止使用缓存。
open_log_file_cache
指令的设置示例如下:
open_log_file_cache max=1000 inactive=20s min_uses=2 valid=1m;
Ⅰ.简介
Nginx有非常灵活的日志记录模式。每个级别的配置可以有各自独立的访问日志。日志格式通过log_format命令定义。
Ⅱ.语法
Syntax:log_format name [escape=default | json] string ...;
name 表示格式名称
string 表示定义的格式
Ⅲ.默认值
Default: log_format combined "...";
log_format 有默认的无需设置的combined日志格式,相当于apache的combined日志格式
Ⅳ.环境
Context:http
网站代理LB
全局和局部
代理服务器的日志格式不同
如果Nginx位于负载均衡器,squid,nginx反向代理之后,web服务器无法直接获取到客户端真实的IP地址。
$remote_addr获取的是反向代理的IP地址。反向代理服务器在转发请求的http头信息中,可以增加X-Forwarded-For信息,用来记录客户端IP地址和客户端请求的服务器地址。
nginx代理服务器日志格式如下:
log_format porxy '$http_x_forwarded_for - $remote_user [$time_local] '
' "$request" $status $body_bytes_sent '
' "$http_referer" "$http_user_agent" ';
Ⅴ.定义设置位置
[root@localhost ~]# vim/etc/nginx/nginx.conf
日志部分配置
日志格式允许包含的变量
$remote_addr
远程地址:记录客户端的IP地址
$remote_user
远程用户:记录客户端用户名称
[$time_local]
本地时间:服务器自身时间
$request
"GET /1.html HTTP/1.1"
"GET /index.html HTTP/1.1"
请求:记录请求的URL和HTTP协议
$status
状态:记录请求状态,常见的http状态码200/404/503/100/301/......
$body_bytes_sent
发送客户端的字节数,不包括相应的大小
$http_referer
记录从哪个页面链接访问过来的(超链接)
$http_user_agent
记录客户端浏览器相关信息
$http_x_forwarded_for
代理IP
old
$request_length
请求的长度(包括请求行,请求头和请求正文)
$request_time
请求处理时间,单位为秒,精度毫秒;从读入客户端的第一个字节开始,直到把最后一个字符发送给客户端后进行日志写入为止。
$time_iso8601
ISO8601标准格式下的本地时间
$bytes_sent
发送给客户端的总字节数(可在主配置文件中,增加此项观察)
$mesc
日志写入时间。单位为秒,精度是毫秒。
总有一个404提示
favicon.ico文件是浏览器收藏网址时显示的图标,当第一次访问页面时,浏览器会自动发起请求获取页面的favicon.ico文件。
当/favicon.ico文件不存在时,服务器会记录404日志。
127.0.0.1 - - [26/Jul/2015:22:25:07 +0800] “GET /favicon.ico HTTP/1.1” 404 168 “-” “Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:36.0) Gecko/20100101 Firefox/36.0” “-”
127.0.0.1 - - [26/Jul/2015:22:25:07 +0800] “GET /favicon.ico HTTP/1.1” 404 168 “-” “Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:36.0) Gecko/20100101 Firefox/36.0” “-“
解决办法
当一个站点没有设置favicon.ico时,access.log会记录了大量favicon.ico 404信息。
这样有两个缺点:
1.使access.log文件变大,记录很多没有用的数据。
2.因为大部分是favicon.ico 404信息,当要查看信息时,会影响搜寻效率。
解决方法如下:
在nginx的配置中加入
location = /favicon.ico {
log_not_found off;
access_log off;
}
以上配置说明:
location = /favicon.ico 表示当访问/favicon.ico时,
log_not_found off 关闭日志
access_log off 不记录在access.log
完整配置如下:
server {
listen 80;
server_name fdipzone.com;
root /Users/fdipzone/home;
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log debug;
location = /favicon.ico {
log_not_found off;
access_log off;
}
location / {
index index.html index.htm index.php;
include /usr/local/etc/nginx/conf.d/php-fpm;
}
}
Ⅵ.提示
access_log
error_log
案例:
access_log:
某条日志记录:
192.168.100.254 - - [17/Sep/2020: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
- - 用户
[2020]时间
get获得,下载,还有post提交。
/nginx-logo.png 下载图片
http版本
状态码 什么结果。对,还是错
200 状态码信息 368 请求的资源大小
引用自哪个连接,主页http://192.168.100.10/
Mozilla 5.0浏览器的版本
Windows NT 客户端系统类型
-远程客户端主机地址 (请看官方注释)
-----------------------------------------------------------
error_log:
个性化404:
1.修改配置文件
[root@localhost ~]# /etc/nginx/nginx.conf
http {
error_page 404 /404.html;
}
[root@localhost ~]# /etc/nginx/conf.d/jslinux.conf
server{
location = /404.html {
root /jslinux;
}
}
[root@localhost ~]# systemctl restart nginx
2.创建错误反馈页面
[root@localhost ~]# vim /xuleilinux/404.html
3.访问
访问不存在的页面
4.查看404日志
观察404页面的现象
1.简介:
大量访问到来时,对于每一条日志记录,都将是先打开文件,再写入日志,然后关闭.占用了系统的IO,与业务无关。
可以使用open_log_file_cache来设置
2.Syntax:
open_log_file_cache max=1000 inactive=20s min_uses=3 valid=1m;
max 1000 指的是日志文件的FD,最大的缓存数量为1000。超了怎么办,看下面
min_users 3 20秒内小于3次访问的FD,就给你清掉,结合inactive 20s 的时间。
valid 1m 检查周期为1分钟。
总结:缓存最多1000个,到了极限,每分钟开始清除掉 20秒内小于3次的文件FD.
3.Default:
open_log_file_cache off;
4.Context:
http, server, locatition
http{
} 将整个服务器所有网站,所有页面的日志进行缓存
server{
} 将某一个网站的所有页面日志,进行缓存
location{
}某一个页面的日志,进行缓存
Nginx安装,会默认启动日志轮转。
[root@localhost ~]# rpm -ql nginx | grep log
/etc/logrotate.d/nginx
/var/log/nginx
[root@localhost ~]# vim /etc/logrotate.d/nginx
vim /var/log/nginx/*log{
待切割的日志
create 0644 nginx nginx
创建新的日志文件,属主属组
daily
每天轮转
rotate 10
保留最后10份日志
missingok
丢失不提示
notifempty
空文件不转存
compress
压缩
sharedscripts
运行脚本
postratate
/bin/kill -USR1 `cat /run/nginx.pid 2>/dev/null` 2>/dev/null || true
USR1亦通常被用来告知应用程序重载配置文件;
例如,向Apache HTTP服务器发送一个USR1信号将导致以下步骤的发生:
停止接受新的连接,等待当前连接停止,重新载入配置文件,重新打开日志文件,重启服务器,从而实现相对平滑的不关机的更改。
endscripts
}
测试
[root@localhost ~]# logrotate -f /etc/logrotate.conf
手动轮转
[root@localhost ~]# ls -l /var/log/nginx
查看日志轮转文件
[root@localhost ~]# watch -n1 ls -l /var/log/nginx/
动态查看
[root@localhost ~]# ps aux | grep nginx
62589
[root@localhost ~]# ls -l /proc/62589/fd
查看日志轮转的目录位置
轮转指令
[root@localhost ~]# /usr/sbin/logrotate -s /var/lib/logrotate/logrotate.status /etc/logrotate.conf
1.cron每小时呼唤一次anacron
[root@localhost ~]# vim /etc/cron.hourly/0anacron
2.anacrontab以天,周,月循环往复
[root@localhost ~]# vim /etc/anacrontab
3.天循环
[root@localhost ~]# vim /etc/cron.daily/logrotate
4.立刻循环/手动轮转
[root@localhost ~]# /usr/sbin/logrotate -s /var/lib/logrotate/logrotate.status /etc/logrotate.conf
5.anacron当天的时间戳
[root@localhost ~]# vim /var/spool/anacron/cron.daily
20200920
6.anacron循环后的时间戳
[root@localhost ~]# vim /var/lib/logrotate/logrotate.status
"/var/log/nginx/host.404.log" 2020-09-20-20:8:56
根据该时间确定是否轮转。
日志格式/日志条目
常用字段:
$remote_addr $1
远程客户端地址
$time_local $4
本地时间
$status $9
状态码
$body_bytes_sent $10
请求体积
案例样本:
1.统计2017年9月5日 PV量
[root@localhost ~]# grep '05/Sep/2017' js.log | wc -l
1260
8点-9点
方法1:
[root@localhost ~]# grep '05/Sep/2017:08' js.log | wc -l
方法2:
[root@localhost ~]# awk '$4>="[05/Sep/2017:08:00:00" && $4<="[05/Sep/2017:09:00:00" {print $0}' js.log | wc -l
2.统计2017年9月5日 一天内访问最多的10个IP(IP top10)
[root@localhost ~]# grep '05/Sep/2017' js.log | awk '{ ips[$1]++ } END{for(i in ips){print i,ips[i]} }'| sort -k2 -rn | head -n10
182.140.217.111 138
121.29.54.122 95
121.29.54.124 84
121.29.54.59 73
121.29.54.101 73
121.29.54.62 62
121.29.54.60 56
58.216.107.23 52
119.147.33.22 50
121.31.30.169 42
3.统计2017年9月5日 访问大于100次的IP
[root@localhost ~]# grep '05/Sep/2017' js.log | awk '{ ips[$1]++ } END{for(i in ips){if(ips[i]>100){print i,ips[i]}}}' | sort -k2 -rn | head -n10
182.140.217.111 138
4.统计2017年9月5日 访问最多的10个页面($request top10)
[root@localhost ~]# grep '05/Sep/2017' js.log | awk '{urls[$7]++} END{for(i in urls){print i,urls[i]}}' | sort -k2 -rn | head -n10
/ 60
/img/banner_btn.png 41
/js/jquery-1.8.3.min.js 23
/img/kbxx_bg.png 21
/css/cd_index.css 21
/d/file/works/2017-04-28/afed3f12498e47572f7a31dad04c4717.jpg 20
/js/ymcore.js 19
/img/ico.png 18
/img/huanglaoshi.jpg 17
/e/admin/DoTimeRepage.php 17
5.统计2017年9月5日 每个URL访问内容大小($body_bytes_sent)
[root@localhost ~]# grep '05/Sep/2017' js.log | awk '{ urls[$7]++; size[$7]+=$10} END{for(i in urls){print i,urls[i],size[i]}}'| sort -k2 -rn | head -n10
/ 44 4040481
/e/admin/DoTimeRepage.php 34 5372
/skin/sz/js/minkh.php 25 678973
/js/jquery-1.11.3.min.js 25 75026
/skin/sz/js/page/jquery-1.4.2.min.js 22 173642
/skin/sz/js/page/ready.js 21 1906
/skin/sz/js/table.js 19 3312
/skin/sz/js/page/core.js 18 10184
/img/sz_home/sz_js.png 16 42120
/img/kbxx_bg.png 16 7818
6.统计2017年9月5日 每个IP访问状态码($status)
[root@localhost ~]# grep '05/Sep/2017' js.log | awk '{ip_code[$1" "$9]++} END{for(i in ip_code){print i,ip_code[i]} }' | sort -k1 -rn | head -n10
220.112.25.173 304 1
220.112.25.173 200 30
183.214.128.195 304 18
183.214.128.195 200 10
183.214.128.152 200 10
183.214.128.142 304 18
183.214.128.142 200 5
182.140.217.111 404 7
182.140.217.111 304 109
182.140.217.111 200 22
7.统计2017年9月5日 每个IP的访问状态为404及出现次数($status)
[root@localhost ~]# grep '05/Sep/2017' js.log | awk '$9=="404"{ccc[$1" "$9]++} END{for(i in ccc){print i,ccc[i]}}' | sort -k3 -rn
[root@localhost ~]# grep '05/Sep/2017' js.log | awk '{if($9="404"){ip_code[$1" "$9]++}} END{for(i in ip_code){print i,ip_code[i]}}'
58.216.107.21 404 5
139.215.203.174 404 67
125.211.204.174 404 10
58.216.107.22 404 25
106.117.249.12 404 6
......
8.统计前一分钟的PV量
[root@localhost ~]# date=$(date -d '-1 minute' +%d/%b/%Y:%H:%M);awk -v date=$date '$0 ~ date {i++} END{print i}' js.log
shell中的变量在awk程序中无法使用,因为在执行AWK时,是一个新的进程去处理的,因此就需要-v来向awk程序中传参数了。
比如在shell程序中有一个变量a=15,在awk程序中直接使用变量a是不行的,而用awk -v b=a,这样在AWK程序中就可以使用变量b也就相当于使用a。
9.统计2017年9月5日 8:30-9:00每个IP出现404状态码的数量
[root@localhost ~]# 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]}}' js.log
121.31.30.169 404 2
183.214.128.152 404 10
121.29.54.101 404 1
119.147.33.19 404 1
58.250.143.116 404 2
121.29.54.59 404 1
121.29.54.60 404 1
10.统计2017年9月5日 各种状态码数量
[root@localhost ~]# grep '05/Sep/2017' js.log | awk '{code[$9]++} END{for(i in code){print i,code[i]}}'
301 1
304 821
200 625
404 290
405 1
[root@localhost ~]# grep '05/Sep/2017' js.log | awk '{code[$9]++} END{for(i in code){print i,code[i]}}'
301 1
304 821
200 625
404 290
405 1
百分比
[root@localhost ~]# grep '05/Sep/2017' js.log | awk '{code[$9]++;total++} END{for(i in code){printf i" ";printf code[i]"\t";printf "%.2f",code[i]/total*100;print "%"}}'
301 1 0.06%
304 821 47.24%
200 625 35.96%
404 290 16.69%
405 1 0.06%
微更新:
将主页设置成随机页面,是一种微调更新机制
random_index_module
启动随机主页:
1.创建主页目录
[root@localhost ~]# mkdir /app
2.创建多个目录
[root@localhost ~]# touch /app/{blue.html,green.html,red.html,.yellow.html}
在不同的页面书写不同的内容,例如
[root@localhost ~]# vim /app/green.html
green color</title>
</head>
"background-color:green">
green color!</h1>
</body>
</html>
3.启动随机主页
[root@localhost ~]# vim /etc/nginx/conf.d/default.conf
server{
location / {
#root /usr/share/nginx/html;
#index index.html index.htm;
root /app;
random_index on;
}
}
完成该试验后,请注释掉该功能。避免影响其他实验。
[root@localhost ~]# systemctl restart nginx
刷新主页,观察变化。
4.注意隐藏文件不会被随机选取(即.yellow.html)
统称:
sub_module
网页内容替换:
如果我们用模板生成网站的时候,因为疏漏或者别的原因造成代码不如意,但是此时因为文件数量巨大,不方便全部重新生成。
那么这个时候我们就可以用此模块来暂时实现纠错。另一方面,我们也可以利用这个实现服务器端文字过滤的效果。
启动替换:
[root@localhost ~]# vim /etc/nginx/conf.d/default.conf
启动nginx默认页面
server {
在server{
下面插入
sub_filter nginx 'jslinux';
sub_filter_once on;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
替换模块 将nginx替换成jslinux
单次替换 开启
重启服务,测试页面
1.只替换了一处。
2.将单次替换关闭,再次刷新页面,即可看见全文替换。
sub_filter_once off
模块统称:
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
- sendfile
未使用sendfile() 的传统网络传输过程:
硬盘 >> kernel buffer >> user buffer>> kernel socket buffer >>协议栈
使用 sendfile() 来进行网络传输的过程:
硬盘 >> kernel buffer (快速拷贝到kernelsocket buffer) >>协议栈
sendfile() 不但能减少切换次数而且还能减少拷贝次数。
- tcp_nopush
未使用tcp_nopush()网络资源浪费:
应用程序每产生一次操作就会发送一个包,而典型情况下一个包会拥有一个字节的数据以及40个字节长的包头,于是产生4000%的过载,很轻易地就能令网络发生拥塞。同时也浪费资源。
使用tcp_nopush()网络传输效率提升:
当包累计到一定大小后再发送。
- tcp_nodelay
开启或关闭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
1.观察未压缩传输
拷贝tar包至网站主目录(压缩包的后缀使用.html)
拷贝文本至网站主目录
通过浏览器下载文件并观察下载后大小。
2.启用压缩功能
http { # 在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对于静态文件的处理模块 [root@localhost ~]# systemctl restart nginx
3.观察压缩传输
注意缓存
压缩包和图片类对象本身已经自带压缩功能。所以压缩比例较小低。
文本类对象在压缩试验中,压缩比例体现优越。
再通过浏览器下载文件并观察下载后大小。
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
epoch:指定“Expires”的值为 1 January,1970,00:00:01 GMT
max:指定“Expires”的值为10年。
-1:指定“Expires”的值为当前服务器时间-1s,即永远过期。
off:不修改“Expires”和"Cache-Control"的值
无缓存,每次访问服务器,均是全文传输。
开启缓存可以加速浏览网站。
Ⅰ.观察浏览器缓存
1.开启浏览器缓存,浏览页面。(默认)
第一次返回状态码200.页面对象全文传输
第二次返回状态304.页面对象部分传输2.禁用缓存,浏览页面。
返回码200.全文传输
理解浏览器缓存作用3.解析缓存原理
Ⅱ.理解nginx服务器缓存
4.开启服务器缓存模块
[root@localhost ~]# 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网站
[root@localhost ~]# vim /etc/nginx/conf.d/a.com.conf
[root@localhost ~]# vim /a.com/index.html
'1.jpg' />
注意要将1.jpg图片拷贝至网站主目录。
分离a.com日志
[root@localhost ~]# vim /etc/nginx/nginx.conf
access_log /var/log/nginx/access.log main;
放到a.com.conf
[root@localhost ~]# vim /etc/nginx/conf.d/a.com.conf
access_log /var/log/nginx/a.com.access.log main;
重启nginx
[root@localhost ~]# systemctl restart nginx
2.搭建一个b.com网站
[root@localhost ~]# vim /etc/nginx/conf.d/b.com.conf
[root@localhost ~]# vim /b.com/index.html
'http://a.com/1.jpg' />
盗用链接,用A网站的域名或地址
注意b网站主目录中,根本没有图片。
分离日志,重启nginx
3.访问两个网站页面。均能正常显示图片。
4.注意b.com网站的日志
日志正常
192.168.36.154 - - [20/Sep/2020: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.36.154 - - [20/Sep/2020: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防盗链功能
[root@localhost ~]# vim /etc/nginx/conf.d/a.com.conf
location / {
root /a.com;
index index.html index.htm;
valid_referers none blocked *.a.com;
if ($invalid_referer) {
return 403;
}
}
[root@localhost ~]# systemctl restart nginx
7.再次访问b.com网站,盗链失败。
8.如果希望某些网站能够使用(盗链)资源
[root@localhost ~]# vim /etc/nginx/conf.d/a.com.conf
测试
location / {
root /a.com;
index index.html index.htm;
valid_referers none blocked *.a.com a.com server_name 192.168.36.* b.com;
if ($invalid_referer) {
return 403;
}
}
9.再次盗链,合法盗链成功。
stub_status_module
展示用户和nginx链接数量信息
查询模块是否安装
[root@localhost ~]# nginx -V 2>&1 | grep stub_status
启动状态模块
1.访问默认站点的状态模块
http://192.168.36.154/nginx_status
显示404页面,未启用
2.配置装填模块
[root@localhost ~]# vim /etc/nginx/conf.d/default.conf
server{
location /nginx_status{
stub_status;
allow all;
}
}
3.重启服务再次访问
[root@localhost ~]# systemctl restart nginx
4.观察连接数和请求数
Active connections: 1
当前活动的连接数
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: 0 Writing: 1 Waiting: 0
Reading: 0 读取客户端Header的信息数,请求头
Writing: 1 返回给客户端Header的信息数,响应头
Waiting: 0 等待的请求数,开启了keeplive
Ⅰ.什么是链接
- OSI封装回顾
- TCP封装结构
- TCP三次握手
1、第一次握手:客户端给服务端发一个 SYN 报文,并指明客户端的初始化序列号 ISN(c)。此时客户端处于 SYN_Send 状态。
2、第二次握手:服务器收到客户端的 SYN 报文之后,会以自己的 SYN 报文作为应答,并且也是指定了自己的初始化序列号 ISN(s),同时会把客户端的 ISN + 1 作为 ACK 的值,表示自己已经收到了客户端的 SYN,此时服务器处于 SYN_REVD 的状态。
3、第三次握手:客户端收到 SYN 报文之后,会发送一个 ACK 报文,当然,也是一样把服务器的 ISN + 1 作为 ACK 的值,表示已经收到了服务端的 SYN 报文,此时客户端处于 establised 状态。
4、服务器收到 ACK 报文之后,也处于 establised 状态,此时,双方以建立起了链接。
- TCP四次挥手/四次断开
1、第一次挥手:客户端发送一个 FIN 报文,报文中会指定一个序列号。此时客户端处于FIN_WAIT1状态。
2、第二次握手:服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序列号值 + 1 作为 ACK 报文的序列号值,表明已经收到客户端的报文了,此时服务端处于 CLOSE_WAIT状态。
3、第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发给 FIN 报文,且指定一个序列号。此时服务端处于 LAST_ACK 的状态。
4、第四次挥手:客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答,且把服务端的序列号值 + 1 作为自己 ACK 报文的序列号值,此时客户端处于 TIME_WAIT 状态。需要过一阵子以确保服务端收到自己的 ACK 报文之后才会进入 CLOSED 状态。
5、服务端收到 ACK 报文之后,就处于关闭连接了,处于 CLOSED 状态。
- TCP机制
1.四大计时器:
2.重传计时器(Retransmission)
为了防止数据报丢失,当TCP发送一个报文时,就启动重传计时器,有2种情况:
若在计时器超时之前收到了特定报文的确认,则撤消这个计时器;
特定数据报在计时器超时前没有收到确认,则重传该数据报,并把计时器复位;3.持久计时器(Persistence)
在流量控制中提到死锁现象。要解开死锁,TCP为每一个连接使用一个持久计时器。当发送端TCP接收到rwnd=0的确认时,就启动持久计时器,当计时器截止时间到时,发送端TCP需要发送一个特殊的报文,叫做探测报文。该报文只有1字节,有序号,但无需确认。探测报文提醒接收端TCP:确认已丢失,必须重传。持久计时器截止时间设置为重传时间的数值,但是,如果没有收到从接收端回来的响应,则需要发送另外一个探测报文,并将持久计时器的值加倍和复位。如果结果和上面一样,发送端继续发送探测报文,直到其截止时间增大到阈值(通常为60s)为止。在这以后,发送端每60s发送一个探测报文,直到窗口重新打开;
4.保活计时器(keep-alive)
在某些实现中要使用keeplive timer来防止两个TCP之间出现长时间的空闲,比如客户端打开了服务器端的连接,传送了一些数据,然后就保持静默了,也许该客户端除了故障,在这种情况下,这个连接就永远处于打开状态。保活计时器的解决方法为,当服务器端收到客户端的信息时,就把计时器复位,超时通常设置2小时。若服务器2小时还没有收到客户的信息,就发送探测报文。若发送10个同样的报文(每个相隔75s)还没有收到响应,就认为客户端出了故障,终止这个连接。
5.时间等待(time-wait)
如果最后一个ACK报文丢失了,那么服务器TCP(它为最后的FIN设置了计时器)以为它的FIN丢失了,因而重传。
- TCP流控/拥塞管理
1.原理
接收端处理数据的速度是有限的,如果发送方的速度太快,就会把缓冲区u打满。这个时候如果继续发送数据,就会导致丢包等一系列连锁反应。
所以TCP支持根据接收端能力来决定发送端的发送速度。这个机制叫做流控制。
2.窗口大小
(接收端向发送端主机通知自己可以接受数据的大小,这个大小限制就叫做窗口大小)
Ⅱ.什么是请求
一次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连接。
Ⅳ.关闭长连接
Ⅴ.再次刷新状态观察
ngx_http_limit_req_module
启动请求频率限制
1.测试未限制情况下的访问(压测工具)
[root@localhost ~]# yum install -y httpd-tools
[root@localhost ~]# ab -n 100 -c 10 http://127.0.0.1/
2.启动限制
定义:
limit_req_zone $binary_remote_addr zone=req_zone:10m rate=1r/s;
限制请求 二进制地址 限制策略的名称 占用10M空间 允许每秒1次请求
引用:
limit_req zone=req_zone;
引用 限制策略的名称
[root@localhost ~]# vim /etc/nginx/nginx.conf
[root@localhost ~]# vim /etc/nginx/conf.d/default.conf
#主配置
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;
#引用限制,但是令牌桶有5个。有延迟。速度慢
#limit_req zone=req_zone burst=5 nodelay;
#引用限制,但是令牌桶有5个。无延迟。速度快
#burst=5 表示最大延迟请求数量不大于5。如果太过多的请求被限制延迟是不需要的,这时需要使用nodelay参数,服务器会立刻返回503状态码。
}
}
}
3.重启服务,并测试
[root@localhost ~]# yum install -y httpd-tools
[root@localhost ~]# ab -n 100 -c 10 http://jslinux.com/
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Benchmarking localhost (be patient).....done
Server Software: nginx/1.12.1
Server Hostname: jslinx.com
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
4.观察错误日志
[root@localhost ~]# tail -f /var/log/nginx/error.log
2020/09/20 20: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: "jslinux.com"
由于限制请求导致。limiting requests
ngx_http_limit_conn_module
通过IP地址,限制链接(TCP)。但是实验环境无法测试.
1.启动连接频率限制
[root@localhost ~]# vim /etc/nginx/nginx.conf
http {
limit_conn_zone $binary_remote_addr zone=conn_zone:10m;
}
server {
location / {
...
limit_conn conn_zone 1;
}
}
单个IP,同时只允许有一个tcp连接
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限制同时存在一个连接。
2.测试
[root@localhost ~]# yum install -y httpd-tools
[root@localhost ~]# ab -n 100 -c 10 http://jslinux/
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Benchmarking localhost (be patient).....done
Server Software: nginx/1.12.1
Server Hostname: jslinux.com
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) 每秒钟处理多少个请求。
3.效果不明显
4.了解不同的网站压力测试工具
module:
ngx_http_access_module
Directives:
allow 允许某些主机
deny 拒绝某些主机
Syntax:
allow address | CIDR | unix: | all;
Context:
http, server, location, limit_except
启动控制:
1.限制主机访问
[root@localhost ~]# vim /etc/nginx/conf.d/default.conf
server {
allow 10.18.45.65; #真机ip
allow 10.18.45.181;
deny all;
}
2.测试
服务器无法访问
module:
ngx_http_auth_basic_module
Syntax:
方法1:Syntax: auth_basic string | off;
方法2:Syntax: auth_basic_user_file file;
Context:
http, server, location, limit_except
启用控制:
1.建立认证文件
[root@localhost ~]# yum install -y httpd-tools
生成秘钥的工具是由apache提供
[root@localhost ~]#htpasswd -cm /etc/nginx/conf.d/passwd user1
会话密码
[root@localhost ~]# htpasswd -m /etc/nginx/conf.d/passwd user2
会话密码
[root@localhost ~]# cat /etc/nginx/conf.d/passwd
观察口令文件是否生成。已生成
user1:$apr1$UE/tLtDM$nVm686kAMYb/ArqQDUi8U/
user2:$apr1$bmn0E/gK$enkXKb2V5uFvUy9wdIHlP.
2.启动认证
[root@localhost ~]# vim /etc/nginx/conf.d/default.conf
server {
auth_basic "nginx access test!";
#提示消息
auth_basic_user_file /etc/nginx/conf.d/passwd;
#引用认证文件
...
}
3.重启并验证