admin 管理员组

文章数量: 887016

文章目录

      • 一 Web服务基础介绍:
        • 1.1 互联网发展历程回顾:
        • 1.2:web服务介绍:
          • 1.2.1 Apace-早期的web服务端:
          • 1.2.1.3:Apache event模型
        • 1.2.2 Nginx-高性能的web服务端
        • 1.2.3 用户访问体验统计
        • 1.2.4:性能影响:
          • 1.2.4.1:影响用户体验的几个因素:
          • 1.2.4.2 应用程序工作模式:
          • 1.2.4.3:服务端I/O:
      • 1.3 系统 I/O 模型:
        • 1.3.1 同步/ 异步:
        • 1.3.2 阻塞 / 非阻塞:
        • 1.3.3 系统IO模型组合(==面试题==)
      • 1.4 网络I/O模型(了解)
        • 1.4.1 同步阻塞型IO模型(blocking IO):
        • 1.4.2 同步非阻塞型I/O模型(nonblocking IO):
        • 1.4.3:IO多路复用型(IO multiplexing):
        • 1.4.4:信号驱动式IO(signal-driven IO):
        • 1.4.5:异步(非阻塞) IO(asynchronous IO):
        • 1.4.6:IO对比:
        • 1.4.7:实现方式:
        • 1.4.8:常用模型汇总:
        • 1.4.9:常用模型通知对比
        • 1.4.10:MMAP介绍:
          • 1.4.10.1:传统方式copy数据:
          • 1.4.10.2:mmap方式:
    • 二 Nginx基础
      • 2.1 Nginx功能介绍
        • 2.1.1 基础特性
        • 2.1.2 和web服务相关的功能
      • 2.2 Nginx组织结构
        • 2.2.1 组织模型
        • 2.2.2:进程间通信:
      • 2.3:Nginx模块介绍:
      • 2.4 Nginx安装
        • 2.4.1 Nginx yum安装
          • 2.4.1.1:检查安装:
          • 2.4.1.2 查看帮助
          • 2.4.1.3 验证Nginx
          • 2.4.1.4 Nginx启动脚本
          • 2.4.1.5 配置Nginx
          • 2.4.1.6 启动Nginx
          • 2.4.1.7 访问Nginx
        • 2.4.2 Nginx 编译安装
          • 2.4.2.1 安装Nginx
          • 2.4.2.2 验证版本及编译参数
          • 2.4.2.3 访问编译安装的nginx web界面
          • 2.4.2.4 创建Nginx自启动脚本
          • 2.4.2.5 验证Nginx自启动脚本
          • 2.5.2.6 配置Nginx
          • 2.5.2.7 默认配置文件
    • 三 Nginx 核心配置详解
      • 3.1 全局配置
      • 3.2 http详细配置
      • 3.3 核心配置示例
        • 3.3.1 新建一个PC web站点
        • 3.3.2:新建一个Mobile web站点
        • 3.3.3:root与alias:
        • 3.3.4:location的详细使用:
          • 3.3.4.1:匹配案例-精确匹配:
          • 3.3.4.2:匹配案例-区分大小写:
          • 3.3.4.3:匹配案例-不区分大小写:
          • 3.3.4.4:匹配案例-URI开始
          • 3.3.4.5:匹配案例-文件名后缀
          • 3.3.4.6:匹配案例-优先级
          • 3.3.4.7 生产使用案例
        • 3.3.5 Nginx 四层访问控制:
        • 3.3.6:Nginx账户认证功能
        • 3.3.7:自定义错误页面
        • 3.3.8:自定义访问日志
        • 3.3.9:检测文件是否存在:
        • 3.3.10:长连接配置:
        • 3.3.11:作为下载服务器配置
        • 3.3.12:作为上传服务器
        • 3.3.13:其他配置
    • 四 Nginx 高级配置
      • 4.1:Nginx 状态页
      • 4.2:Nginx 第三方模块:
      • 4.3:Nginx 变量使用
        • 4.3.1:内置变量
        • 4.3.2:自定义变量:
      • 4.4:Nginx 自定义访问日志
        • 4.4.1:自定义默认格式日志
        • 4.4.2:自定义json格式日志
        • 4.4.3:json格式的日志访问统计
      • 4.5:Nginx 压缩功能
      • 4.6:https 功能
        • 4.6.1:ssl 配置参数:
        • 4.6.2:自签名 证书
        • 4.6.3:Nginx证书配置
        • 4.6.4:实现多域名HTTPS
      • 4.7:关于favicon.ico:
      • 4.8:安全选项
        • 4.8.1:隐藏Nginx版本号
        • 4.8.2:升级OpenSSL版本
    • 五:Nginx Rewrite相关功能:
      • 5.1 ngx_http_rewrite_module模块指令
        • 5.1.1 if指令
        • 5.1.2 set指令
        • 5.1.3 break 指令:
        • 5.1.4 return 指令
        • 5.1.5 rewrite_log 指令:
      • 5.2 rewrite 指令:
        • 5.2.1 rewrite flag使用介绍
        • 5.2.2:rewrite案例-域名永久与临时重定向
          • 5.2.2.1 永久重定向
          • 5.2.2.2 临时重定向
        • 5.2.3 rewrite案例--brak与last
          • 5.2.3.1 break案例
          • 5.2.3.2 last案例
        • 5.2.4 rewrite案例-自动跳转https
        • 5.2.5 rewrite**案例**-判断文件是否存在
      • 5.3 Nginx防盗链
        • 5.3.1 实现 web 盗链:
        • 5.3.2:实现防盗链:
    • 6 Nginx 反向代理功能
      • 6.1 实现**http**反向代理
        • 6.1.1 部署后端 Apache服务器
        • 6.1.2 Nginx http 反向代理入门
          • 6.2.1.1 反向代理配置参数
          • 6.1.2.2 反向代理示例--单台web服务器
          • 6.1.2.3 反向代理示例--指定location
          • 6.1.2.4 反向代理示例--缓存功能
          • 6.1.2.5 添加头部报文信息
        • 6.1.3 Nginx http 反向代理高级应用
          • 6.1.3.1 http upstream配置参数
          • 6.1.3.2 反向代理示例--多台web服务器
          • 6.1.3.3 反向代理示例 -- 客户端 IP 透传
        • 6.1.4 实现动静分离
      • 6.2 实现Nginx tcp负载均衡
        • 6.2.1 tcp负载均衡配置参数
        • 6.2.2 负载均衡实例--Redis
        • 6.2.3 负载均衡实例:MySQL
      • 6.3 实现FastCGI
        • 6.3.1 FastCGI 配置指令
        • 6.3.2 FastCGI示例--Nginx与php-fpm在同一服务器
          • 6.3.2.1 php环境准备
          • 6.3.2.2 php相关配置优化
          • 6.2.3.3 准备php测试页面
          • 6.3.2.4 Nginx配置转发
          • 6.3.2.5 访问验证php测试页
          • 6.3.2.6 php-fpm 的运行状态页面
        • 6.3.3 FastCGI示例--Nginx与php不在同一个服务器
          • 6.3.3.1 yum安装较新版本php-fpm
          • 6.3.3.2:修改php-fpm监听配置
          • 6.3.3.3:准备php测试页面
          • 6.3.3.4:启动并验证php-fpm
          • 6.3.3.5:Nginx配置转发
          • 6.3.3.6:访问验证php测试页面:
      • **6.4**:**tengine**使用:
        • 6.4.1 动态模块
        • 6.4.2:concat模块使用:
        • 6.4.3:tengine配置文件:
        • 6.4.4:基于tengine的wordpress站点:
      • 6.5:openresty:
    • 七 系统参数优化
      • 7.1:系统参数优化
      • 八:LNMP项目实战-WordPress站点搭建:

一 Web服务基础介绍:

正常情况下的单次web服务访问流程:

1.1 互联网发展历程回顾:

1993年3月2日,中国科学院高能物理研究所租用AT&T公司(美国电话电报公司)的国际卫星信道建立的接入美国SLAC国家实验室的64K专线正式开通,成为我国连入Internet的第一根专线。

http://www.ihep.cas/kxcb/kpcg/jsywl/201407/t20140714_4156699.html

1995年马云开始创业并推出了一个web网站<<中国黄页>>,1999年创建阿里巴巴 www.alibabagroup, 2003年5月10日创立淘宝网,2004年12月,马云创立第三方网上支付平台支付宝(蚂蚁金服旗下,共有蚂蚁金服支付宝、余额宝、招财宝、蚂蚁聚宝、网商银行、蚂蚁花呗、芝麻信用等子业务板块。),2009年开始举办双十一购物狂欢节,以下是历年交易成交额:

2009年双十一:5000万元;
2010年双十一:9.36亿元;
2011年双十一:33.6亿元;
2012年双十一:191亿元;
2013年双十一:350亿元;
2014年双十一:571亿元;
2015年双十一:912.17亿元;
2016年双十一:1207亿元元;
2017年双十一:1682.69亿元;
2018年双十一:2135亿元;
2019年双十一:2684亿;
。。。。。

2012年1月11日淘宝商城正式更名为“天猫”。
2014年9月19日里巴巴集团于纽约证券交易所正式挂牌上市。
2020年福布斯统计马云财富415亿美元。

1.2:web服务介绍:

Netcraft公司于1994年底在英国成立,多年来一直致力于互联网市场以及在线安全方面的咨询服务,其中在国际上最具影响力的当属其针对网站服务器,域名解析/主机提供商,以及SSL市场所做的客观严谨的分析研究。

https://newscraft/

1.2.1 Apace-早期的web服务端:

