一.Web 服务基础介绍
正常情况下的单次web服务访问流程:
1.1 互联网发展历程回顾
1993年3月2日,中国科学院高能物理研究所租用AT&T公司的国际卫星信道建立的接入美国SLAC国家实验室的64K专线正式开通,成为我国连入Internet的第一根专线。
1995年马云开始创业并推出了一个web网站 中国黄页
1999年创建阿里巴巴www.alibabagroup.com
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亿元
2020年双十一:4982亿元
2021年双十一:5403亿元
2022年双十一:5571亿元
2012年1月11日淘宝商城正式更名为“天猫”
2014年9月19日里巴巴集团于纽约证券交易所正式挂牌上市
1.2 Web 服务介绍
1.2.1 Apache 经典的 Web 服务端
Apache起初由美国的伊利诺伊大学香槟分校的国家超级计算机应用中心开发
目前经历了两大版本分别是1.X和2.X
其可以通过编译安装实现特定的功能
1.2.1.1 Apache prefork 模型
预派生模式,有一个主控制进程,然后生成多个子进程,使用select模型,最大并发1024
每个子进程有一个独立的线程响应用户请求相对比较占用内存,但是比较稳定,可以设置最大和最小进程数
是最古老的一种模式,也是最稳定的模式,适用于访问量不是很大的场景
优点:稳定
缺点:每个用户请求需要对应开启一个进程,占用资源较多,并发性差,不适用于高并发场景
1.2.1.2 Apache worker 模型
一种多进程和多线程混合的模型
有一个控制进程,启动多个子进程
每个子进程里面包含固定的线程
使用线程程来处理请求
当线程不够使用的时候会再启动一个新的子进程,然后在进程里面再启动线程处理请求,
由于其使用了线程处理请求,因此可以承受更高的并发
优点:相比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类型的线程,当有真实请求过来的时候,将请求传递给服务线程,执行完毕后,又允许它释放
缺点:没有线程安全控制
event MPM中,会有一个专门的线程来管理这些keepalive类型的线程
当有真实请求过来的时候,将请求传递给服务线程,执行完毕后,又允许它释放。这样增强了高并发场
景下的请求处理能力
优点:单线程响应多请求,占据更少的内存,高并发下表现更优秀,会有一个专门的线程来管理keep-
alive类型的线程,当有真实请求过来的时候,将请求传递给服务线程,执行完毕后,又允许它释放
缺点:没有线程安全控制
1.2.2 Nginx-高性能的 Web 服务端
Nginx是由1994年毕业于俄罗斯国立莫斯科鲍曼科技大学的同学为俄罗斯rambler.ru公司开发的,开发工作最早从2002年开始,第一次公开发布时间是2004年10月4日,版本号是0.1.0
2019年3月11日F5 与 NGINX达成协议,F5 将收购 NGINX 的所有已发行股票,总价值约为 6.7 亿美元。
6.7亿美金约合44.97亿人民币,nginx核心模块代码长度198430(包括空格、注释),所以一行代码约为2.2万人民币
官网地址 www.nginx.org
Nginx历经十几年的迭代更新(https://nginx.org/en/CHANGES), 目前功能已经非常完善且运行稳定,另外Nginx的版本分为开发版、稳定版和过期版,nginx以功能丰富著称,它即可以作为http服务器,也可以作为反向代理服务器或者邮件服务器能够快速的响应静态网页的请求
支持FastCGI/SSL/Virtual Host/URL Rwrite /Gzip / HTTP Basic Auth/http或者TCP的负载均衡(1.9版本以
上且开启stream模块)等功能,并且支持第三方的功能扩展。
天猫 淘宝 京东 小米 163 新浪等一线互联网公司都在用Nginx或者进行二次开发
基于Nginx的工作场景:
1.2.3 用户访问体验和性能
1.2.3.1 用户访问体验统计
互联网存在用户速度体验的1-3-10原则,即1秒最优,1-3秒较优,3~10秒比较慢,10秒以上用户无法接受。用户放弃一个产品的代价很低,只是换一个URL而已。
全球最大搜索引擎 Google:慢500ms = 20% 将放弃访问。
全球最大的电商零售网站亚马逊:慢100ms = 1% 将放弃交易
有很多研究都表明,性能对用户的行为有很大的影响:
79%的用户表示不太可能再次打开一个缓慢的网站
47%的用户期望网页能在2秒钟以内加载
40%的用户表示如果加载时间超过三秒钟,就会放弃这个网站
页面加载时间延迟一秒可能导致转换损失7%,页面浏览量减少11%
8秒定律:用户访问一个网站时,如果等待网页打开的时间超过8秒,会有超过30%的用户放弃等待
1.2.3.2 影响用户体验的因素
据说马云在刚开始创业在给客户演示时,打开一个网站花了不到四个小时
影响用户体验的因素
1.客户端
- 客户端硬件配置
- 客户端网络速率
- 客户端与服务端距离
2.服务器
- 服务端网络速率
- 服务端硬件配置
- 服务端架构设计
- 服务端应用程序工作模式
- 服务端并发数量服务端响应文件大小及数量 buffer cache
- 服务端I/O压力1.2.4 服务端 I/O 流程
1.2.4 服务端 I/O 流程
I/O在计算机中指Input/Output, IOPS (Input/Output Per Second)即每秒的输入输出量(或读写次数),是衡量磁盘性能的主要指标之一。IOPS是指单位时间内系统能处理的I/O请求数量,一般以每秒处理的I/O请求数量为单位,I/O请求通常为读或写数据操作请求。
一次完整的I/O是用户空间的进程数据与内核空间的内核数据的报文的完整交换,但是由于内核空间与用户空间是严格隔离的,所以其数据交换过程中不能由用户空间的进程直接调用内核空间的内存数据,而是需要经历一次从内核空间中的内存数据copy到用户空间的进程内存当中,所以简单说I/O就是把数据从内核空间中的内存数据复制到用户空间中进程的内存当中。
服务器的I/O
- 磁盘I/O
- 网络I/O : 一切皆文件,本质为对socket文件的读写
1.2.4.1 磁盘 I/O
磁盘I/O是进程向内核发起系统调用,请求磁盘上的某个资源比如是html 文件或者图片,然后内核通过相应的驱动程序将目标文件加载到内核的内存空间,加载完成之后把数据从内核内存再复制给进程内存,如果是比较大的数据也需要等待时间
1.2.4.2 网络 I/O
网络通信就是网络协议栈到用户空间进程的IO就是网络IO
网络I/O 处理过程
- 获取请求数据,客户端与服务器建立连接发出请求,服务器接受请求(1-3)
- 构建响应,当服务器接收完请求,并在用户空间处理客户端的请求,直到构建响应完成(4)
- 返回数据,服务器将已构建好的响应再通过内核空间的网络 I/O 发还给客户端(5-7)
不论磁盘和网络I/O
- 每次I/O,都要经由两个阶段:
- 第一步:将数据从文件先加载至内核内存空间(缓冲区),等待数据准备完成,时间较长
- 第二步:将数据从内核缓冲区复制到用户空间的进程的内存中,时间较短
1.3 I/O 模型
1.3.1 I/O 模型相关概念
同步/异步:关注的是消息通信机制,即调用者在等待一件事情的处理结果时,被调用者是否提供完成状态的通知。
- 同步:synchronous,被调用者并不提供事件的处理结果相关的通知消息,需要调用者主动询问事情是否处理完成
- 异步:asynchronous,被调用者通过状态、通知或回调机制主动通知调用者被调用者的运行状态
阻塞/非阻塞:关注调用者在等待结果返回之前所处的状态
- 阻塞:blocking,指IO操作需要彻底完成后才返回到用户空间,调用结果返回之前,调用者被挂起,干不了别的事情。
- 非阻塞:nonblocking,指IO操作被调用后立即返回给用户一个状态值,而无需等到IO操作彻底完成,在最终的调用结果返回之前,调用者不会被挂起,可以去做别的事情。
1.3.2 网络 I/O 模型
阻塞型、非阻塞型、复用型、信号驱动型、异步
1.3.2.1 阻塞型 I/O 模型(blocking IO)
- 阻塞IO模型是最简单的I/O模型,用户线程在内核进行IO操作时被阻塞
- 用户线程通过系统调用read发起I/O读操作,由用户空间转到内核空间。内核等到数据包到达后,然后将接收的数据拷贝到用户空间,完成read操作
- 用户需要等待read将数据读取到buffer后,才继续处理接收的数据。整个I/O请求的过程中,用户线程是被阻塞的,这导致用户在发起IO请求时,不能做任何事情,对CPU的资源利用率不够
优点:程序简单,在阻塞等待数据期间进程/线程挂起,基本不会占用 CPU 资源
缺点:每个连接需要独立的进程/线程单独处理,当并发请求量大时为了维护程序,内存、线程切换开销较apache 的preforck使用的是这种模式。
同步阻塞:程序向内核发送I/O请求后一直等待内核响应,如果内核处理请求的IO操作不能立即返回,则进程将一直等待并不再接受新的请求,并由进程轮询查看I/O是否完成,完成后进程将I/O结果返回给Client,在IO没有返回期间进程不能接受其他客户的请求,而且是有进程自己去查看I/O是否完成,这种方式简单,但是比较慢,用的比较少。
1.3.2.2 非阻塞型 I/O 模型 (nonblocking IO)
用户线程发起IO请求时立即返回。但并未读取到任何数据,用户线程需要不断地发起IO请求,直到数据到达后,才真正读取到数据,继续执行。即 “轮询”机制存在两个问题:如果有大量文件描述符都要等,那么就得一个一个的read。这会带来大量的Context Switch(read是系统调用,每调用一次就得在用户态和核心态切换一次)。轮询的时间不好把握。这里是要猜多久之后数据才能到。等待时间设的太长,程序响应延迟就过大;设的太短,就会造成过于频繁的重试,干耗CPU而已,是比较浪费CPU的方式,一般很少直接使用这种模型,而是在其他IO模型中使用非阻塞IO这一特性。
非阻塞:程序向内核发送请I/O求后一直等待内核响应,如果内核处理请求的IO操作不能立即返回IO结果,进程将不再等待,而且继续处理其他请求,但是仍然需要进程隔一段时间就要查看内核I/O是否完成。
查看上图可知,在设置连接为非阻塞时,当应用进程系统调用 recvfrom 没有数据返回时,内核会立即返回一个 EWOULDBLOCK 错误,而不会一直阻塞到数据准备好。如上图在第四次调用时有一个数据报准备好了,所以这时数据会被复制到 应用进程缓冲区 ,于是 recvfrom 成功返回数据
当一个应用进程这样循环调用 recvfrom 时,称之为轮询 polling 。这么做往往会耗费大量CPU时间,实际使用很少
1.3.2.3 多路复用 I/O 型(I/O multiplexing)
上面的模型中,每一个文件描述符对应的IO是由一个线程监控和处理
多路复用IO指一个线程可以同时(实际是交替实现,即并发完成)监控和处理多个文件描述符对应各自的IO,即复用同一个线程一个线程之所以能实现同时处理多个IO,是因为这个线程调用了内核中的SELECT,POLL或EPOLL等系统调用,从而实现多路复用IO
优缺点
- 优点:可以基于一个阻塞对象,同时在多个描述符上等待就绪,而不是使用多个线程(每个文件描述符一个线程),这样可以大大节省系统资源
- 缺点:当连接数较少时效率相比多线程+阻塞 I/O 模型效率较低,可能延迟更大,因为单个连接处理需要 2 次系统调用,占用时间会有增加
IO多路复用适用如下场合:
- 当客户端处理多个描述符时(一般是交互式输入和网络套接口),必须使用I/O复用
- 当一个客户端同时处理多个套接字时,此情况可能的但很少出现
- 当一个服务器既要处理监听套接字,又要处理已连接套接字,一般也要用到I/O复用
- 当一个服务器即要处理TCP,又要处理UDP,一般要使用I/O复用
- 当一个服务器要处理多个服务或多个协议,一般要使用I/O复用
1.3.3 几种 IO 对比
I/O 模型中,越往后,阻塞越少,理论上效率也是最优前四种属于同步 I/O,因为其中真正的 I/O
操作(recvfrom)将阻塞进程/线程,只有异步 I/O 模型才与 POSIX 定义的异步 I/O 相匹配
1.3.4 I/O 的具体实现方式
1.3.4.1 I/O常见实现
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库的I/O效率不随描述符数目增加而线性下降,因为它只会对内核上报的“活跃”的描述符进行操作。
4、kqueue:
用于支持BSD系列平台的高校事件驱动模型,主要用在FreeBSD 4.1及以上版本、OpenBSD 2.0级以上版本NetBSD级以上版本及Mac OS X 平台上,该模型也是poll库的变种,因此和epoll没有本质上的区别,都是通过避免轮询操作提供效率。
5、Iocp:Windows系统上的实现方式,对应第5种(异步I/O)模型。
6、rtsig:不是一个常用事件驱动,最大队列1024,不是很常用
7、/dev/poll:
用于支持unix衍生平台的高效事件驱动模型,主要在Solaris 平台、HP/UX,该模型是sun公司在开发Solaris系列平台的时候提出的用于完成事件驱动机制的方案,它使用了虚拟的/dev/poll设备,开发人员将要见识的文件描述符加入这个设备,然后通过ioctl()调用来获取事件通知,因此运行在以上系列平台的时候请使用/dev/poll事件驱动机制。
8、eventport:
该方案也是sun公司在开发Solaris的时候提出的事件驱动库,只是Solaris 10以上的版本,该驱动库看防止内核崩溃等情况的发生。
二.Nginx 架构和安装
2.1 Nginx 概述
2.1.1 Nginx 介绍
Nginx:engine X ,2002年开发,分为社区版和商业版(nginx plus )
2019年3月11日 F5 Networks 6.7亿美元的价格收购
Nginx是免费的、开源的、高性能的HTTP和反向代理服务器、邮件代理服务器、以及TCP/UDP代理服务器
解决C10K问题(10K Connections)
Nginx官网:http://nginx.org
nginx的其它的二次发行版
- Tengine:由淘宝网发起的Web服务器项目。它在Nginx的基础上,针对大访问量网站的需求,添加了很多高级功能和特性。Tengine的性能和稳定性已经在大型的网站如淘宝网,天猫商城等得到了很好的检验。它的最终目标是打造一个高效、稳定、安全、易用的Web平台。从2011年12月开始,Tengine成为一个开源项目官网: https://tengine.taobao.org/
- OpenResty:基于 Nginx 与 Lua 语言的高性能 Web 平台, 章亦春团队开发,官网:http://openresty.org/cn/
2.1.2 Nginx 功能介绍
- 静态的web资源服务器html,图片,js,css,txt等静态资源
- http/https协议的反向代理
- 结合FastCGI/uWSGI/SCGI等协议反向代理动态资源请求
- tcp/udp协议的请求转发(反向代理)
- imap4/pop3协议的反向代理
2.2.3 基础特性
- 模块化设计,较好的扩展性
- 高可靠性
- 支持热部署:不停机更新配置文件,升级版本,更换日志文件
- 低内存消耗:10000个keep-alive连接模式下的非活动连接,仅需2.5M内存
- event-driven,aio,mmap,sendfile
2.2.4 Web 服务相关的功能
- 虚拟主机(server)
- 支持 keep-alive 和管道连接(利用一个连接做多次请求)
- 访问日志(支持基于日志缓冲提高其性能)
- url rewirte
- 路径别名
- 基于IP及用户的访问控制
- 支持速率限制及并发数限制
- 重新配置和在线升级而无须中断客户的工作进程
2.2 Nginx 架构和进程
2.2.1 Nginx 进程结构
web请求处理机制
- 多进程方式:服务器每接收到一个客户端请求就有服务器的主进程生成一个子进程响应客户端,直到用户关闭连接,这样的优势是处理速度快,子进程之间相互独立,但是如果访问过大会导致服务器资源耗尽而无法提供请求
- 多线程方式:与多进程方式类似,但是每收到一个客户端请求会有服务进程派生出一个线程和此客户端进行交互,一个线程的开销远远小于一个进程,因此多线程方式在很大程度减轻了web服务器对系统资源的要求,但是多线程也有自己的缺点,即当多个线程位于同一个进程内工作的时候,可以相互访问同样的内存地址空间,所以他们相互影响,一旦主进程挂掉则所有子线程都不能工作了,IIS服务器使用了多线程的方式,需要间隔一段时间就重启一次才能稳定。
Nginx是多进程组织模型,而且是一个由Master主进程和Worker工作进程组成。
主进程(master process)的功能:
- 对外接口:接收外部的操作(信号)
- 对内转发:根据外部的操作的不同,通过信号管理 Worker
- 监控:监控 worker 进程的运行状态,worker 进程异常终止后,自动重启 worker 进程
- 读取Nginx 配置文件并验证其有效性和正确性
- 建立、绑定和关闭socket连接
- 按照配置生成、管理和结束工作进程
- 接受外界指令,比如重启、升级及退出服务器等指令
- 不中断服务,实现平滑升级,重启服务并应用新的配置
- 开启日志文件,获取文件描述符
- 不中断服务,实现平滑升级,升级失败进行回滚处理
- 编译和处理perl脚本
工作进程(worker process)的功能:
- 所有 Worker 进程都是平等的
- 实际处理:网络请求,由 Worker 进程处理
- Worker进程数量:一般设置为核心数,充分利用CPU资源,同时避免进程数量过多,导致进程竞争CPU资源,
- 增加上下文切换的损耗
- 接受处理客户的请求
- 将请求依次送入各个功能模块进行处理
- I/O调用,获取响应数据
- 与后端服务器通信,接收后端服务器的处理结果
- 缓存数据,访问缓存索引,查询和调用缓存数据
- 发送请求结果,响应客户的请求
- 接收主程序指令,比如重启、升级和退出等
2.2.2Nginx 进程间通信
工作进程是由主进程生成的,主进程使用fork()函数,在Nginx服务器启动过程中主进程根据配置文件决定启动工作进程的数量,然后建立一张全局的工作表用于存放当前未退出的所有的工作进程,主进程生成工作进程后会将新生成的工作进程加入到工作进程表中,并建立一个单向的管道并将其传递给工作进程,该管道与普通的管道不同,它是由主进程指向工作进程的单向通道,包含了主进程向工作进程发出的指令、工作进程ID、工作进程在工作进程表中的索引和必要的文件描述符等信息。
主进程与外界通过信号机制进行通信,当接收到需要处理的信号时,它通过管道向相关的工作进程发送正确的指令,每个工作进程都有能力捕获管道中的可读事件,当管道中有可读事件的时候,工作进程就会从管道中读取并解析指令,然后采取相应的执行动作,这样就完成了主进程与工作进程的交互。
worker进程之间的通信原理基本上和主进程与worker进程之间的通信是一样的,只要worker进程之间能够取得彼此的信息,建立管道即可通信,但是由于worker进程之间是完全隔离的,因此一个进程想要知道另外一个进程的状态信息,就只能通过主进程来实现。
为了实现worker进程之间的交互,master进程在生成worker进程之后,在worker进程表中进行遍历,将该新进程的PID以及针对该进程建立的管道句柄传递给worker进程中的其他进程,为worker进程之间的通信做准备,当worker进程1向worker进程2发送指令的时候,首先在master进程给它的其他worker进程工作信息中找到2的进程PID,然后将正确的指令写入指向进程2的管道,worker进程2捕获到管道中的事件后,解析指令并进行相关操作,这样就完成了worker进程之间的通信。另worker进程可以通过共享内存来通讯的,比如upstream中的zone,或者limit_req、limit_conn中的zone等。操作系统提供了共享内存机制
2.2.3 Nginx 启动和 HTTP 连接建立
- Nginx 启动时,Master 进程,加载配置文件
- Master 进程,初始化监听的 socket
- Master 进程,fork 出多个 Worker 进程
- Worker 进程,竞争新的连接,获胜方通过三次握手,建立 Socket 连接,并处理请求
2.2.4 HTTP 处理过程
2.3 Nginx 模块介绍
nginx 有多种模块
- 核心模块:是 Nginx 服务器正常运行必不可少的模块,提供错误日志记录 、配置文件解析 、事件驱动机制 、进程管理等核心功能
- 标准HTTP模块:提供 HTTP 协议解析相关的功能,比如: 端口配置 、 网页编码设置 、 HTTP响应头设置 等等
- 可选HTTP模块:主要用于扩展标准的 HTTP 功能,让 Nginx 能处理一些特殊的服务,比如: Flash
- 多媒体传输 、解析 GeoIP 请求、 网络传输压缩 、 安全协议 SSL 支持等
- 邮件服务模块:主要用于支持 Nginx 的 邮件服务 ,包括对 POP3 协议、 IMAP 协议和 SMTP协议的支持
- Stream服务模块: 实现反向代理功能,包括TCP协议代理
- 第三方模块:是为了扩展 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 安装
2.4.1 Nginx版本和安装方式
Nginx版本
- Mainline version 主要开发版本,一般为奇数版本号,比如1.19
- Stable version 当前最新稳定版,一般为偶数版本,如:1.20
- Legacy versions 旧的稳定版,一般为偶数版本,如:1.18
Nginx安装可以使用yum或源码安装,但是推荐使用源码编译安装
- yum的版本比较旧
- 编译安装可以更方便自定义相关路径
- 使用源码编译可以自定义相关功能,更方便业务的上的使用
2.4.2.Nginx 编译安装
编译器介绍
源码安装需要提前准备标准的编译器,GCC的全称是(GNU Compiler collection),其有GNU开发,并以GPL即LGPL许可,是自由的类UNIX即苹果电脑Mac OS X操作系统的标准编译器,因为GCC原本只能处理C语言,所以原名为GNU C语言编译器,后来得到快速发展,可以处理C++,Fortran,pascal,objectiveC,java以及Ada等其他语言,此外还需要Automake工具,以完成自动创建Makefile的工作,Nginx的一些模块需要依赖第三方库,比如: pcre(支持rewrite),zlib(支持gzip模块)和openssl(支持ssl模块)等。
2.4.2.1 编译安装 Nginx
官方源码包下载地址:
编译安装示例: 拖入软件压缩包到mobaxterm
安装:
[root@nginx ~]# tar zxf nginx-1.24.0.tar.gz ---解压
进入目录:
[root@nginx ~]# cd nginx-1.24.0/
[root@nginx-node1 nginx-1.24.0]#
安装依赖性:
[root@nginx nginx-1.24.0]# dnf install gcc pcre-devel zlib-devel openssl-devel -y
[root@nginxnginx-1.24.0]# useradd -s /sbin/nologin -M nginx ---- 添加使用用户
编译模块:
[root@nginx nginx-1.24.0]# ./configure --prefix=/usr/local/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 \
--add-module=/root/echo-nginx-module-0.63 \
--add-module=/root/memc-nginx-module-0.20 \
--add-module=/root/srcache-nginx-module-0.33
过了之后会生成Makefile文件,make规则
make clean ---- 可以让之前做的编译模块还原
执行make install
[root@nginx nginx-1.24.0]# make && make install
把nginx软件的命令执行添加到环境变量中
[root@nginx ~]# vim ~/.bash_profile
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# User specific environment and startup programs
export PATH=$PATH:/usr/local/nginx/sbin ---- 添加这个
[root@nginx ~]# source ~/.bash_profile
[root@nginx ~]# du -sh /usr/local/nginx/sbin/nginx
进到这个目录下开启nginx:
[root@nginx ~]# cd /usr/local/nginx/sbin/
[root@nginx sbin]# ls
nginx
[root@nginx sbin]# ./nginx
查看进程和端口:
[root@nginx sbin]# ps aux | grep nginx
root 5687 0.0 0.0 9888 936 ? Ss 22:12 0:00 nginx: master process ./nginx
nginx 5688 0.0 0.2 13696 4664 ? S 22:12 0:00 nginx: worker process
root 5690 0.0 0.1 6412 2240 pts/0 S+ 22:12 0:00 grep --color=auto nginx
[root@nginx sbin]# netstat -antlupe | grep nginx
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 0 31860 5687/nginx: master
如何关闭nginx:
[root@nginx ~]# /usr/local/nginx/sbin/nginx -s stop关闭debug模式:
[root@nginx nginx-1.24.0]# vim auto/cc/gcc
查看版本:
[root@nginx ~]# curl -I 172.25.254.100
HTTP/1.1 200 OK
Server: nginx/1.24.0
Date: Thu, 15 Aug 2024 13:15:50 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Thu, 15 Aug 2024 12:54:39 GMT
Connection: keep-alive
ETag: "66bdfa8f-267"
Accept-Ranges: bytes
更改版本名:
[root@nginx~]# cd nginx-1.24.0/
[root@nginx nginx-1.24.0]# cd src/
[root@nginx src]# cd core/
[root@nginx core]# ls
[root@nginx core]# vim nginx.h/*
* Copyright (C) Igor Sysoev
* Copyright (C) Nginx, Inc.
*/
#ifndef _NGINX_H_INCLUDED_
#define _NGINX_H_INCLUDED_
#define nginx_version 1024000
#define NGINX_VERSION "1.0"
#define NGINX_VER "timingwang/" NGINX_VERSION ---- 这里更改#ifdef NGX_BUILD
#define NGINX_VER_BUILD NGINX_VER " (" NGX_BUILD ")"
#else
#define NGINX_VER_BUILD NGINX_VER
#endif#define NGINX_VAR "NGINX"
#define NGX_OLDPID_EXT ".oldbin"
#endif /* _NGINX_H_INCLUDED_ */
2.5 平滑升级和回滚
有时候我们需要对Nginx版本进行升级以满足对其功能的需求,例如添加新模块,需要新功能,而此时Nginx又在跑着业务无法停掉,这时我们就可能选择平滑升级
2.5.1 平滑升级流程
- 将旧Nginx二进制文件换成新Nginx程序文件(注意先备份)
- 向master进程发送USR2信号
- master进程修改pid文件名加上后缀.oldbin,成为nginx.pid.oldbin
- master进程用新Nginx文件启动新master进程成为旧master的子进程,系统中将有新旧两个Nginx主进程共同提供Web服务,当前新的请求仍然由旧Nginx的worker进程进行处理,将新生成的master进程的PID存放至新生成的pid文件nginx.pid
- 向旧的Nginx服务进程发送WINCH信号,使旧的Nginx worker进程平滑停止
- 向旧master进程发送QUIT信号,关闭老master,并删除Nginx.pid.oldbin文件
- 如果发现升级有问题,可以回滚∶向老master发送HUP,向新master发送QUIT
2.5.2平滑升级和回滚案例
输入网址nginx.org,然后找到新版本复制链接用wget命令下载
[root@nginx ~]# wget https://nginx.org/download/nginx-1.26.2.tar.gz
拖入所需模块:
解压:
[root@nginx~]# tar zxf echo-nginx-module-0.63.tar.gz
[root@nginx~]# tar zxf nginx-1.26.2.tar.gz
进入目录,编译:
[root@nginx nginx-1.26.2]# ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --add-module=/root/echo-nginx-module-0.63 --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这里直接make就可以了
[root@nginx nginx-1.26.2]# make平滑升级:
对旧版本的命令进行备份:
旧版本:[root@nginx sbin]# nginx -s stop
[root@nginx ~]# rm -rf /usr/local/nginx/
[root@nginx ~]# cd /root/nginx-1.24.0/
[root@nginx nginx-1.24.0]# make install[root@nginx nginx-1.24.0]# cd /usr/local/nginx/
[root@nginx nginx]# ls
conf html logs sbin
[root@nginx nginx]# cd sbin/
[root@nginx sbin]# ls
nginx
[root@nginx sbin]# nginxroot@nginx objs]# cd /usr/local/nginx/sbin/
[root@nginx sbin]# ls
nginx
[root@nginx sbin]# cp nginx nginx.old[root@nginx sbin]# \cp -f /root/nginx-1.26.2/objs/nginx /usr/local/nginx/sbin/
[root@nginx sbin]# ps aux | grep nginx
root 14254 0.0 0.0 9868 1928 ? Ss 09:54 0:00 nginx: master process nginx
nginx 14255 0.0 0.1 14200 5128 ? S 09:54 0:00 nginx: worker process
root 14275 0.0 0.0 221664 2304 pts/2 S+ 09:58 0:00 grep --color=auto nginx使用kill -USR2创建新的worker进程,但不会监听端口:
[root@nginx sbin]# kill -USR2 14254
[root@nginx sbin]# ps aux | grep nginx
root 14254 0.0 0.0 9868 2184 ? Ss 09:54 0:00 nginx: master process nginx
nginx 14255 0.0 0.1 14200 5128 ? S 09:54 0:00 nginx: worker process
root 14276 0.0 0.1 9896 6656 ? S 09:59 0:00 nginx: master process nginx
nginx 14277 0.0 0.1 14228 5136 ? S 09:59 0:00 nginx: worker process
root 14279 0.0 0.0 221664 2304 pts/2 S+ 09:59 0:00 grep --color=auto nginx
[root@nginx sbin]#把旧的worker进程回收:
[root@nginx sbin]# kill -WINCH 14254
[root@nginx sbin]# ps aux | grep nginx
root 14254 0.0 0.0 9868 2184 ? Ss 09:54 0:00 nginx: master process nginx
root 14276 0.0 0.1 9896 6656 ? S 09:59 0:00 nginx: master process nginx
nginx 14277 0.0 0.1 14228 5136 ? S 09:59 0:00 nginx: worker process
root 14293 0.0 0.0 221664 2304 pts/2 S+ 10:04 0:00 grep --color=auto nginx
[root@nginx sbin]#[root@nginx ~]# cd nginx-1.24.0/
[root@nginx nginx-1.24.0]# cd src/
[root@nginx src]# cd core/
[root@nginx core]# curl -I 172.25.254.100
HTTP/1.1 200 OK
Server: nginx/1.26.2 ----- 平滑升级成功
Date: Thu, 15 Aug 2024 14:10:49 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Thu, 15 Aug 2024 13:53:46 GMT
Connection: keep-alive
ETag: "66be086a-267"
Accept-Ranges: bytes
版本回滚:
把旧版本激活,新版本回收:激活:
[root@nginx sbin]# kill -HUP 14254
[root@nginx sbin]# ps aux | grep nginx
root 14254 0.0 0.0 9868 2184 ? Ss 09:54 0:00 nginx: master process nginx
root 14276 0.0 0.1 9896 6656 ? S 09:59 0:00 nginx: master process nginx
nginx 14277 0.0 0.1 14228 5392 ? S 09:59 0:00 nginx: worker process
nginx 14339 0.0 0.1 14200 5144 ? S 10:12 0:00 nginx: worker process --- 新的
root 14341 0.0 0.0 221664 2304 pts/2 S+ 10:12 0:00 grep --color=auto nginx
[root@nginx sbin]#回收:
[root@nginx sbin]# kill -WINCH 14276
[root@nginx sbin]# ps aux | grep nginx
root 14254 0.0 0.0 9868 2184 ? Ss 09:54 0:00 nginx: master process nginx
root 14276 0.0 0.1 9896 6656 ? S 09:59 0:00 nginx: master process nginx
nginx 14339 0.0 0.1 14200 5144 ? S 10:12 0:00 nginx: worker process
root 14343 0.0 0.0 221664 2304 pts/2 S+ 10:14 0:00 grep --color=auto nginx
[root@nginx sbin]#回到旧版本了:
[root@nginx core]# curl -I 172.25.254.100
HTTP/1.1 200 OK
Server: timingwang/1.0
Date: Thu, 15 Aug 2024 14:15:36 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Thu, 15 Aug 2024 13:53:46 GMT
Connection: keep-alive
ETag: "66be086a-267"
Accept-Ranges: bytes把新的进程杀掉:
[root@nginx sbin]# cp nginx nginx.new
[root@nginx sbin]# \cp -f nginx.old nginx
[root@nginx sbin]# ls
nginx nginx.new nginx.old
[root@nginx sbin]# ps aux | grep nginx
root 14254 0.0 0.0 9868 2184 ? Ss 09:54 0:00 nginx: master process nginx
root 14276 0.0 0.1 9896 6656 ? S 09:59 0:00 nginx: master process nginx
nginx 14339 0.0 0.1 14200 5400 ? S 10:12 0:00 nginx: worker process
root 14362 0.0 0.0 221664 2304 pts/2 S+ 10:17 0:00 grep --color=auto nginx
[root@nginx sbin]# kill -9 14276
[root@nginx sbin]# ps aux | grep nginx
root 14254 0.0 0.0 9868 2184 ? Ss 09:54 0:00 nginx: master process nginx
nginx 14339 0.0 0.1 14200 5400 ? S 10:12 0:00 nginx: worker process
root 14364 0.0 0.0 221664 2304 pts/2 S+ 10:18 0:00 grep --color=auto nginx
启动脚本的编写
[root@nginx sbin]# vim /lib/systemd/system/nginx.service [Unit] Description=The NGINX HTTP and reverse proxy server After=syslog.target network-online.target remote-fs.target nss-lookup.target Wants=network-online.target [Service] Type=forking PIDFile=/usr/local/nginx/logs/nginx.pid ExecStartPre=/usr/local/nginx/sbin/nginx -t ExecStart=/usr/local/nginx/sbin/nginx ExecReload=/usr/local/nginx/sbin/nginx -s reload ExecStop=/bin/kill -s QUIT $MAINPID PrivateTmp=true [Install] WantedBy=multi-user.target [root@nginx logs]# systemctl daemon-reload [root@nginx logs]# nginx -s stop [root@nginx logs]# ps aux | grep nginx root 14510 0.0 0.0 221664 2304 pts/2 S+ 10:22 0:00 grep --color=auto nginx [root@nginx logs]# systemctl enable --now nginx Created symlink /etc/systemd/system/multi-user.target.wants/nginx.service → /usr/lib/systemd/system/nginx.service. [root@nginx logs]# ps aux | grep nginx root 14544 0.0 0.0 9864 2052 ? Ss 10:23 0:00 nginx: master process /usr/local/nginx/sbin/nginx nginx 14545 0.0 0.1 14196 4996 ? S 10:23 0:00 nginx: worker process root 14547 0.0 0.0 221664 2304 pts/2 S+ 10:23 0:00 grep --color=auto nginx [root@nginx logs]#
nginx配置中的root和alias
新建一个web站点:
[root@nginx core]# vim /usr/local/nginx/conf/nginx.conf
events {
worker_connections 1024;
use epoll; ---- 加上这个,运用epoll
}#gzip on;
include "/usr/local/nginx/conf.d/*.conf"; ------ 再加上子配置文件创建子配置文件目录:
[root@nginx core]# mkdir /usr/local/nginx/conf.d -p
[root@nginx core]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.timingwang.org;
root /data/web/html;
index index.html;
}[root@nginx core]# mkdir -p /data/web/html
[root@nginx core]# echo www.timingwang.org > /data/web/html/index.html
[root@nginx core]# nginx -t ---- 校验语法是否有问题
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@nginx core]# nginx -s reload ---- 刷新访问172.25.254.100
去访问另外的路径,root和alias
[root@nginx core]# vim /usr/local/nginx/conf.d/vhost.conf
root:server {
listen 80;
server_name www.timingwang.org;
root /data/web/html;
index index.html;
location /test1/ {
root /data/web;
}
}
[root@nginx core]# mkdir /data/web/test1 -p
[root@nginx core]# echo /data/web/test1 > /data/web/test1/index.html
[root@nginx core]# nginx -s reload --- 刷新一下访问172.25.254.100/test1
alias:
[root@nginx core]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.timingwang.org;
root /data/web/html;
index index.html;
location /test1/ {
root /data/web;
}
location /test2 {
alias /data/web/test1;
}
}[root@nginx core]# nginx -s reload --- 刷新一下
访问172.25.254.100/test2/
nginx的账户认证功能
创建账户路径:
[root@nginx ~]# htpasswd -cm /usr/local/nginx/.htpasswd admin
New password:
Re-type new password:
Adding password for user admin
[root@nginx ~]# htpasswd -m /usr/local/nginx/.htpasswd wang
New password:
Re-type new password:
Adding password for user wang
[root@nginx ~]#
[root@nginx ~]# cat /usr/local/nginx/.htpasswd
admin:$apr1$m/VIu7Dx$D.uCAJi2GsAR4MVbn2caY0
wang:$apr1$mJBsFc9R$BzRaDwhgw2E/qQ9sYqBPf1
[root@nginx ~]#编写配置文件
[root@nginx ~]# vim /usr/local/nginx/conf.d/vhost.confserver {
listen 80;
server_name www.timingwang.org;
root /data/web/html;
index index.html;
location /wang {
root /data/web;
auth_basic "login passwd !!!";
auth_basic_user_file "/usr/local/nginx/.htpasswd";
}
}创建文件目录:
[root@nginx ~]# mkdir /data/web/wang
[root@nginx ~]# echo wang > /data/web/wang/index.html
[root@nginx ~]# nginx -s reload访问www.timingwang.org/wang
nginx的自定义错误页面
创建文件目录:
[root@nginx ~]# mkdir /data/web/errorpage -p
[root@nginx ~]# echo error page > /data/web/erroepage/40x.html
[root@nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.timingwang.org;
root /data/web/html;
index index.html;
error_page 404 /40x.html;
#error_log /var/log/timingwang.org/error.log;
#access_log /var/log/timingwang.org/access.log;location /wang {
root /data/web;
auth_basic "login passwd";
auth_basic_user_file "/usr/local/nginx/.htpasswd";
}
location = /40x.html {
root /data/web/errorpage;
}
}[root@nginx ~]# systemctl restart nginx.service
网页访问,输入一个错误的uri,172.25.254.100/ppd
nginx-自定义日志
[root@nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.timingwang.org;
root /data/web/html;
index index.html;
error_page 404 /40x.html;
error_log /var/log/timingwang.org/error.log; ----- 加这两行
access_log /var/log/timingwang.org/access.log;location /wang {
root /data/web;
auth_basic "login passwd";
auth_basic_user_file "/usr/local/nginx/.htpasswd";
}
location /40x.html {
root /data/web/errorpage;
}
}建立日志文件目录:
[root@nginx ~]# mkdir /var/log/timingwang.org/ -p
[root@nginx ~]# systemctl restart nginx.service
[root@nginx ~]# curl www.timingwang.org
www.timingwang.org访问正确的域名:
[root@nginx ~]# curl www.timingwang.org
www.timingwang.org
[root@nginx ~]# cat /var/log/timingwang.org/access.log
172.25.254.100 - - [16/Aug/2024:08:07:07 -0400] "GET / HTTP/1.1" 200 19 "-" "curl/7.76.1"访问错误的域名:
[root@nginx ~]# curl www.timingwang.org/aaad
error page
[root@nginx ~]# cat /var/log/timingwang.org/error.log
2024/08/16 08:07:51 [error] 15474#0: *2 open() "/data/web/html/aaad" failed (2: No such file or directory), client: 172.25.254.100, server: www.timingwang.org, request: "GET /aaad HTTP/1.1", host: "www.timingwang.org"
nginx中的文件检测
[root@nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.timingwang.org;
root /data/web/html;
index index.html;
error_page 404 /40x.html;
error_log /var/log/timingwang.org/error.log;
access_log /var/log/timingwang.org/access.log;
try_files $uri $uri.html $uri/index.html /error/default.html;location /wang{
root /data/web;
auth_basic "login passwd";
auth_basic_user_file "/usr/local/nginx/.htpasswd";
}
location /40x.html {
root /data/web/errorpage;
}
}[root@nginx ~]# systemctl restart nginx.service
[root@nginx ~]# rm -rf /data/web/html/index.html
[root@nginx ~]# rm -rf /data/web/html/error
[root@nginx ~]# curl www.timingwang.org ---- 现在检测到文件都没有,报500的错
<html>
<head><title>500 Internal Server Error</title></head>
<body>
<center><h1>500 Internal Server Error</h1></center>
<hr><center>nginx/1.24.0</center>
</body>
</html>创建检测文件的目录:
[root@nginx ~]# mkdir /data/web/html/error
[root@nginx ~]# echo error default > /data/web/html/error/default.html
[root@nginx ~]# curl www.timingwang.org
error default还原回来
[root@nginx ~]# echo www.timingwang.org > /data/web/html/index.html
nginx中的长链接管理
[root@nginx ~]# vim /usr/local/nginx/conf/nginx.conf
#keepalive_timeout 0;
keepalive_timeout 65 60; #----65长链接默认的保持时间,后面没有请求报文了,这里设置多少时间,时间到了就自动退出
60设定了之后,客户会看到这个长链接保持的时间
keepalive_requests 2; #默认是100,请求过程中发出的长链接数量不能超过多少安装长链接测试用的工具telnet
[root@nginx ~]# dnf install telnet -y[root@nginx ~]# telnet www.timingwang.org 80
Trying 172.25.254.100...
Connected to www.timingwang.org.
Escape character is '^]'.
GET / HTTP/1.1 ----- 手动写入请求的报文
HOST: www.timingwang.org ----- 访问的域名,端口HTTP/1.1 200 OK
Server: nginx/1.24.0
Date: Fri, 16 Aug 2024 12:45:43 GMT
Content-Type: text/html
Content-Length: 19
Last-Modified: Fri, 16 Aug 2024 12:45:12 GMT
Connection: keep-alive
ETag: "66bf49d8-13"
Accept-Ranges: byteswww.timingwang.org
这里设置了两次,请求两次之后就会退出。企业中一般不能断开,要一直请求访问
nginx-下载服务器的设定及优化
创建下载文件的目录:
[root@nginx ~]# mkdir /data/web/download -p
[root@nginx ~]# dd if=/dev/zero of=/data/web/download/wangfile bs=1M count=100 ---- 做一个大小为100M的文件,并放到刚才创建的目录。创建的一个数据。
100+0 records in
100+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 0.0394146 s, 2.7 GB/s
[root@nginx ~]#写一个location,访问路径
[root@nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.timingwang.org;
root /data/web/html;
index index.html;
error_page 404 /40x.html;
error_log /var/log/timingwang.org/error.log;
access_log /var/log/timingwang.org/access.log;
try_files $uri $uri.html $uri/index.html /error/default.html;location /wang{
root /data/web;
auth_basic "login passwd";
auth_basic_user_file "/usr/local/nginx/.htpasswd";
}
location /40x.html {
root /data/web/errorpage;
}
location /download {
root /data/web;
autoindex on; ----- 让文件可以长列表显示
autoindex_localtime on; -----on表示显示本机时间而非GMT(格林威治)时间,默为为off显示GMT时间
autoindex_exact_size off; ---- 计算文件确切大小(单位bytes),此为默认值,off只显示大概大小(单位kb、mb、gb)
limit_rate 1024k; -------- 限速,默认不限速 }
}
}
[root@nginx ~]# wget www.timingwang.org/download/wangfile
--2024-08-16 09:11:02-- http://www.timingwang.org/download/wangfile
Resolving www.timingwang.org (www.timingwang.org)... 172.25.254.100
Connecting to www.timingwang.org (www.timingwang.org)|172.25.254.100|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 104857600 (100M) [application/octet-stream]
Saving to: ‘wangfile.1’wangfile.1 26%[===================> ] 26.00M 1.04MB/s eta 71s
nginx-数据压缩功能
Nginx对文件的压缩功能是依赖于模块 ngx_http_gzip_module,默认是内置模块
[root@nginx ~]# vim /usr/local/nginx/conf/nginx.conf
gzip on;
gzip_comp_level 4;
gzip_min_length 1k;
gzip_http_version 1.0;
gzip_vary on;
gzip_types text/plain application/javascript application/x-javascript text/css
application/xml text/javascript application/x-httpd-php image/gif image/png;
示例:
[root@nginx ~]# nginx -t ----检测下语法是否有错
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@nginx ~]#
[root@nginx ~]# systemctl restart nginx.service测试:
[root@nginx ~]# echo hello nginx > /data/web/html/small.html ----- 写入一个小于1k的文件
[root@nginx ~]# du -sh /usr/local/nginx/logs/access.log
208K /usr/local/nginx/logs/access.log
[root@nginx ~]# cat /usr/local/nginx/logs/access.log > /data/web/html/big.html ----写入一个大于1k的文件
[root@nginx ~]#
[root@nginx ~]# curl --head --compressed 172.25.254.100/small.html ---- 小于1k不会被压缩
HTTP/1.1 200 OK
Server: nginx/1.24.0
Date: Fri, 16 Aug 2024 13:32:39 GMT
Content-Type: text/html
Content-Length: 12
Last-Modified: Fri, 16 Aug 2024 13:29:43 GMT
Connection: keep-alive
ETag: "66bf5447-c"
Accept-Ranges: bytes
(--head只看响应报文的头部内容不看)
[root@nginx ~]# curl --head --compressed 172.25.254.100/big.html ----- 大于1k会被压缩
HTTP/1.1 200 OK
Server: nginx/1.24.0
Date: Fri, 16 Aug 2024 13:32:46 GMT
Content-Type: text/html
Last-Modified: Fri, 16 Aug 2024 13:31:01 GMT
Connection: keep-alive
Vary: Accept-Encowang
ETag: W/"66bf5495-33553"
Content-Encowang: gzip[root@nginx ~]#
这里压缩并不是给文件本身压缩,是文件在传输过程中被压缩。
nginx的内置变量
内置变量示例:
[root@nginx ~]# vim /usr/local/nginx/conf.d/vars.conf
server {
listen 80;
server_name var.timingwang.org;
root /data/web/html;
index index.html;
location /var {
default_type /text/html;
echo $remote_addr; ---------- 存放了客户端的地址,注意是客户端的公网IP
echo $args; ---------- 变量中存放了URL中的所有参数
echo $is_args; ---------- 如果有参数为? 否则为空
echo $document_root; ---------- 保存了针对当前资源的请求的系统根目录
echo $document_uri; ---------- 保存了当前请求中不包含参数的URI,注意是不包含请求的指令
echo $host; ---------- 存放了请求的host名称
echo $remote_port; ---------- 客户端请求Nginx服务器时随机打开的端口,这是每个客户端自己的端口
echo $remote_user; ---------- 已经经过Auth Basic Module验证的用户名
echo $request_method; ---------- 请求资源的方式,GET/PUT/DELETE等
echo $request_filename; --------- 当前请求的资源文件的磁盘路径,由root或alias指令与URI请求生成的文件绝对路径
echo $request_uri; --------- 包含请求参数的原始URI,不包含主机名,相当于:$document_uri?$args
echo $scheme; --------- 请求的协议,例如:http,https,ftp等
echo $server_protocol; ---------- 保存了客户端请求资源使用的协议的版本,例如:HTTP/1.0,HTTP/1.1,HTTP/2.0等
echo $server_addr; ---------- 保存了服务器的IP地址
echo $server_name; ---------- 虚拟主机的主机名
echo $server_port; ---------- 虚拟主机的端口号
echo $http_user_agent; ---------- 客户端浏览器的详细信息
echo $http_cookie; ---------- 客户端的所有cookie信息
echo $cookie_key2; ---------- name为任意请求报文首部字部cookie的key名
}
}测试:
[root@nginx conf.d]# curl -b "key1=wang,key2=xiaowang" -u wang:123 var.timingwang.org/var?name=DZ&&id=203621
172.25.254.100
name=DZ
?
/data/web/html
/var
var.timingwang.org
48002
wang
GET
/data/web/html/var
/var?name=DZ
http
HTTP/1.1
172.25.254.100
var.timingwang.org
80
curl/7.76.1
key1=awng,key2=xiaowang
xiaowang
[root@nginx conf.d]#
自定义变量示例:
[root@nginx conf.d]# vim /usr/local/nginx/conf.d/vars.conf
server {
listen 80;
server_name var.timinglee.org;
root /data/web/html;
index index.html;location /var {
default_type text/html;
set $timingwang xiaowang;
echo $timingwang;
}测试:
[root@nginx conf.d]# curl var.timingwang.org/var
xiaowang
[root@nginx conf.d]#
nginx 中rewrite模块功能
if指令:
示例:
[root@nginx conf.d]# vim /usr/local/nginx/conf.d/vars.conf
server {
listen 80;
server_name var.timingwang.org;
root /data/web/html;
index index.html;location /test2 {
if ( !-e $request_filename ){
echo "$request_filename is not exist";
}
}
}测试:
此时不存在test2的目录
[root@nginx conf.d]# curl var.timingwang.org/test2/index.html
/data/web/html/test2/index.html is not exist
[root@nginx conf.d]#
测试:
存在test2的目录,有的话就直接显示内容
创建一个:
[root@nginx conf.d]# mkdir -p /data/web/html/test2/
[root@nginx conf.d]# echo test2 > /data/web/html/test2/index.html
[root@nginx conf.d]# curl var.timingwang.org/test2/index.html
test2
[root@nginx conf.d]#
break指令:
示例:
[root@nginx conf.d]# vim /usr/local/nginx/conf.d/vars.conf
server {
listen 80;
server_name var.timingwang.org;
root /data/web/html;
index index.html;location /test2 {
if ( !-e $request_filename ){
echo "$request_filename is not exist";
#return 409;
}
}location /break {
default_type text/html;
set $name wang;
echo $name;
set $id 203621;
echo $id;
}}
[root@nginx conf.d]# nginx -s reload
[root@nginx conf.d]# curl var.timingwang.org/break
wang
203621
[root@nginx conf.d]#配合if再加上break:
location /break {
default_type text/html;
set $name wang;
echo $name;
if ( $http_user_agent = "curl/7.76.1"){
break;
}
set $id 203621;
echo $id;
}
[root@nginx conf.d]# nginx -s reload
[root@nginx conf.d]# curl var.timingwang.org/break
wang[root@nginx conf.d]#
指定下别的浏览器,break就不生效:
[root@nginx conf.d]# curl -A "filewang" var.timingwang.org/break
wang
203621
[root@nginx conf.d]#
return指令:
根据上面的实验接着往下面加,示例:
[root@nginx conf.d]# vim /usr/local/nginx/conf.d/vars.conflocation /return {
default_type text/html;
if ( !-e $request_filename ){
echo "$request_filename is not exist";
return 301 http://www.baidu.com;
}
echo "$request_filename is not exist";
}
}现在没有return的目录,会定向到www.baidu.com,并且会报301
测试:
[root@nginx conf.d]# curl -I var.timingwang.org/return
HTTP/1.1 301 Moved Permanently
Server: xiaowang/1.1
Date: Sun, 18 Aug 2024 11:12:55 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Keep-Alive: timeout=60
Location: http://www.baidu.com
存在return目录
测试:
[root@nginx conf.d]# mkdir -p /data/web/html/return/
[root@nginx conf.d]#
[root@nginx conf.d]# curl -I var.timingwang.org/return
HTTP/1.1 200 OK
Server: xiaowang/1.1
Date: Sun, 18 Aug 2024 11:15:25 GMT
Content-Type: text/html
Connection: keep-alive
Keep-Alive: timeout=60
Vary: Accept-Encowang[root@nginx conf.d]#
rewrite指令
rewrite案例:域名永久与临时重定向(permanent和redirect)
示例:
[root@nginx conf.d]# vim /usr/local/nginx/conf.d/vars.conf
location / {
root /data/web/var;
index index.html;
rewrite / http://www.timingwang.com permanent; --- 永久重定向 301 两个不能同时启用
#rewrite / http://www.timingwang.com redirext; --- 临时重定向 302
}
[root@nginx conf.d]# mkdir -p /data/web/var
[root@nginx conf.d]# echo var page > /data/web/var/index.html
[root@nginx conf.d]# nginx -s reload测试:
curl 不支持重定向
永久的301:
[root@nginx conf.d]# curl -I var.timingwang.org
HTTP/1.1 301 Moved Permanently
Server: xiaowang/1.1
Date: Sun, 18 Aug 2024 11:40:30 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Keep-Alive: timeout=60
Location: http://www.timingwang.com
[root@nginx conf.d]#换成临时的302:
[root@nginx conf.d]# vim /usr/local/nginx/conf.d/vars.conf
location / {
root /data/web/var;
index index.html;
#rewrite / http://www.timingwang.com permanent;
rewrite / http://www.timingwang.com redirext;
}
案例:break和last
示例:
创建目录:
[root@nginx conf.d]# mkdir /data/web/html/{test1,test2,break,last} -p
[root@nginx conf.d]# echo test1 > /data/web/html/test1/index.html
[root@nginx conf.d]# echo test2 > /data/web/html/test2/index.html
[root@nginx conf.d]# echo break > /data/web/html/break/index.html
[root@nginx conf.d]# echo last > /data/web/html/last/index.html[root@nginx conf.d]# vim /usr/local/nginx/conf.d/vars.conf
server {
listen 80;
server_name var.timingwang.org;
root /data/web/html;
index index.html;location /break {
rewrite ^/break/(.*) /test1/$1;
rewrite ^/test1/(.*) /test2/$1;
}location /last {
rewrite ^/last/(.*) /test1/$1;
rewrite ^/test1/(.*) /test2/$1;
}location /test1 {
default_type text/html;
return 203 "xiaowang hahahahaha";
}location /test2 {
root /data/web/html;
}
}访问:
[root@nginx conf.d]# curl var.timingwang.org/break/
test2
[root@nginx conf.d]# curl var.timingwang.org/test1/
xiaowang hahahahaha
[root@nginx conf.d]# curl var.timingwang.org/test2/
test2break和last效果示例:
[root@nginx conf.d]# vim /usr/local/nginx/conf.d/vars.conf
server {
listen 80;
server_name var.timingwang.org;
root /data/web/html;
index index.html;location /break {
root /data/web/html;
rewrite ^/break/(.*) /test1/$1 break; ----- 加上break,执行到这里就不访问下面的了,看的是test1里面的内容
rewrite ^/test1/(.*) /test2/$1;
}location /last {
root /data/web/html;
rewrite ^/last/(.*) /test1/$1 last;
rewrite ^/test1/(.*) /test2/$1;
}location /test1 {
default_type text/html;
return 203 "xiaowang hahahahaha";
}location /test2 {
root /data/web/html;
}
}测试
[root@nginx ~]# nginx -s reload
[root@nginx ~]# curl var.timingwang.org/break/index.html #访问break时,会终止,但不会跳出当前的location
test1
[root@nginx ~]#
[root@nginx~]# curl var.timingwang.org/last/index.html #访问last时,也会终止,但是会跳出当前的location,继续寻找路径
xiaowang hahahahaha
[root@nginx ~]#
案例:rewrite-自动跳转https(全站加密)
制作证书:
[root@nginx ~]# cd /usr/local/nginx/certs/
[root@nginx certs]#openssl req -newkey rsa:2048 -nodes -sha256 -keyout /usr/local/nginx/certs/timingwang.org.key
-x509 -days 365 -out /usr/local/nginx/certs/timingwang.org.crt[root@nginx certs]# ls
timingwang.org.crt timingwang.org.key
[root@nginx certs]#写配置:
[root@nginx conf.d]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
listen 443 ssl;
server_name www.timingwang.org;
root /data/web/html;
index index.html;
ssl_certificate /usr/local/nginx/certs/timingwang.org.crt;
ssl_certificate_key /usr/local/nginx/certs/timingwang.org.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;location / {
if ( $scheme = http ) {
rewrite /(.*) https://$host/$1 redirect;
}
}[root@nginx conf.d]# echo www.timingwang.org > /data/web/html/index.html
网页访问www.timingwang.org
访问不存在的文件,自动跳转到本地路径访问
示例:
[root@nginx conf.d]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
listen 443 ssl;
server_name www.timingwang.org;
root /data/web/html;
index index.html;
ssl_certificate /usr/local/nginx/certs/timingwang.org.crt;
ssl_certificate_key /usr/local/nginx/certs/timingwang.org.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;location / {
if ( $scheme = http ) {
rewrite /(.*) https://$host/$1 redirect;
}if ( !-e $request_filename ){
rewrite /(.*) https://$host/index.html redirect;
}
}
}此时访问www.timingwang.org后面跟上不存在的文件路径,自动跳转到本地路径,访问内容。
例如:www.timingwang.org/a/b/a/
nginx-盗链及防盗链
示例:
[root@nginx conf.d]# mkdir -p /data/web/html/images
拖入你喜欢的照片
[root@nginx conf.d]# cd /data/web/html/images/
[root@nginx images]# ls
zrn.jpg网页访问172.25.254.100/images/1.jpg
另一台主机托入盗链:
[root@nginx ~]# dnf install httpd -y
[root@nginx ~]# cd /var/www/html/
[root@nginx html]# ls
daolian.png
[root@nginx html]# mv daolian.png /var/www/html/index.html
[root@nginx html]# ls
index.html
[root@nginx html]# cat index.html
<html><head>
<meta http-equiv=Content-Type content="text/html;charset=utf-8">
<title>盗链</title>
</head><body>
<img src="http://www.timingwang.org/images/zrn.jpg" >
<h1 style="color:red">11111111</h1>
<p><a href=http://www.timingwang.org>狂戳11111111</a>11111111</p>
</body></html>
防止盗链发生:
示例:
[root@nginx conf.d]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
listen 443 ssl;
server_name www.timingwang.org;
root /data/web/html;
index index.html;
ssl_certificate /usr/local/nginx/certs/timingwang.org.crt;
ssl_certificate_key /usr/local/nginx/certs/timingwang.org.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;location /images {
valid_referers none blocked server_names *.timingwang.org ~/.baidu/.;
if ( $invalid_referer ){
return 404;
}
}
}此时访问172.25.254.10就访问不到图片了
让别人访问过来看到的不是想要的图片:
[root@nginx conf.d]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
listen 443 ssl;
server_name www.timingwang.org;
root /data/web/html;
index index.html;
ssl_certificate /usr/local/nginx/certs/timingwang.org.crt;
ssl_certificate_key /usr/local/nginx/certs/timingwang.org.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;#location / {
# valid_referers none blocked server_names *.timingwang.org ~/.baidu/.;
# if ( $invalid_referer ){
# return 404;
#}
#}location /images {
valid_referers none blocked server_names *.timingwang.org ~/.baidu/.;
if ( $invalid_referer ){
rewrite ^/ http://www.timingwang.org/tupi.jpg;
}
}
}
nginx 反向代理及动静分离的实现
示例:
两台主机:
172.25.254.10:
[root@nginx ~]# echo 172.25.254.10 > /var/www/html/index.html
172.25.254.20:
[root@nginx-node2 ~]# echo 172.25.254.20 > /var/www/html/index.html
[root@nginx-node2 ~]# systemctl restart httpd
[root@nginx-node2 ~]# mkdir -p /var/www/html/static
[root@nginx-node2 ~]# echo static 172.25.254.20 > /var/www/html/static/index.html172.25.254.100:
[root@nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.timingwang.org;location / {
proxy_pass http://172.25.254.10:80;
}location /static {
proxy_pass http://172.25.254.20:8080;
}
}访问:
动静分离:
172.25.254.10:
[root@nginx ~]# dnf install php -y
[root@nginx ~]# systemctl restart httpd
[root@nginx ~]# vim /var/www/html/index.php
<?php
phpinfo();
?>[root@nginx ~]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.timingwang.org;location ~ \.php$ {
proxy_pass http://172.25.254.10:80;
}location /static {
proxy_pass http://172.25.254.20:8080;
}
}
[root@nginx ~]# nginx -s reload网页访问www.timingwang.org/index.php = 172.25.254.10
nginx反向代理的缓存功能
非缓存场景压测:
示例:
[root@nginx ~]# ab -n1000 -c100 http://www.timingwang.org/static/index.html
This is ApacheBench, Version 2.3 <$Revision: 1903618 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/Benchmarking www.timingwang.org (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests
Server Software: Apache/2.4.57
Server Hostname: www.timingwang.org
Server Port: 80Document Path: /static/index.html
Document Length: 196 bytesConcurrency Level: 100
Time taken for tests: 0.062 seconds
Complete requests: 1000
Failed requests: 0
Non-2xx responses: 1000
Total transferred: 394000 bytes
HTML transferred: 196000 bytes
Requests per second: 16169.72 [#/sec] (mean)
Time per request: 6.184 [ms] (mean)
Time per request: 0.062 [ms] (mean, across all concurrent requests)
Transfer rate: 6221.55 [Kbytes/sec] receivedConnection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.3 0 1
Processing: 1 6 2.0 6 13
Waiting: 1 5 2.0 6 13
Total: 2 6 1.7 6 13Percentage of the requests served within a certain time (ms)
50% 6
66% 7
75% 7
80% 7
90% 8
95% 8
98% 9
99% 11
100% 13 (longest request)
[root@nginx ~]#
作缓存:
[root@nginx ~]# vim /usr/local/nginx/conf/nginx.conf
#gzip on;
proxy_cache_path /usr/local/nginx/proxy_cache levels=1:2:2 keys_zone=proxycache:20m
inactive=120s max_size=1g;
server {
listen 80;
server_name www.timingwang.org;location ~ \.php$ {
proxy_pass http://172.25.254.10:80;
}location /static {
proxy_pass http://172.25.254.20:8080;
proxy_cache proxycache;
proxy_cache_key $request_uri;
proxy_cache_valid 200 302 301 10m;
proxy_cache_valid any 1m;
}
}
[root@nginx ~]# nginx -s reload
缓存的路径,缓存到proxy_cache里面:
[root@nginx nginx]# tree proxy_cache/
proxy_cache/
└── e
└── 50
└── 99
└── 319432ef3663735a9d3cb4e0c1d9950e3 directories, 1 file
[root@nginx nginx]#
nginx 反向代理的负载均衡
七层:
配置nginx反向代理
示例:
[root@nginx nginx]# vim /usr/local/nginx/conf.d/vhost.conf
upstream webcluster {
server 172.25.254.10:80 fail_timeout=15s max_fails=3;
server 172.25.254.20:8080 fail_timeout=15s max_fails=3;
server 172.25.254.100:80 backup;
}
server {
listen 80;
server_name www.timingwang.org;
location / {
proxy_pass http://webcluster;
}
}[root@nginx nginx]# nginx -s reload
默认是轮询
写算法:
[root@nginx nginx]# vim /usr/local/nginx/conf.d/vhost.conf
upstream webcluster {
ip_hash; ---- 算法,让同一个IP请求,访问到同一个主机上面
server 172.25.254.10:80 fail_timeout=15s max_fails=3;
server 172.25.254.20:8080 fail_timeout=15s max_fails=3;
#server 172.25.254.100:80 backup; --- hash写完不能加backup 防止调度到backup上面去
}
server {
listen 80;
server_name www.timingwang.org;location / {
proxy_pass http://webcluster;
}
}
[root@nginx nginx]# nginx -s reload访问的都是同一个主机
[root@nginx nginx]# vim /usr/local/nginx/conf.d/vhost.conf
upstream webcluster {
#ip_hash;
hash $request_uri consistent; ---- 动态算法,hash一致性
server 172.25.254.10:80 fail_timeout=15s max_fails=3;
server 172.25.254.20:8080 fail_timeout=15s max_fails=3;
#server 172.25.254.100:80 backup;
}
server {
listen 80;
server_name www.timingwang.org;location / {
proxy_pass http://webcluster;
}
}
[root@nginx nginx]# nginx -s reloaduri没变,一直访问的是20
172.25.254.10:
[root@nginx ~]# mkdir -p /var/www/html/static
[root@nginx ~]# echo 172.25.254.10 static > /var/www/html/static/index.html改uri,这就是对uri进行hash,一致的
对cookie进行hash
[root@nginx nginx]# vim /usr/local/nginx/conf.d/vhost.conf
upstream webcluster {
#ip_hash;
#hash $request_uri consistent;
hash $cookie_wang; ------- 对cookie进行hash
server 172.25.254.10:80 fail_timeout=15s max_fails=3;
server 172.25.254.20:8080 fail_timeout=15s max_fails=3;
#server 172.25.254.100:80 backup;
}
server {
listen 80;
server_name www.timingwang.org;location / {
proxy_pass http://webcluster;
}
}[root@nginx nginx]# nginx -s reload
对cookie值进行hash,wang=1 or wang=2 对后面的值进行hash
nginx-四层负载(tcp)
示例:
172.25.254.10和20 安装bind
配置DNS
[root@nginx ~]# dnf install bind -y
[root@nginx-node2 ~]# dnf install bind -y[root@nginx ~]# vim /etc/named.conf
// listen-on port 53 { 127.0.0.1; };
// listen-on-v6 port 53 { ::1; };
directory "/var/named";
dump-file "/var/named/data/cache_dump.db";
statistics-file "/var/named/data/named_stats.txt";
memstatistics-file "/var/named/data/named_mem_stats.txt";
secroots-file "/var/named/data/named.secroots";
recursing-file "/var/named/data/named.recursing";
// allow-query { localhost; };
dnssec-validation no; --- 改为no[root@nginx ~]# vim /etc/named.rfc1912.zones
zone "timingwang.org" IN {
type master;
file "timingwang.org.zone";
allow-update { none; };
};[root@nginx ~]# cd /var/named/
[root@nginx named]#
[root@nginx named]# cp named.localhost timingwang.org.zone -p
[root@nginx named]# vim timingwang.org.zone
$TTL 1D
@ IN SOA ns.timingwang.org. root.timingwang.org. (
0 ; serial
1D ; refresh
1H ; retry
1W ; expire
3H ) ; minimum
NS ns.timingwang.org.
ns A 172.25.254.10
www A 172.25.254.10[root@nginx named]# systemctl start named
[root@nginx named]# systemctl start named
[root@nginx named]# dig www.timingwang.org @172.25.254.10; <<>> DiG 9.16.23-RH <<>> www.timingwang.org @172.25.254.10
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 27004
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: 783e7ecaf1c29da10100000066c22dd4285bd72eb63c17c1 (good)
;; QUESTION SECTION:
;www.timingwang.org. IN A;; ANSWER SECTION:
www.timingwang.org. 86400 IN A 172.25.254.10;; Query time: 0 msec
;; SERVER: 172.25.254.10#53(172.25.254.10)
;; WHEN: Sun Aug 18 13:22:28 EDT 2024
;; MSG SIZE rcvd: 91[root@nginx named]#
直接传到172.25.254,20上面
[root@nginx named]# scp -p /etc/named.{conf,rfc1912.zones} root@172.25.254.20:/etc/
The authenticity of host '172.25.254.20 (172.25.254.20)' can't be established.
ED25519 key fingerprint is SHA256:JAc5p6OZrNZsG8UQHYDL8RDEOeKmzy1IWQlXlmvsuSw.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '172.25.254.20' (ED25519) to the list of known hosts.
root@172.25.254.20's password:
named.conf 100% 1727 3.0MB/s 00:00
named.rfc1912.zones 100% 1129 2.8MB/s 00:00
[root@nginx named]#
[root@nginx named]#
scp -p /var/named/timingwang.org.zone root@172.25.254.20:/var/named/timingwang.org.zoneroot@172.25.254.20's password:
timingwang.org.zone 100% 210 394.6KB/s 00:00
[root@nginx named]#
[root@nginx-node2 ~]# vim /var/named/timingwang.org.zone
$TTL 1D
@ IN SOA ns.timingwang.org. root.timingwang.org. (
0 ; serial
1D ; refresh
1H ; retry
1W ; expire
3H ) ; minimum
NS ns.timingwang.org.
ns A 172.25.254.20
www A 172.25.254.20[root@nginx-node2 named]# chgrp named timingwang.org.zone
[root@nginx-node2 ~]# systemctl start named
[root@nginx-node2 named]# dig www.timingwang.org @172.25.254.20; <<>> DiG 9.16.23-RH <<>> www.timingwang.org @172.25.254.20
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 48200
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: 3da0f57e7816a0bb0100000066c22fd3ea997c832e0fcd37 (good)
;; QUESTION SECTION:
;www.timingwang.org. IN A;; ANSWER SECTION:
www.timingwang.org. 86400 IN A 172.25.254.20;; Query time: 0 msec
;; SERVER: 172.25.254.20#53(172.25.254.20)
;; WHEN: Sun Aug 18 13:30:59 EDT 2024
;; MSG SIZE rcvd: 91[root@nginx-node2 named]#
dns负载均衡配置参数(tcp):
注意:tcp的负载均衡要写在http语句块外面
[root@nginx nginx]# vim /usr/local/nginx/conf/nginx.conf
include "/usr/local/nginx/tcpconf.d/*.conf"; ---- 要写在http外面
[root@nginx nginx]# vim /usr/local/nginx/conf.d/dns.conf
stream {
upstream dns {
server 172.25.254.10:53 fail_timeout=15s max_fails=3;
server 172.25.254.20:53 fail_timeout=15s max_fails=3;
}
server {
listen 53 udp reuseport;
proxy_timeout 20s;
proxy_pass dns;
}
}创建目录:
[root@nginx nginx]# mkdir -p /usr/local/nginx/tcpconf.d
[root@nginx nginx]# cd /usr/local/nginx/conf.d
[root@nginx conf.d]#
[root@nginx conf.d]# mv dns.conf /usr/local/nginx/tcpconf.d/[root@nginx tcpconf.d]# nginx -s reload
[root@nginx tcpconf.d]# netstat -antlupe | grep 53
tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN 0 25391 981/cupsd
tcp6 0 0 ::1:631 :::* LISTEN 0 25390 981/cupsd
udp 0 0 0.0.0.0:5353 0.0.0.0:* 70 23648 851/avahi-daemon: r
udp 0 0 0.0.0.0:53 0.0.0.0:* 0 86748 3832/nginx: master
udp6 0 0 :::5353 :::* 70 23649 851/avahi-daemon: r
[root@nginx tcpconf.d]#此时就能解析到172.25.254.10和20了
[root@nginx tcpconf.d]# dig www.timingwang.org @172.25.254.100; <<>> DiG 9.16.23-RH <<>> www.timingwang.org @172.25.254.100
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 15189
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: 8c6fc39065ed27c50100000066c23599d6924761de822212 (good)
;; QUESTION SECTION:
;www.timingwang.org. IN A;; ANSWER SECTION:
www.timingwang.org. 86400 IN A 172.25.254.10;; Query time: 1 msec
;; SERVER: 172.25.254.100#53(172.25.254.100)
;; WHEN: Sun Aug 18 13:55:37 EDT 2024
;; MSG SIZE rcvd: 91[root@nginx tcpconf.d]# dig www.timingwang.org @172.25.254.100
; <<>> DiG 9.16.23-RH <<>> www.timingwang.org @172.25.254.100
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 31342
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: 33a6b4e9a5b11f920100000066c235be1ce27ff22fb787ad (good)
;; QUESTION SECTION:
;www.timingwang.org. IN A;; ANSWER SECTION:
www.timingwang.org. 86400 IN A 172.25.254.20;; Query time: 1 msec
;; SERVER: 172.25.254.100#53(172.25.254.100)
;; WHEN: Sun Aug 18 13:56:14 EDT 2024
;; MSG SIZE rcvd: 91[root@nginx tcpconf.d]#
MySQL的四层负载均衡
安装数据库:
[root@nginx named]# dnf install mariadb-server -y
[root@nginx-node2 named]# dnf install mariadb-server -y[root@nginx named]# vim /etc/my.cnf.d/mariadb-server.cnf
[root@nginx-node2 named]# vim /etc/my.cnf.d/mariadb-server.cnf[mysqld]
server-id=20(10) ---- 两台机子都加个ID,用于区分
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
log-error=/var/log/mariadb/mariadb.log
pid-file=/run/mariadb/mariadb.pid[root@nginx named]# systemctl start mariadb
[root@nginx-node2 named]# systemctl start mariadb[root@nginx named]# mysql
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 3
Server version: 10.5.22-MariaDB MariaDB ServerCopyright (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 USER wang@'%' identified by 'wang';
Query OK, 0 rows affected (0.001 sec)MariaDB [(none)]> GRANT ALL ON *.* to wang@'%';
Query OK, 0 rows affected (0.001 sec)MariaDB [(none)]>
172.25.254.100主机上面:
[root@nginx ~]#vim /usr/local/nginx/tcpconf.d/dns.confstream {
upstream dns {
server 172.25.254.10:53 fail_timeout=15s max_fails=3;
server 172.25.254.20:53 fail_timeout=15s max_fails=3;
}upstream mysql {
server 172.25.254.10:3306 fail_timeout=15s max_fails=3;
server 172.25.254.20:3306 fail_timeout=15s max_fails=3;
}server {
listen 3306;
proxy_timeout 60;
proxy_pass mysql;
}server {
listen 53 udp reuseport;
proxy_timeout 20s;
proxy_pass dns;
}
}
[root@nginx tcpconf.d]# nginx -s reload
[root@nginx tcpconf.d]# netstat -antlupe | grep 3306
tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN 0 88742 3832/nginx: master[root@nginx tcpconf.d]# dnf install mariadb -y
[root@nginx tcpconf.d]# mysql -u wang -p -h 172.25.254.100
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 4
Server version: 10.5.22-MariaDB MariaDB ServerCopyright (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)]> SELECT @@server_id
-> ;
+-------------+
| @@server_id |
+-------------+
| 10 |
+-------------+
1 row in set (0.001 sec)MariaDB [(none)]>
再连一次:
[root@nginx tcpconf.d]# mysql -u wang -p -h 172.25.254.100
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 4
Server version: 10.5.22-MariaDB MariaDB ServerCopyright (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)]> SELECT @@server_id;
+-------------+
| @@server_id |
+-------------+
| 20 |
+-------------+
1 row in set (0.001 sec)MariaDB [(none)]>
nginx-源码编译php
这边重新整了个虚机重新编译纯净Nginx环境,再开始源码编译php
拖入所需压缩包并解压:
[root@nginx ~]# tar xzf nginx-1.26.1.tar.gz
[root@nginx ~]# tar xzf echo-nginx-module-0.63.tar.gz
[root@nginx ~]# tar xzf memc-nginx-module-0.20.tar.gz
[root@nginx ~]# tar xzf memcache-8.2.tgz
[root@nginx ~]# tar xzf php-8.3.9.tar.gz
[root@nginx ~]# tar xzf srcache-nginx-module-0.33.tar.gz
源码编译php:
源码编译Nginx:
安装Nginx编译所需的依赖性:
[root@nginx nginx-1.26.1]# dnf install gcc pcre-devel zlib-devel openssl-devel -y
[root@nginx ~]# cd nginx-1.26.1/
[root@nginx nginx-1.26.1]# useradd -s /sbin/nologin -M nginx[root@nginx nginx-1.26.1]# ./configure --prefix=/usr/local/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 --add-module=/root/echo-nginx-module-0.63 --add-module=/root/memc-nginx-module-0.20 --add-module=/root/srcache-nginx-module-0.33
[root@nginx nginx-1.26.1]# make && make install
[root@nginx ~]# vim auto/cc/gcc
# debug
#CFLAGS="$CFLAGS -g"[root@nginx ~]# vim ~/.bash_profile
# .bash_profile# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi# User specific environment and startup programs
export PATH=$PATH:/usr/local/nginx/sbin ---- 添加这个[root@nginx ~]# source ~/.bash_profile
[root@nginx ~]# cd /usr/local/nginx/sbin/
[root@nginx sbin]# ./nginx源码编译php:
安装所需依赖性:
[root@nginx ~]# yum install -y bzip2 systemd-devel libxml2-devel sqlite-devel libpng-devel
[root@nginx ~]# yum install libcurl-devel-7.76.1-29.el9_4.x86_64
[root@nginx ~]# wget -O /etc/yum.repos.d/epel.repo https://mirrors.aliyun.com/repo/epel-7.repo
[root@nginx ~]# yum install oniguruma-devel解压源码并开始安装:
[root@nginx ~]# cd php-8.3.9/
[root@nginx php-8.3.9]# ./configure --prefix=/usr/local/php \
> --with-config-file-path=/usr/local/php/etc \
> --enable-fpm \
> --with-fpm-user=nginx \
> --with-fpm-group=nginx \
> --with-curl \
> --with-iconv \
> --with-mhash \
> --with-zlib \
> --with-openssl \
> --enable-mysqlnd \
> --with-mysqli \
> --with-pdo-mysql \
> --disable-debug \
> --enable-sockets \
> --enable-soap \
> --enable-xml \
> --enable-ftp \
> --enable-gd \
> --enable-exif \
> --enable-mbstring \
> --enable-bcmath \
> --with-fpm-systemd[root@nginx php-8.3.9]# make && make install
[root@nginx php-8.3.9]# vim /usr/local/nginx/conf/nginx.conf
建议写到http后面
include "/usr/local/nginx/conf.d/*.conf";
[root@nginx conf]# mkdir -p /usr/local/nginx/conf.d/php相关配置优化:
[root@nginx php-8.3.9]# cd /usr/local/php/etc/
[root@nginx etc]# cp php-fpm.conf.default php-fpm.conf
[root@nginx etc]# vim php-fpm.conf
[global]
; Pid file
; Note: the default prefix is /usr/local/php/var
; Default Value: none
pid = run/php-fpm.pid ---- 这个去掉注释,指定pid文件存放位置[root@nginx etc]# cd php-fpm.d/
[root@nginx php-fpm.d]# cp www.conf.default www.conf
[root@nginx php-fpm.d]# vim www.conf ----- 查看端口生成主配置文件:
[root@nginx php-fpm.d]# cd /root/php-8.3.9/
[root@nginx php-8.3.9]# cp php.ini-production /usr/local/php/etc/php.ini
[root@nginx php-8.3.9]# vim /usr/local/php/etc/php.ini ----- 更改时区
[Date]
; Defines the default timezone used by the date functions
; https://php.net/date.timezone
date.timezone = Asia/Shanghai生成启动文件
[root@nginx php-8.3.9]# cp sapi/fpm/php-fpm.service /lib/systemd/system/
[root@nginx php-8.3.9]# vim /lib/systemd/system/php-fpm.service
# Mounts the /usr, /boot, and /etc directories read-only for processes invoked by this unit.
#ProtectSystem=full ----- 注释掉该内容[root@nginx php-8.3.9]# systemctl daemon-reload
[root@nginx php-8.3.9]# systemctl start php-fpm.service
[root@nginx php-8.3.9]# netstat -antlupe | grep php
tcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTEN 0 201110 149942/php-fpm: mas
[root@nginx php-8.3.9]#
Nginx和php整合
把php路径添加到环境变量中:
[root@nginx ~]# vim ~/.bash_profile
# .bash_profile# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi# User specific environment and startup programs
export PATH=$PATH:/usr/local/nginx/sbin:/usr/local/php/bin:/usr/local/php/sbin
[root@nginx ~]# source ~/.bash_profile创建php目录,存放php页面
[root@nginx ~]# mkdir -p /data/web/php
[root@nginx bin]# vim /data/web/php/index.php
<?php
phpinfo();
?>[root@nginx php]# vim /usr/local/nginx/conf.d/vhost.conf
server {
listen 80;
server_name www.xiaowang.org;
root /data/web/php;
index index.html;location ~ \.php$ {
fastcgi_pass 0.0.0.0:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
}
[root@nginx php]# nginx -s reload网页访问:www.xiaowang.org/index.php/
Nginx-php的缓存优化
安装memcache模块并解压
[root@nginx ~]# tar zxf memcache-8.2.tgz
[root@nginx ~]# cd memcache-8.2/
[root@nginx memcache-8.2]# yum install autoconf
[root@nginx memcache-8.2]# phpize ---- 用来生成configure file
Configuring for:
PHP Api Version: 20230831
Zend Module Api No: 20230831
Zend Extension Api No: 420230831
[root@nginx memcache-8.2]# ./configure && make && make install查看是否生成模块:
[root@nginx ~]# cd /usr/local/php/lib/php/extensions/no-debug-non-zts-20230831/
[root@nginx no-debug-non-zts-20230831]# ls
memcache.so opcache.so[root@nginx no-debug-non-zts-20230831]# cd
[root@nginx ~]# systemctl restart php-fpm.service
配置php加载memcache模块
[root@nginx ~]# vim /usr/local/php/etc/php.ini
;extension=soap
;extension=sockets
;extension=sodium
;extension=sqlite3
;extension=tidy
;extension=xsl
;extension=zip;zend_extension=opcache
extension=memcache ---------- 加上memcache模块
;;;;;;;;;;;;;;;;;;;
; Module Settings ;
;;;;;;;;;;;;;;;;;;;
[root@nginx ~]# systemctl restart php-fpm.service
复制测试文件到nginx发布目录中
[root@nginx memcache-8.2]# cp example.php memcache.php /data/web/php/ ---- 模拟向memcache发送数据,看效果
[root@nginx memcache-8.2]# vim /data/web/php/memcache.php
安装memcache模块
[root@nginx ~]# dnf install memcached -y
[root@nginx ~]# systemctl enable --now memcached.service
Created symlink /etc/systemd/system/multi-user.target.wants/memcached.service → /usr/lib/systemd/system/memcached.service.
[root@nginx ~]#
[root@nginx ~]# vim /etc/sysconfig/memcached ------ 查看信息
[root@nginx ~]# systemctl start memcached.service
[root@nginx ~]# netstat -antlupe | grep mem ---- 查看端口是否开启
tcp 0 0 127.0.0.1:11211 0.0.0.0:* LISTEN 980 192566 187646/memcached
tcp6 0 0 ::1:11211 :::* LISTEN 980 192567 187646/memcached
[root@nginx ~]#去网页访问:http://www.xiaowang.org/example.php
http://www.xiaowang.org/memcache.php
http://www.xiaowang.org/example.php
这个网页刷新的越多,memcache网页绿色柱状就会越多
绿色表示直接从memcache中取的值,橙色的表示不在memcache里,从外面取的值。
压测查看:
内存比较小,看不出来什么效果
[root@nginx ~]# ab -n1000 -c10 http://www.xiaowang.org/index.php
再来一次
[root@nginx ~]# ab -n1000 -c10 http://www.xiaowang.org/index.php
Nginx-memcache高速缓存
示例:
[root@nginx ~]# vim /usr/local/nginx/conf.d/php.conf
upstream memcache{
server 127.0.0.1:11211;
keepalive 512;
}
server {
listen 80;
server_name www.xiaowang.org;
root /data/web/php;
index index.html;location /memc {
internal;
memc_connect_timeout 100ms;
memc_send_timeout 100ms;
memc_read_timeout 100ms;
set $mem_key $query_string;
set $memc_exptime 300;
memc_pass memcache;
}location ~ \.php$ {
set $key $uri$args;
srcache_fetch GET /memc $key;
srcache_store PUT /memc $key;
fastcgi_pass 172.25.254.120:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
}[root@nginx ~]# nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful[root@nginx ~]# nginx -s reload
再进行压测:
ab -n500 -c10 http://www.xiaowang.org/index.php
Nginx-二次开发版本
示例:
[root@nginx ~]# nginx -s stop ---- 停掉Nginx,别让它占用80端口
[root@nginx ~]# netstat -antlupe | grep nginx
[root@nginx ~]# tar zxf openresty-1.25.3.1.tar.gz
[root@nginx ~]# cd openresty-1.25.3.1/
[root@nginx openresty-1.25.3.1]# dnf -y install gcc pcre-devel openssl-devel perl
[root@nginx openresty-1.25.3.1]# cd /usr/local/src
[root@nginx src]# wget https://openresty.org/download/openresty-1.17.8.2.tar.gz编译安装openresty
[root@nginx openresty-1.25.3.1]# ./configure --prefix=/usr/local/openresty --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-http_sub_module --without-http_memcached_module --with-stream_realip_module[root@nginx openresty-1.25.3.1]# make && make install
[root@nginx bin]# vim ~/.bash_profile
# .bash_profile# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi# User specific environment and startup programs
export PATH=$PATH:/usr/local/nginx/sbin:/usr/local/php/bin:/usr/local/php/sbin:/usr/local/openresty/bin[root@nginx bin]# source ~/.bash_profile
[root@nginx bin]# openresty
[root@nginx bin]# netstat -antlupe | grep 80
tcp 0 0 127.0.0.1:11211 0.0.0.0:* LISTEN 980 206856 187885/memcached
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 0 255222 211989/nginx: maste
tcp 0 0 0.0.0.0:9000 0.0.0.0:* LISTEN 0 230905 188036/php-fpm: mas
tcp6 0 0 ::1:11211 :::* LISTEN 980 206857 187885/memcached
udp 0 0 0.0.0.0:5353 0.0.0.0:* 70 24380 850/avahi-daemon: r
[root@nginx bin]#网页访问172.25.254.120
应用服务器TOMCAT
安装 Tomcat ,推荐从Apache官网下载源码包直接安装启动
首先准备三台纯净环境的主机(tomcat,tomcat-node1,2),先在在两台服务主机上配置环境
由于tomcat-node1和tomcat-node2上的操作都一样,所以下面的示例部分只有node1,但是node2上也要进行配置。
1.安装java环境
node1和node2都一样操作,后面演示内容都将只在
[root@tomcat-node1 ~]# yum install java-1.8.0-openjdk.x86_64 -y
2.安装并启动tomcat
node1和node2都一样操作
[root@tomcat-node1 ~]# tar zxf apache-tomcat-9.0.93.tar.gz -C /usr/local/
[root@tomcat-node1 ~]# ln -s /usr/local/apache-tomcat-9.0.93/ /usr/local/tomcat
[root@tomcat-node1 ~]# /usr/local/tomcat/bin/startup.sh
Using CATALINA_BASE: /usr/local/tomcat
Using CATALINA_HOME: /usr/local/tomcat
Using CATALINA_TMPDIR: /usr/local/tomcat/temp
Using JRE_HOME: /usr
Using CLASSPATH: /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar
Using CATALINA_OPTS:
Tomcat started.
3.查看端口
[root@tomcat-node1 ~]# netstat -antlupe | grep java
tcp6 0 0 127.0.0.1:8005 :::* LISTEN 0 37031 11768/java
tcp6 0 0 :::8080 :::* LISTEN 0 37019 11768/java
测试:在浏览器中输入IP地址加端口号
tomcat的文件结构和组成
目录结构
目录 说明
-------------------------------------------------------bin 服务启动、停止等相关程序和文件
conf 配置文件
lib 库目录
logs 日志目录
webapps 应用程序,应用部署目录,相当于nginx的默认发布目录
work jsp 编译后的结果文件,建议提前预热访问
查看tomcat相关目录和文件
[root@tomcat-node1 ~]# tar zxf apache-tomcat-9.0.93.tar.gz -C /usr/local/
[root@tomcat-node1 ~]# ls /usr/local/tomcat/
bin CONTRIBUTING.md logs RELEASE-NOTES webapps
BUILDING.txt lib NOTICE RUNNING.txt work
conf LICENSE README.md temp
生成tomcat启动文件
node1和node2都一样操作
[root@tomcat-node1 ~]# vim /usr/local/tomcat/conf/tomcat.conf
[root@tomcat-node1 ~]# cat /usr/local/tomcat/conf/tomcat.conf
JAVA_HOME=/etc/alternatives/jre_openjdk
生成启动文件
node1和node2都一样操作
[root@tomcat-node1 ~]# useradd -s /sbin/nologin -M tomcat
[root@tomcat-node1 ~]# chown -R tomcat.tomcat /usr/local/tomcat
传入test.jsp页面文件并拷贝到指定目录:
[root@tomcat-node1 ~]# cp test.jsp /usr/local/tomcat/webapps/ROOT/
[root@tomcat-node1 ~]# vim /lib/systemd/system/tomcat.service
[Unit]
Description=Tomcat
#After=syslog.target network.target remote-fs.target nss-lookup.target
After=syslog.target network.target
[Service]
Type=forking
EnvironmentFile=/usr/local/tomcat/conf/tomcat.conf
ExecStart=/usr/local/tomcat/bin/startup.sh
ExecStop=/usr/local/tomcat/bin/shutdown.sh
PrivateTmp=true
User=tomcat
Group=tomcat
[Install]
WantedBy=multi-user.target[root@tomcat ~]# nginx -s reload
使用memcached让会话保持一致
[root@tomcat-node1 ~]# vim /etc/sysconfig/memcached
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
OPTIONS="-l 0.0.0.0,::1" #修改为0.0.0.0[root@tomcat-node1 ~]# cd jar/
[root@tomcat-node1 jar]# cp *.jar /usr/local/tomcat/lib/[root@tomcat-node1 ~]# vim /usr/local/tomcat/conf/context.xml
<Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
memcachedNodes="m1:172.25.254.10:11211,m2:172.25.254.20:11211"
failoverNodes="m1"
requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"
/>[root@tomcat-node1 ~]# systemctl restart tomcat
[root@tomcat-node1 ~]# systemctl restart memcached
网页访问www.timinglee.org/test.jsp 访问到后输入数据,然后那访问到的那台机子tomcat挂掉,再输入数据,看是否能读取到之前的数据
访问到172.25.254.10了,现在把10上面的tomcat挂掉,再输入数据
[root@tomcat-node1 ~]# systemctl stop tomcat