pache起初由美国的伊利诺伊大学香槟分校的国家超级计算机应用中心开发,目前经历了两大版本分别是1.X和2.X,其可以通过编译安装实现特定的功能,目前支持三种不同的MPM(multi-processing module,多进程处理模块,官方网站 http://www.apache。

1.2.1.1:Apache prefork模型

预派生模式,有一个主控制进程,然后生成多个子进程,使用select模型,最大并发1024,每个子进程有一个独立的线程响应用户请求,相对比较占用内存,但是比较稳定,可以设置最大和最小进程数,是最古老的一种模式,也是最稳定的模式,适用于访问量不是很大的场景。

优点:稳定
缺点:大量用户访问慢,占用资源,1024个进程不适用于高并发场景

1.2.1.2 :Apache woker 模型

一种多进程和多线程混合的模型,有一个控制进程,启动多个子进程,每个子进程里面包含固定的线程,使用线程程来处理请求,当线程不够使用的时候会再启动一个新的子进程,然后在进程里面再启动线程处理请求,由于其使用了线程处理请求,因此可以承受更高的并发。

优点:相比prefork 占用的内存较少,可以同时处理更多的请求

缺点:使用keepalive的长连接方式,某个线程会一直被占据,即使没有传输数据,也需要一直等待到超时才会被释放。如果过多的线程,被这样占据,也会导致在高并发场景下的无服务线程可用。(该问题在prefork模式下,同样会发生)

1.2.1.3:Apache event模型

Apache中最新的模式,2012年发布的apache 2.4.X系列正式支持event 模型,属于事件驱动模型(epoll),每个进程响应多个请求,在现在版本里的已经是稳定可用的模式。它和worker模式很像,最大的区别在于,它解决了keepalive场景下,长期被占用的线程的资源浪费问题(某些线程因为被keepalive,空挂在哪里等待,中间几乎没有请求过来,甚至等到超时)。event MPM中,会有一个专门的线程来管理这些keepalive类型的线程,当有真实请求过来的时候,将请求传递给服务线程,执行完毕后,又允许它释放。这样增强了高并发场景下的请求处理能力。

优点:单线程响应多请求,占据更少的内存,高并发下表现更优秀,会有一个专门的线程来管理keep-alive类型的线程,当有真实请求过来的时候,将请求传递给服务线程,执行完毕后,又允许它释放

缺点:没有线程安全控制

1.2.2 Nginx-高性能的web服务端

Nginx是由1994年毕业于俄罗斯国立莫斯科鲍曼科技大学的同学为俄罗斯rambler.ru公司开发的,开发工作最早从2002年开始,第一次公开发布时间是2004年10月4日,版本号是0.1.0,官网地址

Nginx历经十几年的迭代更新(https://nginx/en/CHANGES), 目前功能已经非常完善且运行稳定,另外Nginx的版本分为开发版、稳定版和过期版,Nginx以功能丰富著称,它即可以作为http服务器,也可以作为反向代理服务器或者邮件服务器,能够快速的响应静态网页的请求,支持FastCGI/SSL/Virtual Host/URL Rwrite/Gzip/HTTP Basic Auth/http或者TCP的负载均衡(1.9版本以上且开启stream模块)等功能,并且支持第三方的功能扩展

为什么使用Nginx:
天猫 淘宝 小米 163 京东新浪等一线互联网公司都在用Nginx或者进行二次开发

基于Nginx的访问流程如下:

说明:nginx会根据请求的类型进行动静分离,静态的请求交给存储服务器,动态请求交给MySQL

1.2.3 用户访问体验统计

互联网存在用户速度体验的1-3-10原则,即1秒最优,1-3秒较优,3~10秒比较慢,10秒以上用户无法接受。用户放弃一个产品的代价很低,只是换一个URL而已。

http://baijiahao.baidu/s?id=1643187950686234006&wfr=spider&for=pc #用户体验的重要性
http://www.sohu/a/218426004_573333

全球最大搜索引擎 Google:慢500ms = 20% 将放弃访问。
全球最大的电商零售网站 亚马逊:慢100ms = 1% 将放弃交易

1.2.4:性能影响:

有很多研究都表明,性能对用户的行为有很大的影响:
79%的用户表示不太可能再次打开一个缓慢的网站
47%的用户期望网页能在2秒钟以内加载
40%的用户表示如果加载时间超过三秒钟,就会放弃这个网站
页面加载时间延迟一秒可能导致转换损失7%,页面浏览量减少11%
8秒定律:用户访问一个网站时,如果等待网页打开的时间超过8秒,会有超过30%的用户放弃等待

1.2.4.1:影响用户体验的几个因素:

据说马云在刚开始创业在给客户演示时,打开一个网站花了两个多小时。
https://www.shuimiao/NjHaO/

客户端原因:

  • 客户端硬件配置
  • 客户端网络速率
  • 客户端与服务端距离

服务端原因:

  • 服务端网络速率
  • 服务端硬件配置
  • 服务端架构设计
  • 服务端应用程序工作模式
  • 服务端并发数量
  • 服务端响应文件大小及数量
  • 服务端I/O压力
1.2.4.2 应用程序工作模式:

httpd MPM(Multi-Processing Module,多进程处理模块)模式:

  • prefork:进程模型,两级结构,主进程master负责生成子进程,每个子进程负责响应一个请求
  • worker:线程模型,三级结构,主进程master负责生成子进程,每个子进程负责生成多个线程,每个线程响应一个请求
  • event:线程模型,三级结构,主进程master负责生成子进程,每个子进程生成多个线程,每个线程响应一个请求,但是增加了一个监听线程,用于解决在设置了keep-alived场景下线程的空等待问题。

Nginx(Master+Worker)模式

  • 主进程
  • 工作进程 #直接处理客户的请求
#Centos 7.x目前默认为prefork模式,ubuntu 18.04已经使用event模式
Apache线程验证方式:
[root@localhost ~]# httpd -V #Centos系统
AH00558: httpd: Could not reliably determine the server's fully qualified domain name,using localhost.localdomain. Set the 'ServerName' directive globally to suppress thismessage
Server version: Apache/2.4.6 (CentOS)
Server built:   Aug 8 2019 11:41:18
Server's Module Magic Number: 20120211:24
Server loaded:  APR 1.4.8, APR-UTIL 1.5.2
Compiled using: APR 1.4.8, APR-UTIL 1.5.2
Architecture:   64-bit
Server MPM:     prefork #MPM模式为prefork
threaded: 		no

# ps -ef | grep httpd
root   2757 1    0 04:03 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND
apache 2758 2757 0 04:03 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND
apache 2759 2757 0 04:03 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND
apache 2760 2757 0 04:03 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND
apache 2761 2757 0 04:03 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND
apache 2762 2757 0 04:03 ? 00:00:00 /usr/sbin/httpd -DFOREGROUND
root   2786 2369 0 04:13 pts/0 00:00:00 grep --color=auto httpd

# cat /proc/2760/status
Name: httpd
State: S (sleeping)
..............
Threads: 1
..............

#Ubuntu 18.04.3系统:
root@mq-node1:~# apachectl -V
Server version: Apache/2.4.29 (Ubuntu)
Server built:   2019-09-16T12:58:48
Server's Module Magic Number: 20120211:68
Server loaded:  APR 1.6.3, APR-UTIL 1.6.1
Compiled using: APR 1.6.3, APR-UTIL 1.6.1
Architecture:   64-bit
Server MPM: 	event #MPM模式为event
threaded: 		yes (fixed thread count)
forked: 		yes (variable process count)

# ps -ef | grep apache2
root 	 918 	1 	 0 20:08 ? 	   00:00:00 /usr/sbin/apache2 -k start
www-data 919 	918  0 20:08 ? 	   00:00:00 /usr/sbin/apache2 -k start
www-data 920 	918  0 20:08 ?     00:00:00 /usr/sbin/apache2 -k start
root 	 1202   1172 0 20:12 pts/0 00:00:00 grep --color=auto apache2

# cat /proc/919/status
Name: apache2
Umask: 0022
State: S (sleeping)
..............
Threads: 27
..............
1.2.4.3:服务端I/O:

I/O在计算机中指Input/Output, IOPS (Input/Output Per Second)即每秒的输入输出量(或读写次数),是衡量磁盘性能的主要指标之一。IOPS是指的是在单位时间内系统能处理的I/O请求数量,一般以每秒处理的I/O请求数量为单位,I/O请求通常为读或写数据操作请求。

机械磁盘的寻道时间、旋转延迟和数据传输时间:

  • 寻道时间:是指磁头移动到正确的磁道上所花费的时间,寻道时间越短则I/O处理就越快,目前磁盘的寻道时间一般在3-15毫秒左右。
  • 旋转延迟:是指将磁盘片旋转到数据所在的扇区到磁头下面所花费的时间,旋转延迟取决于磁盘的转速,通常使用磁盘旋转一周所需要时间的1/2之一表示,比如7200转的磁盘平均训传延迟大约为60*1000/7200/2=4.17毫秒,公式的意思为 (每分钟60秒*1000毫秒每秒/7200转每分钟/2),如果是15000转的则为60*1000/15000/2=2毫秒。
  • 数据传输时间:指的是读取到数据后传输数据的时间,主要取决于传输速率,这个值等于数据大小除以传输速率,目前的磁盘接口每秒的传输速度可以达到600MB,因此可以忽略不计。

注意:web服务器千万不要用7200转的机械盘,最低用10000的

范例:

常见的机械磁盘平均寻道时间值:
7200转/分的磁盘平均物理寻道时间:9毫秒
10000转/分的磁盘平均物理寻道时间:6毫秒
15000转/分的磁盘平均物理寻道时间:4毫秒

常见磁盘的平均延迟时间:
7200转的机械盘平均延迟:60\*1000/7200/2 = 4.17ms
10000转的机械盘平均延迟:60\*1000/10000/2 = 3ms
15000转的机械盘平均延迟:60\*1000/15000/2 = 2ms

每秒最大IOPS的计算方法:
7200转的磁盘IOPS计算方式:1000毫秒/(9毫秒的寻道时间+4.17毫秒的平均旋转延迟时间)=1000/13.13=75.9 IOPS
10000转的磁盘的IOPS计算方式:1000毫秒/(6毫秒的寻道时间+3毫秒的平均旋转延迟时间)=1000/9=111 IOPS
15000转的磁盘的IOPS计算方式:15000毫秒/(4毫秒的寻道时间+2毫秒的平均旋转延迟时间)=1000/6=166.6 IOPS 

一次完整的I/O是 用户空间的进程数据与内核空间的内核数据的报文的完整交换过程 ,但是由于内核空间与用户空间是严格隔离的,所以其数据交换过程中不能由用户空间的进程直接调用内核空间的内存数据,而是需要经历一次从内核空间中的内存数据copy到用户空间的进程内存当中,所以简单说 一次 I/O 就是把数据从内核空间中的内存数据复制到用户空间中进程的内存当中的整个过程

而网络通信就是从网络协议栈到用户空间进程的IO,也就是网络IO。

磁盘I/O是进程向内核发起系统调用,请求磁盘上的某个资源比如是文件或者是图片,然后内核通过相应的驱动程序将目标图片加载到内核的内存空间,加载完成之后把数据从内核内存再复制给进程内存,如果是比较大的数据也需要等待时间。

每次IO,都要经由两个阶段

  • 第一步:将数据从磁盘文件先加载至内核内存空间(缓冲区),此步骤需要等待数据准备完成,时间较长
  • 第二步:将数据从内核缓冲区复制到用户空间的进程的内存中,时间较短

1.3 系统 I/O 模型:

1.3.1 同步/ 异步:

关注的是事件处理的消息通信机制,即在等待一件事情的处理结果时,被调用者是否提供完成通知。

同步:synchronous,调用者等待被调用者返回消息后才能继续执行,如果被调用者不提供消息返回则为同步,同步需要调用者主动询问事情是否处理完成。
异步:asynchronous,被调用者通过状态、通知或回调机制主动通知调用者,即异步会主动返回被调用者的状态给调用者。

说明:被调用者通常是内核,调用者就是web服务(Nginx、PHP)

  • 同步:进程发出请求调用后,内核不提供通知机制,即文件IO处理完成后不通知进程,需要进程自己去问内核是否处理完成。
  • 异步:进程发出请求调用后,内核会在调用处理完成后返回调用结果给进程,Nginx是异步的。

1.3.2 阻塞 / 非阻塞:

关注调用者在等待结果返回之前所处的状态

  • 阻塞:blocking,指IO操作需要彻底完成后才返回到用户空间,调用结果返回之前,调用者被挂起,干不了别的事情。
  • 非阻塞:nonblocking,指IO操作被调用后立即返回给用户一个状态值,无需等到IO操作彻底完成,最终的调用结果返回之前,调用者不会被挂起,可以去做别的事情。

1.3.3 系统IO模型组合(面试题

以我去吃饭为例:我点了10个包子

  • 同步与异步:

    我点包子之后厨师是否告诉我:

    • 同步:厨师做好包子后会放到指定位置,但是做好包子之前需要自己一次次去看包子做好没有,厨师不会在包子做好之后通知我。
    • 异步:厨师做好包子后告诉我包子做好放哪了。
  • 阻塞与非阻塞::

    我点包子后的状态:

    • 阻塞:在厨师做包子期间一直在包子盘子前面等着,不能干别的事情。
    • 非阻塞:点完包子就可以去干别的事情,比如去逛逛街或者买买买。
  • IO模型组合:

    • 同步阻塞:我点完包子后不能去做别的事情,而且不知道包子有没有做好,需要自己一直等着并一次次的问厨师做好没有。
    • 同步非阻塞:点完包子后可以去做别的事情,但是不能长时间做别的事情,因为我还是不知道包子有没有做好,也要自己一直等着并一次次的问厨师做好没有,只能抽空做点别的。
    • 异步阻塞:我点完包子后不能去走做别的事情,但是厨师在做好包子后会告诉我,也就是我不用再一次次为厨师包子有没有做好了。
    • 异步非阻塞:我点完包子后可以做别的事情,而且可以一直在做别的去事情,因为厨师在做好包子后会告诉我。

1.4 网络I/O模型(了解)

阻塞型、非阻塞型、复用型、信号驱动型、异步

1.4.1 同步阻塞型IO模型(blocking IO):

阻塞IO模型是最简单的IO模型,用户线程在内核进行IO操作时被阻塞

  • 用户请求到达系统服务进程,然后进程通过系统调用read向内核发起IO读操作,即将用户请求由用户空间转到内核空间,内核接收到IO请求后开始从磁盘读取文件到内核内存,即在等用户请求的文件从磁盘到达内核内存后,然后将接收的数据拷贝到用户空间,然后完成read操作。
  • 用户请求需要等待内核将数据读取到进程内存后,处理用户的进程才可以继续处理该请求,整个IO请求的过程中,请求进程是被阻塞的,这导致进程在发起IO请求时,不能做任何事情,而且对CPU的资源利用率不够。

优点:程序简单,在阻塞等待数据期间进程挂起,基本不会占用 CPU 资源

缺点:每个连接需要独立的进程单独处理,当并发请求量大时为了维护程序,内存、进程切换开销较大,apache的preforck使用的是这种模式。

同步阻塞:程序向内核发送IO请求后一直等待内核响应,如果内核处理请求的IO操作不能立即返回,则进程将一直等待并不再接受新的请求,并由进程轮训查看IO是否完成,完成后进程将IO结果返回给Client,在IO没有返回期间进程不能接受其他客户的请求,而且是有进程自己去查看IO是否完成,这种方式简单,但是比较慢,用的比较少。

1.4.2 同步非阻塞型I/O模型(nonblocking IO):

用户请求进程向内核发起IO请求时立即返回,但并未读取到任何数据,进程需要不断地发起IO请求,直到数据到达进程空间的内存后,才真正读取到数据并继续执行,即前期需要一次次 “轮询”去查看请求是否数据是否准备报,但是此机制存在两个问题:1.如果有大量文件描述符都要等,那么就得一个一个的read,这会带来大量的Context Switch(read是系统调用,每调用一次就得在用户态和核心态切换一次)2.轮询的时间不好把握,这里是要猜多久之后数据才能到,等待时间设的太长,程序响应延迟就过大,但是设的太短,就会造成过于频繁的重试,干耗CPU而已,所以是比较浪费CPU的方式,因此一般很少直接使用这种模型,而是在其他IO模型中使用非阻塞IO这一特性。

同步非阻塞:应用进程向内核发送请IO求后一直等待内核响应,如果内核处理请求的IO操作不能立即返回IO结果,进程将不再等待,而且继续处理其他请求,但是仍然需要进程隔一段时间就要查看内核IO是否完成。

1.4.3:IO多路复用型(IO multiplexing):

IO multiplexing就是我们说的select,poll,epoll,有些地方也称这种IO方式为event driven IO(事件驱动IO),select/poll/epoll的好处就在于单个process就可以同时处理多个网络连接的IO。它的基本原理就是select,poll,epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程。

当用户进程调用了select,那么整个进程会被block,而同时,kernel会“监视”所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回,这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。

Apache prefork是此模式的主进程+多进程/单线程+select,work是主进程+多进程/多线程+poll模式

1.4.4:信号驱动式IO(signal-driven IO):

信号驱动IO:signal-driven I/O

用户进程可以通过sigaction系统调用注册一个信号处理程序,然后进程可以继续向下执行,当有IO操作准备就绪时,由内核通知触发一个SIGIO信号处理程序执行,然后将用户进程所需要的数据从内核空间拷贝到用户空间,此模型的优势在于等待数据报到达期间进程不被阻塞,进程可以继续执行,只要等待来自信号处理函数的通知。

优点:进程没有在等待数据时被阻塞,内核直接返回调用接收信号,不影响进程继续处理其他请求因此可以提高资源的利用率

缺点:信号 I/O 在大量 IO 操作时可能会因为信号队列溢出导致没法通知

异步阻塞:进程向内核发送IO调用后,不用等待内核响应,可以继续接受其他请求,内核收到进程请求后进行的IO如果不能立即返回,就由内核等待结果,直到IO完成后内核再通知进程,apache event模型就是主进程+多进程/多线程+信号驱动

1.4.5:异步(非阻塞) IO(asynchronous IO):

相对于同步IO,异步IO不是顺序执行,用户进程进行aio_read系统调用之后,无论内核数据是否准备好,都会直接返回给用户进程,然后用户态进程可以去做别的事情,等到socket数据准备好了,内核直接复制数据给进程,然后从内核向进程发送通知,异步非阻塞IO的两个阶段,进程都是非阻塞的。

Linux提供了AIO库函数实现异步,但是用的很少,目前有很多开源的异步IO库,例如libevent、libev、libuv等,异步过程如下图所示:

异步非阻塞:程序进程向内核发送IO调用后,不用等待内核响应,可以继续接受其他请求,内核调用的IO如果不能立即返回,内核会继续处理其他事物,直到IO完成后将结果通知给内核,内核在将IO完成的结果返回给进程,期间进程可以接受新的请求,内核也可以处理新的事物,因此相互不影响,可以实现较大的同时并实现较高的IO复用,因此异步非阻塞使用最多的一种通信方式,nginx就是是异步非阻塞模型

1.4.6:IO对比:

这五种网络 I/O 模型中,越往后,阻塞越少,理论上效率也是最优前四种属于同步 I/O,因为其中真正的 I/O 操作(recvfrom)将阻塞进程/线程,只有异步 I/O 模型才与 POSIX 定义的异步 I/O 相匹配。

1.4.7:实现方式:

Nginx支持在多种不同的操作系统实现不同的事件驱动模型,但是其在不同的操作系统甚至是不同的系统版本上面的实现方式不尽相同,主要有以下实现方式:

  1. select:(用的较少

    select库是在linux和windows平台都基本支持的 事件驱动模型库,并且在接口的定义也基本相同,只是部分参数的含义略有差异,最大并发限制1024,是最早期的事件驱动模型。

  2. poll :(不推荐使用,降低性能

    在Linux 的基本驱动模型,windows不支持此驱动模型,是select的升级版,取消了最大的并发限制,在编译nginx的时候可以使用–with-poll_module和–without-poll_module这两个指定是否编译select库。

  3. epoll:

    epoll是库是Nginx服务器支持的最高性能的事件驱动库之一,是公认的非常优秀的事件驱动模型,它和select和poll有很大的区别,epoll是poll的升级版,但是与poll的效率有很大的区别.

    epoll的处理方式是创建一个待处理的事件列表,然后把这个列表发给内核,返回的时候在去轮训检查这个表,以判断事件是否发生,epoll支持一个进程打开的最大事件描述符的上限是系统可以打开的文件的最大数,同时epoll库的IO效率不随描述符数目增加而线性下降,因为它只会对内核上报的“活跃”的描述符进行操作。

  4. rtsig:

    不是一个常用事件驱动,最大队列1024,不是很常用

  5. kqueue

    用于支持BSD系列平台的高效事件驱动模型,主要用在FreeBSD 4.1及以上版本、OpenBSD 2.0级以上版本,NetBSD级以上版本及Mac OS X 平台上,该模型也是poll库的变种,因此和epoll没有本质上的区别,都是通过避免轮训操作提供效率。

  6. /dev/poll:

    用于支持unix衍生平台的高效事件驱动模型,主要在Solaris 平台、HP/UX,该模型是sun公司在开发Solaris系列

    平台的时候提出的用于完成事件驱动机制的方案,它使用了虚拟的/dev/poll设备,开发人员将要见识的文件描述符加入这个设备,然后通过ioctl()调用来获取事件通知,因此运行在以上系列平台的时候请使用/dev/poll事件驱动机制。

  7. eventport:

    该方案也是sun公司在开发Solaris的时候提出的事件驱动库,只是Solaris 10以上的版本,该驱动库看防止内核崩溃等情况的发生。

  8. Iocp:

    Windows系统上的实现方式,对应第5种(异步I/O)模型。

1.4.8:常用模型汇总:
\selectpollepoll
操作方式遍历遍历回调
底层实现数组链表哈希表
IO效率每次调用都进行线性遍历,时间复杂度为O(n)每次调用都进行线性遍历,时间复杂度为O(n)时间通知方式,每当fd就绪。系统注册的回调函数就会被调用,将就绪fd放到rdllist里面,时间复杂度为O(1)
最大连接数1024(x86)或2048(x64)无上限无上限
fd拷贝每次调用select,都需要把fd集合从用户态拷贝到内核态每次调用poll,都需要把fd集合从用户态拷贝到内核态调用epoll_ctl时拷贝进内核并保存,之后每次epoll_wait不拷贝

说明:O(1) 表示算法的运行时间为常量,即无论是1000个还是10000个,耗费时间一样

O(n): 表示该算法是线性算法

fd表示事件描述符

1.4.9:常用模型通知对比

水平触发-- 多次通知,需要关心数据是否取完,即数据取走之后即不再通知进程,以避免重复多次无效通知,通知效率较低。

边缘触发-- 一次通知,需要关心数据是否取走,即只通知一次怎么保证数据被进程成功取走了,以避免数据丢失,通知效率较高。

Select

POSIX所规定,目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点,本质上是通过设置或者检查存放fd标志位的数据结构来进行下一步处理

缺点

  • 单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024,可以通过修改宏定义FD_SETSIZE,再重新编译内核实现,但是这样也会造成效率的降低。
  • 单个进程可监视的fd数量被限制,默认是1024,修改此值需要重新编译内核。
  • 对socket是线性扫描,即采用轮询的方法,效率较低。
  • select 采取了内存拷贝方法来实现内核将 FD 消息通知给用户空间,这样一个用来存放大量fd的数据结构,这样会使得用户空间和内核空间在传递该结构时复制开销大。

poll

  • 本质上和select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态。
  • 其没有最大连接数的限制,原因是它是基于链表来存储的。
  • 大量的fd的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意义。
  • poll特点是“水平触发”,如果报告了fd后,没有被处理,那么下次poll时会再次报告该fd。

epoll

在Linux 2.6内核中提出的select和poll的增强版本。
支持水平触发LT和边缘触发ET,最大的特点在于边缘触发,它只告诉进程哪些fd刚刚变为就需态,并且只会通知一次
使用“事件”的就绪通知方式,通过epoll_ctl注册fd,一旦该fd就绪,内核就会采用类似callback的回调机制来激活该fd,epoll_wait便可以收到通知 。

优点:

  • 没有最大并发连接的限制:能打开的FD的上限远大于1024(1G的内存能监听约10万个端口),具体查看/proc/sys/fs/file-max,此值和系统内存大小相关
  • 效率提升:非轮询的方式,不会随着FD数目的增加而效率下降;只有活跃可用的FD才会调用callback函数,即epoll
  • 最大的优点就在于它只管理“活跃”的连接,而跟连接总数无关
  • 内存拷贝,利用mmap(Memory Mapping)加速与内核空间的消息传递;即epoll使用mmap减少复制开销
1.4.10:MMAP介绍:

mmap(memory mapping)系统调用使得进程之间通过映射同一个普通文件实现共享内存,普通文件被映射到进程地址空间后,进程可以像访问普通内存一样对文件进行访问。

1.4.10.1:传统方式copy数据:

1.4.10.2:mmap方式:

二 Nginx基础

Nginx:engine X ,2002年开始开发,2004年开源,2019年3月11日,Nginx公司被F5 Networks以6.7亿美元收购,Nginx官网:http://nginx,Nginx 商业版为Nginx Plus:https://www.nginx/products/nginx/

Nginx 则是免费的、开源的、高性能的HTTP和反向代理服务器、邮件代理服务器、以及TCP/UDP代理服务器,解决C10K问题(10K Connections),http://www.ideawu/blog/archives/740.html

nginx的其它的二次发行版:

  • Tengine:由淘宝网发起的Web服务器项目。它在Nginx的基础上,针对大访问量网站的需求,添加了很多高级功能和特性,Tengine的性能和稳定性已经在大型的网站如淘宝网,天猫商城等得到了很好的检验,它的最终目标是打造一个高效、稳定、安全、易用的Web平台,从2011年12月开始,Tengine成为一个开源项目,官网 http://tengine.taobao/
  • OpenResty:基于 Nginx 与 Lua 语言的高性能 Web 平台, 章亦春团队开发,官网:http://openresty/cn/

2.1 Nginx功能介绍

  • 静态的web资源服务器html,图片,js,css,txt等静态资源

  • 结合FastCGI/uWSGI/SCGI等协议反向代理动态资源请求

  • http/https协议的反向代理

  • imap4/pop3协议的反向代理

  • tcp/udp协议的请求转发(反向代理)

2.1.1 基础特性

特性

  • 模块化设计,较好的扩展性
  • 高可靠性(很少宕机)
  • 支持热部署:不停机更新配置文件,升级版本,更换日志文件
  • 低内存消耗:10000个keep-alive连接模式下的非活动连接,仅需2.5M内存
  • event-driven,aio,mmap,sendfile

基本功能

  • 静态资源的web服务器
  • http协议反向代理服务器
  • pop3/imap4协议反向代理服务器
  • FastCGI(LNMP),uWSGI(python)等协议
  • 模块化(非DSO),如zip,SSL模块
2.1.2 和web服务相关的功能
  • 虚拟主机(server)
  • 支持 keep-alive 和管道连接(利用一个连接做多次请求)
  • 访问日志(支持基于日志缓冲提高其性能)
  • url rewirte
  • 路径别名
  • 基于IP及用户的访问控制
  • 支持速率限制及并发数限制
  • 重新配置和在线升级而无须中断客户的工作进程

2.2 Nginx组织结构

web请求处理机制:

  1. 多进程方式:服务器每接收到一个客户端请求就有服务器的主进程生成一个子进程响应客户端,直到用户关闭连接,这样的优势是处理速度快,各子进程之间相互独立,但是如果访问过大会导致服务器资源耗尽而无法提供请求。

  2. 多线程方式:与多进程方式类似,但是每收到一个客户端请求会有服务进程派生出一个线程来个客户方进行交互,一个线程的开销远远小于一个进程,因此多线程方式在很大程度减轻了web服务器对系统资源的要求,但是多线程也有自己的缺点,即当多个线程位于同一个进程内工作的时候,可以相互访问同样的内存地址空间,所以他们相互影响,另外一旦主进程挂掉则所有子线程都不能工作了,IIS服务器使用了多线程的方1式,需要间隔一段时间就重启一次才能稳定。

2.2.1 组织模型

Nginx是多进程组织模型,而且是一个由Master主进程和Worker工作进程组成。

主进程(master process)的功能

  • 读取Nginx 配置文件并验证其有效性和正确性
  • 建立、绑定和关闭socket连接
  • 按照配置生成、管理和结束工作进程
  • 接受外界指令,比如重启、升级及退出服务器等指令
  • 不中断服务,实现平滑升级,重启服务并应用新的配置
  • 开启日志文件,获取文件描述符
  • 不中断服务,实现平滑升级,升级失败进行回滚处理
  • 编译和处理perl脚本

工作进程(woker process)的功能

  • 接受处理客户的请求
  • 将请求依次送入各个功能模块进行处理
  • IO调用,获取响应数据
  • 与后端服务器通信,接收后端服务器的处理结果
  • 缓存数据,访问缓存索引,查询和调用缓存数据
  • 发送请求结果,响应客户的请求
  • 接收主程序指令,比如重启、升级和退出等

2.2.2:进程间通信:

工作进程是有主进程生成的,主进程使用fork()函数,在Nginx服务器启动过程中主进程根据配置文件决定启动工作进程的数量,然后建立一张全局的工作表用于存放当前未退出的所有的工作进程,主进程生成工作进程后会将新生成的工作进程加入到工作进程表中,并建立一个单向的管道并将其传递给工作进程,该管道与普通的管道不同,它是由主进程指向工作进程的单向通道,包含了主进程向工作进程发出的指令、工作进程ID、工作进程在工作进程表中的索引和必要的文件描述符等信息。

主进程与外界通过信号机制进行通信,当接收到需要处理的信号时,它通过管道向相关的工作进程发送正确的指令,每个工作进程都有能力捕获管道中的可读事件,当管道中有可读事件的时候,工作进程就会从管道中读取并解析指令,然后采取相应的执行动作,这样就完成了主进程与工作进程的交互。

说明

  1. 工作进程之间的通信原理基本上和主进程与工作进程之间的通信是一样的,只要工作进程之间能够取得彼此的信息,建立管道即可通信,但是由于工作进程之间是完全隔离的,因此一个进程想要知道另外一个进程的状态信息就只能通过主进程来设置了。
  2. 为了实现工作进程之间的交互,主进程在生成工作进程之后,在工作进程表中进行遍历,将该新进程的ID以及针对该进程建立的管道句柄传递给工作进程中的其他进程,为工作进程之间的通信做准备,当工作进程1向工作进程2发送指令的时候,首先在主进程给它的其他工作进程工作信息中找到2的进程ID,然后将正确的指令写入指向进程2的管道,工作进程2捕获到管道中的事件后,解析指令并进行相关操作,这样就完成了工作进程之间的通信。
  3. 用户的请求只能被一个进程处理一次

2.3:Nginx模块介绍:

  1. 核心模块:是 Nginx 服务器正常运行 必不可少 的模块,提供 错误日志记录 、 配置文件解析 、 事件驱动机制 、进程管理 等核心功能

  2. 标准HTTP模块:提供 HTTP 协议解析相关的功能,比如: 端口配置 、 网页编码设置 、 HTTP响应头设置 等等

  3. 可选HTTP模块:主要用于扩展标准的 HTTP 功能,让 Nginx 能处理一些特殊的服务,比如: Flash 多媒体传输 、解析 GeoIP 请求、 网络传输压缩 、 安全协议 SSL 支持

  4. 邮件服务模块:主要用于支持 Nginx 的 邮件服务 ,包括对 POP3 协议、 IMAP 协议和 SMTP协议的支持 (基本用不上

  5. 第三方模块:是为了扩展 Nginx 服务器应用,完成开发者自定义功能,比如: Json 支持、 Lua 支持等

nginx高度模块化,但其模块早期不支持DSO机制;1.9.11版本支持动态装载和卸载

模块分类:

核心模块:core module
标准模块:
HTTP 模块: ngx_http_*
	HTTP Core modules 默认功能
	HTTP Optional modules 需编译时指定
Mail 模块 ngx_mail_*
Stream 模块 ngx_stream_*
第三方模块

2.4 Nginx安装

Nginx的安装版本分为Mainline version(主要开发版本,其实就是还处于开发版)、Stable version(当前最新稳定版)和Legacy versions(旧的稳定版)

Nginx安装可以使用yum或源码安装,但是推荐使用源码,一是yum的版本比较旧,二是编译安装可以更方便自定义相关路径,三是使用源码编译可以自定义相关功能,更方便业务的上的使用,源码安装需要提前准备标准的编译器

GCC的全称是(GNU Compiler collection),其有GNU开发,并以GPL即LGPL许可,是自由的类UNIX即苹果电脑Mac OS X操作系统的标准编译器,因为GCC原本只能处理C语言,所以原名为GNU C语言编译器,后来得到快速发展,可以处理C++,Fortran,pascal,objective-C,java以及Ada等其他语言,此外还需要Automake工具,以完成自动创建Makefile的工作,Nginx的一些模块需要依赖第三方库,比如pcre(支持rewrite),zlib(支持gzip模块)和openssl(支持ssl模块)等。

2.4.1 Nginx yum安装

需要提前配置好epel源

官方提供的仓库:http://nginx/en/linux_packages.html#RHEL-CentOS

[root@s1 ~]# yum install epel-release -y

#或者使用官方提供的仓库,里面有新版的nginx
[root@Centos7 ~]#vim /etc/yum.repos.d/nginx.repo
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx/keys/nginx_signing.key
module_hotfixes=true

[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx/keys/nginx_signing.key
module_hotfixes=true

[root@Centos7 ~]# yum install -y nginx
[root@Centos7 ~]# rpm -ql nginx
/etc/logrotate.d/nginx
/etc/nginx/fastcgi.conf
/etc/nginx/fastcgi.conf.default
/etc/nginx/fastcgi_params
/etc/nginx/fastcgi_params.default
/etc/nginx/koi-utf
/etc/nginx/koi-win
/etc/nginx/mime.types
/etc/nginx/mime.types.default
/etc/nginx/nginx.conf
/etc/nginx/nginx.conf.default
/etc/nginx/scgi_params
/etc/nginx/scgi_params.default
/etc/nginx/uwsgi_params
/etc/nginx/uwsgi_params.default
/etc/nginx/win-utf
/usr/bin/nginx-upgrade
/usr/lib/systemd/system/nginx.service
/usr/lib64/nginx/modules
/usr/sbin/nginx
/usr/share/doc/nginx-1.18.0
.................
/var/lib/nginx
/var/lib/nginx/tmp
/var/log/nginx

[root@Centos7 ~]# which nginx
/usr/sbin/nginx
2.4.1.1:检查安装:

查看nginx安装包信息

[root@Centos7 ~]#rpm -qi nginx
Name        : nginx
Epoch       : 1
Version     : 1.16.1
Release     : 1.el7
Architecture: x86_64
Install Date: Mon 13 Jul 2020 10:37:26 PM CST
Group       : Unspecified
Size        : 1689960
License     : BSD
Signature   : RSA/SHA256, Fri 04 Oct 2019 06:38:33 AM CST, Key ID 6a2faea2352c64e5
Source RPM  : nginx-1.16.1-1.el7.src.rpm
Build Date  : Thu 03 Oct 2019 01:15:40 PM CST
Build Host  : buildvm-13.phx2.fedoraproject
Relocations : (not relocatable)
Packager    : Fedora Project
Vendor      : Fedora Project
URL         : http://nginx/
Bug URL     : https://bugz.fedoraproject/nginx
Summary     : A high performance web server and reverse proxy server
Description :
Nginx is a web server and a reverse proxy server for HTTP, SMTP, POP3 and IMAP protocols, with a strong focus on high concurrency, performance and low memory usage.
2.4.1.2 查看帮助

使用安装完成的二进制文件nginx

[root@Centos7 ~]# nginx -h
nginx version: nginx/1.16.1
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 #测试配置文件是否异常
 -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 #发送信号
 -p prefix     : set prefix path (default: /usr/share/nginx/) #指定Nginx 目录
 -c filename   : set configuration file (default: /etc/nginx/nginx.conf) #配置文件路径
 -g directives : set global directives out of configuration file #设置全局指令
2.4.1.3 验证Nginx
[root@Centos7 ~]#nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@Centos7 ~]#nginx -V
nginx version: nginx/1.16.1
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC) 
built with OpenSSL 1.0.2k-fips  26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/usr/share/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 --http-client-body-temp-path=/var/lib/nginx/tmp/client_body --http-proxy-temp-path=/var/lib/nginx/tmp/proxy --http-fastcgi-temp-path=/var/lib/nginx/tmp/fastcgi --http-uwsgi-temp-path=/var/lib/nginx/tmp/uwsgi --http-scgi-temp-path=/var/lib/nginx/tmp/scgi --pid-path=/run/nginx.pid --lock-path=/run/lock/subsys/nginx --user=nginx --group=nginx --with-file-aio --with-ipv6 --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-stream_ssl_preread_module --with-http_addition_module --with-http_xslt_module=dynamic --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_degradation_module --with-http_slice_module --with-http_stub_status_module --with-http_perl_module=dynamic --with-http_auth_request_module --with-mail=dynamic --with-mail_ssl_module --with-pcre --with-pcre-jit --with-stream=dynamic --with-stream_ssl_module --with-google_perftools_module --with-debug --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -m64 -mtune=generic' --with-ld-opt='-Wl,-z,relro -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -Wl,-E'
2.4.1.4 Nginx启动脚本
[root@s1 ~]# cat /usr/lib/systemd/system/nginx.service
[Unit]
Description=The nginx HTTP and reverse proxy server
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
PIDFile=/run/nginx.pid
# Nginx will fail to start if /run/nginx.pid already exists but has the wrong
# SELinux context. This might happen when running `nginx -t` from the cmdline.
# https://bugzilla.redhat/show_bug.cgi?id=1268621
ExecStartPre=/usr/bin/rm -f /run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
KillSignal=SIGQUIT
TimeoutStopSec=5
KillMode=process
PrivateTmp=true

[Install]
WantedBy=multi-user.target
2.4.1.5 配置Nginx

默认配置文件:/etc/nginx/nginx.conf,,默认配置如下:

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
    worker_connections 1024;
}
http {
    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;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;
    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;
    include /etc/nginx/conf.d/*.conf;
    server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  _;
        root         /usr/share/nginx/html;
        include /etc/nginx/default.d/*.conf;
        location / {
        }
        error_page 404 /404.html;
            location = /40x.html {
        }
        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }
}
2.4.1.6 启动Nginx
[root@Centos7 ~]#systemctl start nginx
[root@Centos7 ~]#systemctl status nginx
● nginx.service - The nginx HTTP and reverse proxy server
   Loaded: loaded (/usr/lib/systemd/system/nginx.service; disabled; vendor preset: disabled)
   Active: active (running) since Mon 2020-07-13 22:43:52 CST; 8s ago
  Process: 3141 ExecStart=/usr/sbin/nginx (code=exited, status=0/SUCCESS)
  Process: 3138 ExecStartPre=/usr/sbin/nginx -t (code=exited, status=0/SUCCESS)
  Process: 3136 ExecStartPre=/usr/bin/rm -f /run/nginx.pid (code=exited, status=0/SUCCESS)
 Main PID: 3143 (nginx)
   CGroup: /system.slice/nginx.service
           ├─3143 nginx: master process /usr/sbin/nginx
           ├─3144 nginx: worker process
           └─3145 nginx: worker process

Jul 13 22:43:52 Centos7.8 systemd[1]: Starting The nginx HTTP and reverse proxy server...
Jul 13 22:43:52 Centos7.8 nginx[3138]: nginx: the configuration file /etc/nginx/nginx.conf ... ok
Jul 13 22:43:52 Centos7.8 nginx[3138]: nginx: configuration file /etc/nginx/nginx.conf test...ful
Jul 13 22:43:52 Centos7.8 systemd[1]: Started The nginx HTTP and reverse proxy server.
Hint: Some lines were ellipsized, use -l to show in full.

[root@Centos7 ~]#ps -ef | grep nginx
root       3143      1  0 22:43 ?        00:00:00 nginx: master process /usr/sbin/nginx
nginx      3144   3143  0 22:43 ?        00:00:00 nginx: worker process
nginx      3145   3143  0 22:43 ?        00:00:00 nginx: worker process
root       3149   3006  0 22:44 pts/1    00:00:00 grep --color=auto nginx
2.4.1.7 访问Nginx

2.4.2 Nginx 编译安装

准备编译安装的基础环境:

[root@Centos7 ~]# yum install -y vim lrzsz tree screen psmisc lsof tcpdump wget ntpdate gcc gcc-c++ glibc glibc-devel pcre pcre-devel openssl openssl-devel systemd-devel net-tools iotop bc zip unzip zlib-devel bash-completion nfs-utils automake libxml2 libxml2-devel libxslt libxslt-devel perl perl-ExtUtils-Embed

说明

  • gcc为GNU Compiler Collection的缩写,可以编译C和C++源代码等,它是GNU开发的C和C++以及其他很多种语言的编译器(最早的时候只能编译C,后来很快进化成一个编译多种语言的集合,如Fortran、Pascal、ObjectiveC、Java、Ada、 Go等。)

    gcc 在编译C++源代码的阶段,只能编译 C++ 源文件,而不能自动和 C++ 程序使用的库链接(编译过程分为编译、链接两个阶段,注意不要和可执行文件这个概念搞混,相对可执行文件来说有三个重要的概念:编译(compile)、链接(link)、加载(load)。源程序文件被编译成目标文件,多个目标文件连同库被链接成一个最终的可执行文件,可执行文件被加载到内存中运行)。因此,通常使用 g++ 命令来完成 C++ 程序的编译和连接,该程序会自动调用 gcc 实现编译。

  • gcc-c++也能编译C源代码,只不过把会把它当成C++源代码,后缀为.c的,gcc把它当作是C程序,而g++当作是c++程序;后缀为.cpp的,两者都会认为是c++程序,注意,虽然c++是c的超集,但是两者对语法的要求是有区别的。

  • automake是一个从Makefile.am文件自动生成Makefile.in的工具。为了生成Makefile.in,automake还需用到perl,由于automake创建的发布完全遵循GNU标准,所以在创建中不需要perl。libtool是一款方便生成各种程序库的工具。

  • pcre pcre-devel:在Nginx编译需要 PCRE(Perl Compatible Regular Expression),因为Nginx 的Rewrite模块和HTTP 核心模块会使用到PCRE正则表达式语法。

  • zlip zlib-devel:nginx启用压缩功能的时候,需要此模块的支持。

  • openssl openssl-devel:开启SSL的时候需要此模块的支持。

2.4.2.1 安装Nginx

官方源码包下载地址:
https://nginx/en/download.html

[root@Centos7 ~]# cd /usr/local/src/
[root@Centos7 src]# wget https://nginx/download/nginx-1.16.1.tar.gz
[root@Centos7 src]# tar xf nginx-1.18.0.tar.gz
[root@Centos7 src]# cd nginx-1.18.0/

编译是为了检查系统环境是否符合编译安装的要求,比如是否有gcc编译工具,是否支持编译参数当中的模块,并根据开启的参数等生成Makefile文件为下一步做准备:
[root@Centos7 nginx-1.18.0]#./configure --prefix=/apps/nginx \
--user=nginx \
--group=nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_stub_status_module \
--with-http_gzip_static_module \
--with-pcre \
--with-stream \
--with-stream_ssl_module \
--with-stream_realip_module

[root@Centos7 nginx-1.18.0]# make #编译步骤,根据Makefile文件生成相应的模块
[root@Centos7 nginx-1.18.0]# make install #创建目录,并将生成的模块和文件复制到相应的目录:
[root@Centos7 nginx-1.18.0]# useradd nginx -s /sbin/nologin -u 2000 #以普通用户启动nginx
[root@Centos7 nginx-1.18.0]# chown nginx.nginx -R /apps/nginx/

#说明:configure是一个shell脚本文件,在脚本中传递一些参数,来编译程序
[root@Centos7 nginx-1.18.0]#file configure 
configure: POSIX shell script, ASCII text executable

[root@Centos7 ~]#/apps/nginx/sbin/nginx -h
nginx version: nginx/1.18.0
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   #nginx迁移或扩容时需要知道之前的编译参数,此选项很有用
  -t            : test configuration and exit  #测试配置并退出,常用选项
  -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 #发送信号(启动之后 )
  -p prefix     : set prefix path (default: /apps/nginx/)
  -c filename   : set configuration file (default: conf/nginx.conf)
  -g directives : set global directives out of configuration file #在配置文件以外设置一个全局指令,docker中会使用
  
#可以创建软连接
ln -sv /apps/nginx/sbin/nginx /usr/bin/

reload之后的效果:

备注:nginx完成安装以后,有四个主要的目录

  • conf:该目录中保存了nginx所有的配置文件,其中nginx.conf是nginx服务器的最核心最主要的配置文件,其他的.conf则是用来配置nginx相关的功能的,例如fastcgi功能使用的是fastcgi.conf和fastcgi_params两个文件,配置文件一般都有个样板配置文件,是文件名.default结尾,使用的使用将其复制为并将default去掉即可。
  • html:该目录中保存了nginx服务器的web文件,但是可以更改为其他目录保存web文件,另外还有一个50x的web文件是默认的错误页面提示页面。
  • logs:该目录用来保存nginx服务器的访问日志错误日志等日志,logs目录可以放在其他路径,比如/var/logs/nginx里面。
  • sbin:该目录用来保存nginx二进制启动脚本,可以接受不同的参数以实现不同的功能。
2.4.2.2 验证版本及编译参数
[root@Centos7 nginx-1.18.0]# /apps/nginx/sbin/nginx -V
nginx version: nginx/1.18.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC)
built with OpenSSL 1.0.2k-fips 26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/apps/nginx --user=nginx --group=nginx --withhttp_ssl_module --with-http_v2_module --with-http_realip_module --withhttp_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module
2.4.2.3 访问编译安装的nginx web界面

2.4.2.4 创建Nginx自启动脚本

Nginx 1.16.1

[root@Centos7 ~]# cat /usr/lib/systemd/system/nginx.service
[Unit]
Description=The nginx HTTP and reverse proxy server
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
PIDFile=/run/nginx.pid
# Nginx will fail to start if /run/nginx.pid already exists but has the wrong
# SELinux context. This might happen when running `nginx -t` from the cmdline.
# https://bugzilla.redhat/show_bug.cgi?id=1268621
ExecStartPre=/usr/bin/rm -f /run/nginx.pid
ExecStartPre=/apps/nginx/sbin/nginx -t
ExecStart=/apps/nginx/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
KillSignal=SIGQUIT
TimeoutStopSec=5
KillMode=process
PrivateTmp=true

[Install]
WantedBy=multi-user.target

Nginx 1.18.0

[root@Centos7 ~]#cat /lib/systemd/system/nginx.service
[Unit]
Description=nginx - high performance web server
Documentation=http://nginx/en/docs/
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

[Service]
Type=forking
PIDFile=/apps/nginx/run/nginx.pid
ExecStart=/apps/nginx/sbin/nginx -c /apps/nginx/conf/nginx.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID

[Install]
WantedBy=multi-user.target

#同时也要修改nginx的默认配置文件
[root@Centos7 ~]#vim /apps/nginx/conf/nginx.conf
pid        /apps/nginx/run/nginx.pid;
#创建pid存放目录
[root@Centos7 ~]#mkdir /apps/nginx/run/ -p
2.4.2.5 验证Nginx自启动脚本
[root@Centos7 nginx-1.18.0]# systemctl daemon-reload
[root@Centos7 nginx-1.18.0]# systemctl start nginx
[root@Centos7 nginx-1.18.0]# systemctl enable nginx
Created symlink from /etc/systemd/system/multi-user.target.wants/nginx.service to
/usr/lib/systemd/system/nginx.service.

[root@Centos7 nginx-1.18.0]# systemctl status nginx
● nginx.service - nginx - high performance web server
   Loaded: loaded (/usr/lib/systemd/system/nginx.service; disabled; vendor preset: disabled)
   Active: active (running) since Tue 2020-07-14 15:20:35 CST; 32s ago
     Docs: http://nginx/en/docs/
  Process: 5048 ExecStart=/apps/nginx/sbin/nginx -c /apps/nginx/conf/nginx.conf (code=exited, status=0/SUCCESS)
 Main PID: 5049 (nginx)
   CGroup: /system.slice/nginx.service
           ├─5049 nginx: master process /apps/nginx/sbin/nginx -c /apps/nginx/conf/nginx.conf
           └─5050 nginx: worker process

Jul 14 15:20:35 Centos7.8 systemd[1]: Starting nginx - high performance web server...
Jul 14 15:20:35 Centos7.8 systemd[1]: Started nginx - high performance web server.

nginx常见问题

  1. 端口占用

  2. 目录和文件不存在

  3. 权限错误

  4. 配置文件错误

    • 服务的启动错误日志

    • 缩进(yaml)

  5. 系统环境

    • 模块缺少

问题排错

重启虚拟机后,再次重启nginx会报错: nginx: [error] open() “/var/run/nginx/nginx.pid” failed (2: No such file or directory)

问题原因:

提示信息说明在 /var/run/nginx/ 目录下找不到 nginx.pid 文件,解决方式有两种:

  • 第一种方式:创建默认目录 /var/run/nginx/

  • 第二种方式:修改 nginx.conf 文件,指定 pid文件 所在目录

2.5.2.6 配置Nginx

Nginx的配置文件的组成部分:
主配置文件:nginx.conf,子配置文件 include conf.d/*.conf

fastcgi, uwsgi,scgi等协议相关的配置文件
mime.types:支持的mime类型,MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型,MIME消息能包含文本、图像、音频、视频以及其他应用程序专用的数据,是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。

Nginx主配置文件的配置指令方式:
directive value [value2 ...];
注意:
(1) 指令必须以分号结尾
(2) 支持使用配置变量
	内建变量:由Nginx模块引入,可直接引用
	自定义变量:由用户使用set命令定义
			   set variable_name value;
	引用变量:$variable_name

MIME参考文档:https://developer.mozilla/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_Types

2.5.2.7 默认配置文件
[root@Centos7 ~]# grep -v "#" /apps/nginx/conf/nginx.conf | grep -v "^$"
#全局配置端,对全局生效,主要设置nginx的启动用户/组,启动的工作进程数量,工作模式,Nginx的PID路径,日志路径等。
user nginx nginx;   #指定用户和组来启动nginx
worker_processes 1; #启动工作进程数数量,推荐和CPU数量保持一致
events { #events设置快,主要影响nginx服务器与用户的网络连接,比如是否允许同时接受多个网络连接,使用哪种事件驱动模型处理请求,每个工作进程可以同时支持的最大连接数,是否开启对多工作进程下的网络连接进行序列化等。
	worker_connections 1024; #设置单个nginx工作进程可以接受的最大并发,作为web服务器的时候最大并发数为worker_connections * worker_processes,作为反向代理的时候为(worker_connections * worker_processes)/2 
} 
http { #http块是Nginx服务器配置中的重要部分,缓存、代理和日志格式定义等绝大多数功能和第三方模块都可以在这设置,http块可以包含多个server块,而一个server块中又可以包含多个location块,server块可以配置文件引入、MIME-Type定义、日志自定义、是否启用sendfile、连接超时时间和单个链接的请求上限等。
	include mime.types;
	default_type application/octet-stream;
	sendfile on; #作为web服务器的时候打开sendfile加快静态文件传输,指定是否使用sendfile系统调用来传输文件,sendfile系统调用在两个文件描述符之间直接传递数据(完全在内核中操作),从而避免了数据在内核缓冲区和用户缓冲区之间的拷贝,操作效率很高,被称之为零拷贝,硬盘 >> kernel buffer (快速拷贝到kernelsocket buffer) >>协议栈。
	keepalive_timeout 65; #长连接超时时间,单位是秒
	server { #设置一个虚拟机主机,可以包含自己的全局快,同时也可以包含多个location模块。比如本虚拟机监听的端口、本虚拟机的名称和IP配置,多个server 可以使用一个端口,比如都使用80端口提供web服务、
		listen 80; #配置server监听的端口
		server_name localhost;  #本server的名称,当访问此名称的时候nginx会调用当前serevr内部的配置进程匹配。
		location / { #location其实是server的一个指令,为nginx服务器提供比较多而且灵活的指令,都是在location中体现的,主要是基于nginx接受到的请求字符串,对用户请求的UIL进行匹配,并对特定的指令进行处理,包括地址重定向、数据缓存和应答控制等功能都是在这部分实现,另外很多第三方模块的配置也是在location模块中配置。
			root html; #相当于默认页面的目录名称,默认是相对路径,可以使用绝对路径配置。
			index index.html index.htm; #默认的页面文件名称
		}
		error_page 500 502 503 504 /50x.html; #错误页面的文件名称
		location = /50x.html { #location处理对应的不同错误码的页面定义到/50x.html,这个跟对应其server中定义的目录下。
			root   html; #定义默认页面所在的目录
		}
	}
	
#和邮件相关的配置
#mail {
# 			...
# 		  } 		mail 协议相关配置段

#tcp代理配置,1.9版本以上支持
#stream {
#		    ...
# 		 } 			stream 服务器相关配置段
#导入其他路径的配置文件
#include /apps/nginx/conf.d/*.conf
}

说明

web服务器的总链接=工作进程数*单个工作进程最大并发值

七层反向代理服务器= ( 工作进程数*单个工作进程最大并发值 ) /2

如下图:

三 Nginx 核心配置详解

3.1 全局配置

user nginx nginx; #启动Nginx工作进程的用户和组
worker_processes [number | auto]; #启动Nginx工作进程的数量
worker_cpu_affinity 00000001 00000010 00000100 00001000; #将Nginx工作进程绑定到指定的CPU核心,默认Nginx是不进行进程绑定的,绑定并不是意味着当前nginx进程独占以一核心CPU,但是可以保证此进程不会运行在其他核心上,这就极大减少了nginx的工作进程在不同的cpu核心上的来回跳转,减少了CPU对进程的资源分配与回收以及内存管理等,因此可以有效的提升nginx服务器的性能。

[root@Centos7 ~]#ps axo pid,cmd,psr,user | grep nginx
4106 nginx: master process /apps   1 root
4181 nginx: worker process 		   0 nginx
4182 nginx: worker process 		   1 nginx
4184 grep --color=auto nginx 	   0 root

#错误日志记录配置,语法:error_log file [debug | info | notice | warn | error | crit |alert | emerg]
#error_log logs/error.log;
#error_log logs/error.log notice;
error_log /apps/nginx/logs/error.log error;

#pid文件保存路径
pid 	/apps/nginx/logs/nginx.pid;

worker_priority 0; #工作进程nice值,-20~19
worker_rlimit_nofile 65536; #这个数字包括Nginx的所有连接(例如与代理服务器的连接等),而不仅仅是与客户端的连接,另一个考虑因素是实际的并发连接数不能超过系统级别的最大打开文件数的限制.

[root@Centos7 ~]# watch -n1 'ps -axo pid,cmd,nice | grep nginx' #验证进程优先级

daemon off; #前台运行Nginx服务用于测试、docker等环境。
master_process off|on; #是否开启Nginx的master-woker工作模式,仅用于开发调试场景。

events { #事件模型配置参数
	worker_connections 65536; #设置单个工作进程的最大并发连接数
	use epoll; #使用epoll事件驱动,Nginx支持众多的事件驱动,比如select、poll、epoll,只能设置在events模块中设置。
	accept_mutex on; #优化同一时刻只有一个请求而避免多个睡眠进程被唤醒的设置,on为防止被同时唤醒,默认为off,全部唤醒的过程也成为"惊群",因此nginx刚安装完以后要进行适当的优化。
	multi_accept on; #Nginx服务器的每个工作进程可以同时接受多个新的网络连接,但是需要在配置文件中配置,此指令默认为关闭,即默认为一个工作进程只能一次接受一个新的网络连接,打开后几个同时接受多个。
}

3.2 http详细配置

http {
    include       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  logs/access.log  main;

#自定义优化参数
    sendfile        on; #实现文件零拷贝
    #tcp_nopush     on; #在开启了sendfile的情况下,合并请求后统一发送给客户端。
    #tcp_nodelay   off; #在开启了keepalived模式下的连接是否启用TCP_NODELAY选项,当为off时,延迟0.2s发送,默认On时,不延迟发送,立即发送用户相应报文。
    #keepalive_timeout  0;
    keepalive_timeout  65;  #设置会话保持时间
    #gzip  on; #开启文件压缩

    server {
        listen       80; #设置监听地址和端口
        server_name  localhost; #设置server name,可以以空格隔开写多个并支持正则表达式,如*.magedu www.magedu.* www.(site\d+)\.magedu\$ default_server
        #charset koi8-r; #设置编码格式,默认是俄语格式,可以改为utf-8
        #access_log  logs/host.access.log  main;
        location / {
            root   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   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {  #以http的方式转发php请求到指定web服务器
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {  #以fastcgi的方式转发php请求到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 {  #拒绝web形式访问指定文件,如很多的网站都是通过.htaccess文件来改变自己的重定向等功能。
        #    deny  all;
        #}
        location ~ /passwd.html {
			deny all;
		}
    }


    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {  #自定义虚拟server
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm; #指定默认网页文件,此指令由ngx_http_index_module模块提供
    #    }
    #}


    # HTTPS server
    #
    #server {  #https服务器配置
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    location /linux38/passwd.ht {
		deny all;
	}
	
    #}
}

3.3 核心配置示例

基于不同的IP、不同的端口以及不用得域名实现不同的虚拟主机,依赖于核心模块ngx_http_core_module实现。

3.3.1 新建一个PC web站点
[root@s2 ~]# mkdir /apps/nginx/conf/conf.d
[root@s2 ~]# cat /apps/nginx/conf/conf.d/pc.conf
server {
  listen 80;
  server_name www.magedu;
  location / {
	root /data/nginx/html/pc;
  }
} 

[root@s2 ~]# mkdir /data/nginx/html/pc -p
[root@s2 ~]# echo "pc web" > /data/nginx/html/pc/index.html
[root@s2 ~]# vim /apps/nginx/conf/nginx.conf
include /apps/nginx/conf/conf.d/*.conf;
[root@s2 ~]# systemctl reload nginx
访问测试
3.3.2:新建一个Mobile web站点
[root@s2 ~]# cat /apps/nginx/conf/conf.d/mobile.conf
server {
  listen 80;
  server_name mobile.magedu;
  location / {
	root /data/nginx/html/mobile;
  }
} 

[root@s2 ~]# mkdir /data/nginx/html/mobile -p
[root@s2 ~]# echo "mobile web" >> /data/nginx/html/mobile/index.html

[root@s2 ~]# systemctl reload nginx
3.3.3:root与alias:

root:指定web的家目录,在定义location的时候,文件的绝对路径等于 root+location,如:

server {
  listen 80;
  server_name www.magedu;
  location / {
	root /data/nginx/html/pc;
  }
  
  location /about {
    root /data/nginx/html/pc; #必须要在html目录中创建一个about目录才可以访问,否则报错。
	index index.html;
  }
}

[root@s2 ~]# mkdir /data/nginx/html/pc/about
[root@s2 ~]# echo about > /data/nginx/html/pc/about/index.html

重启Nginx并访问测试

alias:定义路径别名,会把访问的路径重新定义到其指定的路径,如:

server {
  listen 80;
  server_name www.magedu;
  location / {
	root /data/nginx/html/pc;
  }

  location /about { #使用alias的时候uri后面如果加了斜杠则下面的路径配置必须加斜杠,否则403
	alias /data/nginx/html/pc; #当访问about的时候,会显示alias定义的/data/nginx/html/pc里面的内容。
	index index.html;
  }
}

重启Nginx并访问测试
http://www.magedu/about/index.html #访问指定文件资源
3.3.4:location的详细使用:

在没有使用正则表达式的时候,nginx会先在server中的多个location选取匹配度最高的一个uri,uri是用户请求的字符串,即域名后面的web文件路径,然后使用该location模块中的正则url和字符串,如果匹配成功就结束搜索,并使用此location处理此请求。

语法规则: location [=|~|~*|^~] /uri/ {}

=   #用于标准uri前,需要请求字串与uri精确匹配,如果匹配成功就停止向下匹配并立即处理请求。
~   #用于标准uri前,表示包含正则表达式并且区分大小写,并且匹配
!~  #用于标准uri前,表示包含正则表达式并且区分大小写,并且不匹配

~*  #用于标准uri前,表示包含正则表达式并且不区分大写,并且匹配
!~* #用于标准uri前,表示包含正则表达式并且不区分大小写,并且不匹配

^~  #用于标准uri前,表示包含正则表达式并且匹配以什么开头
$   #用于标准uri前,表示包含正则表达式并且匹配以什么结尾
\   #用于标准uri前,表示包含正则表达式并且转义字符。可以转. * ?等
*   #用于标准uri前,表示包含正则表达式并且代表任意长度的任意字符
3.3.4.1:匹配案例-精确匹配:

在server部分使用location配置一个web界面,要求:当访问nginx 服务器的/login的时候要显示指定html文件的内容:

[root@s2 ~]# cat /apps/nginx/conf/conf.d/pc.conf
server {
  listen 80;
  server_name www.magedu;
  location / {
	root /data/nginx/html/pc;
  }
  location = /1.jpg {
    root /var/www/nginx/images;
	index index.html;
  }
}

上传图片到/var/www/nginx/images,重启Nginx并访问测试
访问测试:http://www.magedu/1.jpg

说明:= 精确匹配,通常用于匹配企业logo或者是一些固定的URI,匹配的优先级最高

3.3.4.2:匹配案例-区分大小写:

如果uri中包含大写字母,则以下location匹配Ax.jpg条件不成功,因为~为区分大小写,那么当用户的请求被执行匹配时发现location中定义的是大写的A,则匹配失败,即要么继续往下匹配其他的location(如果有),要么报错给客户端。

location ~ /A.?\.jpg { #匹配字母A开头的图片,后面?表示A后面零次或一个字符
  index index.html;
  root /opt/nginx/html/image;
}

重启Nginx并访问测试
将只能访问以小写字符的AX.jpg图片,不能识别大写的JPG结尾的图片
访问测试:http://www.magedu/aA.jpg #直接访问资源名称即可

3.3.4.3:匹配案例-不区分大小写:

对用户请求的uri做模糊匹配,也就是uri中无论都是大写、都是小写或者大小写混合,此模式也都会匹配,通常使用此模式匹配用户request中的静态资源并继续做下一步操作。

正则表达式匹配:
# location ~ /A.?\.jpg {
#   index index.html;
#   root /opt/nginx/html/image;
# }

  location ~* /A.?\.jpg {
	index index.html;
	root /opt/nginx/html/image;
  }
  
访问测试:http://www.magedu/aA.jpg #直接访问资源名称即可
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
精确匹配指定名称:
# location ~ /aa.jpg {
#   index index.html;
#   root /opt/nginx/html/image;
# }

  location ~* /aa.jpg {
	index index.html;
	root /opt/nginx/html/image;
  }

重启Nginx并访问测试

说明:对于不区分大小写的location,则可以访问任意大小写结尾的图片文件,如区分大小写则只能访问aa.jpg,不区分大小写则可以访问aa.jpg以外的资源比如Aa.JPG、aA.jPG这样的混合名称文件,但是要求nginx服务器的资源目录有相应的文件,比如有Aa.JPG有aA.jPG。

重点:
Nginx匹配一次文件名是否区分大小写
Nginx可以在服务器找到指定的资源

3.3.4.4:匹配案例-URI开始

用的相对较少

location ^~ /images {
  root /data/nginx;
  index index.html;
}

location /images1 {
  alias /data/nginx/html/pc;
  index index.html;
}

重启Nginx并访问测试,实现效果是访问images和images1返回不同的结果
[root@s2 images]# curl http://www.magedu/images/
images
[root@s2 images]# curl http://www.magedu/images1/
pc web
3.3.4.5:匹配案例-文件名后缀

用的比较多

[root@s2 ~]# mkdir /data/nginx/images1
#上传一个和images目录不一样内容的的图片1.j到/data/nginx/images1

location ~* \.(gif|jpg|jpeg|bmp|png|tiff|tif|ico|wmf|js)$ {
  root /data/nginx/images1;
  index index.html;
}
重启Nginx并访问测试
3.3.4.6:匹配案例-优先级
location ~* /1.jpg {
  index index.html;
  root /data/nginx/pc/html/linux38/images;
}

location = /1.jpg { #通常用于精确匹配指定文件,如favicon.ico、employcode.js、index.jsp等
  index index.html;
  root /data/nginx/pc/html/python/images;
}

上传图片到并重启nginx访问测试

匹配优先级:=, ^~, ~/~*,/

location优先级:(location =) > (location 完整路径) > (location ^~ 路径) > (location ,* 正则顺序) > (location 部分起始路径) > (/)

3.3.4.7 生产使用案例
直接匹配网站根会加速Nginx访问处理:
location = / {
   ......;
}
location / {
   ......;
}

静态资源配置:
location ^~ /static/ {
   ......;
}
# 或者下面写法 (用的更多)
location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ {
   ......;
}

多应用配置
location ~* /app1 {
   ......;
}
location ~* /app2 {
   ......;
}
3.3.5 Nginx 四层访问控制:

访问控制基于模块ngx_http_access_module实现,可以通过匹配客户端源IP地址进行限制。

location /about {
	alias /data/nginx/html/pc;
	index index.html;
	deny 192.168.1.1;
	allow 192.168.1.0/24;
	allow 10.1.1.0/16;
	allow 2001:0db8::/32;
	deny all; #先允许小部分,再拒绝大部分
}

注意:在防火墙上拒绝效果最好

3.3.6:Nginx账户认证功能
[root@s2 ~]# yum install httpd-tools -y #Centos
[root@s2 ~]# apt install apache2-utils #Ubuntu
[root@s2 ~]# htpasswd -cbm /apps/nginx/conf/.htpasswd user1 123456
Adding password for user user1
[root@s2 ~]# htpasswd -bm /apps/nginx/conf/.htpasswd user2 123456
Adding password for user user2
[root@s2 ~]# tail /apps/nginx/conf/.htpasswd
user1:$apr1$Rjm0u2Kr$VHvkAIc5OYg.3ZoaGwaGq/
user2:$apr1$nIqnxoJB$LR9W1DTJT.viDJhXa6wHv.

[root@s2 ~]# vim /apps/nginx/conf/conf.d/pc.conf
  location = /login/ {
	root /data/nginx/html/pc;
	index index.html;
	auth_basic   		"login password";
	auth_basic_user_file /apps/nginx/conf/.htpasswd;
  }
  
重启Nginx并访问测试
3.3.7:自定义错误页面
listen 80;
server_name www.magedu;
error_page 500 502 503 504 404 /error.html;
location = /error.html {
  root html;
}
重启nginx并访问不存在的页面进行测试
3.3.8:自定义访问日志
[root@s2 ~]# mkdir /data/nginx/logs
  listen 80;
  server_name www.magedu;
  error_page 500 502 503 504 404 /error.html; #默认目录下面创建error.html页面
  access_log /data/nginx/logs/www-magedu-net_access.log;
  error_log /data/nginx/logs/www-magedu-net_error.log;
  location = /error.html {
	root html;
  }
重启nginx并访问不存在的页面进行测试并验证是在指定目录生成新的日志文件
3.3.9:检测文件是否存在:

try_files会按顺序检查文件是否存在,返回第一个找到的文件或文件夹(结尾加斜线表示为文件夹),如果所有文件或文件夹都找不到,会进行一个内部重定向到最后一个参数。只有最后一个参数可以引起一个内部重定向,之前的参数只设置内部URI的指向。最后一个参数是回退URI且必须存在,否则会出现内部500错误。

location /about {
  root /data/nginx/html/pc;
  #alias /data/nginx/html/pc;
  index index.html;
  #try_files $uri /about/default.html;
  #try_files $uri $uri/index.html $uri.html /about/default.html;
  try_files $uri $uri/index.html $uri.html =489;
}

[root@s2 ~]# echo "default" >> /data/nginx/html/pc/about/default.html
重启nginx并测试,当访问到http://www.magedu/about/xx.html等不存在的uri会显示default,如果是自定义的状态码则会显示在返回数据的状态码中,如:
[root@s2 about]# curl --head http://www.magedu/about/xx.html
HTTP/1.1 489 #489就是自定义的状态返回码
Server: nginx
Date: Thu, 21 Feb 2019 00:11:40 GMT
Content-Length: 0
Connection: keep-alive
Keep-Alive: timeout=65
3.3.10:长连接配置:

keepalive_timeout number; 设定保持连接超时时长,0表示禁止长连接,默认为75s,通常配置在http字段作为站点全局配置

keepalive_requests number; 在一次长连接上所允许请求的资源的最大数量,默认为100次 (和用户传输文件一次性最多一百次)

keepalive_requests 3;
keepalive_timeout 65 65;
开启长连接后,返回客户端的会话保持时间为60s,单次长连接累计请求达到指定次数请求或65秒就会被断开,后面的60为发送给客户端应答报文头部中显示的超时时间设置为60s:如不设置客户端将不显示超时时间。
Keep-Alive:timeout=60 #浏览器收到的服务器返回的报文

如果设置为0表示关闭会话保持功能,将如下显示:
Connection:close #浏览器收到的服务器返回的报文
使用命令测试:
[root@s3 apps]# telnet www.magedu 80
Trying 172.18.200.102...
Connected to www.magedu.
Escape character is '^]'.
GET / HTTP/1.1
HOST: www.magedu

#Response Headers(响应头信息):
HTTP/1.1 200 OK
Server: nginx/1.14.2
Date: Thu, 14 Mar 2019 17:23:46 GMT
Content-Type: text/html
Content-Length: 7
Last-Modified: Thu, 14 Mar 2019 14:54:50 GMT
Connection: keep-alive
Keep-Alive: timeout=60
ETag: "5c8a6b3a-7"
Accept-Ranges: bytes

#页面内容
pc web
3.3.11:作为下载服务器配置
[root@s2 about]# mkdir /data/nginx/html/pc/download
#download不需要index.html文件
[root@s2 about]# vim /apps/nginx/conf/conf.d/pc.conf
  location /download {
	autoindex on; 			 #自动索引功能
	autoindex_exact_size on; #计算文件确切大小(单位bytes),off只显示大概大小(单位kb、mb、gb)
	autoindex_localtime on;  #显示本机时间而非GMT(格林威治)时间
	root /data/nginx/html/pc;
  }
  
[root@s2 pc]# cp /root/anaconda-ks.cfg /data/nginx/html/pc/download/
重启Nginx并访问测试下载页面

#更新时间
ntpdate time1.aliyun

limit_rate rate; #限制响应给客户端的传输速率,单位是bytes/second,默认值0表示无限制限速与不限速的对比:
	limit_rate 10k;

3.3.12:作为上传服务器
client_max_body_size 1m; #设置允许客户端上传单个文件的最大值,默认值为1m
client_body_buffer_size size; #用于接收每个客户端请求报文的body部分的缓冲区大小;默认16k;超出此大小时,其将被暂存到磁盘上的由下面client_body_temp_path指令所定义的位置
client_body_temp_path path [level1 [level2 [level3]]];
#设定存储客户端请求报文的body部分的临时存储路径及子目录结构和数量,目录名为16进制的数字,使用hash之后的
值从后往前截取1位、2位、2位作为文件名:
[root@s3 ~]# md5sum /data/nginx/html/pc/index.html
95f6f65f498c74938064851b1bb 96 3d 4 /data/nginx/html/pc/index.html
1级目录占1位16进制,即2^4=16个目录 0-f
2级目录占2位16进制,即2^8=256个目录 00-ff
3级目录占2位16进制,即2^8=256个目录 00-ff
配置示例:
	client_max_body_size 10m;
	client_body_buffer_size 16k;
	client_body_temp_path /apps/nginx/temp 1 2 2; #reload Nginx会自动创建temp目录

3.3.13:其他配置
keepalive_disable none | browser ...;
#对哪种浏览器禁用长连接
limit_except method ... { ... },仅用于location
限制客户端使用除了指定的请求方法之外的其它方法
	method:GET, HEAD, POST, PUT, DELETE,MKCOL, COPY, MOVE, OPTIONS, PROPFIND,PROPPATCH, LOCK, UNLOCK, PATCH
	limit_except GET {
		allow 192.168.0.0/24;
		allow 192.168.7.101;
		deny all;
	}

#除了GET和HEAD 之外其它方法仅允许192.168.1.0/24网段主机使用
[root@s2 about]# mkdir /data/nginx/html/pc/upload
[root@s2 about]# echo "upload" > /data/nginx/html/pc/upload/index.html
[root@s2 about]# vim /apps/nginx/conf/conf.d/pc.conf
  location /upload {
	root /data/magedu/pc;
	index index.html;
	limit_except GET {
	  allow 172.18.200.101;
	  deny all;
	}
  }
  
#重启Nginx并进行测试上传文件
[root@s2 pc]# systemctl restart nginx
[root@s2 pc]#
[root@s2 pc]# curl -XPUT /etc/issue http://www.magedu/about
curl: (3) <url> malformed
<html>
<head><title>405 Not Allowed</title></head> #Nginx已经允许但是程序未支持上传功能
<body bgcolor="white">
<center><h1>405 Not Allowed</h1></center>
<hr><center>nginx</center>
</body>
</html>
[root@s1 ~]# curl -XPUT /etc/issue http://www.magedu/upload
curl: (3) <url> malformed
<html>
<head><title>403 Forbidden</title></head> #Nginx拒绝上传
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
</html>
aio on | off #是否启用asynchronous file I/O(AIO)功能,需要编译开启
linux 2.6以上内核提供以下几个系统调用来支持aio:
1、SYS_io_setup:建立aio 的context
2、SYS_io_submit: 提交I/O操作请求
3、SYS_io_getevents:获取已完成的I/O事件
4、SYS_io_cancel:取消I/O操作请求
5、SYS_io_destroy:毁销aio的context
directio size | off; #directio是直接读写文件到磁盘,启用直接I/O,默认为关闭,当文件大于等于给定大小时,例如directio 4m,可以和sebdfile结合使用,比如当大于此值使用AIO,当小于此值使用sendfile。

open_file_cache off; #是否缓存打开过的文件信息,一般加到主配置文件
open_file_cache max=N [inactive=time];
	nginx可以缓存以下三种信息:
	(1) 文件元数据:文件的描述符、文件大小和最近一次的修改时间
	(2) 打开的目录结构
	(3) 没有找到的或者没有权限访问的文件的相关信息
	max=N:可缓存的缓存项上限数量;达到上限后会使用LRU(Least recently used,最近最少使用)算法实现管理
	inactive=time:缓存项的非活动时长,在此处指定的时长内未被命中的或命中的次数少于open_file_cache_min_uses指令所指定的次数的缓存项即为非活动项,将被删除

open_file_cache_errors on | off;
	是否缓存查找时发生错误的文件一类的信息
	默认值为off
	
open_file_cache_min_uses number;
	open_file_cache指令的inactive参数指定的时长内,至少被命中此处指定的次数方可被归类为活动项默认值为1

open_file_cache_valid time;
	缓存项有效性的检查验证频率,默认值为60s
	
open_file_cache max=10000 inactive=60s; #最大缓存10000个文件,非活动数据超时时长60s
open_file_cache_valid 60s;  #每间隔60s检查一下缓存数据有效性
open_file_cache_min_uses 5; #60秒内至少被命中访问5次才被标记为活动数据
open_file_cache_errors on;  #缓存错误信息

server_tokens off; #隐藏Nginx server版本。

四 Nginx 高级配置

4.1:Nginx 状态页

基于nginx模块ngx_http_stub_status_module实现,在编译安装nginx的时候需要添加编译参数–with-http_stub_status_module,否则配置完成之后监测会是提示语法错误。

配置示例:
location /nginx_status {
	stub_status;
	allow 192.168.0.0/16;
	allow 127.0.0.1;
	deny all;
}

状态页用于输出nginx的基本状态信息:
输出信息示例:
Active connections: 291
server accepts handled requests
	16630948 16630948 31070465
	上面三个数字分别对应accepts,handled,requests三个值
Reading: 6 Writing: 179 Waiting: 106

Active connections: 当前处于活动状态的客户端连接数,包括连接等待空闲连接数。
accepts:统计总值,Nginx自启动后已经接受的客户端请求的总数。
handled:统计总值,Nginx自启动后已经处理完成的客户端请求的总数,通常等于accepts,除非有因为worker_connections限制等被拒绝的连接。
requests:统计总值,Nginx自启动后客户端发来的总的请求数。
Reading:当前状态,正在读取客户端请求报文首部的连接的连接数。越小越好
Writing:当前状态,正在向客户端发送响应报文过程中的连接数。越小越好
Waiting:当前状态,正在等待客户端发出请求的空闲连接数,开启 keep-alive的情况下,这个值等于 active – (reading+writing),

说明:Active connections,Reading,Writing,Waiting这几个值很重要!

4.2:Nginx 第三方模块:

第三模块是对nginx 的功能扩展,第三方模块需要在编译安装Nginx 的时候使用参数–add-module=PATH指定路径添加,有的模块是由公司的开发人员针对业务需求定制开发的,有的模块是开源爱好者开发好之后上传到github进行开源的模块,nginx支持第三方模块需要从源码重新编译支持,比如开源的echo模块 https://github/openresty/echo-nginx-module:

[root@s2 pc]# systemctl stop nginx
[root@s2 pc]# vim /apps/nginx/conf/conf.d/pc.conf
location /main {
	index index.html;
	default_type text/html;
	echo "hello world,main-->";
	echo_reset_timer;
	echo_location /sub1;
	echo_location /sub2;
	echo "took $echo_timer_elapsed sec for total.";
}
location /sub1 {
	echo_sleep 1;
	echo sub1;
}
location /sub2 {
	echo_sleep 1;
	echo sub2;
}

[root@s2 pc]# /apps/nginx/sbin/nginx -t
nginx: [emerg] unknown directive "echo_reset_timer" in
/apps/nginx/conf/conf.d/pc.conf:86
nginx: configuration file /apps/nginx/conf/nginx.conf test failed

#解决以上报错问题
[root@s2 src]# yum install git -y
[root@s2 src]# git clone https://github/openresty/echo-nginx-module.git
[root@s2 src]# cd nginx-1.12.2/
[root@s2 src]# ./configure \
--prefix=/apps/nginx \
--user=nginx --group=nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_stub_status_module \
--with-http_gzip_static_module \
--with-pcre \
--with-stream \
--with-stream_ssl_module \
--with-stream_realip_module \
--with-http_perl_module \
--add-module=/usr/local/src/echo-nginx-module
[root@s2 src]# make && make install

#确认语法检测通过
[root@s2 pc]# /apps/nginx/sbin/nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful

#重启nginx访问测试:
[root@s2 pc]# systemctl restart nginx
[root@s2 pc]# curl http://www.magedu/main
hello world,main-->
sub1
sub2
took 2.010 sec for total.
 

4.3:Nginx 变量使用

nginx的变量可以在配置文件中引用,作为功能判断或者日志等场景使用,变量可以分为内置变量和自定义变量,内置变量是由nginx模块自带,通过变量可以获取到众多的与客户端访问相关的值。

4.3.1:内置变量
$remote_addr;
#存放了客户端的地址,注意是客户端的公网IP,也就是一家人访问一个网站,则会显示为路由器的公网IP。

$args#变量中存放了URL中的指令,例如http://www.magedu/main/index.do?
id=20190221&partner=search中的id=20190221&partner=search

$document_root#保存了针对当前资源的请求的系统根目录,如/apps/nginx/html。

$document_uri#保存了当前请求中不包含指令的URI,注意是不包含请求的指令,比如
http://www.magedu/main/index.do?id=20190221&partner=search会被定义为/main/index.do 。

$host#存放了请求的host名称

$http_user_agent#客户端浏览器的详细信息

$http_cookie#客户端的cookie信息。

limit_rate 10240;
echo $limit_rate;
#如果nginx服务器使用limit_rate配置了显示网络速率,则会显示,如果没有设置, 则显示0。

$remote_port#客户端请求Nginx服务器时随机打开的端口,这是每个客户端自己的端口。

$remote_user#已经经过Auth Basic Module验证的用户名。

$request_body_file#做反向代理时发给后端服务器的本地资源的名称。

$request_method#请求资源的方式,GET/PUT/DELETE等

$request_filename#当前请求的资源文件的路径名称,由root或alias指令与URI请求生成的文件绝对路径,如/apps/nginx/html/main/index.html

$request_uri#包含请求参数的原始URI,不包含主机名,如:/main/index.do?id=20190221&partner=search 。

$scheme#请求的协议,如ftp,https,http等。

$server_protocol#保存了客户端请求资源使用的协议的版本,如HTTP/1.0,HTTP/1.1,HTTP/2.0等。

$server_addr#保存了服务器的IP地址。

$server_name#请求的服务器的主机名。

$server_port#请求的服务器的端口号。
4.3.2:自定义变量:

假如需要自定义变量名称和值,使用指令set $variable value;,则方法如下:

Syntax: set $variable value;
Default: —
Context: server, location, if

set $name magedu;
echo $name;
set $my_port $server_port;
echo $my_port;
echo "$server_name:$server_port";

4.4:Nginx 自定义访问日志

访问日志是记录客户端即用户的具体请求内容信息,全局配置模块中的error_log是记录nginx服务器运行时的日志保存路径和记录日志的level,因此有着本质的区别,而且Nginx的错误日志一般只有一个,但是访问日志可以在不同server中定义多个,定义一个日志需要使用access_log指定日志的保存路径,使用log_format指定日志的格式,格式中定义要保存的具体日志内容。

4.4.1:自定义默认格式日志

如果是要保留日志的源格式,只是添加相应的日志内容,则配置如下:

log_format nginx_format1 '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'
'$server_name:$server_port';

access_log logs/access.log nginx_format1;

#重启nginx并访问测试日志格式
==> /apps/nginx/logs/access.log <==
192.168.0.1 - - [22/Feb/2019:08:44:14 +0800] "GET /favicon.ico HTTP/1.1" 404 162 "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0" "-"www.magedu:80
4.4.2:自定义json格式日志

Nginx 的默认访问日志记录内容相对比较单一,默认的格式也不方便后期做日志统计分析,生产环境中通常将nginx日志转换为json日志,然后配合使用ELK做日志收集-统计-分析。

log_format access_json '{"@timestamp":"$time_iso8601",'
    '"host":"$server_addr",'
    '"clientip":"$remote_addr",'
    '"size":$body_bytes_sent,'
    '"responsetime":$request_time,'
    '"upstreamtime":"$upstream_response_time",'
    '"upstreamhost":"$upstream_addr",'
    '"http_host":"$host",'
    '"uri":"$uri",'
    '"domain":"$host",'
    '"xff":"$http_x_forwarded_for",'
    '"referer":"$http_referer",'
    '"tcp_xff":"$proxy_protocol_addr",'
    '"http_user_agent":"$http_user_agent",'
    '"status":"$status"}';
access_log /apps/nginx/logs/access_json.log access_json;

#重启Nginx并访问测试日志格式
{"@timestamp":"2019-02-22T08:55:32+08:00","host":"192.168.7.102","clientip":"192.168.0.1","size":162,"response time":0.000,"upstreamtime":"-","upstreamhost":"-
","http_host":"www.magedu","uri":"/favicon.ico","domain":"www.magedu","xff":"-","referer":"-","tcp_xff":"","http_user_agent":"Mozilla/5.0 (Windows NT 6.1; Win64;
x64; rv:65.0) Gecko/20100101 Firefox/65.0","status":"404"}
4.4.3:json格式的日志访问统计
#!/usr/bin/env python
#coding:utf-8
#Author:Zhang ShiJie
status_200= []
status_404= []
with open("access_json.log") as f:
	for line in f.readlines():
		line = eval(line)
		if line.get("status") == "200":
			status_200.append(line.get)
		elif line.get("status") == "404":
			status_404.append(line.get)
		else:
			print("状态码 ERROR")
f.close()

print "状态码200的有--:",len(status_200)
print "状态码404的有--:",len(status_404)

#保存日志文件到指定路径并进测试:
[root@s2 ~]# python nginx_json.py
状态码200的有--: 1910
状态码404的有--: 13

4.5:Nginx 压缩功能

Nginx支持对指定类型的文件进行压缩然后再传输给客户端,而且压缩还可以设置压缩比例,压缩后的文件大小将比源文件显著变小,这样有助于降低出口带宽的利用率,降低企业的IT支出,不过会占用相应的CPU资源。

Nginx对文件的压缩功能是依赖于模块ngx_http_gzip_module,官方文档: https://nginx/en/docs/http/ngx_http_gzip_module.html, 配置指令如下:

#启用或禁用gzip压缩,默认关闭
gzip on | off;

#压缩比由低到高从1到9,默认为1
gzip_comp_level level;

#禁用IE6 gzip功能
gzip_disable "MSIE [1-6]\.";

#gzip压缩的最小文件,小于设置值的文件将不会压缩
gzip_min_length 1k;

#启用压缩功能时,协议的最小版本,默认HTTP/1.1
gzip_http_version 1.0 | 1.1;

#指定Nginx服务需要向服务器申请的缓存空间的个数*大小,默认32 4k|16 8k;
gzip_buffers number size;

#指明仅对哪些类型的资源执行压缩操作;默认为gzip_types text/html,不用显示指定,否则出错
gzip_types mime-type ...;

#如果启用压缩,是否在响应报文首部插入“Vary: Accept-Encoding”
gzip_vary on | off;

#重启nginx并进行访问测试压缩功能
[root@s2 pc]# cp /apps/nginx/logs/access.log /data/nginx/html/pc/test.html
[root@s2 pc]# echo "test1" > /data/nginx/html/pc/test1.html #小于1k的文件测试是否会压缩
[root@s2 pc]# vim /apps/nginx/conf/nginx.conf
	gzip on;
	gzip_comp_level 5;
	gzip_min_length 1k;
	gzip_types text/plain application/javascript application/x-javascript
text/cssapplication/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
	gzip_vary on;
	
重启Nginx并访问测试:
[root@s2 pc]# curl --head --compressed http://www.magedu
HTTP/1.1 200 OK
Server: nginx
Date: Thu, 21 Feb 2019 13:06:18 GMT
Content-Type: text/html
Content-Length: 7
Last-Modified: Tue, 19 Feb 2019 04:09:32 GMT
Connection: keep-alive
Keep-Alive: timeout=65
ETag: "5c6b817c-7"
Accept-Ranges: bytes

[root@s2 ~]# curl --head --compressed http://www.magedu/test.html
HTTP/1.1 200 OK
Server: nginx
Date: Fri, 22 Feb 2019 01:52:23 GMT
Content-Type: text/html
Last-Modified: Thu, 21 Feb 2019 10:31:18 GMT
Connection: keep-alive
Keep-Alive: timeout=65
Vary: Accept-Encoding
ETag: W/"5c6e7df6-171109"
Content-Encoding: gzip #压缩传输

#验证不压缩访问的文件大小:

#验证压缩后访问的文件大小:

4.6:https 功能

Web网站的登录页面都是使用https加密传输的,加密数据以保障数据的安全,HTTPS能够加密信息,以免敏感信息被第三方获取,所以很多银行网站或电子邮箱等等安全级别较高的服务都会采用HTTPS协议,HTTPS其实是有两部分组成:HTTP + SSL / TLS,也就是在HTTP上又加了一层处理加密信息的模块。服务端和客户端的信息传输都会通过TLS进行加密,所以传输的数据都是加密后的数据。

https 实现过程如下

  1. 客户端发起HTTPS请求:
    客户端访问某个web端的https地址,一般都是443端口

  2. 服务端的配置:
    采用https协议的服务器必须要有一套证书,可以通过一些组织申请,也可以自己制作,目前国内很多网站都自己做的,当你访问一个网站的时候提示证书不可信任就表示证书是自己做的,证书就是一个公钥和私钥匙,就像一把锁和钥匙,正常情况下只有你的钥匙可以打开你的锁,你可以把这个送给别人让他锁住一个箱子,里面放满了钱或秘密,别人不知道里
    面放了什么而且别人也打不开,只有你的钥匙是可以打开的。

  3. 传送证书:
    服务端给客户端传递证书,其实就是公钥,里面包含了很多信息,例如证书得到颁发机构、过期时间等等。

  4. 客户端解析证书:
    这部分工作是有客户端完成的,首先回验证公钥的有效性,比如颁发机构、过期时间等等,如果发现异常则会弹出一个警告框提示证书可能存在问题,如果证书没有问题就生成一个随机值,然后用证书对该随机值进行加密,就像2步骤所说把随机值锁起来,不让别人看到。

  5. 传送4步骤的加密数据:
    就是将用证书加密后的随机值传递给服务器,目的就是为了让服务器得到这个随机值,以后客户端和服务端的通信就可以通过这个随机值进行加密解密了。

  6. 服务端解密信息:
    服务端用私钥解密5步骤加密后的随机值之后,得到了客户端传过来的随机值(私钥),然后把内容通过该值进行对称加密,对称加密就是将信息和私钥通过算法混合在一起,这样除非你知道私钥,不然是无法获取其内部的内容,而正好客户端和服务端都知道这个私钥,所以只要机密算法够复杂就可以保证数据的安全性。

  7. 传输加密后的信息:
    服务端将用私钥加密后的数据传递给客户端,在客户端可以被还原出原数据内容。

  8. 客户端解密信息:
    客户端用之前生成的私钥获解密服务端传递过来的数据,由于数据一直是加密的,因此即使第三方获取到数据也无法知道其详细内容。

4.6.1:ssl 配置参数:

nginx 的https 功能基于模块ngx_http_ssl_module实现,因此如果是编译安装的nginx要使用参数ngx_http_ssl_module开启ssl功能,但是作为nginx的核心功能,yum安装的nginx默认就是开启的,编译安装nginx需要指定编译参数–with-http_ssl_module开启,官方文档: https://nginx/en/docs/http/ngx_http_ssl_module.html,配置参数如下:

ssl on | off;
#为指定的虚拟主机配置是否启用ssl功能,此功能在1.15.0废弃,使用listen [ssl]替代。

ssl_certificate /path/to/file;
#当前虚拟主机使用使用的公钥文件,一般是crt文件

ssl_certificate_key /path/to/file;
#当前虚拟主机使用的私钥文件,一般是key文件

ssl_protocols [SSLv2] [SSLv3] [TLSv1] [TLSv1.1] [TLSv1.2];
#支持ssl协议版本,早期为ssl,现在是TSL,默认为后三个

ssl_session_cache off | none | [builtin[:size]] [shared:name:size];
#配置ssl缓存
	off: 关闭缓存
	none: 通知客户端支持ssl session cache,但实际不支持
	builtin[:size]:使用OpenSSL内建缓存,为每worker进程私有
	[shared:name:size]:在各worker之间使用一个共享的缓存,需要定义一个缓存名称和缓存空间大小,一兆可以存储4000个会话信息,多个虚拟主机可以使用相同的缓存名称。

ssl_session_timeout time;#客户端连接可以复用ssl session cache中缓存的有效时长,默认5m
4.6.2:自签名 证书
#自签名CA证书
[root@s2 ~]# cd /apps/nginx/
[root@s2 nginx]# mkdir certs
[root@s2 nginx]# cd certs/
[root@s2 nginx]# openssl req -newkey rsa:4096 -nodes -sha256 -keyout ca.key -x509 -days 3650 -out ca.crt #自签名CA证书
Generating a 4096 bit RSA private key
.................++
.....
Country Name (2 letter code) [XX]:CN #国家代码,https://country-code.cl/
State or Province Name (full name) []:BeiJing #省份
Locality Name (eg, city) [Default City]:Beijing #城市名称
Organization Name (eg, company) [Default Company Ltd]:magedu.Ltd #公司名称
Organizational Unit Name (eg, section) []:magedu #部门
Common Name (eg, your name or your server's hostname) []:magedu.ca #通用名称
Email Address []:2973707860@qq #邮箱
[root@s2 certs]# ll ca.crt
-rw-r--r-- 1 root root 2118 Feb 22 12:10 ca.crt

#自制key和csr文件
[root@s2 certs]# openssl req -newkey rsa:4096 -nodes -sha256 -keyout www.magedu.key -out www.magedu.csr
Generating a 4096 bit RSA private key
........................................................................++......
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:BeiJing
Locality Name (eg, city) [Default City]:BeiJing
Organization Name (eg, company) [Default Company Ltd]:magedu
Organizational Unit Name (eg, section) []:magedu
Common Name (eg, your name or your server's hostname) []:www.magedu
Email Address []:2973707860@qq

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
[root@s2 certs]# ll
total 16
-rw-r--r-- 1 root root 2118 Feb 22 12:10 ca.crt
-rw-r--r-- 1 root root 3272 Feb 22 12:10 ca.key
-rw-r--r-- 1 root root 1760 Feb 22 12:18 www.magedu.csr
-rw-r--r-- 1 root root 3272 Feb 22 12:18 www.magedu.key

#签发证书
[root@s2 certs]# openssl x509 -req -days 3650 -in www.magedu.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out www.magedu.crt
Signature ok
subject=/C=CN/ST=BeiJing/L=BeiJing/O=magedu/OU=magedu/CN=www.magedu/emailAd
dress=2973707860@qq
Getting CA Private Key
#验证证书内容
[root@s2 certs]# openssl x509 -in www.magedu.crt -noout -text
Certificate:
	Data:
		Version: 1 (0x0)
		Serial Number:
			bb:76:ea:fe:f4:04:ac:06
	Signature Algorithm: sha256WithRSAEncryption
		Issuer: C=CN, ST=BeiJing, L=Beijing, O=magedu.Ltd, OU=magedu,
CN=magedu.ca/emailAddress=2973707860@qq
		Validity
			Not Before: Feb 22 06:14:03 2019 GMT
			Not After : Feb 22 06:14:03 2020 GMT
		Subject: C=CN, ST=BeiJing, L=BeiJing, O=magedu, OU=magedu,
CN=www.magedu/emailAddress=2973707860@qq
		Subject Public Key Info:
			Public Key Algorithm: rsaEncryption
				Public-Key: (4096 bit)

4.6.3:Nginx证书配置
listen 80;
listen 443 ssl;
ssl_certificate /apps/nginx/certs/www.magedu.crt;
ssl_certificate_key /apps/nginx/certs/www.magedu.key;
ssl_session_cache shared:sslcache:20m;
ssl_session_timeout 10m;
#重启Nginx并访问验证

4.6.4:实现多域名HTTPS

Nginx支持基于单个IP实现多域名的功能,并且还支持单IP多域名的基础之上实现HTTPS,其实是基于Nginx的SNI(Server Name Indication)功能实现,SNI是为了解决一个Nginx服务器内使用一个IP绑定多个域名和证书的功能,其具体功能是客户端在连接到服务器建立SSL链接之前先发送要访问站点的域名(Hostname),这样服务器再根据这个域名返回给客户端一个合适的证书。

#制作key和csr文件
[root@s2 certs]# openssl req -newkey rsa:4096 -nodes -sha256 -keyout mobile.magedu.key -out mobile.magedu.csr
Generating a 4096 bit RSA private key
..........
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:BeiJing
Locality Name (eg, city) [Default City]:BeiJing
Organization Name (eg, company) [Default Company Ltd]:magedu
Organizational Unit Name (eg, section) []:magedu
Common Name (eg, your name or your server's hostname) []:mobile.magedu
Email Address []:2973707860@qq
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
#签名证书
[root@s2 certs]# openssl x509 -req -days 3650 -in mobile.magedu.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out mobile.magedu.crt
Signature ok
subject=/C=CN/ST=BeiJing/L=BeiJing/O=magedu/OU=magedu/CN=mobile.magedu/emailAddress
=2973707860@qq
Getting CA Private Key
#验证证书内容
[root@s2 certs]# openssl x509 -in mobile.magedu.crt -noout -text
Certificate:
Data:
Version: 1 (0x0)
Serial Number:
bb:76:ea:fe:f4:04:ac:07
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=CN, ST=BeiJing, L=Beijing, O=magedu.Ltd, OU=magedu,
CN=magedu.ca/emailAddress=2973707860@qq
Validity
Not Before: Feb 22 13:50:43 2019 GMT
Not After : Feb 19 13:50:43 2029 GMT
Subject: C=CN, ST=BeiJing, L=BeiJing, O=magedu, OU=magedu,
CN=mobile.magedu/emailAddress=2973707860@qq
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (4096 bit)
..............
#Nginx 配置
[root@s2 certs]# cat /apps/nginx/conf/conf.d/mobile.conf
server {
listen 80;
server_name mobile.magedu;
location / {
root html;
index index.html index.htm;
}
location /linux38 {
root /data/nginx/mobile/html;
index index.html index.htm;
}
location /python {
root /data/nginx/mobile/html;
index index.html index.htm;
}
}
server {
listen 443 ssl;
server_name mobile.magedu;
ssl_certificate /apps/nginx/certs/mobile.magedu.crt;
ssl_certificate_key /apps/nginx/certs/mobile.magedu.key;
ssl_session_cache shared:sslcache:20m;
ssl_session_timeout 10m;
location / {
root html;
index index.html index.htm;
}
location /linux38 {
root /data/nginx/mobile/html;
index index.html index.htm;
}
location /python {
root /data/nginx/mobile/html;
index index.html index.htm;
}
}

4.7:关于favicon.ico:

favicon.ico 文件是浏览器收藏网址时显示的图标,当客户端使用浏览器问页面时,浏览器会自己主动发起请求获取页面的favicon.ico文件,但是当浏览器请求的favicon.ico文件不存在时,服务器会记录404日志,而且浏览器也会显示404报错。

解决办法:

#一:服务器不记录访问日志:
	#location = /favicon.ico {
	  #log_not_found off;
	  #access_log off;
	#}
	
#二:将图标保存到指定目录访问:
	#location ~ ^/favicon\.ico$ {
	location = /favicon.ico {
	  root /data/nginx/html/pc/images;
	  expires 90d; #设置文件过期时间
	}

4.8:安全选项

4.8.1:隐藏Nginx版本号

更改nginx源码信息并重新编译Nginx

# vim src/http/ngx_http_header_filter_module.c
49 static u_char ngx_http_server_string[] = "Server: linux38" CRLF; #定义响应报文中的server字段信息

4.8.2:升级OpenSSL版本

心脏出血(英语:Heartbleed),也简称为心血漏洞,是一个出现在加密程序库OpenSSL的安全漏洞,该程序库广泛用于实现互联网的传输层安全(TLS)协议。它于2012年被引入了软件中,2014年4月首次向公众披露。只要使用的是存在缺陷的OpenSSL实例,无论是服务器还是客户端,都可能因此而受到攻击。此问题的原因是在实现TLS的心跳扩展时没有对输入进行适当验证(缺少边界检查),因此漏洞的名称来源于“心跳”(heartbeat)。该程
序错误属于缓冲区过读,即可以读取的数据比应该允许读取的还多。

准备OpenSSL源码包:
# pwd
/usr/local/src
# tar xvf openssl-1.1.1d

编译安装Nginx并制定新版本OpenSSL路径:
# cd /usr/local/src/nginx-1.16.1/
#./configure --prefix=/apps/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --withhttp_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --withstream_realip_module --with-select_module --with-file-aio --addmodule=/usr/local/src/echo-nginx-module --with-openssl=/usr/local/src/openssl-1.1.1d
# make && make install

验证并启动Nginx:
# /apps/nginx/sbin/nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
# /apps/nginx/sbin/nginx

五:Nginx Rewrite相关功能:

Nginx服务器利用ngx_http_rewrite_module 模块解析和处理rewrite请求,此功能依靠 PCRE(perl compatible regularex pression),因此编译之前要安装PCRE库,rewrite是nginx服务器的重要功能之一,用于实现URL的重写,URL的重写是非常有用的功能,比如它可以在我们改变网站结构之后,不需要客户端修改原来的书签,也无需其他网站修改我们的链接,就可以设置为访问,另外还可以在一定程度上提高网站的安全性。

5.1 ngx_http_rewrite_module模块指令

https://nginx/en/docs/http/ngx_http_rewrite_module.html

5.1.1 if指令

用于条件匹配判断,并根据条件判断结果选择不同的Nginx配置,可以配置在server或location块中进行配置,Nginx的if语法仅能使用if做单次判断,不支持使用if else或者if elif这样的多重判断,用法如下:

if (条件匹配) {
	action
}

使用正则表达式对变量进行匹配,匹配成功时if指令认为条件为true,否则认为false,变量与表达式之间使用以下符号链接:

=#比较变量和字符串是否相等,相等时if指令认为该条件为true,反之为false。
!=: #比较变量和字符串是否不相等,不相等时if指令认为条件为true,反之为false。
~: #表示在匹配过程中区分大小写字符,(可以通过正则表达式匹配),满足匹配条件为真,不满足为假。
!~:#为区分大小写字符且匹配结果不匹配,不满足为真,满足为假。
~*: #表示在匹配过程中不区分大小写字符,(可以通过正则表达式匹配),满足匹配条件为真,不满足为假。
!~*: #为不区分大小字符且匹配结果不匹配,满足为假,不满足为真。
-f! -f: #判断请求的文件是否存在和是否不存在
-d! -d: #判断请求的目录是否存在和是否不存在。
-x! -x: #判断文件是否可执行和是否不可执行。
-e! -e: #判断请求的文件或目录是否存在和是否不存在(包括文件,目录,软链接)。

#实例-1:
location /main {
	index index.html;
	default_type text/html;
	if ( $scheme = http ){
	  echo "if-----> $scheme";
	}
    if ( $scheme = https ){
	  echo "if ----> $scheme";
	}
	
	#if (-f $request_filename) {
	#   echo "file is exist";
	#}
	if (!-f $request_filename) {
	    echo "file is not exist";
	    #return 409;
	}
}

注: 如果$变量的值为空字符串或是以0开头的任意字符串,则if指令认为该条件为false,其他条件为true

5.1.2 set指令

指定key并给其定义一个变量,变量可以调用Nginx内置变量赋值给key,另外set定义格式为set $key v a l u e , 及 无 论 是 k e y 还 是 v a l u e 都 要 加 value,及无论是key还是value都要加 valuekeyvalue符号。

location /main {
  root /data/nginx/html/pc;
  index index.html;
  default_type text/html;
  set $name magedu;
  echo $name;
  set $my_port $server_port;
  echo $my_port;
}
5.1.3 break 指令:

用于中断**当前相同作用域(location)中的其他Nginx配置,与该指令处于同一作用域的Nginx配置中,位于它前面的配置生效,位于后面的指令配置就不再生效了,Nginx服务器在根据配置处理请求的过程中遇到该指令的时候,回到上一层作用域继续向下读取配置,该指令可以在server块和location块以及if块中使用,使用语法如下:

location /main {
  root /data/nginx/html/pc;
  index index.html;
  default_type text/html;
  set $name magedu;
  echo $name;
  break;
  set $my_port $server_port;
  echo $my_port;
}
5.1.4 return 指令

从nginx版本0.8.2开始支持,return用于完成对请求的处理,并直接向客户端返回响应状态码,比如其可以指定重定向URL(对于特殊重定向状态码,301/302等) 或者是指定提示文本内容(对于特殊状态码403/500等),处于此指令后的所有配置都将不被执行,return可以在server、if和location块进行配置,用法如下:

return code; #返回给客户端指定的HTTP状态码
return code (text); #返回给客户端的状态码及响应体内容,可以调用变量
return code URL; #返回给客户端的URL地址

例如:
location /main {
  root /data/nginx/html/pc;
  default_type text/html;
  index index.html;
	if ( $scheme = http ){
	  #return 666;
	  #return 666 "not allow http";
	  #return 301 http://www.baidu;
	  return 500 "service error";
	  echo "if-----> $scheme"; #return后面的将不再执行
	} 
	if ( $scheme = https ){
	  echo "if ----> $scheme";
    }
}
5.1.5 rewrite_log 指令:

设置是否开启记录ngx_http_rewrite_module模块日志记录到error_log日志文件当中,可以配置在http、server、location或if当中,需要日志级别为notice 。

location /main {
	index index.html;
	default_type text/html;
	set $name magedu;
	echo $name;
	rewrite_log on;
	break;
	set $my_port $server_port;
	echo $my_port;
}

#重启nginx,访问并验证error_log:
[root@s2 ~]# tail -f /apps/nginx/logs/error.log
2019/02/27 15:10:02 [warn] 5815#0: *3 using uninitialized "my_port" variable, client:192.168.0.1, server: www.magedu, request: "GET /main HTTP/1.1", host:"www.magedu"

5.2 rewrite 指令:

通过正则表达式的匹配来改变URI,可以同时存在一个或多个指令,按照顺序依次对URI进行匹配,rewrite主要是针对用户请求的URL或者是URI做具体处理,以下是URL和URI的具体介绍:

  • URI(universal resource identifier):通用资源标识符,标识一个资源的路径,可以不带协议。

  • URL(uniform resource location):统一资源定位符,是用于在Internet中描述资源的字符串,是URI的子集,主要包括传输协议(scheme)、主机(IP、端口号或者域名)和资源具体地址(目录和文件名)等三部分

    一般格式为scheme://主机名[:端口号][/资源路径],如:http://www.a:8080/path/file/index.html就是一个URL路径,URL必须带访问协议。

    每个URL都是一个URI,但是URI不都是URL。

范例:

http://example:8080/path/to/resource.txt #URI/URL
ftp://example/resource.txt #URI/URL
/absolute/path/to/resource.txt #URI

rewrite的官方介绍地址:https://nginx/en/docs/http/ngx_http_rewrite_module.html#rewrite, rewrite可
以配置在server、location、if,其具体使用方式为:

rewrite regex replacement [flag];

rewrite将用户请求的URI基于regex所描述的模式进行检查,匹配到时将其替换为表达式指定的新的URI。

注意:如果在同一级配置块中存在多个rewrite规则,那么会自下而下逐个检查;被某条件规则替换完成后,会重新一轮的替换检查,隐含有循环机制,但不超过10次;如果超过,提示500响应码,[flag]所表示的标志位用于控制此循环机制,如果替换后的URL是以http://或https://开头,则替换结果会直接以重向返回给客户端, 即永久重定向301

5.2.1 rewrite flag使用介绍

利用nginx的rewrite的指令,可以实现url的重新跳转,rewrtie有四种不同的flag,分别是redirect(临时重定向)、permanent(永久重定向)、break和last。其中前两种是跳转型的flag,后两种是代理型,跳转型是指有客户端浏览器重新对新地址进行请求,代理型是在WEB服务器内部实现跳转的。

Syntax: rewrite regex replacement [flag]; #通过正则表达式处理用户请求并返回替换后的数据包。
Default: —
Context: server, location, if

flag理解为结束符

redirect;
#临时重定向,重写完成后以临时重定向方式直接返回重写后生成的新URL给客户端,由客户端重新发起请求;使用相对路径,或者http://或https://开头,状态码:302

permanent;
#重写完成后以永久重定向方式直接返回重写后生成的新URL给客户端,由客户端重新发起请求,状态码:301

last;
#重写完成后停止对当前URI在当前location中后续的其它重写操作,而后对新的URL启动新一轮重写检查,不建议在location中使用

break;
#重写完成后停止对当前URL在当前location中后续的其它重写操作,而后直接将匹配结果返还给客户端即结束循环并返回数据给客户端,建议在location中使用
5.2.2:rewrite案例-域名永久与临时重定向

要求:因业务需要,将访问源域名 www.magedu 的请求永久重定向到www.magedu 。

临时重定向不会缓存域名解析记录(A记录),但是永久重定向会缓存。

location / {
  root /data/nginx/html/pc;
  index index.html;
  rewrite / http://www.magedu permanent;
  #rewrite / http://www.magedu redirect;
}
#重启Nginx并访问域名www.magedu进行测试

5.2.2.1 永久重定向

域名永久重定向,京东早期的域名 www.360buy 由于与360公司类似,于是后期永久重定向到了 www.jd ,永久重定向会缓存DNS解析记录。

5.2.2.2 临时重定向

域名临时重定向,告诉浏览器域名不是固定重定向到当前目标域名,后期可能随时会更改,因此浏览器不会缓存当前域名的解析记录,而浏览器会缓存永久重定向的DNS解析记录,这也是临时重定向与永久重定向最大的本质区别。

5.2.3 rewrite案例–brak与last

大部分场合下,break单次重写就足够了

要求:访问about的请求被转发至images,而访问images传递请求再次被转发至images1,以此测试last和break分别有什么区别:

5.2.3.1 break案例
#Nginx配置:
break测试案例:当客户端访问break的时候,测试通过rewrite将URL重写为test1,然后再通过rewrite将test1重写为test2测试两条write规则最终哪一条生效,并且测试重写后的URL会不会到其他	location重新匹配。
    location /break {
	  #return 666 "break";
	  root /data/nginx;
	  index index.html;
	  rewrite ^/break/(.*) /test1/$1 break; #break匹配成功后不再向下匹配,也不会跳转到其他的location,即直接结束匹配并给客户端返回结果数据。
	  rewrite ^/test1/(.*) /test2/$1 break; #break不会匹配后面的rewrite规则也不匹配其他location
	} 
	
	location = /test1 {
	  return 999 "new test1";
	  #index index.html;
	  #root /data/nginx;
	}
	
	location = /test2 {
	  return 666 "new test2";
	  #root /opt/nginx;
	  #index index.html;
	}
	
创建资源路径:
# mkdir /data/nginx/break
# mkdir /data/nginx/test1
# mkdir /data/nginx/test2
# cat /data/nginx/break/index.html
break
# cat /data/nginx/test1/index.html
test1
# cat /data/nginx/test2/index.html
test2

# /apps/nginx/sbin/nginx -t
# /apps/nginx/sbin/nginx -s reload

break访问测试:
[root@s3 ~]# curl -L http://www.magedu/break/index.html
test1 #最终的结果不会超出break的location而且不会继续匹配当前location后续的write规则,而且直接返回数据给客户端。

break适用于不改变客户端访问方式,但是要将访问的目的URL做单次重写的场景,比如有V1/V2两个版本的网站前端页面并存,旧版本的网站数据已经保存到了statics不能丢失,但是要将访问新版本的资源重写到新的静态资源路径到新的目录static:
	location /statics {
	  root /data/nginx;
	  index index.html;
	  rewrite ^/statics/(.*) /static/$1 break;
}
5.2.3.2 last案例
last:对某个location的URL匹配成功后会停止当前location的后续rewrite规则,并结束当前location,然后将匹配生成的新URL跳转至其他location继续匹配,直到没有location可匹配后将最后一次location的数据返回给客户端。

	location /test1 {
	  #return 999 "new test1";
	  index index.html;
	  root /data/nginx;
	  rewrite ^/test1/(.*) /test2/$1 last;
	}
	
	location /test2 {
	  return 666 "new test2";
	  #root /opt/nginx;
	  #index index.html;
	}
	
	location /last {
	  root /data/nginx;
	  index index.html;
	  rewrite ^/last/(.*) /test1/$1 last;
	  #rewrite ^/test1/(.*) /test2/$1 last; #如果第一条rewrite规则匹配成功则不执行本条,否则执行本条rewrite规则。
	}
	
last访问测试:
[root@s3 ~]# curl -L http://www.magedu/last/index.html
new test2 #会匹配多个location,直到最终全部匹配完成,返回最后一个location的匹配结果给客户端。

last适用于要不改变客户端访问方式但是需做多次目的URL重写的场景,场景不是很多。
5.2.4 rewrite案例-自动跳转https

要求:基于通信安全考虑公司网站要求全站https,因此要求将在不影响用户请求的情况下将http请求全部自动跳转至https,另外也可以实现部分location跳转

server {
  listen 443 ssl;
  listen 80;
  ssl_certificate /apps/nginx/certs/www.magedu.crt;
  ssl_certificate_key /apps/nginx/certs/www.magedu.key;
  ssl_session_cache shared:sslcache:20m;
  ssl_session_timeout 10m;
  server_name www.magedu;
  location / {
	root /data/nginx/html/pc;
	index index.html;
	if ($scheme = http ){     #未加条件判断,会导致死循环
	  rewrite / https://www.magedu permanent;
	}
  }
} 

#重启Nginx并访问测试
[root@s3 ~]# curl -L -k -i https://www.magedu/
HTTP/1.1 200 OK
Server: nginx
Date: Fri, 15 Mar 2019 19:53:07 GMT
Content-Type: text/html
Content-Length: 7
Last-Modified: Thu, 14 Mar 2019 14:54:50 GMT
Connection: keep-alive
Keep-Alive: timeout=60
ETag: "5c8a6b3a-7"
Accept-Ranges: bytes

pc web

如果是因为规则匹配问题导致的陷入死循环,则报错如下:

5.2.5 rewrite案例-判断文件是否存在

要求:当用户访问到公司网站的时输入了一个错误的URL,可以将用户重定向至官网首页。

location / {
  root /data/nginx/html/pc;
  index index.html;
  if (!-f $request_filename) {
	#return 404 "linux35";
	rewrite (.*) http://www.magedu/index.html;
  }
} 

#重启Nginx并访问测试

5.3 Nginx防盗链

防盗链基于客户端携带的referer实现,referer是记录打开一个页面之前记录是从哪个页面跳转过来的标记信息,如果别人只链接了自己网站图片或某个单独的资源,而不是打开了网站的整个页面,这就是盗链,referer就是之前的那个网站域名,正常的referer信息有以下几种:

none:请求报文首部没有referer首部,比如用户直接在浏览器输入域名访问web网站,就没有referer信息。

blocked:请求报文有referer首部,但无有效值,比如为空。

server_names:referer首部中包含本主机名及即nginx 监听的server_name。

arbitrary_string:自定义指定字符串,但可使用*作通配符。

regular expression:被指定的正则表达式模式匹配到的字符串,要使用~开头,例如: ~.*\.magedu\

正常通过搜索引擎搜索web 网站并访问该网站的referer信息如下:

#通过搜索引擎访问web网站的referer信息:
==> /apps/nginx/logs/access_json.log <==
{"@timestamp":"2019-02-28T13:58:46+08:00","host":"192.168.7.102","clientip":"192.168.0.1","siz
e":0,"responsetime":0.000,"upstreamtime":"-","upstreamhost":"-","http_host":"www.magedu","uri":"/index.html","domain":"www.magedu","xff":"-","referer":"https://www.baidu/s?ie=utf-
8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=www.magedu&oq=www.mageedu&rsv_pq=d63060680002eb69&rsv_t=de01TWnmyTdcJqph7SfI1hXgXLJxSSfUPcQ3QkWdJk%2FLNrN95ih3XOhbRs4&rqlang=cn&rsv_enter=1&inputT=321&rsv_sug3=41&rsv_sug2=0&rsv_sug4=1626","tcp_xff":"","http_user_agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36","status":"304"}
5.3.1 实现 web 盗链:

在一个web 站点盗链另一个站点的资源信息,比如图片、视频等。

[root@s2 conf.d]# pwd
/apps/nginx/conf/conf.d

[root@s2 conf.d]# cat mageedu.conf
server {
  listen 80;
  server_name www.mageedu;
  
  location / {
	index index.html;
	root "/data/nginx/html/mageedu";
	access_log /apps/nginx/logs/www.mageedu.log access_json;
  }
} 

#准备盗链web页面:
[root@s2 conf.d]# mkdir /data/nginx/html/mageedu
[root@s2 conf.d]# cat /data/nginx/html/mageedu/index.html
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>盗链页面</title>
</head>
<body>
<a href="http://www.magedu">测试盗链</a>
<img src="http://www.magedu/images/1.jpg">
</body>
</html>

#重启Nginx并访问http://www.mageedu/测试
#验证两个域名的日志,是否会在被盗连的web站点的日志中出现以下盗链日志信息:
==> /apps/nginx/logs/access_json.log <==
{"@timestamp":"2019-02-28T13:27:37+08:00","host":"192.168.7.102","clientip":"192.168.0.1","size":0,"responsetime":0.000,"upstreamtime":"-","upstreamhost":"-","http_host":"www.magedu","uri":"/images/1.jpg","domain":"www.magedu","xff":"-","referer":"http://www.mageedu/","tcp_xff":"","http_user_agent":"Mozilla/5.0(Windows NT 6.1; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0","status":"304"}

5.3.2:实现防盗链:

基于访问安全考虑,nginx支持通过ungx_http_referer_module模块 https://nginx/en/docs/http/ngx_http_referer_module.html#valid_referers 检查访问请求的referer信息是否有效实现防盗链功能,定义方式如下:

[root@s2 ~]# vim /apps/nginx/conf/conf.d/pc.conf
location /images {
  root /data/nginx/html/pc;
  index index.html;
  valid_referers none blocked server_names
    *.example example.* www.example/galleries/
    ~\.google\.;
    
  if ($invalid_referer) {
	return 403;
  }
}

定义防盗链:

location ^~ /images {
  root /data/nginx;
  index index.html;
  valid_referers none blocked server_names *.magedu www.magedu.* api.online.test/v1/hostlist ~\.google\. ~\.baidu\.; #定义有效的referer
  if ($invalid_referer) { #假如是使用其他的无效的referer访问:
    return 403; #返回状态码403
  }
}
#重启Nginx并访问测试

使用浏览器访问盗链网站 www.mageedu, 验证是否提前状态码403:

6 Nginx 反向代理功能

反向代理:反向代理也叫reverse proxy,指的是代理外网用户的请求到内部的指定web服务器,并将数据返回给用户的一种方式,这是用的比较多的一种方式。

Nginx除了可以在企业提供高性能的web服务之外,另外还可以将本身不具备的请求通过某种预定义的协议转发至其它服务器处理,不同的协议就是Nginx服务器与其他服务器进行通信的一种规范,主要在不同的场景使用以下模块实现不同的功能:
逻辑调用关系:

ngx_http_proxy_module: 将客户端的请求以http协议转发至指定服务器进行处理。
ngx_stream_proxy_module:将客户端的请求以tcp协议转发至指定服务器处理。
ngx_http_fastcgi_module:将客户端对php的请求以fastcgi协议转发至指定服务器助理。
ngx_http_uwsgi_module:将客户端对Python的请求以uwsgi协议转发至指定服务器处理。

生产环境部署结构:

6.1 实现http反向代理

要求:将用户对域 www.nagedu 的请求转发值后端服务器处理,官方文档: https://nginx/en/docs/http/ngx_http_proxy_module.html

环境准备:

192.168.7.102 #Nginx 代理服务器
192.168.7.103 #后端web A,Apache部署
192.168.7.104 #后端web B,Apache部署

访问逻辑图:

6.1.1 部署后端 Apache服务器
[root@s3 ~]# yum install httpd -y
[root@s3 ~]# echo "web1 192.168.7.103" > /var/www/html/index.html
[root@s3 ~]# systemctl start httpd && systemctl enable httpd

[root@s4 ~]# yum install httpd -y
[root@s4 ~]# echo "web2 192.168.7.104" >> /var/www/html/index.html
[root@s4 ~]# systemctl start httpd && systemctl enable httpd

#访问测试
[root@s4 ~]# curl http://192.168.7.103
web1 192.168.7.103
[root@s3 ~]# curl http://192.168.7.104
web2 192.168.7.104
6.1.2 Nginx http 反向代理入门

官方文档:https://nginx/en/docs/http/ngx_http_proxy_module.html#proxy_pass

6.2.1.1 反向代理配置参数
proxy_pass;
#用来设置将客户端请求转发给的后端服务器的主机,可以是主机名、IP地址:端口的方式,也可以代理到预先设置的主机群组,需要模块gx_http_upstream_module支持。
  location /web {
	index index.html;
	proxy_pass http://192.168.7.103:80;
	#不带斜线将访问的/web,等于访问后端服务器 http://192.168.7.103:80/web/index.html,即后端服务器配置的站点根目录要有web目录才可以被访问,这是一个追加/web到后端服务器http://servername:port/WEB/INDEX.HTML的操作

	proxy_pass http://192.168.7.103:80/;
	#带斜线,等于访问后端服务器的http://192.168.7.103:80/index.html 内容返回给客户端
  } 
  
#重启Nginx测试访问效果:
# curl -L http://www.magedu/web/index.html

proxy_hide_header field;
#用于nginx作为反向代理的时候,在返回给客户端http响应的时候,隐藏后端服务版本相应头部的信息,可以设置在http/server或location块,
  location /web {
	index index.html;
	proxy_pass http://192.168.7.103:80/;
	proxy_hide_header ETag;
  }
  
proxy_pass_header field;
#默认nginx在响应报文中不传递后端服务器的首部字段Date, Server, X-Pad, X-Accel等参数,如果要传递的话则要使用 proxy_pass_header field声明将后端服务器返回的值传递给客户端。

proxy_pass_request_body on | off;
#是否向后端服务器发送HTTP包体部分,可以设置在http/server或location块,默认即为开启

proxy_pass_request_headers on | off;
#是否将客户端的请求头部转发给后端服务器,可以设置在http/server或location块,默认即为开启

proxy_set_header;
#可以更改或添加客户端的请求头部信息内容并转发至后端服务器,比如在后端服务器想要获取客户端的真实IP的时候,就要更改每一个报文的头部,如下:

#proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-For $remote_addr;
#添加HOST到报文头部,如果客户端为NAT上网那么其值为客户端的共用的公网IP地址,常用于在日之中记录客户端的真实IP地址。

proxy_connect_timeout time;
#配置nginx服务器与后端服务器尝试建立连接的超时时间,默认为60秒,用法如下:
proxy_connect_timeout 60s;
#60s为自定义nginx与后端服务器建立连接的超时时间

proxy_read_time time;
#配置nginx服务器向后端服务器或服务器组发起read请求后,等待的超时时间,默认60s
proxy_send_time time;
#配置nginx项后端服务器或服务器组发起write请求后,等待的超时时间,默认60s

proxy_http_version 1.0#用于设置nginx提供代理服务的HTTP协议的版本,默认http 1.0

proxy_ignore_client_abort off;
#当客户端网络中断请求时,nginx服务器中断其对后端服务器的请求。即如果此项设置为on开启,则服务器会忽略客户端中断并一直等着代理服务执行返回,如果设置为off,则客户端中断后Nginx也会中断客户端请求并立即记录499日志,默认为off。

proxy_headers_hash_bucket_size 128#当配置了 proxy_hide_header和proxy_set_header的时候,用于设置nginx保存HTTP报文头的hash表的上限。
proxy_headers_hash_max_size 512#设置proxy_headers_hash_bucket_size的最大可用空间

server_names_hash_bucket_size 512;
#server_name hash表申请空间大小
server_names_hash_max_szie 512;
#设置服务器名称hash表的上限大小
6.1.2.2 反向代理示例–单台web服务器
[root@s2 conf.d]# mv pc.conf pc.conf.bak0304
[root@s2 conf.d]# cp mobile.conf pc.conf
[root@s2 conf.d]# cat pc.conf
server {
  listen 80;
  server_name www.magedu;
  location / {
	proxy_pass http://192.168.7.103:80/;
  }
} 

#重启Nginx 并访问测试
6.1.2.3 反向代理示例–指定location
server {
  listen 80;
  server_name www.magedu;
  location / {
	index index.html index.php;
	root /data/nginx/html/pc;
  }
  
  location /web {
	#proxy_pass http://192.168.7.103:80/; #注意有后面的/,
	proxy_pass http://192.168.7.104:80/;
  }
} 

#后端web服务器必须要有相对于的访问URL
[root@s3 ~]# mkdir /var/www/html/web
[root@s3 ~]# echo "web1 page for apache" > /var/www/html/web/index.html
[root@s4 ~]# mkdir /var/www/html/web
[root@s4 ~]# echo "web2 page for apache" > /var/www/html/web/index.html

#重启Nginx并访问测试:
[root@s2 ~]# curl -L http://www.magedu/
pc web
[root@s2 ~]# curl -L http://www.magedu/web
web2 page for apache

#Apache的访问日志:
[root@s4 ~]# tail -f /var/log/httpd/access_log
192.168.7.102 - - [04/Mar/2019:18:52:00 +0800] "GET /web/ HTTP/1.1" 200 21 "-""curl/7.29.0"
192.168.7.102 - - [04/Mar/2019:18:52:00 +0800] "GET /web HTTP/1.0" 301 233 "-""curl/7.29.0"
192.168.7.102 - - [04/Mar/2019:18:52:00 +0800] "GET /web/ HTTP/1.1" 200 21 "-""curl/7.29.0"
6.1.2.4 反向代理示例–缓存功能

缓存功能默认关闭状态

proxy_cache zone | off; 默认off
#指明调用的缓存,或关闭缓存机制;Context:http, server, location

proxy_cache_key string;
#缓存中用于“键”的内容,默认值:proxy_cache_key $scheme$proxy_host$request_uri;

proxy_cache_valid [code ...] time;
#定义对特定响应码的响应内容的缓存时长,定义在http{...}中
	示例:
	proxy_cache_valid 200 302 10m;
	proxy_cache_valid 404 1m;
	proxy_cache_path;
	定义可用于proxy功能的缓存;Context:http
	proxy_cache_path path [levels=levels] [use_temp_path=on|off] keys_zone=name:size [inactive=time] [max_size=size][manager_files=number] [manager_sleep=time]
[manager_threshold=time] [loader_files=number] [loader_sleep=time]
[loader_threshold=time] [purger=on|off] [purger_files=number] [purger_sleep=time]
[purger_threshold=time];

示例:在http配置定义缓存信息
proxy_cache_path /var/cache/nginx/proxy_cache #定义缓存保存路径,proxy_cache会自动创建
levels=1:2:2 #定义缓存目录结构层次,1:2:2可以生成2^4x2^8x2^8=1048576个目录
keys_zone=proxycache:20m #指内存中缓存的大小,主要用于存放key和metadata(如:使用次数)
inactive=120s; #缓存有效时间
max_size=1g; #最大磁盘占用空间,磁盘存入文件内容的缓存空间最大值


#调用缓存功能,需要定义在相应的配置段,如server{...};或者location等
proxy_cache proxycache;
proxy_cache_key $request_uri;
proxy_cache_valid 200 302 301 10m; #指定的状态码返回的数据缓存多长时间
proxy_cache_valid any 1m;


proxy_cache_use_stale error http_502 http_503;
#在被代理的后端服务器出现哪种情况下,可直接使用过期的缓存响应客户端,
proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 | http_502 | http_503 | http_504 | http_403 | http_404 | off ; #默认是off


proxy_cache_methods GET | HEAD | POST ...;
#对哪些客户端请求方法对应的响应进行缓存,GET和HEAD方法总是被缓存

非缓存场景压测

[root@s3 app1]# pwd
/var/www/html/app1
[root@s3 app1]# cp /var/log/messages ./log.html #准备测试页面
[root@s2 pc]# ab -n 2000 -c200 http://www.magedu/web/log.html
	Total transferred: 		3059318000 bytes
	HTML transferred: 		3058760000 bytes
	Requests per second: 	155.14 [#/sec] (mean)
	Time per request: 		1289.166 [ms] (mean)
	Time per request: 		6.446 [ms] (mean, across all concurrent requests)
	Transfer rate: 			231747.94 [Kbytes/sec] received

准备缓存配置

[root@s2 pc]# vim /apps/nginx/conf/nginx.conf
proxy_cache_path /data/nginx/proxycache levels=1:1:1 keys_zone=proxycache:20m inactive=120s max_size=1g; #配置在nginx.conf http配置段

[root@s2 pc]# vim /apps/nginx/conf/conf.d/pc.conf
location /web { #要缓存的URL 或者放在server配置项对所有URL都进行缓存
	proxy_pass http://192.168.7.104:80/;
	proxy_set_header clientip $remote_addr;
	proxy_cache proxycache;
	proxy_cache_key $request_uri;
	proxy_cache_valid 200 302 301 1h;
	proxy_cache_valid any 1m;
}

[root@s2 pc]# /apps/nginx/sbin/nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
[root@s2 pc]# systemctl start nginx

访问并验证缓存文件

#访问web并验证缓存目录
[root@s2 pc]# curl http://www.magedu/web/log.html
[root@s2 pc]# ab -n 2000 -c200 http://www.magedu/web/log.html
	Total transferred: 		3059318000 bytes
	HTML transferred: 		3058760000 bytes
	Requests per second: 	1922.78 [#/sec] (mean)
	Time per request: 		104.016 [ms] (mean)
	Time per request: 		0.520 [ms] (mean, across all concurrent requests)
	Transfer rate: 			2872259.55 [Kbytes/sec] received

#验证缓存目录结构及文件大小
[root@s2 pc]# tree /data/nginx/proxycache/
/data/nginx/proxycache/
└── f 
	└── 0 
		└── 6 
			└── 50b643197ae7d66aaaa5e7e1961b060f
3 directories, 1 file
[root@s2 pc]# ll -h /data/nginx/proxycache/f/0/6/50b643197ae7d66aaaa5e7e1961b060f
-rw------- 1 nginx nginx 1.5M Mar 7 14:30 /data/nginx/proxycache/f/0/6/50b643197ae7d66aaaa5e7e1961b060f

#验证文件内容:
[root@s2 pc]# head -n100 /data/nginx/proxycache/f/0/6/50b643197ae7d66aaaa5e7e1961b060f
#会在文件首部添加相应码
HTTP/1.1 200 OK
Date: Thu, 07 Mar 2019 18:35:37 GMT
Server: Apache/2.4.6 (CentOS)
Last-Modified: Thu, 07 Mar 2019 14:14:47 GMT
ETag: "175624-58381ba95ac05"
Accept-Ranges: bytes
Content-Length: 1529380
Connection: close
Content-Type: text/html; charset=UTF-8

192.168.0.1 - - [18/Feb/2019:10:26:33 +0800] "GET / HTTP/1.1" 200 612
6.1.2.5 添加头部报文信息

nginx基于模块ngx_http_headers_module可以实现对头部报文添加指定的key与值, https://nginx/en/docs/http/ngx_http_headers_module.html

Syntax: add_header name value [always];
Default: —
Context: http, server, location, if in location

#添加自定义首部,如下:
add_header name value [always];
	add_header X-Via $server_addr;
	add_header X-Cache $upstream_cache_status;
	add_header X-Accel $server_name;
	
#添加自定义响应信息的尾部, 1.13.2版后支持
add_trailer name value [always];

Nginx配置

location /web {
  proxy_pass http://192.168.7.103:80/;
  proxy_set_header clientip $remote_addr;
  proxy_cache proxycache;
  proxy_cache_key $request_uri;
  proxy_cache_valid 200 302 301 1h;
  proxy_cache_valid any 1m;
  add_header X-Via $server_addr;
  add_header X-Cache $upstream_cache_status;
  add_header X-Accel $server_name;
}

验证头部信息

6.1.3 Nginx http 反向代理高级应用

在上一个章节中Nginx可以将客户端的请求转发至单台后端服务器但是无法转发至特定的一组的服务器,而且不能对后端服务器提供相应的服务器状态监测,但是Nginx可以基于ngx_http_upstream_module模块提供服务器分组转发、权重分配、状态监测、调度算法等高级功能,官方文档: https://nginx/en/docs/http/ngx_http_upstream_module.html

6.1.3.1 http upstream配置参数
upstream name {
} 

#自定义一组服务器,配置在http内
server address [parameters];
#配置一个后端web服务器,配置在upstream内,至少要有一个server服务器配置。

#server支持的parameters如下:
weight=number #设置权重,默认为1。
max_conns=number #给当前server设置最大活动链接数,默认为0表示没有限制。
fail_timeout=time #对后端服务器的单次监测超时时间,默认为10秒。
max_fails=number #在fail_timeout时间对后端服务器连续监测失败多少次就标记为不可用。
backup #设置为备份服务器,当所有服务器不可用时将重新启用次服务器。
down #标记为down状态。
resolve #当server定义的是主机名的时候,当A记录发生变化会自动应用新IP而不用重启Nginx。


hash KEY consistent;
#基于指定key做hash计算,使用consistent参数,将使用ketama一致性hash算法,适用于后端是Cache服务器(如varnish)时使用,consistent定义使用一致性hash运算,一致性hash基于取模运算。

hash $request_uri consistent; #基于用户请求的uri做hash


ip_hash;
#源地址hash调度方法,基于的客户端的remote_addr(源地址)做hash计算,以实现会话保持,


least_conn;
#最少连接调度算法,优先将客户端请求调度到当前连接最少的后端服务器
6.1.3.2 反向代理示例–多台web服务器
upstream webserver {
  #hash $request_uri consistent;
  #ip_hash;
  #least_conn;
  server 192.168.7.103:80 weight=1 fail_timeout=15s max_fails=3; #后端服务器状态监测
  server 192.168.7.104:80 weight=1 fail_timeout=15s max_fails=3;
  server 192.168.7.101:80 weight=1 fail_timeout=15s max_fails=3 backup;
} 

server {
  listen 80;
  server_name www.magedu;
  location / {
	index index.html index.php;
	root /data/nginx/html/pc;
  }
  
  location /web {
	index index.html;
	proxy_pass http://webserver/;
  }
} 

#重启Nginx 并访问测试
[root@s2 ~]# curl http://www.magedu/web
web1 192.168.7.103
[root@s2 ~]# curl http://www.magedu/web
web2 192.168.7.104

关闭192.168.7.103和192.168.7.104,测试nginx backup服务器可用性:

[root@s4 ~]# while true;do curl http://www.magedu/web;sleep 1;done

6.1.3.3 反向代理示例 – 客户端 IP 透传
[root@s2 conf.d]# cat pc.conf
upstream webserver {
  #hash $request_uri consistent; #consistent 一致性hash算法
  #server 192.168.7.103:80 weight=1 fail_timeout=5s max_fails=3;
  server 192.168.7.104:80 weight=1 fail_timeout=5s max_fails=3;
  server 192.168.7.101:80 weight=1 fail_timeout=5s max_fails=3 backup;
} 

server {
  listen 80;
  server_name www.magedu;
  location / {
	index index.html index.php;
	root /data/nginx/html/pc;
  }
  
  location /web {
	index index.html;
	proxy_pass http://webserver/;
	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; #添加客户端IP到报文头部
  }
}

#重启nginx
#后端web服务器配置
1、Apache:
[root@s4 ~]# vim /etc/httpd/conf/httpd.conf
LogFormat "%{X-Forwarded-For}i %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{UserAgent}i\"" combined

#重启apache访问web界面并验证apache日志:
192.168.7.104 192.168.7.102 - - [05/Mar/2019:00:36:03 +0800] "GET / HTTP/1.0" 200 19 "-" "curl/7.29.0"
192.168.0.1 192.168.7.102 - - [05/Mar/2019:00:40:46 +0800] "GET / HTTP/1.0" 200 19 "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36"

2、Nginx:
[root@s1 conf.d]# cat /apps/nginx/conf/nginx.conf
"$http_x_forwarded_for"' #默认日志格式就有此配置

重启nginx访问web界面并验证日志格式:
192.168.7.102 - - [04/Mar/2019:16:33:24 +0800] "GET // HTTP/1.0" 200 24 "-" "curl/7.29.0" "192.168.7.104"
192.168.7.102 - - [04/Mar/2019:16:40:51 +0800] "GET / HTTP/1.0" 200 24 "-" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36" "192.168.0.1"
6.1.4 实现动静分离

要求:将客户端对图片的访问

画图

6.2 实现Nginx tcp负载均衡

支持的时间太晚,导致目前用的较少

Nginx在1.9.0版本开始支持tcp模式的负载均衡,在1.9.13版本开始支持udp协议的负载,udp主要用于DNS的域名解析,其配置方式和指令和http 代理类似,其基于ngx_stream_proxy_module模块实现tcp负载,另外基于模块ngx_stream_upstream_module实现后端服务器分组转发、权重分配、状态监测、调度算法等高级功能。

官方文档:https://nginx/en/docs/stream/ngx_stream_core_module.html

6.2.1 tcp负载均衡配置参数
stream { #定义stream
  upstream backend { #定义后端服务器
	hash $remote_addr consistent; #定义调度算法
	
	server backend1.example:12345 weight=5; #定义具体server
	server 127.0.0.1:12345 max_fails=3 fail_timeout=30s;
	server unix:/tmp/backend3;
  } 
  
  upstream dns { #定义后端服务器
	server 192.168.0.1:53535; #定义具体server
	server dns.example:53;
  } 

  server { #定义server
	listen 12345; #监听IP:PORT
	proxy_connect_timeout 1s; #连接超时时间
	proxy_timeout 3s; #转发超时时间
	proxy_pass backend; #转发到具体服务器组
  } 
  
  server {
	listen 127.0.0.1:53 udp reuseport;
	proxy_timeout 20s;
	proxy_pass dns;
  } 
  
  server {
	listen [::1]:12345;
	proxy_pass unix:/tmp/stream.socket;
  }
}
6.2.2 负载均衡实例–Redis

服务器安装redis

[root@s4 ~]# yum install redis -y
[root@s4 ~]# vim /etc/redis.conf
bind 0.0.0.0
......
[root@s4 ~]# systemctl start redis
[root@s4 ~]# systemctl enable redis
[root@s4 ~]# ss -tnl | grep 6379
LISTEN 	0 	128 	*:6379 		*:*

nginx配置:

[root@s2 ~]# mkdir /apps/nginx/conf/tcp
[root@s2 ~]# cat /apps/nginx/conf/tcp/tcp.conf
stream {
  upstream redis_server {
	#hash $remote_addr consistent;
	server 192.168.7.104:6379 max_fails=3 fail_timeout=30s;
  } 
  
  server {
	listen 192.168.7.102:6379;
	proxy_connect_timeout 3s;
	proxy_timeout 3s;
	proxy_pass redis_server;
  }
} 

[root@s2 ~]# vim /apps/nginx/conf/nginx.conf
21 include /apps/nginx/conf/tcp/tcp.conf; #注意此处的include与http模块平级

#重启nginx并访问测试
[root@s2 ~]# systemctl restart nginx
[root@s2 ~]# ss -tnl | grep 6379
LISTEN 	0 	128 	192.168.7.102:6379 	*:*

#测试通过nginx 负载连接redis:
[root@s4 ~]# redis-cli -h 192.168.7.102
192.168.7.102:6379> set name jack
OK
192.168.7.102:6379> get name
"jack"
192.168.7.102:6379>

6.2.3 负载均衡实例:MySQL

服务器安装MySQL:

[root@s4 ~]# yum install mariadb mariadb-server -y
[root@s4 ~]# systemctl start mariadb
[root@s4 ~]# mysql_secure_installation #安全初始化
[root@s4 ~]# systemctl enable mariadb
[root@s4 ~]# mysql -uroot -p123456
MariaDB [(none)]> GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123456' WITH GRANT OPTION;
MariaDB [(none)]> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]> exit

nginx配置:

[root@s2 ~]# cat /apps/nginx/conf/tcp/tcp.conf
stream {
  upstream redis_server {
    server 192.168.7.104:6379 max_fails=3 fail_timeout=30s;
  } 
  
  upstream mysql_server {
	least_conn;
	server 192.168.7.104:3306 max_fails=3 fail_timeout=30s;
  }
###################################################################
  server {
	listen 192.168.7.102:3306;
	proxy_connect_timeout 6s;
	proxy_timeout 15s;
	proxy_pass mysql_server;
  }
  
  server {
	listen 192.168.7.102:6379;
	proxy_connect_timeout 3s;
	proxy_timeout 3s;
	proxy_pass redis_server;
  }
} 

#重启nginx并访问测试:
[root@s2 ~]# systemctl restart nginx

#测试通过nginx负载连接MySQL:
[root@s4 ~]# mysql -uroot -p123456 -h 192.168.7.102
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 32
Server version: 5.5.60-MariaDB MariaDB Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> create database linux34;
Query OK, 1 row affected (0.00 sec)

MariaDB [(none)]> show databases;
+--------------------+
| Database 			 |
+--------------------+
| information_schema |
| linux34 			 |
| mysql 			 |
| performance_schema |
+--------------------+
4 rows in set (0.01 sec)

MariaDB [(none)]>

6.3 实现FastCGI

CGI的由来:

最早的Web服务器只能简单地响应浏览器发来的HTTP请求,并将存储在服务器上的HTML文件返回给浏览器,也就是静态html文件(http://www.zbbz/index.html),但是后期随着网站功能增多网站开发也越来越复杂,以至于出现动态技术,比如像php(1995年)、java(1995)、python(1991)语言开发的网站,但是nginx/apache服务器并不能直接运行 php、java这样的文件,apache实现的方式是打补丁,但是nginx却通过与第三方基于协议实现,即通过某种特定协议将客户端请求转发给第三方服务处理,第三方服务器会新建新的进程处理用户的请求,处理完成后返回数据给Nginx并回收进程,最后nginx在返回给客户端,那这个约定就是通用网关接口(common gateway interface,简称CGI),CGI(协议) 是web服务器和外部应用程序之间的接口标准,是cgi程序和web服务器之间传递信息的标准化接口。

CGI的通信方式:

为什么会有FastCGI?

CGI协议虽然解决了语言解析器和seb server之间通讯的问题,但是它的效率很低,因为web server每收到一个请求都会创建一个CGI进程,PHP解析器都会解析php.ini文件,初始化环境,请求结束的时候再关闭进程,对于每一个创建的CGI进程都会执行这些操作,所以效率很低,而FastCGI是用来提高CGI性能的,FastCGI每次处理完请求之后不会关闭掉进程,而是保留这个进程,使这个进程可以处理多个请求。这样的话每个请求都不用再重新创建一个进程了,大大提升了处理效率。

FastCGI通信方式:

什么是PHP-FPM?
PHP-FPM(FastCGI Process Manager:FastCGI进程管理器)是一个实现了Fastcgi的管理程序,并且提供进程管理的功能,进程包括master进程和worker进程,master进程只有一个,负责监听端口,接受来自web server的请求。worker进程一般会有多个,每个进程中会嵌入一个PHP解析器,进行PHP代码的处理。

6.3.1 FastCGI 配置指令

Nginx基于模块ngx_http_fastcgi_module实现通过fastcgi协议将指定的客户端请求转发至php-fpm处理,其配置指令如下:

fastcgi_pass address;
#转发请求到后端服务器,address为后端的fastcgi server的地址,可用位置:location, if in location

fastcgi_index name;
#fastcgi默认的主页资源,示例:fastcgi_index index.php;

fastcgi_param parameter value [if_not_empty];
#设置传递给FastCGI服务器的参数值,可以是文本,变量或组合,可用于将Nginx的内置变量赋值给自定义key
fastcgi_param REMOTE_ADDR $remote_addr; #客户端源IP
fastcgi_param REMOTE_PORT $remote_port; #客户端源端口
fastcgi_param SERVER_ADDR $server_addr; #请求的服务器IP地址
fastcgi_param SERVER_PORT $server_port; #请求的服务器端口
fastcgi_param SERVER_NAME $server_name; #请求的server name

Nginx默认配置示例:
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;
}

缓存定义指令:

fastcgi_cache_path path [levels=levels] [use_temp_path=on|off] keys_zone=name:size [inactive=time] [max_size=size] [manager_files=number] [manager_sleep=time] [manager_threshold=time] [loader_files=number] [loader_sleep=time] [loader_threshold=time] [purger=on|off] [purger_files=number] [purger_sleep=time] [purger_threshold=time];

定义fastcgi的缓存;
	path #缓存位置为磁盘上的文件系统路径
	max_size=size #磁盘path路径中用于缓存数据的缓存空间上限
	levels=levels:#十六进制的缓存目录的层级数量,以及每一级的目录数量,levels=ONE:TWO:THREE,示例:leves=1:2:2
	keys_zone=name:size #设置缓存名称及k/v映射的内存空间的名称及大小
	inactive=time #缓存有效时间,默认10分钟,需要在指定时间满足fastcgi_cache_min_uses 次数被视为活动缓存。

缓存调用指令:

fastcgi_cache zone | off;
#调用指定的缓存空间来缓存数据,可用位置:http, server, location

fastcgi_cache_key string;
#定义用作缓存项的key的字符串,示例:fastcgi_cache_key $request_uri;

fastcgi_cache_methods GET | HEAD | POST ...;
#为哪些请求方法使用缓存

fastcgi_cache_min_uses number;
#缓存空间中的缓存项在inactive定义的非活动时间内至少要被访问到此处所指定的次数方可被认作活动项

fastcgi_keep_conn on | off;
#收到后端服务器响应后,fastcgi服务器是否关闭连接,建议启用长连接

fastcgi_cache_valid [code ...] time;
#不同的响应码各自的缓存时长

fastcgi_hide_header field; #隐藏响应头指定信息
fastcgi_pass_header field; #返回响应头指定信息,默认不会将Status、X-Accel-...返回
6.3.2 FastCGI示例–Nginx与php-fpm在同一服务器

php安装可以通过yum或者编译安装,使用yum安装相对比较简单,编译安装更方便自定义参数或选项。

说明:服务器压力不大时,nginx通常与php-fpm在同一服务器

6.3.2.1 php环境准备

使用base源自带的php版本,https://www.php/docs.php

#yum安装默认版本php
[root@s2 ~]# yum install php-fpm php-mysql -y #默认版本
[root@s2 ~]# systemctl start php-fpm && systemctl enable php-fpm
[root@s2 ~]# ps -ef | grep php-fpm
root   4925    1 0 17:13 ? 00:00:00 php-fpm: master process (/etc/phpfpm.conf)
apache 4927 4925 0 17:13 ? 00:00:00 php-fpm: pool www
apache 4928 4925 0 17:13 ? 00:00:00 php-fpm: pool www
apache 4929 4925 0 17:13 ? 00:00:00 php-fpm: pool www
apache 4930 4925 0 17:13 ? 00:00:00 php-fpm: pool www
apache 4931 4925 0 17:13 ? 00:00:00 php-fpm: pool www
root   4933 3235 0 17:13 pts/0 00:00:00 grep --color=auto php-fpm
6.3.2.2 php相关配置优化
[root@s2 ~]# grep "^[a-Z]" /etc/php-fpm.conf
include=/etc/php-fpm.d/*.conf
pid = /run/php-fpm/php-fpm.pid
error_log = /var/log/php-fpm/error.log
daemonize = yes #是否后台启动

[root@s2 ~]# cat /etc/php-fpm.d/www.conf
[www]
listen = 127.0.0.1:9000 #监听地址及IP
listen.allowed_clients = 127.0.0.1 #允许客户端从哪个源IP地址访问,要允许所有行首加 ;注释即可
user = nginx #php-fpm启动的用户和组,会涉及到后期文件的权限问题
group = nginx
pm = dynamic #动态模式进程管理
pm.max_children = 500 #静态方式下开启的php-fpm进程数量,在动态方式下他限定php-fpm的最大进程数
pm.start_servers = 100 #动态模式下初始进程数,必须大于等于pm.min_spare_servers和小于等于
pm.max_children的值。
pm.min_spare_servers = 100 #最小空闲进程数
pm.max_spare_servers = 200 #最大空闲进程数
pm.max_requests = 500000 #进程累计请求回收值,会回收并重新生成新的子进程
pm.status_path = /pm_status #状态访问URL
ping.path = /ping #ping访问动地址
ping.response = ping-pong #ping返回值
slowlog = /var/log/php-fpm/www-slow.log #慢日志路径
php_admin_value[error_log] = /var/log/php-fpm/www-error.log #错误日志
php_admin_flag[log_errors] = on
php_value[session.save_handler] = files #phpsession保存方式及路径
php_value[session.save_path] = /var/lib/php/session #当时使用file保存session的文件路径

修改配置文件后记得重启php-fpm

[root@s2 ~]# systemctl restart php-fpm
6.2.3.3 准备php测试页面
[root@s2 ~]# mkdir /data/nginx/php
[root@s2 ~]# cat /data/nginx/php/index.php #php测试页面
<?php
  phpinfo();
?>
6.3.2.4 Nginx配置转发

Nginx安装完成之后默认生成了与fastcgi的相关配置文件,一般保存在nginx的安装路径的conf目录当中,比如/apps/nginx/conf/fastcgi.conf、/apps/nginx/conf/fastcgi_params。

[root@s2 ~]# vim /apps/nginx/conf/conf.d/pc.conf #在指定文件配置fastcgi
location ~ \.php$ {
  root 			/data/nginx/php; #$document_root调用root目录
  fastcgi_pass  127.0.0.1:9000;
  fastcgi_index index.php;
  #fastcgi_param SCRIPT_FILENAME /data/nginx/php$fastcgi_script_name;
  fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  #如果SCRIPT_FILENAME是绝对路径则可以省略root /data/nginx/php;
  include fastcgi_params;
}
#重启Nginx并访问web测试
systemctl restart nginx
6.3.2.5 访问验证php测试页

fastcgi_pass常见的错误:
File not found. #路径不对
502: php-fpm处理超时、服务停止运行等原因导致的无法连接或请求超时
6.3.2.6 php-fpm 的运行状态页面

访问配置文件里面指定的路径,会返回php-fpm的当前运行状态。

Nginx配置:

location ~ ^/(pm_status|ping)$ {
  #access_log off;
  #allow 127.0.0.1;
  #deny all;
  include fastcgi_params;
  fastcgi_pass 127.0.0.1:9000;
  fastcgi_param PATH_TRANSLATED $document_root$fastcgi_script_name;
}

重启Nginx并测试:

[root@Centos7 ~]#curl http://www.magedu/pm_status
pool:                 www
process manager:      dynamic
start time:           21/Jul/2020:16:58:35 +0800
start since:          42
accepted conn:        2
listen queue:         0
max listen queue:     0
listen queue len:     128
idle processes:       4
active processes:     1
total processes:      5
max active processes: 1
max children reached: 0
slow requests:        0
[root@Centos7 ~]#curl http://www.magedu/ping
pong
[root@Centos7 ~]#curl http://www.magedu/pm_status?full
pool:                 www
process manager:      dynamic
start time:           21/Jul/2020:16:58:35 +0800
start since:          85
accepted conn:        4
listen queue:         0
max listen queue:     0
listen queue len:     128
idle processes:       4
active processes:     1
total processes:      5
max active processes: 1
max children reached: 0
slow requests:        0

************************
pid:                  2099
state:                Idle
start time:           21/Jul/2020:16:58:35 +0800
start since:          85
requests:             1
request duration:     393
request method:       GET
request URI:          /pm_status
content length:       0
user:                 -
script:               -
last request cpu:     0.00
last request memory:  262144

************************
pid:                  2100
state:                Idle
start time:           21/Jul/2020:16:58:35 +0800
start since:          85
requests:             0
request duration:     0
request method:       -
request URI:          -
content length:       0
user:                 -
script:               -
last request cpu:     0.00
last request memory:  0

************************
pid:                  2101
state:                Idle
start time:           21/Jul/2020:16:58:35 +0800
start since:          85
requests:             1
request duration:     301
request method:       GET
request URI:          /pm_status
content length:       0
user:                 -
script:               -
last request cpu:     0.00
last request memory:  262144

************************
pid:                  2102
state:                Running
start time:           21/Jul/2020:16:58:35 +0800
start since:          85
requests:             1
request duration:     477
request method:       GET
request URI:          /pm_status?full
content length:       0
user:                 -
script:               -
last request cpu:     0.00
last request memory:  0

************************
pid:                  2103
state:                Idle
start time:           21/Jul/2020:16:58:35 +0800
start since:          85
requests:             1
request duration:     242
request method:       GET
request URI:          /ping
content length:       0
user:                 -
script:               -
last request cpu:     0.00
last request memory:  262144

[root@Centos7 ~]#curl http://www.magedu/pm_status?html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3/1999/xhtml" xml:lang="en" lang="en">
<head><title>PHP-FPM Status Page</title></head>
<body>
<table>
<tr><th>pool</th><td>www</td></tr>
<tr><th>process manager</th><td>dynamic</td></tr>
<tr><th>start time</th><td>21/Jul/2020:16:58:35 +0800</td></tr>
<tr><th>start since</th><td>116</td></tr>
<tr><th>accepted conn</th><td>5</td></tr>
<tr><th>listen queue</th><td>0</td></tr>
<tr><th>max listen queue</th><td>0</td></tr>
<tr><th>listen queue len</th><td>128</td></tr>
<tr><th>idle processes</th><td>4</td></tr>
<tr><th>active processes</th><td>1</td></tr>
<tr><th>total processes</th><td>5</td></tr>
<tr><th>max active processes</th><td>1</td></tr>
<tr><th>max children reached</th><td>0</td></tr>
<tr><th>slow requests</th><td>0</td></tr>
</table>
</body></html>

[root@Centos7 ~]#curl http://www.magedu/pm_status?json
{"pool":"www","process manager":"dynamic","start time":1595321915,"start since":147,"accepted conn":6,"listen queue":0,"max listen queue":0,"listen queue len":128,"idle processes":4,"active processes":1,"total processes":5,"max active processes":1,"max children reached":0,"slow requests":0}
6.3.3 FastCGI示例–Nginx与php不在同一个服务器

nginx会处理静态请求,但是会转发动态请求到后端指定的php-fpm服务器,因此代码也需要放在后端的php-fpm服务器,即静态页面放在Nginx上而动态页面放在后端php-fpm服务器,正常情况下,一般都是采用6.3.2的部署方式。

6.3.3.1 yum安装较新版本php-fpm
[root@s4 ~]# rpm -ivh https://mirrors.tuna.tsinghua.edu/remi/enterprise/remi-release-7.rpm 
[root@nginx-web2 ~]#yum install https://mirrors.tuna.tsinghua.edu/remi/enterprise/remi-release-7.rpm
#包含较新的PHP等软件包

#[root@s4 ~]# yum install php56-php-fpm php56-php-mysql -y #安装指定版本的php
[root@nginx-web2 ~]#yum install php72-php-fpm php72-php-mysql -y
验证安装路径:
[root@nginx-web2 ~]#rpm -ql php72-php-fpm
/etc/logrotate.d/php72-php-fpm
/etc/opt/remi/php72/php-fpm.conf
/etc/opt/remi/php72/php-fpm.d
/etc/opt/remi/php72/php-fpm.d/www.conf
/etc/opt/remi/php72/sysconfig/php-fpm
/etc/systemd/system/php72-php-fpm.service.d
/opt/remi/php72/root/usr/sbin/php-fpm
......
/var/opt/remi/php72/run/php-fpm

生成php72配置文件:
[root@s4 ~]# cp /opt/remi/php72/root/usr/share/doc/php72-php-common-7.2.24/php.iniproduction /opt/remi/php72/root/usr/etc/php.ini

[root@s4 ~]# cp /opt/remi/php72/root/usr/share/doc/php72-php-fpm-7.2.24/phpfpm.conf.default /opt/remi/php72/root/usr/etc//php-fpm.conf
6.3.3.2:修改php-fpm监听配置

php-fpm默认监听在127.0.0.1的9000端口,也就是无法远程连接,因此要做相应的修改。

#php56修改监听配置
[root@s4 ~]# vim /opt/remi/php56/root/etc/php-fpm.d/www.conf
listen = 10.0.0.27:9000 #指定监听IP
#listen.allowed_clients = 127.0.0.1 #注释运行的客户端

#php72修改监听配置
[root@nginx-web2 ~]#vim /etc/opt/remi/php72/php-fpm.d/www.conf
user = nginx
group = nginx
listen = 10.0.0.27:9000
; listen.allowed_clients = 127.0.0.1
6.3.3.3:准备php测试页面
#准备php数据目录
[root@s4 ~]# mkdir /data/nginx/php -p
[root@s4 ~]# vim /data/nginx/php/index.php
<?php
  phpinfo();
?>
6.3.3.4:启动并验证php-fpm
#启动php-fpm56
[root@s4 ~]# systemctl start php56-php-fpm
[root@s4 ~]# systemctl enable php56-php-fpm
#启动php-fpm72
[root@s4 ~]# systemctl start php72-php-fpm
[root@s4 ~]# systemctl enable php56-php-fpm
#验证php-fpm进程及端口:
[root@s4 ~]# ps -ef | grep php-fpm
[root@nginx-web2 ~]#ps -ef |grep php
root       1910      1  0 20:24 ?        00:00:00 php-fpm: master process (/etc/opt/remi/php72/php-fpm.conf)
nginx      1911   1910  0 20:24 ?        00:00:00 php-fpm: pool www
nginx      1912   1910  0 20:24 ?        00:00:00 php-fpm: pool www
nginx      1913   1910  0 20:24 ?        00:00:00 php-fpm: pool www
nginx      1914   1910  0 20:24 ?        00:00:00 php-fpm: pool www
nginx      1915   1910  0 20:24 ?        00:00:00 php-fpm: pool www
root       1917   1009  0 20:24 pts/0    00:00:00 grep --color=auto php
[root@s4 ~]# ss -tnl | grep 9000
LISTEN 0 128 127.0.0.1:9000 *:*
[root@s4 ~]# netstat -tuanlp | grep 9000
tcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTEN 5339/php-fpm: maste
6.3.3.5:Nginx配置转发
location ~ \.php$ {
  root /data/nginx/php;
  fastcgi_pass 10.0.0.27:9000;
  fastcgi_index index.php;
  #fastcgi_param SCRIPT_FILENAME /data/php$fastcgi_script_name;
  fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  include fastcgi_params;
}

#重启nginx
[root@s2 ~]# systemctl restart nginx
6.3.3.6:访问验证php测试页面:

php 56:

php72:

6.4tengine使用:

Tengine使用:http://tengine.taobao/

关闭nginx,下载tengine源码并使用nginx参编译安装,tengine与nginx版本不一致会导致编译参数不通用。

6.4.1 动态模块

http://tengine.taobao/document_cn/dso_cn.html

这个模块主要是用来运行时动态加载模块,而不用每次都要重新编译Tengine.

如果你想要编译官方模块为动态模块,你需要在configure的时候加上类似这样的指令(–withhttp_xxx_module),./configure --help可以看到更多的细节.

如果只想要安装官方模块为动态模块(不安装Nginx),那么就只需要configure之后,执行 make dso_install命令.动态加载模块的个数限制为128个.

如果已经加载的动态模块有修改,那么必须重起Tengine才会生效.

只支持HTTP模块.

模块 在Linux/FreeeBSD/MacOS下测试成功.

v2.1.2 centos 7.2~7.7

[root@nginx-web1 tengine-2.1.2]#./configure --prefix=/apps/tengine-2.1.2 --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre  --add-module=/usr/local/src/echo-nginx-module

# make && make install

# yum install lua lua-devel
# ./configure --help | grep shared

# ./configure --prefix=/apps/tengine-2.1.2 --user=nginx --group=nginx --withhttp_ssl_module --with-http_v2_module --with-http_realip_module --withhttp_stub_status_module --with-http_gzip_static_module --with-pcre --withhttp_lua_module=shared

# make dso_install

# ll /apps/tengine-2.1.2/modules/ngx_http_lua_module.so

# vim /apps/tengine-2.1.2/conf/nginx.conf
worker_processes 1;

dso {
  load ngx_http_lua_module.so;
} 

#/apps/tengine-2.1.2/sbin/nginx -t
the configuration file /apps/tengine-2.1.2/conf/nginx.conf syntax is ok
configuration file /apps/tengine-2.1.2/conf/nginx.conf test is successful

v2.3.2

# wget http://tengine.taobao/download/tengine-2.3.2.tar.gz
# tar xvf tengine-2.3.2.tar.gz
# cd tengine-2.3.2/
# /apps/nginx/sbin/nginx -V #如果需要兼容Nginx则使用之前Nginx的编译参数
# ./configure --prefix=/apps/tengine-2.3.2 --user=nginx --group=nginx --withhttp_ssl_module --with-http_v2_module --with-http_realip_module --withhttp_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module
# make
# make install
6.4.2:concat模块使用:

网站中的css、js等文件都是小文件,单个文件大小几k甚至几个字节,所以文件的特点是小而多,会造成网站加载时http请求较多,且网络传输时间比较短,甚至有时候请求时间比传输时间还长,当公司网站中的这类小文件很多时,大量的http请求就会造成传输效率低,影响网站的访问速度和客户端体验,这时合并http请求就非常有必要了,concat模块就提供了合并文件http请求的功能,这个模块由淘宝开发,功能和apache的mod_concat模块类似。

Tengine-2.1.2 concat模块使用:
http://tengine.taobao/document_cn/http_concat_cn.html

1、安装tengine先不打开concat:
# ./configure --prefix=/apps/tengine --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-file-aio

2、通过动态模块实现concat功能:
http://tengine.taobao/document_cn/dso_cn.html
#./configure --prefix=/apps/tengine --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-file-aio --with-http_concat_module=shared --withhttp_lua_module=shared

# vim /apps/tenginx/conf/nginx.conf
worker_processes 1;
#error_log logs/error.log info;
#pid logs/nginx.pid;

dso {
	load ngx_http_lua_module.so;
	load ngx_http_concat_module.so;
} 

#/apps/tengine/sbin/nginx -t
# /apps/tengine/sbin/nginx -s reload

3、通过重新编译tengine实现concat功能:
#直接编译至tengine
--with-http_concat_module
6.4.3:tengine配置文件:

兼容Nginx指定版本的配置参数

pc.conf配置文件:
# cat /apps/tenginx/conf/conf.d/pc.conf
server {
  listen 80;
  server_name www.magedu *.www.magedu pc.magedu;
  aio on;
  location / {
	concat on;
	root html;
	index index.html index.htm;
  } 
  
  location ~ \.php$ {
	root /data/nginx/php;
	fastcgi_pass 172.18.0.202:9000;
	fastcgi_index index.php;
	#fastcgi_param SCRIPT_FILENAME /data/nginx/php$fastcgi_script_name;
	fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
	include fastcgi_params;
  }
}
6.4.4:基于tengine的wordpress站点:

6.5:openresty:

http://openresty/cn/

OpenResty® 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。

OpenResty® 通过汇聚各种设计精良的 Nginx 模块(主要由 OpenResty 团队自主开发),从而将 Nginx 有效地变成一个强大的通用 Web 应用平台。这样,Web 开发人员和系统工程师可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua 模块,快速构造出足以胜任 10K 乃至 1000K 以上单机并发连接的高性能 Web 应用系统。

OpenResty® 的目标是让你的Web服务直接跑在 Nginx 服务内部,充分利用 Nginx 的非阻塞 I/O 模型,不仅仅对HTTP 客户端请求,甚至于对远程后端诸如 MySQL、PostgreSQL、Memcached 以及 Redis 等都进行一致的高性能响应。

# pwd
/usr/local/src
# wget https://openresty/download/openresty-1.15.8.2.tar.gz
# tar xf openresty-1.15.8.2.tar.gz
# cd openresty-1.15.8.2/
# ./configure --prefix=/apps/openresty --user=nginx --group=nginx --withhttp_ssl_module --with-http_v2_module --with-http_realip_module --withhttp_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module

# make && make install

# ll /apps/openresty/
total 280
drwxr-xr-x 8 root root 4096 Jan 8 08:44 ./
drwxr-xr-x 5 root root 4096 Jan 8 08:44 ../
drwxr-xr-x 2 root root 4096 Jan 8 08:44 bin/
-rw-r--r-- 1 root root 22924 Jan 8 08:44 COPYRIGHT
drwxr-xr-x 6 root root 4096 Jan 8 08:44 luajit/
drwxr-xr-x 6 root root 4096 Jan 8 08:44 lualib/
drwxr-xr-x 6 root root 4096 Jan 8 08:44 nginx/
drwxr-xr-x 47 root root 4096 Jan 8 08:44 pod/
-rw-r--r-- 1 root root 226755 Jan 8 08:44 resty.index
drwxr-xr-x 5 root root 4096 Jan 8 08:44 site/

# /apps/openresty/bin/openresty

七 系统参数优化

7.1:系统参数优化

默认的Linux内核参数考虑的是最通用场景,不符合用于支持高并发访问的Web服务器的定义,根据业务特点来进行调整,当Nginx作为静态web内容服务器、反向代理或者提供压缩服务器的服务器时,内核参数的调整都是不同的,此处针对最通用的、使Nginx支持更多并发请求的TCP网络参数做简单的配置,修改/etc/sysctl.conf来更改内核参数
net.ipv4.ip_nonlocal_bind = 1 #允许非本地IP地址socket监听,必须项  
net.ipv4.ip_forward = 1 #开启IPv4转发,必须项
net.ipv4.tcp_timestamps = 0 #是否开启数据包时间戳,记录数据包的时间戳,判断是新的数据包还是旧的,如果是旧的就丢弃,配合下面两个选项的时候一定要打开才生效。在web服务器可以设置为1,在负载均衡要关闭
net.ipv4.tcp_tw_reuse = 0 #端口复用,kernel会复用处于TIME_WAIT状态的socket,即允许将TIME_WAIT状态的socket用于连接新的TCP连接,负载服务器建议打开
net.ipv4.tcp_tw_recycle = 0 #快速回收TIME_WAIT状态,用于大量TIME_OUT场景

fs.file-max = 1000000
#表示单个进程较大可以打开的句柄数

net.ipv4.tcp_tw_reuse = 1
#参数设置为 1 ,表示允许将TIME_WAIT状态的socket重新用于新的TCP链接,这对于服务器来说意义重大,因为总有大量TIME_WAIT状态的链接存在

net.ipv4.tcp_keepalive_time = 600
#当keepalive启动时,TCP发送keepalive消息的频度;默认是2小时,将其设置为10分钟,可更快的清理无效链接

net.ipv4.tcp_fin_timeout = 30
#当服务器主动关闭链接时,socket保持在FIN_WAIT_2状态的较大时间

net.ipv4.tcp_max_tw_buckets = 5000
#表示操作系统允许TIME_WAIT套接字数量的较大值,如超过此值,TIME_WAIT套接字将立刻被清除并打印警告信息,

默认为8000,过多的TIME_WAIT套接字会使Web服务器变慢
net.ipv4.ip_local_port_range = 1024 65000
#定义UDP和TCP链接的本地端口的取值范围

net.ipv4.tcp_rmem = 10240 87380 12582912
#定义了TCP接受socket请求缓存的内存最小值、默认值、较大值

net.ipv4.tcp_wmem = 10240 87380 12582912
#定义TCP发送缓存的最小值、默认值、较大值

net.coredev_max_backlog = 8096
#当网卡接收数据包的速度大于内核处理速度时,会有一个列队保存这些数据包。这个参数表示该列队的较大值

net.core.rmem_default = 6291456
#表示内核套接字接受缓存区默认大小

net.core.wmem_default = 6291456
#表示内核套接字发送缓存区默认大小

net.core.rmem_max = 12582912
#表示内核套接字接受缓存区较大大小

net.core.wmem_max = 12582912
#表示内核套接字发送缓存区较大大小
注意:以上的四个参数,需要根据业务逻辑和实际的硬件成本来综合考虑

net.ipv4.tcp_syncookies = 1
#与性能无关。用于解决TCP的SYN攻击

net.ipv4.tcp_max_syn_backlog = 8192
#这个参数表示TCP三次握手建立阶段接受SYN请求列队的较大长度,默认1024,将其设置的大一些可使出现Nginx繁忙来不及accept新连接时,Linux不至于丢失客户端发起的链接请求

net.ipv4.tcp_tw_recycle = 1
#这个参数用于设置启用timewait快速回收

net.core.somaxconn=262114
#选项默认值是128,这个参数用于调节系统同时发起的TCP连接数,在高并发的请求中,默认的值可能会导致链接超时或者重传,因此需要结合高并发请求数来调节此值。

net.ipv4.tcp_max_orphans=262114
#选项用于设定系统中最多有多少个TCP套接字不被关联到任何一个用户文件句柄上。如果超过这个数字,孤立链接将立即被复位并输出警告信息。这个限制指示为了防止简单的DOS攻击,不用过分依靠这个限制甚至认为的减小这个值,更多的情况是增加这个值


#资源限制相关配置,修改后重启生效
[root@Centos7 ~]#vim /etc/security/limits.conf
root             soft    nofile          1000000

八:LNMP项目实战-WordPress站点搭建:

LNMP项目实战:
L:Linux(centos 7.6) http://mirrors.cqu.edu/CentOS/7.6.1810/isos/x86_64/
N:Nginx(1.12.2) https://nginx/en/download.html
M:MySQL(5.6.43) https://dev.mysql/downloads/mysql/5.6.html#downloads
P:PHP(7.2.15) http://php/downloads.php
Worldpress(5.0.3):https://cn.wordpress/download/

本文标签: 详解 nginx