一、Nginx基础篇【一】
1.1.背景介绍
Nginx一个具有高性能的【HTTP】和【反向代理】的【WEB服务器】,同时也是一个【POP3/SMTP/IMAP代理服务器】,是由伊戈尔·赛索耶夫(俄罗斯人)使用C语言编写的,Nginx的第一个版本是2004年10月4号发布的0.1.0版本。
1.2.名词解释
1.2.1. WEB服务器:
WEB服务器也叫网页服务器,英文名叫Web Server,主要功能是为用户提供网上信息浏览服务。
1.2.2. HTTP:
HTTP是超文本传输协议的缩写,是用于从WEB服务器传输超文本到本地浏览器的传输协议,也是互联网上应用最为广泛的一种网络协议。HTTP是一个客户端和服务器端请求和应答的标准,客户端是终端用户,服务端是网站,通过使用Web浏览器、网络爬虫或者其他工具,客户端发起一个到服务器上指定端口的HTTP请求。
1.2.3. POP3/SMTP/IMAP:
POP3(Post Offic Protocol 3)邮局协议的第三个版本,
SMTP(Simple Mail Transfer Protocol)简单邮件传输协议,
IMAP(Internet Mail Access Protocol)交互式邮件存取协议,
通过上述名词的解释,我们可以了解到Nginx也可以作为电子邮件代理服务器。
1.2.4. 反向代理
正向代理
反向代理
1.2.5.常见服务器对比
Netcraft公司于1994年底在英国成立,多年来一直致力于互联网市场以及在线安全方面的咨询服务,
其中在国际上最具影响力的当属其针对网站服务器、SSL市场所做的客观严谨的分析研究,
公司官网每月公布的调研数据(Web Server Survey)已成为当今人们了解全球网站数量
以及服务器市场分额情况的主要参考依据,时常被诸如华尔街杂志,英国BBC,Slashdot等媒体报道或引用。
Nginx的官方网站:http://nginx.org/
1.2.5.1.IIS
全称(Internet Information Services)即互联网信息服务,是由微软公司提供的基于windows系统的互联网基本服务。windows作为服务器在稳定性与其他一些性能上都不如类UNIX操作系统,因此在需要高性能Web服务器的场合下,IIS可能就会被"冷落".
1.2.5.2.Tomcat
Tomcat是一个运行Servlet和JSP的Web应用软件,Tomcat技术先进、性能稳定而且开放源代码,因此深受Java爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web应用服务器。但是Tomcat天生是一个重量级的Web服务器,对静态文件和高并发的处理比较弱。
1.2.5.3.Apache
Apache的发展时期很长,同时也有过一段辉煌的业绩。从上图可以看出大概在2014年以前都是市场份额第一的服务器。Apache有很多优点,如稳定、开源、跨平台等。但是它出现的时间太久了,在它兴起的年代,互联网的产业规模远远不如今天,所以它被设计成一个重量级的、不支持高并发的Web服务器。在Apache服务器上,如果有数以万计的并发HTTP请求同时访问,就会导致服务器上消耗大量能存,操作系统内核对成百上千的Apache进程做进程间切换也会消耗大量的CUP资源,并导致HTTP请求的平均响应速度降低,这些都决定了Apache不可能成为高性能的Web服务器。这也促使了Lighttpd和Nginx的出现。
1.2.5.4.Lighttpd
Lighttpd是德国的一个开源的Web服务器软件,它和Nginx一样,都是轻量级、高性能的Web服务器,欧美的业界开发者比较钟爱Lighttpd,而国内的公司更多的青睐Nginx,同时网上Nginx的资源要更丰富些。
1.2.5.5.其他的服务器
Google Servers,Weblogic, Webshpere(IBM)...
1.3.Nginx的优点
(1)速度更快、并发更高
单次请求或者高并发请求的环境下,Nginx都会比其他Web服务器响应的速度更快。一方面在正常情况下,单次请求会得到更快的响应,另一方面,在高峰期(如有数以万计的并发请求),Nginx比其他Web服务器更快的响应请求。Nginx之所以有这么高的并发处理能力和这么好的性能原因在于Nginx采用了多进程和I/O多路复用(epoll)的底层实现。
(2)配置简单,扩展性强
Nginx的设计极具扩展性
,它本身就是由很多模块组成,这些模块的使用可以通过配置文件的配置来添加。这些模块有官方提供的也有第三方提供的模块,如果需要完全可以开发服务自己业务特性的定制模块。
(3)高可靠性
Nginx
采用的是多进程
模式运行,其中有一个master主进程
和N多个worker进程
,worker进程的数量我们可以手动设置,每个worker进程之间都是相互独立提供服务,并且master主进程可以在某一个worker进程出错时,快速去"拉起"新的worker进程提供服务。
(4)热部署
现在互联网项目都要求以7*24小时进行服务的提供,针对于这一要求,Nginx也提供了热部署功能
,即可以在Nginx不停止的情况下,对Nginx进行文件升级、更新配置和更换日志文件等功能。
(5)成本低、BSD许可证
BSD是一个开源的许可证,世界上的开源许可证有很多,现在比较流行的有六种分别是GPL、BSD、MIT、Mozilla、Apache、LGPL。
Nginx本身是开源的,我们不仅可以免费的将Nginx应用在商业领域,而且还可以在项目中直接修改Nginx的源码来定制自己的特殊要求。
OpenRestry [Nginx+Lua] Tengine[淘宝]
1.4.Nginx的功能特性及常用功能
Nginx提供的基本功能服务从大体上归纳为"基本HTTP服务"、“高级HTTP服务”和"邮件服务"等三大类。
1.4.1.基本HTTP服务
Nginx可以提供基本HTTP服务,可以作为HTTP代理服务器和反向代理服务器,支持通过缓存加速访问,可以完成简单的负载均衡和容错,支持包过滤功能,支持SSL等。
- 处理静态文件、处理索引文件以及支持自动索引;
- 提供反向代理服务器,并可以使用缓存加上反向代理,同时完成负载均衡和容错;
- 提供对FastCGI、memcached等服务的缓存机制,,同时完成负载均衡和容错;
- 使用Nginx的模块化特性提供过滤器功能。Nginx基本过滤器包括gzip压缩、ranges支持、chunked响应、XSLT、SSI以及图像缩放等。其中针对包含多个SSI的页面,经由FastCGI或反向代理,SSI过滤器可以并行处理。
- 支持HTTP下的安全套接层安全协议SSL
- 支持基于加权和依赖的优先权的HTTP/2
1.4.2.高级HTTP服务
- 支持基于名字和IP的虚拟主机设置
- 支持HTTP/1.0中的KEEP-Alive模式和管线(PipeLined)模型连接
- 自定义访问日志格式、带缓存的日志写操作以及快速日志轮转。
- 提供3xx~5xx错误代码重定向功能
- 支持重写(Rewrite)模块扩展
- 支持重新加载配置以及在线升级时无需中断正在处理的请求
- 支持网络监控
- 支持FLV和MP4流媒体传输
1.4.3.邮件服务
Nginx提供邮件代理服务也是其基本开发需求之一,主要包含以下特性:
- 支持IMPA/POP3代理服务功能
- 支持内部SMTP代理服务功能
1.5.Nginx常用的功能模块
静态资源部署
Rewrite地址重写
正则表达式
反向代理
负载均衡
轮询、加权轮询、ip_hash、url_hash、fair
Web缓存
环境部署
高可用的环境
用户认证模块...
1.6.Nginx的核心组成
nginx二进制可执行文件
nginx.conf配置文件
error.log错误的日志记录
access.log访问日志记录
1.7.Nginx环境准备
1.7.1.Nginx版本介绍
Nginx的官方网站为: http://nginx.org
Nginx的官方下载网站为http://nginx.org/en/download.html
1.7.2.获取Nginx源码
打开上述网站,就可以查看到Nginx的所有版本,选中自己需要的版本进行下载。
1.7.3.准备服务器系统
1.7.3.1.环境准备
VMware WorkStation
Centos7
MobaXterm
xsheel,SecureCRT
网络
FinalShell SSH工具官网:http://www.hostbuf.com/
FinalShell SSH工具官网下载:http://www.hostbuf.com/t/988.html
Centos官网:https://www.centos.org/download/
MobaXterm官网:https://mobaxterm.mobatek.net/
MobaXterm官网下载:https://mobaxterm.mobatek.net/download.html
1.7.3.2.确认centos的内核
准备一个内核为2.6及以上版本的操作系统,因为linux2.6及以上内核才支持epoll,而Nginx需要解决高并发压力问题是需要用到epoll
# 查询linux的内核版本
uname -a
1.7.3.3.确保centos能联网
ping www.baidu.com
1.7.3.4.确认关闭防火墙
关闭的方式有如下两种:
# 关闭运行的防火墙,系统重新启动后,防火墙将重新打开
systemctl stop firewalld
# 永久关闭防火墙,,系统重新启动后,防火墙依然关闭
systemctl disable firewalld
# 查看防火墙状态
systemctl status firewalld
1.7.3.5.确认停用selinux
selinux(security-enhanced linux),美国安全局对于强制访问控制的实现,在linux2.6内核以后的版本中,selinux已经成功内核中的一部分。可以说selinux是linux史上最杰出的新安全子系统之一。虽然有了selinux,我们的系统会更安全,但是对于我们的学习Nginx的历程中,会多很多设置,所以这块建议大家将selinux进行关闭。
# 查看状态
sestatus
如果查看不是disabled状态,我们可以通过修改配置文件来进行设置,修改SELINUX=disabled,然后重启下系统即可生效。
vim /etc/selinux/config
# 重启系统
reboot
1.8.Nginx安装方式介绍
Nginx的安装方式有两种分别是:
通过Nginx源码
通过Nginx源码简单安装 (1)
通过Nginx源码复杂安装 (3)
通过yum安装 (2)
1.8.1.Nginx源码安装需要提前准备
1.8.1.1.GCC编译器
Nginx是使用C语言编写的程序,因此想要运行Nginx就需要安装一个编译工具。
GCC就是一个开源的编译器集合,用于处理各种各样的语言,其中就包含了C语言。
# 安装gcc
yum install -y gcc
# 查看gcc是否安装成功
gcc --version
1.8.1.2.PCRE
Nginx在编译过程中需要使用到PCRE库(perl Compatible Regular Expressoin 兼容正则表达式库),因为在Nginx的Rewrite模块和http核心模块都会使用到PCRE正则表达式语法。
# 安装 PCRE库
yum install -y pcre pcre-devel
rpm -qa pcre pcre-devel
1.8.1.3.zlib
zlib库提供了开发人员的压缩算法,在Nginx的各个模块中需要使用gzip压缩,所以我们也需要提前安装其库及源代码zlib和zlib-devel
yum install -y zlib zlib-devel
rpm -qa zlib zlib-devel
1.8.1.4.OpenSSL
- OpenSSL是一个开放源代码的软件库包,应用程序可以使用这个包进行安全通信,并且避免被窃听。
- SSL:Secure Sockets Layer安全套接协议的缩写,可以在Internet上提供秘密性传输,其目标是保证两个应用间通信的
保密性和可靠性
。- - 在Nginx中,如果服务器需要提供安全网页时就需要用到OpenSSL库,所以我们需要对OpenSSL的库文件及它的开发安装包进行一个安装。
yum install -y openssl openssl-devel
rpm -qa openssl openssl-devel
上述命令,一个个来的话比较麻烦,我们也可以通过一条命令来进行安装
# 一条命令来进行全部安装
yum install -y gcc pcre pcre-devel zlib zlib-devel openssl openssl-devel
gcc --version
rpm -qa pcre pcre-devel zlib zlib-devel openssl openssl-devel
1.8.1.5.警告时缺少安装包
安装gcc
yum -y install gcc
checking for OS
+ Linux 3.10.0-693.el7.x86_64 x86_64 checking for C compiler ... not found
./configure: error: C compiler cc is not found
安装perl库
yum install -y pcer-devl
./configure: error: the HTTP rewrite module requires the PCRE library.
You can either disable the module by using --without-http_rewrite_module option, or install the PCRE library into the system, or build the PCRE library statically from the source with nginx by using --with-pcre=<path> option.
安装zlib库
yum install -y zlib zlib-devel
./configure: error: the HTTP gzip module requires the zlib library.
You can either disable the module by using --without-http_gzip_module
option, or install the zlib library into the system, or build the zlib library statically from the source with nginx by using --with-zlib=<path> option.
1.8.2.方案一:Nginx的源码简单安装
1.8.2.1.进入官网查找需要下载版本的链接地址,然后使用wget命令进行下载
yum -y install wget
wget http://nginx.org/download/nginx-1.24.0.tar.gz
1.8.2.2.将下载的资源进行包管理
mkdir -p /app/nginx/core
mv nginx-1.24.0.tar.gz /app/nginx/core
1.8.2.3.解压缩
cd /app/nginx/core
tar -zxvf nginx-1.24.0.tar.gz
1.8.2.4.进入资源文件中,发现configure
cd /app/nginx/core/nginx-1.24.0
./configure
# 或者指定路径
./configure --prefix=/usr/local/nginx
1.8.2.5.编译
make
1.8.2.6.安装
make install
1.8.2.7.启动Nginx
进入安装好的目录 /usr/local/nginx/sbin
cd /usr/local/nginx/sbin
./nginx -V 查看版本详细信息
./nginx 启动
./nginx -s stop 快速停止
./nginx -s quit 优雅关闭,在退出前完成已经接受的连接请求
./nginx -s reload 重新加载配置
1.8.2.8.看下目录结构
# 指定的目录以树状结构展示出来
yum install tree
tree /usr/local/nginx/
1.8.2.9.卸载nginx
# 先看下nginx是否在运行中
ps aux | grep nginx
# 如果在运行中,则停止
nginx -s stop 或者直接杀死进程 pkill nginx或 kill -9 进程号
# 找到所有nginx有关文件
find / -name nginx*
# 删除有关nginx的文件(linux中一切都文件)
rm -rf /usr/local/nginx*
find / -name nginx*
# 卸载nginx的有关依赖
yum remove nginx
1.8.3.方案二:yum安装
官网:http://nginx.org/en/docs/install.html
RHEL and derivatives:http://nginx.org/en/linux_packages.html#RHEL
使用源码进行简单安装,我们会发现安装的过程比较繁琐,需要提前准备GCC编译器、PCRE兼容正则表达式库、zlib压缩库、OpenSSL安全通信的软件库包,然后才能进行Nginx的安装。
1.8.3.1.官方安装步骤
RHEL and derivatives:http://nginx.org/en/linux_packages.html#RHEL
RHEL and derivatives
This section applies to Red Hat Enterprise Linux and its derivatives such as CentOS, Oracle Linux, Rocky Linux, AlmaLinux.
Install the prerequisites:
sudo yum install yum-utils
To set up the yum repository, create the file named /etc/yum.repos.d/nginx.repo
with the following contents:
vim /etc/yum.repos.d/nginx.repo
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
By default, the repository for stable nginx packages is used. If you would like to use mainline nginx packages, run the following command:
# 切换成主线版本,暂时不需要
sudo yum-config-manager --enable nginx-mainline
To install nginx, run the following command:
sudo yum install nginx
When prompted to accept the GPG key, verify that the fingerprint matches 573B FD6B 3D8F BC64 1079 A6AB ABF5 BD82 7BD9 BF62
, and if so, accept it.
1.8.3.2.安装yum-utils
sudo yum install -y yum-utils
1.8.3.3.添加yum源文件
vim /etc/yum.repos.d/nginx.repo
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
1.8.3.4.查看是否安装成功
yum list | grep nginx
1.8.3.5.使用yum进行安装
yum -y install nginx
1.8.3.6.查看nginx的安装位置
whereis nginx
1.8.3.7.启动测试
cd /usr/sbin
./nginx
1.8.4.源码简单安装和yum安装的差异:
# 查看到所安装Nginx的版本及相关配置信息
./nginx -V
简单安装
yum安装
1.8.5.解压Nginx目录
执行tar -zxvf nginx-1.24.0.tar.gz
对下载的资源进行解压缩,进入压缩后的目录,可以看到如下结构
tar -zxvf nginx-1.24.0.tar.gz
内容解释:
- auto:存放的是编译相关的脚本
- CHANGES:版本变更记录
- CHANGES.ru:俄罗斯文的版本变更记录
- conf:nginx默认的配置文件
configure:nginx软件的自动脚本程序,是一个比较重要的文件,作用如下:
- (1)检测环境及根据环境检测结果生成C代码
- (2)生成编译代码需要的Makefile文件
- contrib:存放的是几个特殊的脚本文件,其中README中对脚本有着详细的说明
- html:存放的是Nginx自带的两个html页面,访问Nginx的首页和错误页面
- LICENSE:许可证的相关描述文件
- man:nginx的man手册
- README:Nginx的阅读指南
- src:Nginx的源代码
1.8.6.方案三:Nginx的源码指定编译参数复杂安装
1.8.6.1.Nginx编译参数
这种方式和简单的安装配置不同的地方在第一步,通过./configure
来对编译参数进行设置,需要我们手动来指定。那么都有哪些参数可以进行设置,接下来我们进行一个详细的说明。
- PATH:是和路径相关的配置信息
- with:是启动模块,默认是关闭的
- without:是关闭模块,默认是开启的
--prefix=PATH
指向Nginx的安装目录,默认值为/usr/local/nginx
--sbin-path=PATH
指向(执行)程序文件(nginx)的路径,默认值为<prefix>/sbin/nginx
--modules-path=PATH
指向Nginx动态模块安装目录,默认值为<prefix>/modules
--conf-path=PATH
指向配置文件(nginx.conf)的路径,默认值为<prefix>/conf/nginx.conf
--error-log-path=PATH
指向错误日志文件的路径,默认值为<prefix>/logs/error.log
--http-log-path=PATH
指向访问日志文件的路径,默认值为<prefix>/logs/access.log
--pid-path=PATH
指向Nginx启动后进行ID的文件路径,默认值为<prefix>/logs/nginx.pid
--lock-path=PATH
指向Nginx锁文件的存放路径,默认值为<prefix>/logs/nginx.lock
1.8.6.2.卸载Nginx
在使用上述命令之前,需要将之前服务器已经安装的nginx进行卸载,卸载的步骤分为三步骤:
步骤一:需要将nginx的进程关闭
./nginx -s stop
步骤二:将安装的nginx进行删除
cd ~
find / -name nginx*
rm -rf /usr/local/nginx
步骤三:将安装包之前编译的环境清除掉
cd /app/nginx/core/nginx-1.24.0
make clean
1.8.6.3.指定编译参数,重新编译Nginx
./configure --prefix=/usr/local/nginx \
--sbin-path=/usr/local/nginx/sbin/nginx \
--modules-path=/usr/local/nginx/modules \
--conf-path=/usr/local/nginx/conf/nginx.conf \
--error-log-path=/usr/local/nginx/logs/error.log \
--http-log-path=/usr/local/nginx/logs/access.log \
--pid-path=/usr/local/nginx/logs/nginx.pid \
--lock-path=/usr/local/nginx/logs/nginx.lock \
--with-http_gzip_static_module
# 编译安装
make & make install
18.7.make报错修改ngx_http_lua_headers_in.c文件
‘ngx_http_headers_in_t’没有名为‘cookies’的成员
In file included from /usr/include/dlfcn.h:25:0,
from src/os/unix/ngx_linux_config.h:58,
from src/core/ngx_config.h:26,
from /nginx/module/lua-nginx-module/src/ddebug.h:11,
from /nginx/module/lua-nginx-module/src/ngx_http_lua_headers_in.c:10:
/nginx/module/lua-nginx-module/src/ngx_http_lua_headers_in.c:162:18: 错误:‘ngx_http_headers_in_t’没有名为‘cookies’的成员
offsetof(ngx_http_headers_in_t, cookies),
^
make[1]: *** [objs/addon/src/ngx_http_lua_headers_in.o] 错误 1
make[1]: 离开目录“/nginx/core/nginx-1.24.0”
make: *** [build] 错误 2
vi /nginx/module/lua-nginx-module/src/ngx_http_lua_headers_in.c
1.9.Nginx目录结构分析
1.9.1.Nginx目录结构
# 安装tree工具展示目录结构
yum -y install tree
# 查看centos系统上的文件目录结构
tree /usr/local/nginx
# 显示所有文件和目录
tree /usr/local/nginx -a
1.9.2.基本运行原理
1.9.3.conf:nginx所有配置文件目录
CGI(Common Gateway Interface)通用网关【接口】,主要解决的问题是从客户端发送一个请求和数据,服务端获取到请求和数据后可以调用调用CGI【程序】处理及相应结果给客户端的一种标准规范。
[root@192 sbin]# tree /usr/local/nginx
/usr/local/nginx
├── client_body_temp
├── conf # 用来存放配置文件相关的
│ ├── fastcgi.conf # fastcgi相关配置文件
│ ├── fastcgi.conf.default # fastcgi.conf的备份文件
│ ├── fastcgi_params # fastcgi的参数文件
│ ├── fastcgi_params.default # fastcgi的参数备份文件
│ ├── koi-utf
│ ├── koi-win
│ ├── mime.types # 媒体类型,记录的是HTTP协议中的Content-Type的值和文件后缀名的对应关系
│ ├── mime.types.default # mime.types的备份文件
│ ├── nginx.conf # 这个是Nginx的核心配置文件
│ ├── nginx.conf.default # nginx.conf的备份文件
│ ├── scgi_params # scgi的参数文件
│ ├── scgi_params.default # scgi的参数备份文件
│ ├── uwsgi_params # uwsgi的参数文件
│ ├── uwsgi_params.default # uwsgi的参数备份文件
│ └── win-utf # koi-utf、koi-win、win-utf这三个文件都是与编码转换映射相关的配置文件,用来将一种编码转换成另一种编码
├── fastcgi_temp
├── html # 存放nginx自带的两个静态的html页面
│ ├── 50x.html # 访问失败后的失败页面
│ └── index.html # 成功访问的默认首页
├── logs # 记录入门的文件,当nginx服务器启动后,这里面会有 access.log error.log 和nginx.pid三个文件出现
│ ├── access.log # 访问日志
│ ├── error.log # 错误日志
│ └── nginx.pid # nginx进程的PID
├── proxy_temp
├── sbin # nginx的主程序
│ └── nginx # nginx是用来控制Nginx的启动和停止等相关的命令
├── scgi_temp
└── uwsgi_temp
more /usr/local/nginx/logs/nginx.pid
tail -f /usr/local/nginx/logs/access.log
tail -f /usr/local/nginx/logs/error.log
1.10.Nginx服务器启动、重启和停止Nginx的服务
1.10.1.方式一:Nginx服务的信号控制
Nginx中的master和worker进程?
Nginx的工作方式?
如何获取进程的PID?
信号有哪些?
如何通过信号控制Nginx的启停等相关操作?
前面在提到Nginx的高性能,其实也和它的架构模式有关。Nginx默认采用的是多进程的方式来工作的,当将Nginx启动后,我们通过ps -ef | grep nginx
命令可以查看到如下内容:
ps -ef | grep nginx
从上图中可以看到,Nginx后台进程中包含一个master进程和多个worker进程,master进程主要用来管理worker进程,包含接收外界的信息,并将接收到的信号发送给各个worker进程,监控worker进程的状态,当worker进程出现异常退出后,会自动重新启动新的worker进程。而worker进程则是专门用来处理用户请求的,各个worker进程之间是平等的并且相互独立,处理请求的机会也是一样的。nginx的进程模型,我们可以通过下图来说明下:
我们现在作为管理员,只需要通过给master进程发送信号就可以来控制Nginx,这个时候我们需要有两个前提条件,一个是要操作的master进程,一个是信号。
1.10.1.1.要想操作Nginx的master进程,就需要获取到master进程的进程号ID。
方式一:通过ps -ef | grep nginx
;
ps -ef | grep nginx
方式二:在讲解nginx的./configure
的配置参数的时候,有一个参数是--pid-path=PATH
默认是/usr/local/nginx/logs/nginx.pid
,所以可以通过查看该文件来获取nginx的master进程ID.
more /usr/local/nginx/logs/nginx.pid
1.10.1.2.信号
信号 | 作用 |
---|---|
TERM/INT | 立即关闭整个服务 |
QUIT | "优雅"地关闭整个服务 |
HUP | 重读配置文件并使用服务对新配置项生效 |
USR1 | 重新打开日志文件,可以用来进行日志切割 |
USR2 | 平滑升级到最新版的nginx |
WINCH | 所有子进程不在接收处理新连接,相当于给work进程发送QUIT指令 |
调用命令为kill -signal PID
signal:即为信号;PID即为获取到的master线程ID
- 发送TERM/INT信号给master进程,会将Nginx服务立即关闭。
kill -TERM PID
kill -TERM `cat /usr/local/nginx/logs/nginx.pid`
kill -INT PID
kill -INT `cat /usr/local/nginx/logs/nginx.pid`
- 发送QUIT信号给master进程,master进程会控制所有的work进程不再接收新的请求,等所有请求处理完后,在把进程都关闭掉。
kill -QUIT PID
kill -TERM `cat /usr/local/nginx/logs/nginx.pid`
- 发送HUP信号给master进程,master进程会把控制旧的work进程不再接收新的请求,等处理完请求后将旧的work进程关闭掉,然后根据nginx的配置文件重新启动新的work进程
kill -HUP PID
kill -TERM `cat /usr/local/nginx/logs/nginx.pid`
- 发送USR1信号给master进程,告诉Nginx重新开启日志文件
kill -USR1 PID
kill -TERM `cat /usr/local/nginx/logs/nginx.pid`
- 发送USR2信号给master进程,告诉master进程要平滑升级,这个时候,会重新开启对应的master进程和work进程,整个系统中将会有两个master进程,并且新的master进程的PID会被记录在
/usr/local/nginx/logs/nginx.pid
而之前的旧的master进程PID会被记录在/usr/local/nginx/logs/nginx.pid.oldbin
文件中,接着再次发送QUIT信号给旧的master进程,让其处理完请求后再进行关闭
kill -USR2 PID
kill -USR2 `cat /usr/local/nginx/logs/nginx.pid`
kill -QUIT PID
kill -QUIT `cat /usr/local/nginx/logs/nginx.pid.oldbin`
- 发送WINCH信号给master进程,让master进程控制不让所有的work进程在接收新的请求了,请求处理完后关闭work进程。注意master进程不会被关闭掉
kill -WINCH PID /kill -WINCH`cat /usr/local/nginx/logs/nginx.pid`
1.10.2.方式二:Nginx的命令行控制参数使用
此方式是通过Nginx安装目录下的sbin下的可执行文件nginx来进行Nginx状态的控制,我们可以通过./nginx -h
来查看都有哪些参数可以用:
[root@192 sbin]# ./nginx -h
nginx version: nginx/1.24.0
Usage: nginx [-?hvVtTq] [-s signal] [-p prefix]
[-e filename] [-c filename] [-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/local/nginx/)
-e filename : set error log file (default: /usr/local/nginx/logs/error.log)
-c filename : set configuration file (default: /usr/local/nginx/conf/nginx.conf)
-g directives : set global directives out of configuration file
- -?和-h:显示帮助信息
- -v:打印版本号信息并退出
- -V:打印版本号信息和配置信息并退出
- -t:测试nginx的配置文件语法是否正确并退出
- -T:测试nginx的配置文件语法是否正确并列出用到的配置文件信息然后退出
- -q:在配置测试期间禁止显示非错误消息
-s:signal信号,后面可以跟 :
- stop [快速关闭,类似于TERM/INT信号的作用]
- quit [优雅的关闭,类似于QUIT信号的作用]
- reopen [重新打开日志文件类似于USR1信号的作用]
- reload [类似于HUP信号的作用]
- -p:prefix,指定Nginx的prefix路径,(默认为:/usr/local/nginx/)
- -c:filename,指定Nginx的配置文件路径,(默认为: /usr/local/nginx/conf/nginx.conf)
- -g:用来补充Nginx配置文件,向Nginx服务指定启动时应用全局的配置
1.11.Nginx服务器版本升级和新增模块
如果想对Nginx的版本进行更新,或者要应用一些新的模块,最简单的做法就是停止当前的Nginx服务,然后开启新的Nginx服务。但是这样会导致在一段时间内,用户是无法访问服务器。为了解决这个问题,我们就需要用到Nginx服务器提供的平滑升级功能。这个也是Nginx的一大特点,使用这种方式,就可以使Nginx在7*24小时不间断的提供服务了。接下来我们分析下需求:
需求:Nginx的版本最开始使用的是nginx-1.22.1,由于服务升级,需要将Nginx的版本升级到nginx-1.24.0,要求Nginx不能中断提供服务。
为了应对上述的需求,这里我们给大家提供两种解决方案:
方案一:使用Nginx服务信号完成Nginx的升级
方案二:使用Nginx安装目录的make命令完成升级
1.11.1.环境准备
1.11.1.1.先准备两个版本的Nginx分别是 1.22.1和1.24.0
1.11.1.2.使用Nginx源码安装的方式将1.22.1版本安装成功并正确访问
进入安装目录
./configure
make && make install
1.11.1.3.将Nginx1.24.0进行参数配置和编译,不需要进行安装。
进入安装目录
./configure
make
1.11.2.方案一:使用Nginx服务信号进行升级
1.11.2.1.将1.22.1版本的sbin目录下的nginx进行备份
cd /usr/local/nginx/sbin
mv nginx nginxold
1.11.2.2.将Nginx1.24.0安装目录编译后的objs目录下的nginx文件,拷贝到原来/usr/local/nginx/sbin
目录下
cd /nginx/core/nginx-1.24.0/objs
cp nginx /usr/local/nginx/sbin
1.11.2.3.发送信号USR2给Nginx的1.22.1版本对应的master进程
kill -USR2 `cat /usr/local/nginx/logs/nginx.pid`
1.11.2.4.发送信号QUIT给Nginx的1.22.1版本对应的master进程
kill -QUIT `more /usr/local/logs/nginx.pid.oldbin`
1.11.3.方案二:使用Nginx安装目录的make命令完成升级
1.11.3.1.将1.22.1版本的sbin目录下的nginx进行备份
cd /usr/local/nginx/sbin
mv nginx nginxold
1.11.3.2.将Nginx1.24.0安装目录编译后的objs目录下的nginx文件,拷贝到原来/usr/local/nginx/sbin
目录下
cd /nginx/core/nginx-1.24.0/objs
cp nginx /usr/local/nginx/sbin
1.11.3.3.进入到安装目录,执行make upgrade
make upgrade
1.11.3.4.查看是否更新成功
cd /usr/local/nginx/sbin
./nginx -v
在整个过程中,其实Nginx是一直对外提供服务的。并且当Nginx的服务器启动成功后,我们是可以通过浏览器进行直接访问的,同时我们可以通过更改html目录下的页面来修改我们在页面上所看到的内容。
1.12.安装成系统服务,通过systemctl方法来启动nginx
1.12.1.创建脚本
vi /usr/lib/systemd/system/nginx.service
1.12.2.服务脚本内容
[Unit]
Description=nginx web service
Documentation=http://nginx.org/en/docs/
After=network.target
[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStartPre=/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/usr/local/nginx/sbin/nginx -s stop
PrivateTmp=true
[Install]
WantedBy=default.target
[Unit]:服务的说明
Description:描述服务
After:描述服务类别
[Service]服务运行参数的设置
Type=forking是后台运行的形式ExecStartpre是检查配置文件
ExecStart为服务的具体运行命令
ExecReload为重启命令
ExecStop为停止命令
PrivateTmp=True表示给服务分配独立的临时空间
注意:[Service]的启动、重启、停止命令全部要求使用绝对路径
[Install]运行级别下服务安装的相关设置,可设置为多用户,即系统运行级别为3
1.12.3.进行权限设置
chmod 755 /usr/lib/systemd/system/nginx.service
1.12.4.开机启动
# 重新加载系统服务
systemctl daemon-reload
# 启动服务
systemctl start nginx
#停止
systemctl stop nginx
#重启
systemctl restart nginx
#重新加载配置文件
systemctl reload nginx
# 查看nginx状态
systemctl status nginx
# 开机启动
systemctl enable nginx.service
# 查看nginx是否启动
ps -ef | grep nginx
1.13.Nginx核心配置文件结构
Nginx的核心配置文件默认是放在/usr/local/nginx/conf/nginx.conf
。
1.13.1.Nginx基础配置文件nginx.conf 内容解读和基本配置方法
# 指令名 指令值; #全局块,主要设置Nginx服务器整体运行的配置指令
worker_processes 1; # 默认为1,表示开启一个业务进程
# events块,主要设置,Nginx服务器与用户的网络连接,这一部分对Nginx服务器的性能影响较大
events { # 事件驱动模块
worker_connections 1024; # 单个业务进程可接受连接数
}
# http块,是Nginx服务器配置中的重要部分,代理、缓存、日志记录、第三方模块配置...
http {
include mime.types; # 引入http mime类型
default_type application/octet-stream; # 如果mime类型没有匹配上,默认使用二进制流的方式传输
sendfile on; # 使用limux的sendfile(socket,file,len)高效网络传输,也就是数据0拷贝
keepalive_timeout 65;
# server块,是Nginx配置和虚拟主机vhost相关的内容
server { # 虚拟主机配置
listen 80; # 监听端口号80
server_name localhost; # 域名、主机名
# location块,基于Nginx服务器接收请求字符串与location后面的值进行匹配,对特定请求进行处理
location / { # 匹配路径
root html; # 文件根目录
index index.html index.htm; # 默认页名称
}
error_page 500 502 503 504 /50x.html; # 报编码错误对应页面
location = /50x.html {
root html;
}
}
}
1.13.2.未开启sendfile
1.13.3.开启sendfile on;
简单小结下:
nginx.conf配置文件中默认有三大块:全局块、events块、http块
http块中可以配置多个server块,每个server块又可以配置多个location块。
1.13.4.全局块
1.13.4.1.user指令
1.13.4.1.1.user:用于配置运行Nginx服务器的worker进程的用户和用户组。
语法 | user user [group] |
---|---|
默认值 | nobody |
位置 | 全局块 |
该属性也可以在编译的时候指定,语法如下./configure --user=user --group=group
,如果两个地方都进行了设置,最终生效的是配置文件中的配置。
1.13.4.1.2.设置一个用户信息"www"
cd /usr/local/nginx/conf
vim nginx.conf
# 添加以下内容
user www;
cd /usr/local/nginx/sbin
./nginx -t
1.13.4.1.3.创建一个用户
useradd www
# 删除一个用户
userdel -rf www
1.13.4.1.4.修改user属性
user www
1.13.4.1.5.创建/root/html/index.html
页面,添加如下内容
mkdir -p /root/html
vi /root/html/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>欢迎来到 nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>欢迎来到 nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>谢谢使用 nginx.</em></p>
<p><em>I am WWW</em></p>
</body>
</html>
1.13.4.1.6.修改nginx.conf
vi /usr/local/nginx/conf/nginx.conf
location / {
root /root/html;
index index.html index.htm;
}
1.13.4.1.7.测试启动访问--403
1.13.4.1.8.分析原因:因为当前用户没有访问/root/html目录的权限
1.13.4.1.9.将文件创建到 /home/www/html/index.html
,修改配置
mkdir -p /home/www
cd /home/www
cp -r /root/html/ ./
vi /usr/local/nginx/conf/nginx.conf
cd /usr/local/nginx/sbin
location / {
root /home/www/html;
index index.html index.htm;
}
1.13.4.1.10.再次测试启动访问
综上所述,使用user指令可以指定启动运行工作进程的用户及用户组,这样对于系统的权限访问控制的更加精细,也更加安全。
1.13.4.2.work process指令
master_process:用来指定是否开启工作进程。
语法 | master_process on\ | off; |
---|---|---|
默认值 | master_process on; | |
位置 | 全局块 |
worker_processes:
用于配置Nginx生成工作进程的数量,这个是Nginx服务器实现并发处理服务的关键所在。理论上来说workder process的值越大,可以支持的并发处理量也越多,但事实上这个值的设定是需要受到来自服务器自身的限制,建议将该值和服务器CPU的内核数保存一致
。
语法 | worker_processes num/auto; |
---|---|
默认值 | 1 |
位置 | 全局块 |
如果将worker_processes设置成2,则会看到如下内容:
1.13.4.3.其他指令
daemon
:设定Nginx是否以守护进程的方式启动。
守护式进程是linux后台执行的一种服务进程,特点是独立于控制终端,不会随着终端关闭而停止。
语法 | daemon on\ | off; |
---|---|---|
默认值 | daemon on; | |
位置 | 全局块 |
pid
:用来配置Nginx当前master进程的进程号ID存储的文件路径。
语法 | pid file; |
---|---|
默认值 | 默认为:/usr/local/nginx/logs/nginx.pid |
位置 | 全局块 |
该属性可以通过./configure --pid-path=PATH
来指定
error_log
:用来配置Nginx的错误日志存放路径
语法 | error_log file [日志级别]; |
---|---|
默认值 | error_log logs/error.log error; |
位置 | 全局块、http、server、location |
该属性可以通过./configure --error-log-path=PATH
来指定
其中日志级别的值有:debug|info|notice|warn|error|crit|alert|emerg
,翻译过来为调试|信息|通知|警告|错误|临界|警报|紧急
,这块建议大家设置的时候不要设置成info以下的等级
,因为会带来大量的磁盘I/O消耗,影响Nginx的性能
。
1.13.4.4.include:用来引入其他配置文件,使Nginx的配置更加灵活
语法 | include file; |
---|---|
默认值 | 无 |
位置 | any |
1.13.5.events块
1.13.5.1.accept_mutex:用来设置Nginx网络连接序列化
语法 | accept_mutex on\ | off; |
---|---|---|
默认值 | accept_mutex on; | |
位置 | events |
这个配置主要用来解决常说的"惊群"问题。
大致意思是在某一个时刻,客户端发来一个请求连接,Nginx后台是以多进程的工作模式,也就是说有多个worker进程会被同时唤醒,但是最终只会有一个进程可以获取到连接,如果每次唤醒的进程数目太多,就会影响Nginx的整体性能。
如果将上述值设置为on(开启状态),将会对多个Nginx进程接收连接进行序列号,一个个来唤醒接收,就防止了多个进程对连接的争抢。
1.13.5.2.multi_accept:用来设置是否允许同时接收多个网络连接
语法 | multi_accept on\ | off; |
---|---|---|
默认值 | multi_accept off; | |
位置 | events |
如果multi_accept被禁止了,nginx一个工作进程只能同时接受一个新的连接。否则,一个工作进程可以同时接受所有的新连接
1.13.5.3.worker_connections:用来配置单个worker进程最大的连接数
语法 | worker_connections number; |
---|---|
默认值 | worker_commections 512; |
位置 | events |
这里的连接数不仅仅包括和前端用户建立的连接数,而是包括所有可能的连接数。另外,number值不能大于操作系统支持打开的最大文件句柄数量。
1.13.5.4.use:用来设置Nginx服务器选择哪种事件驱动来处理网络消息。
语法 | use method; |
---|---|
默认值 | 根据操作系统定 |
位置 | events |
注意:此处所选择事件处理模型是Nginx优化部分的一个重要内容,method的可选值有select/poll/epoll/kqueue等,之前在准备centos环境的时候,我们强调过要使用linux内核在2.6以上,就是为了能使用epoll函数
来优化Nginx。
另外这些值的选择,我们也可以在编译的时候使用
--with-select_module
、--without-select_module
、
--with-poll_module
、 --without-poll_module
来设置是否需要将对应的事件驱动模块编译到Nginx的内核。
1.13.5.5.events指令配置实例
打开Nginx的配置文件 nginx.conf,添加如下配置
events {
#设置Nginx网络连接序列化
accept_mutex on;
#设置Nginx的worker进程是否可以同时接收多个请求
multi_accept on;
#设置Nginx的worker进程最大的连接数
worker_connections 1024;
#设置Nginx使用的事件驱动模型
use epoll;
}
启动测试
./nginx -t
./nginx -s reload
1.13.6.http块
1.13.6.1.定义MIME-Type
我们都知道浏览器中可以显示的内容有HTML、XML、GIF等种类繁多的文件、媒体等资源,浏览器为了区分这些资源,就需要使用MIME Type。所以说MIME Type是网络资源的媒体类型。Nginx作为web服务器,也需要能够识别前端请求的资源类型。
在Nginx的配置文件中,默认有两行配置
include mime.types;
default_type application/octet-stream;
location /get_text {
return 200 "<h1>This is Nginx's Text</h1>";
}
1.13.6.2.default_type:用来配置Nginx响应前端请求默认的MIME类型。
语法 | default_type mime-type; |
---|---|
默认值 | default_type text/plain; |
位置 | http、server、location |
在default_type之前还有一句include mime.types
,include之前我们已经介绍过,相当于把mime.types文件中MIMT类型与相关类型文件的文件后缀名的对应关系加入到当前的配置文件中。
举例来说明:
有些时候请求某些接口的时候需要返回指定的文本字符串或者json字符串,如果逻辑非常简单或者干脆是固定的字符串,那么可以使用nginx快速实现,这样就不用编写程序响应请求了,可以减少服务器资源占用并且响应性能非常快。
如何实现:
location /get_text {
#这里也可以设置成text/plain
default_type text/html;
return 200 "<h1>This is Nginx's Text</h1>";
}
location /get_json{
default_type application/json;
return 200 '{"name":"TOM","age":18}';
}
1.13.6.3.自定义服务日志
Nginx中日志的类型分access.log、error.log。
access.log
:用来记录用户所有的访问请求。
error.log
:记录nginx本身运行时的错误信息,不会记录用户的访问请求。
Nginx服务器支持对服务日志的格式、大小、输出等进行设置,需要使用到两个指令,分别是access_log和log_format指令。
(1)access_log:用来设置用户访问日志的相关属性。
语法 | access_log path[format[buffer=size]] |
---|---|
默认值 | access_log logs/access.log combined; |
位置 | http , server , location |
(2)log_format:用来指定日志的输出格式。
语法 | log_format name [escape=default\ | json\ | none] string....; |
---|---|---|---|
默认值 | log_format combined "..."; | ||
位置 | http |
#access_log logs/access.log main;
log_format myformat '==========> This is My Format:$http_user_agent';
access_log logs/my.log myformat;
1.13.6.4.其他配置指令
(1)sendfile:用来设置Nginx服务器是否使用sendfile()传输文件,该属性可以大大提高Nginx处理静态资源的性能
语法 | sendfile on\ | off; |
---|---|---|
默认值 | sendfile off; | |
位置 | http、server、location |
(2)keepalive_timeout:用来设置长连接
的超时时间。
为什么要使用keepalive?
我们都知道HTTP是一种无状态协议,客户端向服务端发送一个TCP请求,服务端响应完毕后断开连接。
如何客户端向服务端发送多个请求,每个请求都需要重新创建一次连接,效率相对来说比较多,使用keepalive模式,
可以告诉服务器端在处理完一个请求后保持这个TCP连接的打开状态,若接收到来自这个客户端的其他请求,
服务端就会利用这个未被关闭的连接,而不需要重新创建一个新连接,提升效率,但是这个连接也不能一直保持,
这样的话,连接如果过多,也会是服务端的性能下降,这个时候就需要我们进行设置其的超时时间。
语法 | keepalive_timeout time; |
---|---|
默认值 | keepalive_timeout 75s; |
位置 | http、server、location |
(3)keepalive_requests:用来设置一个keep-alive连接使用的次数。
语法 | keepalive_requests number; |
---|---|
默认值 | keepalive_requests 100; |
位置 | http、server、location |
1.13.7.server块和location块
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 404 /50x.html;
location = /50x.html {
root html;
}
}
1.14.nginx.conf 和 常用文件
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
# 指令名 指令值; #全局块,主要设置Nginx服务器整体运行的配置指令
worker_processes 1; # 默认为1,表示开启一个业务进程
# events块,主要设置,Nginx服务器与用户的网络连接,这一部分对Nginx服务器的性能影响较大
events { # 事件驱动模块
accept_mutex on; #设置Nginx网络连接序列化,防止多个进程对连接的争抢
multi_accept on; #设置Nginx的worker进程是否可以同时接收多个网络请求
worker_connections 1024; # 设置Nginx单个worker进程最大的连接数
use epoll; #设置Nginx使用的事件驱动模型,使用epoll函数来优化Ngin
}
# http块,是Nginx服务器配置中的重要部分,代理、缓存、日志记录、第三方模块配置...
http {
include mime.types; # 引入http mime类型
default_type application/octet-stream; # 如果mime类型没有匹配上,默认使用二进制流的方式传输
sendfile on; # 使用limux的sendfile(socket,file,len)高效网络传输,也就是数据0拷贝
tcp_nopush on; # 主要是用来提升网络包的传输效率
tcp_nodelay on; # 提高网络包传输的实时性
keepalive_timeout 65;
include nginx_gzip.conf;
# server块,是Nginx配置和虚拟主机vhost相关的内容
server { # 虚拟主机配置
listen 80; # 监听端口号80
server_name localhost; # 域名、主机名
# location块,基于Nginx服务器接收请求字符串与location后面的值进行匹配,对特定请求进行处理
location / { # 匹配路径
root html; # 文件根目录
index index.html index.htm; # 默认页名称
}
error_page 500 502 503 504 /50x.html; # 报编码错误对应页面
location = /50x.html {
root html;
}
}
}
nginx_gzip.conf
# Gzip压缩功能的实例配置
gzip on; #开启gzip功能
gzip_types *; #压缩源文件类型,根据具体的访问资源类型设定
gzip_comp_level 6; #gzip压缩级别
gzip_min_length 1024; #进行压缩响应页面的最小长度,content-length
gzip_buffers 4 16K; #缓存空间大小
gzip_http_version 1.1; #指定压缩响应所需要的最低HTTP请求版本
gzip_vary on; #往头信息中添加压缩标识
gzip_disable "MSIE [1-6]\."; #对IE6以下的版本都不进行压缩
gzip_proxied off; #nginx作为反向代理压缩服务端返回数据的条件
gzip on;
gzip_types *;
gzip_comp_level 6;
gzip_min_length 1024;
gzip_buffers 4 16K;
gzip_http_version 1.1;
gzip_vary on;
gzip_disable "MSIE [1-6]\.";
gzip_proxied off;
./configure --prefix=/usr/local/nginx \
--sbin-path=/usr/local/nginx/sbin/nginx \
--modules-path=/usr/local/nginx/modules \
--conf-path=/usr/local/nginx/conf/nginx.conf \
--error-log-path=/usr/local/nginx/logs/error.log \
--http-log-path=/usr/local/nginx/logs/access.log \
--pid-path=/usr/local/nginx/logs/nginx.pid \
--lock-path=/usr/local/nginx/logs/nginx.lock \
--with-http_gzip_static_module \
--with-http_ssl_module \
--with-stream
# 编译安装
make & make install
二、Nginx进阶篇
2.1.Nginx服务器基础配置实例
2.1.1.需求
(1)有如下访问:
http://192.168.229.136:8081/server1/location1
访问的是:index_sr1_location1.html
http://192.168.229.136:8081/server1/location2
访问的是:index_sr1_location2.html
http://192.168.229.136:8082/server2/location1
访问的是:index_sr2_location1.html
http://192.168.229.136:8082/server2/location2
访问的是:index_sr2_location2.html
(2)如果访问的资源不存在,
返回自定义的404页面
(3)将/server1和/server2的配置使用不同的配置文件分割
将文件放到/home/www/conf.d目录下,然后使用include进行合并
(4)为/server1和/server2各自创建一个访问日志文件
2.1.2.准备相关文件及内容,目录如下:
mkdir -p /home/www/myweb/server1/location1
mkdir -p /home/www/myweb/server1/location2
mkdir -p /home/www/myweb/server1/logs
mkdir -p /home/www/myweb/server2/location1
mkdir -p /home/www/myweb/server2/location2
mkdir -p /home/www/myweb/server2/logs
mkdir -p /home/www/conf.d
touch /home/www/myweb/404.html
touch /home/www/myweb/server1/location1/index_sr1_location1.html
touch /home/www/myweb/server1/location2/index_sr1_location2.html
touch /home/www/myweb/server2/location1/index_sr2_location1.html
touch /home/www/myweb/server2/location2/index_sr2_location2.html
# 使用echo追加内容到某个文件,可以使用>> , 使用后会在文本后面继续追加内容,若文件中原来就有内容也不会被覆盖掉。
# > 表示覆盖,如果直接使用> 后,文本的内容会被覆盖为新的内容。
echo this is 404.html >> /home/www/myweb/404.html
echo this is index_src1_location1.html >> /home/www/myweb/server1/location1/index_sr1_location1.html
echo this is index_src1_location2.html >> /home/www/myweb/server1/location2/index_sr1_location2.html
echo this is index_src2_location1.html >> /home/www/myweb/server2/location1/index_sr2_location1.html
echo this is index_src2_location2.html >> /home/www/myweb/server2/location2/index_sr2_location2.html
yum -y install tree
tree /home/www
2.1.3.nginx.conf
rm -rf /usr/local/nginx/conf/nginx.conf
vi /usr/local/nginx/conf/nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
2.1.3. nginx.conf配置的内容如下:
vi /usr/local/nginx/conf/nginx.conf
##全局块 begin##
#配置允许运行Nginx工作进程的用户和用户组
user www;
#配置运行Nginx进程生成的worker进程数
worker_processes 2;
#配置Nginx服务器运行对错误日志存放的路径
error_log logs/error.log;
#配置Nginx服务器允许时记录Nginx的master进程的PID文件路径和名称
pid logs/nginx.pid;
#配置Nginx服务是否以守护进程方法启动
#daemon on;
##全局块 end##
##events块 begin##
events{
#设置Nginx网络连接序列化
accept_mutex on;
#设置Nginx的worker进程是否可以同时接收多个请求
multi_accept on;
#设置Nginx的worker进程最大的连接数
worker_connections 1024;
#设置Nginx使用的事件驱动模型
use epoll;
}
##events块 end##
##http块 start##
http{
#定义MIME-Type
include mime.types;
default_type application/octet-stream;
#配置允许使用sendfile方式运输
sendfile on;
#配置连接超时时间
keepalive_timeout 65;
#配置请求处理日志格式
log_format server1 '===>server1 access log';
log_format server2 '===>server2 access log';
##server块 开始##
include /home/www/conf.d/*.conf;
##server块 结束##
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
##http块 end##
2.1.4.server1.conf
vi /home/www/conf.d/server1.conf
server{
#配置监听端口和主机名称
listen 8081;
server_name localhost;
#配置请求处理日志存放路径
access_log /home/www/myweb/server1/logs/access.log server1;
#配置错误页面
error_page 404 /404.html;
#配置处理/server1/location1请求的location
location /server1/location1{
root /home/www/myweb;
index index_sr1_location1.html;
}
#配置处理/server1/location2请求的location
location /server1/location2{
root /home/www/myweb;
index index_sr1_location2.html;
}
#配置错误页面转向
location = /404.html {
root /home/www/myweb;
index 404.html;
}
}
2.1.5.server2.conf
vi /home/www/conf.d/server2.conf
server{
#配置监听端口和主机名称
listen 8082;
server_name localhost;
#配置请求处理日志存放路径
access_log /home/www/myweb/server2/logs/access.log server2;
#配置错误页面,对404.html做了定向配置
error_page 404 /404.html;
#配置处理/server1/location1请求的location
location /server2/location1{
root /home/www/myweb;
index index_sr2_location1.html;
}
#配置处理/server2/location2请求的location
location /server2/location2{
root /home/www/myweb;
index index_sr2_location2.html;
}
#配置错误页面转向
location = /404.html {
root /home/www/myweb;
index 404.html;
}
}
2.1.6.访问测试:
tail -f /home/www/myweb/server1/logs/access.log
tail -f /home/www/myweb/server2/logs/access.log
2.2.Nginx配置成系统服务
把Nginx应用服务设置成为系统服务,方便对Nginx服务的启动和停止等相关操作,具体实现步骤:
2.2.1.在/usr/lib/systemd/system
目录下添加nginx.service
vim /usr/lib/systemd/system/nginx.service
[Unit]
Description=nginx web service
Documentation=http://nginx.org/en/docs/
After=network.target
[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStartPre=/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/usr/local/nginx/sbin/nginx -s stop
PrivateTmp=true
[Install]
WantedBy=default.target
[Unit]:服务的说明
Description:描述服务
After:描述服务类别
[Service]服务运行参数的设置
Type=forking是后台运行的形式ExecStartpre是检查配置文件
ExecStart为服务的具体运行命令
ExecReload为重启命令
ExecStop为停止命令
PrivateTmp=True表示给服务分配独立的临时空间
注意:[Service]的启动、重启、停止命令全部要求使用绝对路径
[Install]运行级别下服务安装的相关设置,可设置为多用户,即系统运行级别为3
2.2.2.添加完成后如果权限有问题需要进行权限设置
chmod 755 /usr/lib/systemd/system/nginx.service
2.2.3.使用系统命令来操作Nginx服务
# 重新加载系统服务
systemctl daemon-reload
# 启动服务
systemctl start nginx
#停止
systemctl stop nginx
#重启
systemctl restart nginx
#重新加载配置文件
systemctl reload nginx
# 查看nginx状态
systemctl status nginx
# 开机启动
systemctl enable nginx.service
# 查看nginx是否启动
ps -ef | grep nginx
2.4.Nginx命令配置到系统环境
将该二进制可执行文件加入到系统的环境变量,在任何目录都可以使用nginx对应的相关命令。
cd /usr/local/nginx/sbin
./nginx -V
2.4.1.修改/etc/profile
文件
vim /etc/profile
#在最后一行添加 shift+g 快速到最后一行
export PATH=$PATH:/usr/local/nginx/sbin
2.4.2.使之立即生效
source /etc/profile
2.4.3.执行nginx命令
nginx -V
三、Nginx静态资源部署
https://nginx.org/en/docs/http/ngx_http_core_module.html
3.1.Nginx静态资源概述
静态资源即指在服务器端真实存在并且能直接拿来展示的一些文件,比如常见的html页面、css文件、js文件、图 片、视频等资源;
动态资源即指在服务器端真实存在但是要想获取需要经过一定的业务逻辑处理,根据不同的条件展示在页面不同这 一部分内容,比如说报表数据展示、根据当前登录用户展示相关具体数据等资源;
Nginx处理静态资源的内容,需要考虑这几个问题:
(1)静态资源的配置指令
(2)静态资源的配置优化
(3)静态资源的压缩配置指令
(4)静态资源的缓存处理
(5)静态资源的访问控制,包括跨域问题和防盗链问题
3.2.Nginx静态资源的配置指令
3.2.1.listen指令
listen:用来配置监听端口。
语法 | listen address[:port] [default_server]...;<br/>listen port [default_server]...; | |
---|---|---|
默认值 | listen *:80 \ | *:8000 |
位置 | server |
listen的设置比较灵活,我们通过几个例子来把常用的设置方式熟悉下:
listen 127.0.0.1:8000; // listen localhost:8000 监听指定的IP和端口
listen 127.0.0.1; 监听指定IP的所有端口
listen 8000; 监听指定端口上的连接
listen *:8000; 监听指定端口上的连接
default_server属性是标识符,用来将此虚拟主机设置成默认主机。所谓的默认主机指的是如果没有匹配到对应的address:port,则会默认执行的。如果不指定默认使用的是第一个server。
server{
listen 8080;
server_name 127.0.0.1;
location /{
root html;
index index.html;
}
}
server{
listen 8080 default_server;
server_name localhost;
default_type text/plain;
return 444 'This is a error request';
}
3.2.2.server_name指令
server_name
:用来设置虚拟主机服务名称。
127.0.0.1 、 localhost 、域名[www.baidu.com | www.jd.com]
语法 | server_name name ...;<br/>name可以提供多个中间用空格分隔 |
---|---|
默认值 | server_name ""; |
位置 | server |
关于server_name的配置方式有三种,分别是:
精确匹配
通配符匹配
正则表达式匹配
3.2.2.1.配置方式一:精确匹配
如:
server {
listen 80;
server_name www.nginx521.cn;
...
}
补充小知识点:
hosts是一个没有扩展名的系统文件,可以用记事本等工具打开,其作用就是将一些常用的网址域名与其对应的IP地址建立一个关联“数据库”,
当用户在浏览器中输入一个需要登录的网址时,系统会首先自动从hosts文件中寻找对应的IP地址,一旦找到,系统会立即打开对应网页,
如果没有找到,则系统会再将网址提交DNS域名解析服务器进行IP地址的解析。
windows:C:\Windows\System32\drivers\etc
centos:/etc/hosts
因为域名是要收取一定的费用,所以我们可以使用修改hosts文件来制作一些虚拟域名来使用。需要修改 /etc/hosts
文件来添加
vim /etc/hosts
127.0.0.1 www.study.cn
127.0.0.1 www.test.cn
127.0.0.1 www.nginx521.cn
127.0.0.1 www.study.com
127.0.0.1 www.test.com
127.0.0.1 www.nginx521.com
3.2.2.2.配置方式二:使用通配符配置
server_name
中支持通配符"*",但需要注意的是通配符不能出现在域名的中间,只能出现在首段或尾段,如:
server {
listen 80;
server_name *.nginx521.cn www.nginx521.*;
...
}
下面的配置就会报错
server {
listen 80;
server_name www.*.cn www.nginx521.c*;
...
}
3.2.2.3.配置三:使用正则表达式配置
server_name
中可以使用正则表达式,并且使用~
作为正则表达式字符串的开始标记。
常见的正则表达式
代码 | 说明 |
---|---|
^ | 匹配搜索字符串开始位置 |
$ | 匹配搜索字符串结束位置 |
. | 匹配除换行符\n之外的任何单个字符 |
\ | 转义字符,将下一个字符标记为特殊字符 |
[xyz] | 字符集,与任意一个指定字符匹配 |
[a-z] | 字符范围,匹配指定范围内的任何字符 |
\w | 与以下任意字符匹配 A-Z a-z 0-9 和下划线,等效于[A-Za-z0-9_] |
\d | 数字字符匹配,等效于[0-9] |
{n} | 正好匹配n次 |
{n,} | 至少匹配n次 |
{n,m} | 匹配至少n次至多m次 |
* | 零次或多次,等效于{0,} |
+ | 一次或多次,等效于{1,} |
? | 零次或一次,等效于{0,1} |
配置如下:
server{
listen 80;
server_name ~^www\.(\w+)\.com$;
default_type text/plain;
return 200 $1 $2 ..;
}
注意 ~后面不能加空格,括号可以取值,
~标识为一个正则表达式
$1 获取第一个括号值,以此类推
3.2.2.4.匹配执行顺序
由于server_name指令支持通配符和正则表达式,因此在包含多个虚拟主机的配置文件中,可能会出现一个名称被多个虚拟主机的server_name匹配成功,当遇到这种情况,当前的请求交给谁来处理呢?
user www;
worker_processes 2;
events {
accept_mutex on;
multi_accept on;
worker_connections 1024;
use epoll;
}
http {
include mime.types;
default_type text/plain;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name ~^www\.\w+\.com$;
return 200 'regex_success';
}
server {
listen 80;
server_name www.test.*;
return 200 'wildcard_after_success';
}
server {
listen 80;
server_name *.test.com;
return 200 'wildcard_before_success';
}
server {
listen 80;
server_name www.test.com;
return 200 'exact_success';
}
server {
listen 80 default_server;
server_name _;
return 444 'default_server not found server !!!';
}
}
3.2.2.5.结论:
exact_success
wildcard_before_success
wildcard_after_success
regex_success
default_server not found server!!
No1:准确匹配server_name
No2:通配符在开始时匹配server_name成功
No3:通配符在结束时匹配server_name成功
No4:正则表达式匹配server_name成功
No5:被默认的default_server处理,如果没有指定默认找第一个server
3.2.3.location指令
server{
listen 80;
server_name localhost;
location / {
}
location /abc{
}
...
}
location:用来设置请求的URI
语法 | location [ = \ | ~ \ | ~* \ | ^~ \ | @ ] uri{...} |
---|---|---|---|---|---|
默认值 | — | ||||
位置 | server,location |
uri变量是待匹配的请求字符串,可以不包含正则表达式,也可以包含正则表达式,那么nginx服务器在搜索匹配location的时候,是先使用不包含正则表达式进行匹配,找到一个匹配度最高的一个,然后在通过包含正则表达式的进行匹配,如果能匹配到直接访问,匹配不到,就使用刚才匹配度最高的那个location来处理请求。
属性介绍:
不带符号,要求必须以指定模式开始
user www;
worker_processes 2;
events {
accept_mutex on;
multi_accept on;
worker_connections 1024;
use epoll;
}
http {
include mime.types;
default_type text/plain;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name 127.0.0.1;
location /abc{
return 200 'access success';
}
}
}
以下访问都是正确的
http://192.168.229.136/abc
http://192.168.229.136/abcdef
= : 用于不包含正则表达式的uri前,必须与指定的模式精确匹配
server {
listen 80;
server_name 127.0.0.1;
location =/abc{
default_type text/plain;
return 200 "access success";
}
}
可以匹配到
http://192.168.229.136/abc
http://192.168.229.136/abc?p1=TOM
匹配不到
http://192.168.229.136/abc/
http://192.168.229.136/abcdef
~ : 用于表示当前uri中包含了正则表达式,并且区分大小写
~*: 用于表示当前uri中包含了正则表达式,并且不区分大小写
换句话说,如果uri包含了正则表达式
,需要用上述两个符合来标识
server {
listen 80;
server_name 127.0.0.1;
location ~^/abc\w${
default_type text/plain;
return 200 "access success";
}
}
server {
listen 80;
server_name 127.0.0.1;
location ~*^/abc\w${
default_type text/plain;
return 200 "access success";
}
}
^~: 用于不包含正则表达式的uri前
,功能和不加符号的一致,唯一不同的是,如果模式匹配
,那么就停止搜索其他模式
了。
server {
listen 80;
server_name 127.0.0.1;
location ^~/abc{
default_type text/plain;
return 200 "access success";
}
}
3.2.4.设置请求资源的目录root / alias
3.2.4.1.root:设置请求的根目录
语法 | root path; |
---|---|
默认值 | root html; |
位置 | http、server、location |
path为Nginx服务器接收到请求以后查找资源的根目录路径。
3.2.4.2.alias:用来更改location的URI
语法 | alias path; |
---|---|
默认值 | — |
位置 | location |
path为修改后的根路径。
3.2.4.3.在/usr/local/nginx/html
目录下创建一个 images目录,并在目录下放入一张图片java.png
图片
location /images {
root html;
#root /usr/local/nginx/html;
}
访问图片的路径为:
http://192.168.229.136/images/java.png
3.2.4.4.如果把root改为alias
location /images {
alias /usr/local/nginx/html; # 404 error
}
再次访问上述地址,页面会出现404的错误,查看错误日志会发现是因为地址不对,所以验证了:
root的处理结果是: root路径+location路径
/usr/local/nginx/html/images/mv.png
alias的处理结果是:使用alias路径替换location路径
/usr/local/nginx/html/images
需要在alias后面路径改为
location /images {
alias /usr/local/nginx/html/images;
}
3.2.4.5.如果location路径是以/结尾,则alias也必须是以/结尾,root没有要求
将上述配置修改为
location /images/ {
alias /usr/local/nginx/html/images; # 404 error
}
访问就会出问题,查看错误日志还是路径不对,所以需要把alias后面加上 /
3.2.4.6.小结:
root的处理结果是: root路径+location路径
alias的处理结果是:使用alias路径替换location路径
alias是一个目录别名的定义,root则是最上层目录的含义。
如果location路径是以/结尾,则alias也必须是以/结尾,root没有要求
3.2.5.index指令
index:设置网站的默认首页
语法 | index file ...; |
---|---|
默认值 | index index.html; |
位置 | http、server、location |
index后面可以跟多个设置,如果访问的时候没有指定具体访问的资源,则会依次进行查找,找到第一个为止。
举例说明:
location / {
root /usr/local/nginx/html;
index index.html index.htm;
}
访问该location的时候,可以通过 http://ip:port/,地址后面如果不添加任何内容,
则默认依次访问index.html和index.htm,找到第一个来进行返回
3.2.6.error_page指令
error_page:设置网站的错误页面
语法 | error_page code ... [=[response]] uri; |
---|---|
默认值 | — |
位置 | http、server、location...... |
当出现对应的响应code后,如何来处理。
举例说明:
(1)可以指定具体跳转的地址
server {
error_page 404 http://www.itcast.cn;
}
(2)可以指定重定向地址
server{
error_page 404 /50x.html;
error_page 500 502 503 504 /50x.html;
location =/50x.html{
root html;
}
}
(3)使用location的@符合完成错误信息展示
server{
error_page 404 @jump_to_error;
location @jump_to_error {
default_type text/plain;
return 404 'Not Found Page...';
}
}
可选项=[response]
的作用是用来将相应代码更改为另外一个
server{
error_page 404 =200 /50x.html;
location =/50x.html{
root html;
}
}
这样的话,当返回404找不到对应的资源的时候,在浏览器上可以看到,
最终返回的状态码是200,这块需要注意下,编写error_page
后面的内容,404后面需要加空格,200前面不能加空格
3.3.静态资源优化配置语法
Nginx对静态资源如何进行优化配置。这里从三个属性配置进行优化:
sendfile on;
tcp_nopush on;
tcp_nodeplay on;
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
3.3.1.sendfile,用来开启高效的文件传输模式。
语法 | sendfile on \ | off; |
---|---|---|
默认值 | sendfile off; | |
位置 | http、server、location... |
请求静态资源的过程:客户端通过网络接口向服务端发送请求,操作系统将这些客户端的请求传递给服务器端应用程序,服务器端应用程序会处理这些请求,请求处理完成以后,操作系统还需要将处理得到的结果通过网络适配器传递回去。
如:
echo '<h1>Welcome to Nginx ...</h1>' >> /usr/local/nginx/html/welcome.html
user www;
worker_processes 2;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
在html目录下有一个welcome.html页面,访问地址
http://192.168.229.136/welcome.html
3.3.2.tcp_nopush:该指令必须在sendfile打开
的状态下才会生效,主要是用来提升网络包的传输效率
语法 | tcp_nopush on\ | off; |
---|---|---|
默认值 | tcp_nopush off; | |
位置 | http、server、location |
3.3.3.tcp_nodelay:该指令必须在keep-alive连接开启
的情况下才生效,来提高网络包传输的实时性
语法 | tcp_nodelay on\ | off; |
---|---|---|
默认值 | tcp_nodelay on; | |
位置 | http、server、location |
经过刚才的分析,"tcp_nopush"和”tcp_nodelay“看起来是"互斥的",那么为什么要将这两个值都打开,这个大家需要知道的是在linux2.5.9以后的版本中两者是可以兼容的,三个指令
都开启的好处是,
sendfile可以开启高效的文件传输模式,
tcp_nopush开启可以确保在发送到客户端之前数据包已经充分“填满”, 这大大减少了网络开销,并加快了文件发送的速度。
然而,当它到达最后一个可能因为没有“填满”而暂停的数据包时,Nginx会忽略tcp_nopush参数,
然后,tcp_nodelay强制套接字发送数据。
由此可知,TCP_NOPUSH可以与TCP_NODELAY一起设置,它比单独配置TCP_NODELAY具有更强的性能。
所以我们可以使用如下配置来优化Nginx静态资源的处理
sendfile on; # 使用limux的sendfile(socket,file,len)高效网络传输,也就是数据0拷贝
tcp_nopush on; # 主要是用来提升网络包的传输效率
tcp_nodelay on; # 提高网络包传输的实时性
3.4.Nginx静态资源压缩模块实战
假如在满足上述优化的前提下,我们传送一个1M的数据和一个10M的数据那个效率高?
答案显而易见,传输内容小,速度就会快。
在Nginx的配置文件中可以通过配置gzip来对静态资源进行压缩,相关的指令可以配置在http块、server块和location块中,Nginx可以通过
ngx_http_gzip_module模块
ngx_http_gzip_static_module模块
ngx_http_gunzip_module模块
对这些指令进行解析和处理。
(1)Gzip各模块支持的配置指令
(2)Gzip压缩功能的配置
(3)Gzip和sendfile的冲突解决
(4)浏览器不支持Gzip的解决方案
3.4.1.Gzip模块配置指令:ngx_http_gzip_module模块
Gzip模块配置指令都来自ngx_http_gzip_module模块,该模块会在nginx安装的时候内置到nginx的安装环境中,也就是说我们可以直接使用这些指令。
https://nginx.org/en/docs/http/ngx_http_gzip_module.html
jquery官网:https://jquery.com/download/
https://code.jquery.com/jquery-3.7.1.js
http://192.168.229.136/jquery-3.7.1.js
3.4.1.1. gzip指令:该指令用于开启或者关闭gzip功能
语法 | gzip on\ | off; |
---|---|---|
默认值 | gzip off; | |
位置 | http、server、location... |
注意只有该指令为打开状态,下面的指令才有效果
http{
gzip on;
}
3.4.1.2. gzip_types指令:该指令可以根据响应页的MIME类型选择性地开启Gzip压缩功能
语法 | gzip_types mime-type ...; |
---|---|
默认值 | gzip_types text/html; |
位置 | http、server、location |
所选择的值可以从mime.types文件
中进行查找,也可以使用"*"代表所有
。
http{
gzip_types application/javascript;
}
3.4.1.3. gzip_comp_level指令:该指令用于设置Gzip压缩程度
该指令用于设置Gzip压缩程度,级别从1-9, 1表示要是程度最低,要是效率最高,9刚好相反,压缩程度最高,但是效率最低最费时间。
语法 | gzip_comp_level level; |
---|---|
默认值 | gzip_comp_level 1; |
位置 | http、server、location |
http{
gzip_comp_level 6;
}
3.4.1.4. gzip_vary指令:否携带“Vary:Accept-Encoding”头域的响应头部
该指令用于设置使用Gzip进行压缩发送是否携带“Vary:Accept-Encoding”头域的响应头部。主要是告诉接收方,所发送的数据经过了Gzip压缩处理
语法 | gzip_vary on\ | off; |
---|---|---|
默认值 | gzip_vary off; | |
位置 | http、server、location |
3.4.1.5. gzip_buffers指令:该指令用于处理请求压缩的缓冲区数量和大小。
语法 | gzip_buffers number size; | |
---|---|---|
默认值 | gzip_buffers 32 4k\ | 16 8k; |
位置 | http、server、location |
其中number:指定Nginx服务器向系统申请缓存空间个数,size指的是每个缓存空间的大小。
主要实现的是申请number个每个大小为size的内存空间。
这个值的设定一般会和服务器的操作系统有关,所以建议此项不设置,使用默认值即可
。
gzip_buffers 4 16K; #缓存空间大小
3.4.1.6. gzip_disable指令:针对不同种类客户端发起的请求,可以选择性地开启和关闭Gzip功能。
语法 | gzip_disable regex ...; |
---|---|
默认值 | — |
位置 | http、server、location |
regex:根据客户端的浏览器标志(user-agent)来设置,支持使用正则表达式。
指定的浏览器标志不使用Gzip,该指令一般是用来排除一些明显不支持Gzip的浏览器
。
# IE 6 以下的版本禁用
gzip_disable "MSIE [1-6]\.";
3.4.1.7. gzip_http_version指令:针对不同的HTTP协议版本,可以选择性地开启和关闭Gzip功能。
语法 | gzip_http_version 1.0\ | 1.1; |
---|---|---|
默认值 | gzip_http_version 1.1; | |
位置 | http、server、location |
该指令是指定使用Gzip的HTTP最低版本
,该指令一般采用默认值即可
。
3.4.1.8. gzip_min_length指令:该指令针对传输数据的大小,可以选择性地开启和关闭Gzip功能
语法 | gzip_min_length length; |
---|---|
默认值 | gzip_min_length 20; |
位置 | http、server、location |
nignx计量大小的单位:bytes[字节] / kb[千字节] / M[兆]
例如: 1024 / 10k|K / 10m|M
Gzip压缩功能对大数据的压缩效果明显,但是如果要压缩的数据比较小的化,可能出现越压缩数据量越大的情况,因此我们需要根据响应内容的大小来决定是否使用Gzip功能,响应页面的大小可以通过头信息中的Content-Length
来获取。
但是如何使用了Chunk编码动态压缩,该指令将被忽略。
建议设置为1K或以上。
3.4.1.9. gzip_proxied指令:该指令设置是否对服务端返回的结果进行Gzip压缩。
语法 | gzip_proxied off\ | expired\ | no-cache\ | <br/>no-store\ | private\ | no_last_modified\ | no_etag\ | auth\ | any; |
---|---|---|---|---|---|---|---|---|---|
默认值 | gzip_proxied off; | ||||||||
位置 | http、server、location |
语法 | 含义 |
---|---|
off | 关闭Nginx服务器对后台服务器返回结果的Gzip压缩 |
expired | 启用压缩,如果header头中包含 "Expires" 头信息 |
no-cache | 启用压缩,如果header头中包含 "Cache-Control:no-cache" 头信息 |
no-store | 启用压缩,如果header头中包含 "Cache-Control:no-store" 头信息 |
private | 启用压缩,如果header头中包含 "Cache-Control:private" 头信息 |
no_last_modified | 启用压缩,如果header头中不包含 "Last-Modified" 头信息 |
no_etag | 启用压缩 ,如果header头中不包含 "ETag" 头信息 |
auth | 启用压缩 , 如果header头中包含 "Authorization" 头信息 |
any | 无条件启用压缩 |
3.4.2.Gzip压缩功能的实例配置
# Gzip压缩功能的实例配置
gzip on; #开启gzip功能
gzip_types *; #压缩源文件类型,根据具体的访问资源类型设定
gzip_comp_level 6; #gzip压缩级别
gzip_min_length 1024; #进行压缩响应页面的最小长度,content-length
gzip_buffers 4 16K; #缓存空间大小
gzip_http_version 1.1; #指定压缩响应所需要的最低HTTP请求版本
gzip_vary on; #往头信息中添加压缩标识
gzip_disable "MSIE [1-6]\."; #对IE6以下的版本都不进行压缩
gzip_proxied off; #nginx作为反向代理压缩服务端返回数据的条件
这些配置在很多地方可能都会用到,所以我们可以将这些内容抽取到一个配置文件中,然后通过include指令把配置文件再次加载到nginx.conf配置文件中,方法使用。
nginx_gzip.conf
gzip on;
gzip_types *;
gzip_comp_level 6;
gzip_min_length 1024;
gzip_buffers 4 16K;
gzip_http_version 1.1;
gzip_vary on;
gzip_disable "MSIE [1-6]\.";
gzip_proxied off;
nginx.conf
include nginx_gzip.conf;
3.4.3.Gzip和sendfile共存问题:使用ngx_http_gzip_static_module模块
的gzip_static指令
来解决
开启sendfile以后,在读取磁盘上的静态资源文件的时候,可以减少拷贝的次数,可以不经过用户进程将静态文件通过网络设备发送出去,但是Gzip要想对资源压缩,是需要经过用户进程进行操作的。所以如何解决两个设置的共存问题。
3.4.3.1.gzip_static指令
gzip_static: 检查与访问资源同名的.gz文件时,response中以gzip相关的header返回.gz文件的内容。
语法 | gzip_static on \ | off \ | always; |
---|---|---|---|
默认值 | gzip_static off; | ||
位置 | http、server、location |
添加上述命令后,会报一个错误,unknown directive "gzip_static"
主要的原因是Nginx默认是没有添加ngx_http_gzip_static_module模块
。
user www;
worker_processes 2;
events {
accept_mutex on; #设置Nginx网络连接序列化,防止多个进程对连接的争抢
multi_accept on; #设置Nginx的worker进程是否可以同时接收多个网络请求
worker_connections 1024; # 设置Nginx单个worker进程最大的连接数
use epoll; #设置Nginx使用的事件驱动模型,使用epoll函数来优化Ngin
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on; # 主要是用来提升网络包的传输效率
tcp_nodelay on; # 提高网络包传输的实时性
keepalive_timeout 65;
gzip_static on;
include nginx_gzip.conf;
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
3.4.3.2.添加ngx_http_gzip_static_module模块到Nginx的实现步骤
3.4.3.2.1.查询当前Nginx的配置参数
nginx -V
nginx version: nginx/1.24.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)
configure arguments:
--prefix=/usr/local/nginx
--sbin-path=/usr/local/nginx/sbin/nginx
--modules-path=/usr/local/nginx/modules
--conf-path=/usr/local/nginx/conf/nginx.conf
--error-log-path=/usr/local/nginx/logs/error.log
--http-log-path=/usr/local/nginx/logs/access.log
--pid-path=/usr/local/nginx/logs/nginx.pid
--lock-path=/usr/local/nginx/logs/nginx.lock
3.4.3.2.2.将nginx安装目录下sbin目录中的nginx二进制文件进行更名
cd /usr/local/nginx/sbin
mv nginx nginxold
3.4.3.2.3.进入Nginx的安装目录
cd /nginx/core/nginx-1.24.0/
3.4.3.2.4.执行make clean清空之前编译的内容
make clean
3.4.3.2.5.使用configure来配置参数
./configure --with-http_gzip_static_module
./configure \
--prefix=/usr/local/nginx \
--sbin-path=/usr/local/nginx/sbin/nginx \
--modules-path=/usr/local/nginx/modules \
--conf-path=/usr/local/nginx/conf/nginx.conf \
--error-log-path=/usr/local/nginx/logs/error.log \
--http-log-path=/usr/local/nginx/logs/access.log \
--pid-path=/usr/local/nginx/logs/nginx.pid \
--lock-path=/usr/local/nginx/logs/nginx.lock \
--with-http_gzip_static_module
3.4.3.2.6.使用make命令进行编译
make
3.4.3.2.7.将objs目录下的nginx二进制执行文件移动到nginx安装目录下的sbin目录中
mv objs/nginx /usr/local/nginx/sbin
3.4.3.2.8.执行更新命令
make upgrade
3.4.3.3.gzip_static测试使用
3.4.3.3.1.直接访问http://192.168.200.133/jquery.js
3.4.3.3.2.使用gzip命令进行压缩
cd /usr/local/nginx/html
gzip jquery-3.7.1.js
3.4.3.3.3.再次访问http://192.168.200.133/jquery.js
3.5.静态资源的缓存处理
3.5.1.缓存
缓存(cache),原始意义是指访问速度比一般随机存取存储器(RAM)快的一种高速存储器,
通常它不像系统主存那样使用DRAM技术,而使用昂贵但较快速的SRAM技术。缓存的设置是所有现代计算机系统发挥高性能的重要因素之一。
3.5.2.web缓存
Web缓存是指一个Web资源(如html页面,图片,js,数据等)存在于Web服务器和客户端(浏览器)之间的副本。
缓存会根据进来的请求保存输出内容的副本;当下一个请求来到的时候,如果是相同的URL,缓存会根据缓存机制决定是直接使用副本响应访问请求,还是向源服务器再次发送请求。
比较常见的就是浏览器会缓存访问过网站的网页,当再次访问这个URL地址的时候,如果网页没有更新,就不会再次下载网页,而是直接使用本地缓存的网页。
只有当网站明确标识资源已经更新,浏览器才会再次下载网页
3.5.3.web缓存的种类
客户端缓存
浏览器缓存
服务端缓存
Nginx / Redis / Memcached等
3.5.4.浏览器缓存
是为了节约网络的资源加速浏览,浏览器在用户磁盘上对最近请求过的文档进行存储,当访问者再次请求这个页面时,浏览器就可以从本地磁盘显示文档,这样就可以加速页面的阅览.
3.5.5.为什么要用浏览器缓存
- 成本最低的一种缓存实现
- 减少网络带宽消耗
- 降低服务器压力
- 减少网络延迟,加快页面打开速度
3.5.6.浏览器缓存的执行流程
HTTP协议中和页面缓存相关的字段:
header | 说明 |
---|---|
Expires | 缓存过期的日期和时间 |
Cache-Control | 设置和缓存相关的配置信息 |
Last-Modified | 请求资源最后修改时间 |
ETag | 请求变量的实体标签的当前值,比如文件的MD5值 |
(1)用户首次通过浏览器发送请求到服务端获取数据,客户端是没有对应的缓存,所以需要发送request请求来获取数据;
(2)服务端接收到请求后,获取服务端的数据及服务端缓存的允许后,返回200的成功状态码并且在响应头上附上对应资源以及缓存信息;
(3)当用户再次访问相同资源的时候,客户端会在浏览器的缓存目录中查找是否存在响应的缓存文件
(4)如果没有找到对应的缓存文件,则走(2)步
(5)如果有缓存文件,接下来对缓存文件是否过期进行判断,过期的判断标准是(Expires),
(6)如果没有过期,则直接从本地缓存中返回数据进行展示
(7)如果Expires过期,接下来需要判断缓存文件是否发生过变化
(8)判断的标准有两个,一个是ETag(Entity Tag),一个是Last-Modified
(9)判断结果是未发生变化,则服务端返回304,直接从缓存文件中获取数据
(10)如果判断是发生了变化,重新从服务端获取数据,并根据缓存协商(服务端所设置的是否需要进行缓存数据的设置)来进行数据缓存。
3.5.7.浏览器缓存相关设置指令
Nginx需要进行缓存相关设置,就需要用到如下的指令
3.5.7.1.expires指令:用来控制页面缓存的作用
expires:该指令用来控制页面缓存的作用。可以通过该指令控制HTTP应答中的“Expires"和”Cache-Control"
语法 | expires [modified] time<br/>expires epoch\ | max\ | off; |
---|---|---|---|
默认值 | expires off; | ||
位置 | http、server、location |
time
:可以整数也可以是负数;指定过期时间,如果是负数,Cache-Control则为no-cache;如果为整数或0,则Cache-Control的值为max-age=time;
epoch
: 指定Expires的值为'1 January,1970,00:00:01 GMT'(1970-01-01 00:00:00),Cache-Control的值no-cache
max
:指定Expires的值为'31 December2037 23:59:59GMT' (2037-12-31 23:59:59) ,Cache-Control的值为10年
off
:默认不缓存。
location ~ .*\.(html|js|css|png)$ {
expires 1000;
}
3.5.7.2.add_header指令
add_header指令是用来添加指定的响应头和响应值。
语法 | add_header name value [always]; |
---|---|
默认值 | — |
位置 | http、server、location... |
3.5.7.3.Cache-Control作为响应头信息,可以设置如下值:
缓存响应指令:
Cache-Control: must-revalidate
Cache-Control: no-cache
Cache-Control: no-store
Cache-Control: no-transform
Cache-Control: public
Cache-Control: private
Cache-Control: proxy-revalidate
Cache-Control: max-age=<seconds>
Cache-Control: s-maxage=<seconds>
指令 | 说明 |
---|---|
must-revalidate | 可缓存但必须再向源服务器进行确认 |
no-cache | 缓存前必须确认其有效性 |
no-store | 不缓存请求或响应的任何内容 |
no-transform | 代理不可更改媒体类型 |
public | 可向任意方提供响应的缓存 |
private | 仅向特定用户返回响应 |
proxy-revalidate | 要求中间缓存服务器对缓存的响应有效性再进行确认 |
max-age=<秒> | 响应最大Age值 |
s-maxage=<秒> | 公共缓存服务器响应的最大Age值 |
max-age=[秒]:
3.6.Nginx的跨域问题解决
主要从以下方面进行解决:
- 什么情况下会出现跨域问题?
- 实例演示跨域问题
- 具体的解决方案是什么?
3.6.1.同源策略
浏览器的同源策略:是一种约定,是浏览器最核心也是最基本的安全功能,如果浏览器少了同源策略,则浏览器的正常功能可能都会受到影响。
同源: 协议、域名(IP)、端口相同即为同源
http://192.168.229.136/user/1
https://192.168.229.136/user/1
不满足同源策略
http://192.168.229.136/user/1
http://192.168.229.1362/user/1
不
http://192.168.229.136/user/1
http://192.168.229.136:8080/user/1
不
http://www.nginx.com/user/1
http://www.nginx.org/user/1
不
http://192.168.229.136/user/1
http://192.168.229.136:8080/user/1
不
http://www.nginx.org:80/user/1
http://www.nginx.org/user/1
协议、域名(IP)、端口相同即为同源 满足
3.6.2.跨域问题
有两台服务器分别为A,B
如果从服务器A的页面发送异步请求到服务器B获取数据,如果服务器A和服务器B不满足同源策略,则就会出现跨域问题。
3.6.3.跨域问题的案例演示
3.6.3.1.nginx的html目录下新建一个a.html
vi /usr/local/nginx/html/a.html
<html>
<head>
<meta charset="utf-8">
<title>跨域问题演示</title>
<script src="jquery-3.7.1.js"></script>
<script>
$(function(){
$("#btn").click(function(){
$.get('http://192.168.229.136:8080/getUser',function(data){
alert(JSON.stringify(data));
});
});
});
</script>
</head>
<body>
<input type="button" value="获取数据" id="btn"/>
</body>
</html>
3.6.3.2.在nginx.conf配置如下内容
server{
listen 8080;
server_name localhost;
location /getUser{
default_type application/json;
return 200 '{"id":1,"name":"TOM","age":18}';
}
}
server{
listen 80;
server_name localhost;
location /{
root html;
index index.html;
}
}
3.6.3.3.通过浏览器访问测试【跨域问题导致的错误】
3.6.4.解决方案【跨域问题】
使用add_header指令,该指令可以用来添加一些头信息
语法 | add_header name value... |
---|---|
默认值 | — |
位置 | http、server、location |
此处用来解决跨域问题,需要添加两个头信息,一个是Access-Control-Allow-Origin
,Access-Control-Allow-Methods
Access-Control-Allow-Origin: 直译过来是允许跨域访问的源地址信息,可以配置多个(多个用逗号分隔),也可以使用*
代表所有源
Access-Control-Allow-Methods:直译过来是允许跨域访问的请求方式,值可以为 GET POST PUT DELETE...,可以全部设置,也可以根据需要设置,多个用逗号分隔
具体配置方式
location /getUser{
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE;
default_type application/json;
return 200 '{"id":1,"name":"TOM","age":18}';
}
3.7.静态资源防盗链
3.7.1.什么是资源盗链
资源盗链指的是此内容不在自己服务器上,而是通过技术手段,绕过别人的限制将别人的内容放到自己页面上最终展示给用户。以此来盗取大网站的空间和流量。简而言之就是用别人的东西成就自己的网站。
效果演示
京东:https://img14.360buyimg.com/n7/jfs/t1/101062/37/2153/254169/5dcbd410E6d10ba22/4ddbd212be225fcd.jpg
<html>
<head>
<meta charset="utf-8">
<title>跨域问题演示</title>
<script src="jquery-3.7.1.js"></script>
<script>
$(function(){
$("#btn").click(function(){
$.get('http://192.168.229.136:8080/getUser',function(data){
alert(JSON.stringify(data));
});
});
});
</script>
</head>
<body>
<input type="button" value="获取数据" id="btn"/>
<img src="https://imgcps.jd.com/img-cubic/creative_server_ci…bPmiqLotK0QBkIKCgblipvojZAQB1i5ueXD9AI/cr/s/q.jpg"/><br/>
<img src="https://img.alicdn.com/imgextra/i1/6000000004918/O…01UqkSO91mCUlvBl6tH_!!6000000004918-0-octopus.jpg"/><br/>
<img src="https://img14.360buyimg.com/n7/jfs/t1/101062/37/2153/254169/5dcbd410E6d10ba22/4ddbd212be225fcd.jpg"/><br/>
<img src="https://pics7.baidu.com/feed/cf1b9d16fdfaaf516f7e2011a7cda1e8f11f7a1a.jpeg?token=551979a23a0995e5e5279b8fa1a48b34&s=BD385394D2E963072FD48543030030BB"/><br/>
<img src="http://192.168.229.136:8080/java.png"/><br/>
</body>
</html>
我们自己准备一个页面,在页面上引入这两个图片查看效果
从上面的效果,可以看出来,下面的图片地址添加了防止盗链的功能,京东这边我们可以直接使用其图片。
3.7.2.Nginx防盗链的实现原理:
了解防盗链的原理之前,我们得先学习一个HTTP的头信息Referer,当浏览器向web服务器发送请求的时候,一般都会带上Referer,来告诉浏览器该网页是从哪个页面链接过来的。
后台服务器可以根据获取到的这个Referer信息来判断是否为自己信任的网站地址,如果是则放行继续访问,如果不是则可以返回403(服务端拒绝访问)的状态信息。
在本地模拟上述的服务器效果:
3.7.3.Nginx防盗链的具体实现:
valid_referers:nginx会通就过查看referer自动和valid_referers后面的内容进行匹配,如果匹配到了就将$invalid_referer变量置0,如果没有匹配到,则将\$invalid_referer变量置为1,匹配的过程中不区分大小写。
语法 | valid_referers none\ | blocked\ | server_names\ | string... |
---|---|---|---|---|
默认值 | — | |||
位置 | server、location |
none: 如果Header中的Referer为空,允许访问
blocked:在Header中的Referer不为空,但是该值被防火墙或代理进行伪装过,如不带"http://" 、"https://"等协议头的资源允许访问。
server_names:指定具体的域名或者IP
string: 可以支持正则表达式和*的字符串。如果是正则表达式,需要以~
开头表示,例如
location ~*\.(png|jpg|gif){
valid_referers none blocked www.baidu.com 192.168.229.136 *.example.com example.* www.example.org ~\.google\.;
if ($invalid_referer){
return 403;
}
root /usr/local/nginx/html;
}
3.7.4.针对目录进行防盗链
遇到的问题:图片有很多,该如何批量进行防盗链?
配置如下:
location /images {
valid_referers none blocked www.baidu.com 192.168.200.222 *.example.com example.* www.example.org ~\.google\.;
if ($invalid_referer){
return 403;
}
root /usr/local/nginx/html;
}
这样我们可以对一个目录下的所有资源进行防盗链操作。
遇到的问题:Referer的限制比较粗,比如随意加一个Referer,上面的方式是无法进行限制的。那么这个问题改如何解决?
此处我们需要用到Nginx的第三方模块ngx_http_accesskey_module
,第三方模块实现防盗链。
3.8.nginx_static.conf
user www;
worker_processes 2;
events {
accept_mutex on; #设置Nginx网络连接序列化,防止多个进程对连接的争抢
multi_accept on; #设置Nginx的worker进程是否可以同时接收多个网络请求
worker_connections 1024; # 设置Nginx单个worker进程最大的连接数
use epoll; #设置Nginx使用的事件驱动模型,使用epoll函数来优化Ngin
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on; # 主要是用来提升网络包的传输效率
tcp_nodelay on; # 提高网络包传输的实时性
keepalive_timeout 65;
gzip_static on;
include nginx_gzip.conf;
server {
listen 8080;
server_name localhost;
location /images {
root html;
valid_referers none blocked www.baidu.com;
if ($invalid_referer){
return 403;
}
}
#location ~ .*\.(png|jpg|gif)$ {
# valid_referers none blocked www.baidu.com;
# if ($invalid_referer){
# return 403;
# }
# root html/images;
#}
location /getUser {
add_header Access-Control-Allow-Origin http://192.168.229.136;
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE;
default_type application/json;
return 200 '{"id":1,"name":"TOM","age":18}';
}
}
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
location ~ .*\.(html|js|css|png)$ {
expires max;
add_header Cache-Control no-store;
#expires epoch;
#expires 1000;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
四、Rewrite功能配置【ngx_http_rewrite_module模块】
https://nginx.org/en/docs/http/ngx_http_rewrite_module.html
Rewrite
是Nginx服务器提供的一个重要基本功能,是Web服务器产品中几乎必备的功能。主要的作用是用来实现URL的重写
。
注意:Nginx服务器的Rewrite功能的实现依赖于PCRE的支持,因此在编译安装Nginx服务器之前,需要安装PCRE库【正则表达式库】
。
Nginx使用的是ngx_http_rewrite_module模块
来解析和处理Rewrite功能的相关配置
。
4.1."地址重写"与"地址转发"
重写和转发的区别:
地址重写浏览器地址会发生变化而地址转发则不变
一次地址重写会产生两次请求而一次地址转发只会产生一次请求
地址重写到的页面必须是一个完整的路径而地址转发则不需要
地址重写因为是两次请求所以request范围内属性不能传递给新页面而地址转发因为是一次请求所以可以传递值
地址转发速度快于地址重写
4.2.Rewrite的相关命令
set指令
if指令
break指令
return指令
rewrite指令
rewrite_log指令
4.3.Rewrite的应用场景
域名跳转
域名镜像
独立域名
目录自动添加"/"
合并目录
防盗链的实现
Nginx动静分离的原理与使用场景及配置
4.4.Rewrite的相关指令介绍
4.4.1. set指令
该指令用来设置一个新的变量。
语法 | set $variable value; |
---|---|
默认值 | — |
位置 | server、location、if |
variable:变量的名称,该变量名称要用"$"
作为变量的第一个字符,且不要与Nginx服务器预设的全局变量同名
。
value:变量的值,可以是字符串、其他变量或者变量的组合等。
# rewrite
server {
listen 8081;
server_name localhost;
location /server {
set $name TOM;
set $age 18;
default_type text/plain;
return 200 $name==$age;
}
}
4.4.2. Rewrite常用全局变量
变量 | 说明 |
---|---|
$args | 变量中存放了请求URL中的请求参数。比如http://192.168.229.136/server?arg1=value1&args2=value2中的"arg1=value1&arg2=value2",功能和$query_string一样 |
$http_user_agent | 变量存储的是用户访问服务的代理信息(如果通过浏览器访问,记录的是浏览器的相关版本信息) |
$host | 变量存储的是访问服务器的server_name值 |
$document_uri | 变量存储的是当前访问地址的URI。比如http://192.168.229.136/server?id=10&name=zhangsan中的"/server",功能和$uri一样 |
$document_root | 变量存储的是当前请求对应location的root值,如果未设置,默认指向Nginx自带html目录所在位置 |
$content_length | 变量存储的是请求头中的Content-Length的值 |
$content_type | 变量存储的是请求头中的Content-Type的值 |
$http_cookie | 变量存储的是客户端的cookie信息,可以通过add_header Set-Cookie 'cookieName=cookieValue'来添加cookie数据 |
$limit_rate | 变量中存储的是Nginx服务器对网络连接速率的限制,也就是Nginx配置中对limit_rate指令设置的值,默认是0,不限制。 |
$remote_addr | 变量中存储的是客户端的IP地址 |
$remote_port | 变量中存储了客户端与服务端建立连接的端口号 |
$remote_user | 变量中存储了客户端的用户名,需要有认证模块才能获取 |
$scheme | 变量中存储了访问协议 |
$server_addr | 变量中存储了服务端的地址 |
$server_name | 变量中存储了客户端请求到达的服务器的名称 |
$server_port | 变量中存储了客户端请求到达服务器的端口号 |
$server_protocol | 变量中存储了客户端请求协议的版本,比如"HTTP/1.1" |
$request_body_file | 变量中存储了发给后端服务器的本地文件资源的名称 |
$request_method | 变量中存储了客户端的请求方式,比如"GET","POST"等 |
$request_filename | 变量中存储了当前请求的资源文件的路径名 |
$request_uri | 变量中存储了当前请求的URI,并且携带请求参数,比如http://192.168.229.136/server?id=10&name=zhangsan中的"/server?id=10&name=zhangsan" |
http://192.168.229.136:8081/server?username=marry&password=123456
# rewrite
server {
listen 8081;
server_name localhost;
location /server {
set $name TOM;
set $age 18;
default_type text/plain;
return 200 $name==$age=$args=$http_user_agent=$host;
}
}
上述参数还可以在日志文件中使用,这个就要用到前面我们介绍的log_format
指令
log_format main '$remote_addr - $request - $status - $request_uri - $http_user_agent';
access_log logs/rewrite.log main;
4.4.3. if 指令
该指令用来支持条件判断,并根据条件判断结果选择不同的Nginx配置。
语法 | if (condition){...} |
---|---|
默认值 | — |
位置 | server、location |
condition为判定条件,可以支持以下写法:
- 变量名。如果变量名对应的值为空字符串或"0",if都判断为false,其他条件为true。
if ($param){
}
location /testif {
set $username '';
#set $username 'LiBai';
default_type text/plain;
if ($username){
return 200 $username;
}
return 200 'param is empty';
}
- 使用"="和"!="比较变量和字符串是否相等,满足条件为true,不满足为false
if ($request_method = POST){
return 405;
}
curl -X POST http://192.168.229.136:8081/testif?1
注意:此处和Java不太一样的地方是字符串不需要添加引号,并且等号和不等号前后到需要加空格。
使用正则表达式对变量进行匹配,匹配成功返回true,否则返回false。变量与正则表达式之间使用"~","~*","!~","!~*"来连接。
"~"代表匹配正则表达式过程中区分大小写,
"~*"代表匹配正则表达式过程中不区分大小写
"!~"和"!~*"刚好和上面取相反值,如果匹配上返回false,匹配不上返回true
if ($http_user_agent ~ MSIE){
#$http_user_agent的值中是否包含MSIE字符串,如果包含返回true
}
注意:正则表达式字符串一般不需要加引号,但是如果字符串中包含"}"或者是";"等字符时,就需要把引号加上。
- 判断请求的文件是否存在使用"-f"和"!-f",
if (-f $request_filename){
#判断请求的文件是否存在
}
if (!-f $request_filename){
#判断请求的文件是否不存在
}
location / {
root html;
default_type text/html;
if (!-f $request_filename){
return 200 '<h1>file not found</h1>';
}
}
- 判断请求的目录是否存在使用"-d"和"!-d"
- 判断请求的目录或者文件是否存在使用"-e"和"!-e"
- 判断请求的文件是否可执行使用"-x"和"!-x"
4.4.4. break指令
该指令用于中断当前相同作用域中的其他Nginx配置。
与该指令处于同一作用域的Nginx配置中,位于它前面的指令配置生效,位于后面的指令配置无效。
并且break还有另外一个功能就是终止当前的匹配并把当前的URI在本location进行重定向访问处理
。
语法 | break; |
---|---|
默认值 | — |
位置 | server、location、if |
例子:
location /testbreak{
default_type text/plain;
set $username TOM;
if ($args){
Set $username JERRY;
break;
set $username ROSE;
}
add_header username $username;
return 200 $username;
}
4.4.5. return指令
该指令用于完成对请求的处理,直接向客户端返回。在return后的所有Nginx配置都是无效的。
语法 | return code [text];<br/>return code URL;<br/>return URL; |
---|---|
默认值 | — |
位置 | server、location、if |
code:为返回给客户端的HTTP状态代理。可以返回的状态代码为0~999的任意HTTP状态代理
text:为返回给客户端的响应体内容,支持变量的使用
URL:为返回给客户端的URL地址
location /testreturn {
return 200 success;
}
location /testreturn {
return https://www.baidu.com; // 302重定向到百度
}
location /testreturn {
return 302 https://www.baidu.com;
}
location /testreturn {
return 302 www.baidu.com;//不允许这么写
}
4.4.6. rewrite指令
该指令通过正则表达式的使用来改变URI。可以同时存在一个或者多个指令,按照顺序依次对URL进行匹配和处理。
语法 | rewrite regex replacement [flag]; |
---|---|
默认值 | — |
位置 | server、location、if |
4.4.6.1. regex:用来匹配URI的正则表达式
replacement:匹配成功后,用于替换URI中被截取内容的字符串。如果该字符串是以"http://"或者"https://"开头的,则不会继续向下对URI进行其他处理,而是直接返回重写后的URI给客户端。
location rewrite {
rewrite ^/rewrite/url\w*$ https://www.baidu.com;
rewrite ^/rewrite/(test)\w*$ /$1;
rewrite ^/rewrite/(demo)\w*$ /$1;
}
location /test{
default_type text/plain;
return 200 test_success;
}
location /demo{
default_type text/plain;
return 200 demo_success;
}
http://192.168.229.136:8081\rewrite\urlaaa
http://192.168.229.136:8081/rewrite/testaaa
http://192.168.229.136:8081/rewrite/demoaaa
4.4.6.2. flag:用来设置rewrite对URI的处理行为
flag:用来设置rewrite对URI的处理行为,可选值有如下:
- last:终止继续在本location块中处理接收到的URI,并将此处重写的URI作为一个新的URI,使用各location块进行处理。该标志将重写后的URI重写在server块中执行,为重写后的URI提供了转入到其他location块的机会。
location rewrite {
rewrite ^/rewrite/(test)\w*$ /$1 last;
rewrite ^/rewrite/(demo)\w*$ /$1 last;
}
location /test{
default_type text/plain;
return 200 test_success;
}
location /demo{
default_type text/plain;
return 200 demo_success;
}
访问 http://192.168.229.136:8081/rewrite/testabc
,能正确访问
- break:将此处
重写的URI作为一个新的URI
,在本块中继续进行处理。该标志将重写后的地址
在当前的location块中执行,不会将新的URI转向其他的location块。
location rewrite {
#重写为/test /usr/local/nginx/html/test/index.html
rewrite ^/rewrite/(test)\w*$ /$1 break;
rewrite ^/rewrite/(demo)\w*$ /$1 break;
}
location /test{
default_type text/plain;
return 200 test_success;
}
location /demo{
default_type text/plain;
return 200 demo_success;
}
访问 http://192.168.229.136:8081/rewrite/demoabc
,页面报404错误
- redirect:将重写后的URI返回给客户端,状态码为302,指明是临时重定向URI,主要用在replacement变量不是以"http://"或者"https://"开头的情况。
location rewrite {
rewrite ^/rewrite/(test)\w*$ /$1 redirect;
rewrite ^/rewrite/(demo)\w*$ /$1 redirect;
}
location /test{
default_type text/plain;
return 200 test_success;
}
location /demo{
default_type text/plain;
return 200 demo_success;
}
访问http://192.168.229.136:8081/rewrite/testabc
请求会被临时重定向
,浏览器地址也会发生改变
- permanent:将重写后的URI返回给客户端,状态码为
301
,指明是永久重定向URI
,主要用在replacement变量不是以"http://"或者"https://"开头的情况。
location rewrite {
rewrite ^/rewrite/(test)\w*$ /$1 permanent;
rewrite ^/rewrite/(demo)\w*$ /$1 permanent;
}
location /test{
default_type text/plain;
return 200 test_success;
}
location /demo{
default_type text/plain;
return 200 demo_success;
}
访问http://192.168.229.136:8081/rewrite/testabc
请求会被永久重定向,浏览器地址也会发生改变
4.4.7. rewrite_log指令
该指令配置是否开启URL重写日志的输出功能
。
语法 | rewrite_log on\ | off; |
---|---|---|
默认值 | rewrite_log off; | |
位置 | http、server、location、if |
开启后,URL重写的相关日志将以notice级别输出到error_log指令配置的日志文件汇总
。
rewrite_log on;
error_log logs/error.log notice;
4.5.Rewrite的案例
4.5.1.域名跳转
》问题分析
先来看一个效果,如果我们想访问京东网站,大家都知道我们可以输入www.jd.com
,但是同样的我们也可以输入www.360buy.com
同样也都能访问到京东网站。这个其实是因为京东刚开始的时候域名就是www.360buy.com
,后面由于各种原因把自己的域名换成了www.jd.com
, 虽然说域名变量,但是对于以前只记住了www.360buy.com
的用户来说,我们如何把这部分用户也迁移到我们新域名的访问上来,针对于这个问题,我们就可以使用Nginx中Rewrite的域名跳转
来解决。
》环境准备
- 准备三个域名:
vim /etc/hosts
127.0.0.1 www.mini.cn
127.0.0.1 www.minitear.cn
127.0.0.1 www.minitear.com
- 通过Nginx实现访问127.0.0.1 www.mini.cn
server {
listen 80;
server_name 127.0.0.1 www.mini.cn;
location /{
default_type text/html;
return 200 '<h1>welcome to mini</h1>';
}
}
》通过Rewrite完成将www.minitear.com和www.minitear.cn的请求跳转到www.mini.cn
server {
listen 80;
server_name www.minitear.com www.minitear.cn;
rewrite ^/ http://www.mini.cn;
}
问题描述:如何在域名跳转的过程中携带请求的URI?
修改配置信息
server {
listen 80;
server_name www.minitear.com www.minitear.cn;
rewrite ^(.*) http://www.mini.cn$1;
}
www.minitear.cn/findById?id=10010
4.5.2.域名镜像
镜像网站指定是将一个完全相同的网站分别放置到几台服务器上,并分别使用独立的URL进行访问。
其中一台服务器上的网站叫主站,其他的为镜像网站。
镜像网站和主站没有太大的区别,可以把镜像网站理解为主站的一个备份节点。可以通过镜像网站提供网站在不同地区的响应速度。
镜像网站可以平衡网站的流量负载、可以解决网络宽带限制、封锁等。
而我们所说的域名镜像和网站镜像比较类似,上述案例中,将www.minitear.com
和 www.minitear.cn
都能跳转到www.mini.cn
,那么www.mini.cn
我们就可以把它起名叫主域名
,其他两个就是我们所说的镜像域名,当然如果我们不想把整个网站做镜像,只想为其中某一个子目录下的资源做镜像,我们可以在location块中配置rewrite功能,比如:
server {
listen 80;
server_name www.minitear.cn www.minitear.com;
location /user {
rewrite ^/user(.*)$ http://www.mini.cn$1;
}
location /emp{
default_type text/html;
return 200 '<h1>emp_success</h1>';
}
}
http://www.minitear.cn/user/findById?id=10010
http://www.minitear.cn/emp/findById?id=10010
4.5.3.独立域名
一个完整的项目包含多个模块,比如购物网站有商品搜索模块、商品详情模块和购物车模块
等,那么我们如何为每一个模块设置独立的域名。
需求:
http://search.minitear.com:81 访问商品搜索模块
http://item.minitear.com:82 访问商品详情模块
http://cart.minitear.com:83 访问商品购物车模块
server{
listen 81;
server_name search.minitear.com;
rewrite ^(.*) http://www.minitear.cn/search$1;
}
server{
listen 82;
server_name item.minitear.com;
rewrite ^(.*) http://www.minitear.cn/item$1;
}
server{
listen 83;
server_name cart.minitear.com;
rewrite ^(.*) http://www.minitear.cn/cart$1;
}
server {
listen 80;
server_name www.minitear.cn;
location /{
default_type text/plain;
return 200 $request_uri;
}
}
本地的hosts文件添加如下配置:
vi /etc/hosts
127.0.0.1 search.minitear.com
127.0.0.1 item.minitear.com
127.0.0.1 cart.minitear.com
访问
http://search.minitear.com:81/findById?id=10081 访问商品搜索模块
http://item.minitear.com:82/findById?id=10082 访问商品详情模块
http://cart.minitear.com:83/findById?id=10083 访问商品购物车模块
4.5.4.目录自动添加"/"
问题描述
通过一个例子来演示下问题:
server {
listen 8082;
server_name localhost;
location /tear {
root html;
index index.html;
}
}
通过http://192.168.229.136:8082/tear
和通过http://192.168.229.136:8082/tear/
访问的区别?
如果不加斜杠,Nginx服务器内部会自动做一个301的重定向,重定向的地址会有一个指令叫server_name_in_redirect on|off;来决定重定向的地址:
如果该指令为on
重定向的地址为: http://server_name:8082/目录名/;
http://localhost:8082/tear/
如果该指令为off
重定向的地址为: http://原URL中的域名:8082/目录名/;
http://192.168.229.136:8082/tear/
所以就拿刚才的地址来说,http://192.168.229.136:8082/tear如果不加斜杠,
那么按照上述规则,如果指令server_name_in_redirect为on,则301重定向地址变为 http://localhost:8082/tear/,
如果为off,则301重定向地址变为http://192.168.229.136:8082/tear/。
后面这个是正常的,前面地址就有问题。
注意server_name_in_redirect指令在Nginx的0.8.48
版本之前默认都是on
,之后改成了off
,所以现在我们这个版本不需要考虑这个问题,但是如果是0.8.48以前的版本并且server_name_in_redirect设置为on
,我们如何通过rewrite来解决这个问题?
解决方案
我们可以使用rewrite功能为末尾没有斜杠的URL自动添加一个斜杠
server {
listen 80;
server_name localhost;
server_name_in_redirect on;
location /tear{
if (-d $request_filename){
rewrite ^/(.*)([^/])$ http://$host:$server_port/$1$2/ permanent;
#rewrite ^(.*)([^/])$ http://$host:$server_port$1$2/ permanent;
}
}
}
4.5.5.合并目录
搜索引擎优化(SEO)
是一种利用搜索引擎的搜索规则来提高目的网站在有关搜索引擎内排名的方式。我们在创建自己的站点时,可以通过很多种方式来有效的提供搜索引擎优化的程度。其中有一项就包含URL的目录层级一般不要超过三层,否则的话不利于搜索引擎的搜索也给客户端的输入带来了负担,但是将所有的文件放在一个目录下又会导致文件资源管理混乱并且访问文件的速度也会随着文件增多而慢下来,这两个问题是相互矛盾的,那么使用rewrite如何解决上述问题?
举例,网站中有一个资源文件的访问路径时 /server/11/22/33/44/20.html,也就是说20.html存在于第5级目录下,如果想要访问该资源文件,客户端的URL地址就要写成 http://192.168.229.136/server/11/22/33/44/20.html
,
server {
listen 8083;
server_name localhost;
location /server{
root html;
index index.html;
}
}
但是这个是非常不利于SEO搜索引擎优化的,同时客户端也不好记.使用rewrite我们可以进行如下配置:
server {
listen 8083;
server_name localhost;
location /server{
root html;
index index.html;
rewrite ^/server-([0-9]+)-([0-9]+)-([0-9]+)-([0-9]+)\.html$ /server/$1/$2/$3/$4/$5.html last;
}
}
这样的话,客户端只需要输入http://www.web.name/server-11-22-33-44-20.html就可以访问到20.html页面了。
这里也充分利用了rewrite指令支持正则表达式的特性。
http://192.168.229.136:8083/server-11-22-33-44-20.html
4.5.6.防盗链
防盗链之前我们已经介绍过了相关的知识,在rewrite中的防盗链和之前将的原理其实都是一样的,只不过通过rewrite可以将防盗链的功能进行完善下,当出现防盗链的情况,我们可以使用rewrite将请求转发到自定义的一张图片和页面,给用户比较好的提示信息。下面我们就通过根据文件类型实现防盗链的一个配置实例:
location /images {
root html;
valid_referers none blocked www.baidu.com;
if ($invalid_referer){
#return 403;
rewrite ^/ /images/forbidden.png break;
}
}
4.6.nginx_rewrite.conf
user www;
worker_processes 2;
events {
accept_mutex on; #设置Nginx网络连接序列化,防止多个进程对连接的争抢
multi_accept on; #设置Nginx的worker进程是否可以同时接收多个网络请求
worker_connections 1024; # 设置Nginx单个worker进程最大的连接数
use epoll; #设置Nginx使用的事件驱动模型,使用epoll函数来优化Ngin
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on; # 主要是用来提升网络包的传输效率
tcp_nodelay on; # 提高网络包传输的实时性
keepalive_timeout 65;
gzip_static on;
include nginx_gzip.conf;
log_format main '$remote_addr - $request - $status - $request_uri - $http_user_agent';
# rewrite case
server {
listen 80;
server_name www.mini.cn;
location /{
default_type text/html;
return 200 '<h1>welcome to mini !!</h2>';
}
}
server {
listen 8083;
server_name localhost;
location /server {
root html;
index index.html;
rewrite ^/server-([0-9]+)-([0-9]+)-([0-9]+)-([0-9]+)-([0-9]+)\.html$ /server/$1/$2/$3/$4/$5.html last;
}
}
server {
listen 8082;
server_name localhost;
server_name_in_redirect on;
location /tear {
#root html;
#index index.html;
if (-d $request_filename){
rewrite ^/(.*)([^/])$ http://$host:$server_port/$1$2/ permanent;
}
}
}
server {
listen 80;
server_name www.minitear.cn www.minitear.com;
#rewrite ^/ http://www.mini.cn;
#rewrite ^(.*) http://www.mini.cn$1;
location /user {
rewrite ^/user(.*)$ http://www.mini.cn$1;
}
location /emp {
default_type text/html;
return 200 '<h1>emp_success</h1>';
}
}
# rewrite
server {
listen 8081;
server_name localhost;
location /server {
access_log logs/rewrite.log main;
set $name TOM;
set $age 18;
default_type text/plain;
return 200 $name==$age=$args=$http_user_agent=$host;
}
location /testif {
set $username 'LiBai';
default_type text/plain;
if ($args){
return 200 success;
}
if ($request_method = POST){
return 405;
}
if ($http_user_agent ~* safari){
return 200 Chrome;
}
return 200 error;
}
location / {
root html;
default_type text/html;
if (!-f $request_filename){
return 200 '<h1>file not found</h1>';
}
}
location /testbreak {
default_type text/plain;
set $username TOM;
if ($args){
set $username JERRY;
break;
set $username ROSE;
}
add_header username $username;
return 200 $username;
}
location /testreturn {
default_type application/json;
#return 200 '{id:1, name:zhangsan}';
#return https://www.baidu.com;
return 302 https://www.baidu.com;
}
location /rewrite {
rewrite_log on;
error_log logs/error.log notice;
#rewrite ^/rewrite/url\w*$ https://www.baidu.com;
#重写为/test /usr/local/nginx/html/test/index.html
rewrite ^/rewrite/(test)\w*$ /$1 permanent;
rewrite ^/rewrite/(demo)\w*$ /$1 permanent;
}
location /test {
default_type text/plain;
return 200 test_success;
}
location /demo {
default_type text/plain;
return 200 demo_success;
}
}
server {
listen 8080;
server_name localhost;
location /images {
root html;
valid_referers none blocked www.baidu.com;
if ($invalid_referer){
#return 403;
rewrite ^/ /images/forbidden.jpeg break;
}
}
#location ~ .*\.(png|jpg|gif)$ {
# valid_referers none blocked www.baidu.com;
# if ($invalid_referer){
# return 403;
# }
# root html/images;
#}
location /getUser {
add_header Access-Control-Allow-Origin http://192.168.229.136;
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE;
default_type application/json;
return 200 '{"id":1,"name":"TOM","age":18}';
}
}
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
location ~ .*\.(html|js|css|png)$ {
expires max;
add_header Cache-Control no-store;
#expires epoch;
#expires 1000;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
五、Nginx反向代理
5.1.Nginx反向代理概述
关于正向代理和反向代理,我们在前面的章节已经通过一张图给大家详细的介绍过了,简而言之就是正向代理代理的对象是客户端,反向代理代理的是服务端,这是两者之间最大的区别。
Nginx即可以实现正向代理,也可以实现反向代理。
5.1.1.案例演示:Nginx正向代理的简单应用
先提需求:
192.168.229.136 服务端nginx.conf
user www;
worker_processes 2;
events {
accept_mutex on; #设置Nginx网络连接序列化,防止多个进程对连接的争抢
multi_accept on; #设置Nginx的worker进程是否可以同时接收多个网络请求
worker_connections 1024; # 设置Nginx单个worker进程最大的连接数
use epoll; #设置Nginx使用的事件驱动模型,使用epoll函数来优化Ngin
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on; # 主要是用来提升网络包的传输效率
tcp_nodelay on; # 提高网络包传输的实时性
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
5.1.2.服务端【136】的设置:
# 清空原来的日志文件
echo '' > /usr/local/nginx/logs/access.log
cat /usr/local/nginx/logs/access.log
http {
log_format main 'client send request=>clientIp=$remote_addr serverIp=>$host';
server{
listen 80;
server_name localhost;
access_log logs/access.log main;
location {
root html;
index index.html index.htm;
}
}
}
5.1.3.使用客户端【windows】访问服务端【136】,打开日志查看结果
tail -f /usr/local/nginx/logs/access.log
5.1.4.代理服【131】务器设置:
server {
listen 82;
resolver 8.8.8.8; # 设置DNS的IP 用来解析proxy_pass中的域名
location /{
proxy_pass http://$host$request_uri;
}
}
5.1.5.查看代理服务器的IP【192.168.229.131】和Nginx配置监听的端口(82)
5.1.6.在客户端【windows】配置代理服务器
win + r control
备注
:配置代理服务器完成后,记得改回去,否则上不了网络
5.1.7.设置完成后,再次通过浏览器访问服务端【136】
5.1.8.结论
通过对比,上下两次的日志记录,会发现虽然我们是客户端访问服务端,但是如何使用了代理,那么服务端能看到的只是代理发送过去的请求,这样的化,就使用Nginx实现了正向代理的设置。
但是Nginx正向代理,在实际的应用中不是特别多,所以我们简单了解下,接下来我们继续学习Nginx的反向代理,这是Nginx比较重要的一个功能。
5.2.Nginx反向代理的配置语法
Nginx反向代理模块的指令是由ngx_http_proxy_module
模块进行解析,该模块在安装Nginx的时候已经自己加装到Nginx中
反向代理中的常用指令
proxy_pass
proxy_set_header
proxy_redirect
ngx_http_proxy_module
模块:https://nginx.org/en/docs/http/ngx_http_proxy_module.html
5.2.1.proxy_pass
该指令用来设置被代理服务器地址,可以是主机名称、IP地址加端口号形式。
语法 | proxy_pass URL; |
---|---|
默认值 | — |
位置 | location |
URL:为要设置的被代理服务器地址,包含传输协议(http
,https://
)、主机名称或IP地址加端口号、URI等要素。
举例:
proxy_pass http://www.baidu.com;
location /server{
proxy_pass http://192.168.229.131;
}
http://192.168.229.131/server/index.html
location /server{
proxy_pass http://192.168.229.131/;
}
http://192.168.229.131/index.html
在编写proxy_pass的时候,后面的值要不要加"/"?
案例一:
server {
listen 80;
server_name localhost;
location /{
#proxy_pass http://192.168.229.131;
proxy_pass http://192.168.229.131/;
}
}
当客户端访问 http://localhost/index.html,效果是一样的
案例二:
server{
listen 80;
server_name localhost;
location /server{
#proxy_pass http://192.168.229.131;
proxy_pass http://192.168.229.131/;
}
}
当客户端访问 http://localhost/server/index.html这个时候,
第一个proxy_pass就变成了http://localhost/server/index.html
第二个proxy_pass就变成了http://localhost/index.html效果就不一样了。
5.2.2.proxy_set_header
该指令可以更改Nginx服务器接收到的客户端请求的请求头信息,然后将新的请求头发送给代理的服务器
语法 | proxy_set_header field value; |
---|---|
默认值 | proxy_set_header Host $proxy_host;<br/>proxy_set_header Connection close; |
位置 | http、server、location |
需要注意的是,如果想要看到结果,必须在被代理的服务器上来获取添加的头信息。
被代理服务器: [192.168.229.131]
server {
listen 8080;
server_name localhost;
location / {
default_type text/plain; # 设置类型为文本输出在浏览器
return 200 $http_username; # 请求头信息的username值
# 此处会在浏览器页面输出代理服务器设置的username的值
}
}
代理服务器: [192.168.229.136]
server {
listen 8080;
server_name localhost;
location /server {
proxy_pass http://192.168.229.131:8080/; # 被代理的服务器url
proxy_set_header username TOM; # 设置客户端请求的请求头username的值
}
}
访问测试
http://192.168.229.136:8080/server/
5.2.3.proxy_redirect (redirect:改变方向、改变方向、重新寄送)
该指令是用来重置头信息中的"Location"和"Refresh"的值。
语法 | proxy_redirect redirect replacement;<br/>proxy_redirect default;<br/>proxy_redirect off; |
---|---|
默认值 | proxy_redirect default; |
位置 | http、server、location |
》为什么要用该指令?
服务端[192.168.229.131]
server {
listen 8081;
server_name localhost;
if (!-f $request_filename){ # 如果请求的资源不存在
return 302 http://192.168.229.131; # 返回131机器的index.html页面
}
}
代理服务端[192.168.229.136]
server {
listen 8081;
server_name localhost;
location / {
proxy_pass http://192.168.229.131:8081/; # 被代理的服务器url
}
}
代理服务端[192.168.229.136]
server {
listen 8081;
server_name localhost;
location / {
proxy_pass http://192.168.229.131:8081/; # 被代理的服务器url
proxy_redirect http://192.168.229.131 http://192.168.229.136; # 重置头信息,将131替换成136
}
}
server {
listen 80;
server_name localhost;
access_log logs/access.log main;
location / {
#root html;
#index index.html index.htm;
proxy_pass http://192.168.229.131/;
}
}
访问:http://192.168.229.136:8081/aaaaa.html
curl -I http://192.168.229.136:8081/test.html
》该指令的几组选项
proxy_redirect redirect replacement;
redirect:目标,Location的值
replacement:要替换的值
proxy_redirect default;
default;
将location块的uri变量作为replacement,
将proxy_pass变量作为redirect进行替换
proxy_redirect off;
关闭proxy_redirect的功能
5.3.Nginx反向代理实战
服务器1,2,3存在两种情况
第一种情况: 三台服务器的内容不一样。
第二种情况: 三台服务器的内容是一样。
- 如果服务器1、服务器2和服务器3的内容不一样,那我们可以根据用户请求来分发到不同的服务器。
代理服务器 192.168.229.136
server {
listen 8082;
server_name localhost;
location /server1 {
proxy_pass http://192.168.229.131:9001/;
}
location /server2 {
proxy_pass http://192.168.229.131:9002/;
}
location /server3 {
proxy_pass http://192.168.229.131:9003/;
}
}
#服务端 192.168.229.131
#server1
server {
listen 9001;
server_name localhost;
default_type text/html;
return 200 '<h1>192.168.229.131:9001</h1>'
}
#server2
server {
listen 9002;
server_name localhost;
default_type text/html;
return 200 '<h1>192.168.229.131:9002</h1>'
}
#server3
server {
listen 9003;
server_name localhost;
default_type text/html;
return 200 '<h1>192.168.229.131:9003</h1>'
}
- 如果服务器1、服务器2和服务器3的内容是一样的,该如何处理?【nginx负载均衡】
5.4.Nginx的安全控制【--with-http_ssl_module模块】
https://nginx.org/en/docs/http/ngx_http_ssl_module.html
Nginx反向代理是如何来提升web服务器的安全呢?
安全隔离:通过代理分开了客户端到应用程序服务器端的连接,实现了安全措施。在反向代理之前设置防火墙
,仅留一个入口供代理服务器访问。
5.4.1.如何使用SSL对流量进行加密
翻译成大家能熟悉的说法就是将我们常用的http请求转变成https请求,那么这两个之间的区别简单的来说两个都是HTTP协议,只不过https是身披SSL外壳的http.
HTTPS是一种通过计算机网络进行安全通信的传输协议。它经由HTTP进行通信,利用SSL/TLS建立全通信,加密数据包,确保数据的安全性。
SSL(Secure Sockets Layer)安全套接层
TLS(Transport Layer Security)传输层安全
上述这两个是为网络通信提供安全及数据完整性的一种安全协议,TLS和SSL在传输层和应用层对网络连接进行加密。
总结来说为什么要使用https:
http协议是明文传输数据,存在安全问题,而https是加密传输,相当于http+ssl,并且可以防止流量劫持。
Nginx要想使用SSL,需要满足一个条件即需要添加一个模块--with-http_ssl_module
,而该模块在编译的过程中又需要OpenSSL的支持,这个我们之前已经准备好了。
5.4.2.nginx添加SSL的支持【 --with-http_ssl_module
模块的增量添加】
》将原有/usr/local/nginx/sbin/nginx进行备份
》拷贝nginx之前的配置信息
》在nginx的安装源码进行配置指定对应模块 ./configure --with-http_ssl_module
》通过make模板进行编译
》将objs下面的nginx移动到/usr/local/nginx/sbin下
》在源码目录下执行 make upgrade进行升级,这个可以实现不停机添加新模块的功能
./configure --prefix=/usr/local/nginx \
--sbin-path=/usr/local/nginx/sbin/nginx \
--modules-path=/usr/local/nginx/modules \
--conf-path=/usr/local/nginx/conf/nginx.conf \
--error-log-path=/usr/local/nginx/logs/error.log \
--http-log-path=/usr/local/nginx/logs/access.log \
--pid-path=/usr/local/nginx/logs/nginx.pid \
--lock-path=/usr/local/nginx/logs/nginx.lock \
--with-http_gzip_static_module \
--with-http_ssl_module
5.4.3.Nginx的SSL相关指令
因为刚才我们介绍过该模块的指令都是通过ngx_http_ssl_module模块来解析的。
》ssl:该指令用来在指定的服务器开启HTTPS,可以使用 listen 443 ssl,后面这种方式更通用些。
语法 | ssl on \ | off; |
---|---|---|
默认值 | ssl off; | |
位置 | http、server |
server{
listen 443 ssl;
}
》ssl_certificate:为当前这个虚拟主机指定一个带有PEM格式证书的证书。
语法 | ssl_certificate file; |
---|---|
默认值 | — |
位置 | http、server |
》ssl_certificate_key:该指令用来指定PEM secret key文件的路径
语法 | ssl_ceritificate_key file; |
---|---|
默认值 | — |
位置 | http、server |
》ssl_session_cache:该指令用来配置用于SSL会话的缓存
语法 | ssl_sesion_cache off\ | none\ | [builtin[:size]] [shared:name:size] |
---|---|---|---|
默认值 | ssl_session_cache none; | ||
位置 | http、server |
off:禁用会话缓存,客户端不得重复使用会话
none:禁止使用会话缓存,客户端可以重复使用,但是并没有在缓存中存储会话参数
builtin:内置OpenSSL缓存,仅在一个工作进程中使用。
shared:所有工作进程之间共享缓存,缓存的相关信息用name和size来指定
》ssl_session_timeout:开启SSL会话功能后,设置客户端能够反复使用储存在缓存中的会话参数时间。
语法 | ssl_session_timeout time; |
---|---|
默认值 | ssl_session_timeout 5m; |
位置 | http、server |
》ssl_ciphers:指出允许的密码,密码指定为OpenSSL支持的格式
语法 | ssl_ciphers ciphers; |
---|---|
默认值 | ssl_ciphers HIGH:!aNULL:!MD5; |
位置 | http、server |
可以使用openssl ciphers
查看openssl支持的格式。
[root@192 sbin]# openssl ciphers
ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DH-DSS-AES256-GCM-SHA384:DHE-DSS-AES256-GCM-SHA384:DH-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA256:DH-RSA-AES256-SHA256:DH-DSS-AES256-SHA256:DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:DH-RSA-AES256-SHA:DH-DSS-AES256-SHA:DHE-RSA-CAMELLIA256-SHA:DHE-DSS-CAMELLIA256-SHA:DH-RSA-CAMELLIA256-SHA:DH-DSS-CAMELLIA256-SHA:ECDH-RSA-AES256-GCM-SHA384:ECDH-ECDSA-AES256-GCM-SHA384:ECDH-RSA-AES256-SHA384:ECDH-ECDSA-AES256-SHA384:ECDH-RSA-AES256-SHA:ECDH-ECDSA-AES256-SHA:AES256-GCM-SHA384:AES256-SHA256:AES256-SHA:CAMELLIA256-SHA:PSK-AES256-CBC-SHA:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:DH-DSS-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:DH-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-DSS-AES128-SHA256:DH-RSA-AES128-SHA256:DH-DSS-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA:DH-RSA-AES128-SHA:DH-DSS-AES128-SHA:DHE-RSA-SEED-SHA:DHE-DSS-SEED-SHA:DH-RSA-SEED-SHA:DH-DSS-SEED-SHA:DHE-RSA-CAMELLIA128-SHA:DHE-DSS-CAMELLIA128-SHA:DH-RSA-CAMELLIA128-SHA:DH-DSS-CAMELLIA128-SHA:ECDH-RSA-AES128-GCM-SHA256:ECDH-ECDSA-AES128-GCM-SHA256:ECDH-RSA-AES128-SHA256:ECDH-ECDSA-AES128-SHA256:ECDH-RSA-AES128-SHA:ECDH-ECDSA-AES128-SHA:AES128-GCM-SHA256:AES128-SHA256:AES128-SHA:SEED-SHA:CAMELLIA128-SHA:PSK-AES128-CBC-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:EDH-DSS-DES-CBC3-SHA:DH-RSA-DES-CBC3-SHA:DH-DSS-DES-CBC3-SHA:ECDH-RSA-DES-CBC3-SHA:ECDH-ECDSA-DES-CBC3-SHA:DES-CBC3-SHA:IDEA-CBC-SHA:PSK-3DES-EDE-CBC-SHA:KRB5-IDEA-CBC-SHA:KRB5-DES-CBC3-SHA:KRB5-IDEA-CBC-MD5:KRB5-DES-CBC3-MD5:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:ECDH-RSA-RC4-SHA:ECDH-ECDSA-RC4-SHA:RC4-SHA:RC4-MD5:PSK-RC4-SHA:KRB5-RC4-SHA:KRB5-RC4-MD5
》ssl_prefer_server_ciphers:该指令指定是否服务器密码优先客户端密码
语法 | ssl_perfer_server_ciphers on\ | off; |
---|---|---|
默认值 | ssl_perfer_server_ciphers off; | |
位置 | http、server |
5.4.4.虚拟主机与域名解析
5.4.5.域名、dns、ip地址的关系
5.4.6.阿里云域名解析注册
5.4.6.1.注册域名
网站:https://free.aliyun.com?userCode=yu4fhct7
5.4.6.2.解决问题--- 未使用系统分配DNS地址,是你的域名解析DNS地址不是当前系统的DNS地址
5.4.6.3.问题解决
5.4.6.4.添加域名解析
5.4.7.生成证书
方式一:使用阿里云/腾讯云等第三方服务进行购买。
方式二:使用openssl生成证书
先要确认当前系统是否有安装openssl
openssl version
安装下面的命令进行生成
mkdir /root/cert
cd /root/cert
openssl genrsa -des3 -out server.key 1024
openssl req -new -key server.key -out server.csr
cp server.key server.key.org
openssl rsa -in server.key.org -out server.key
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
5.4.8.开启SSL实例
server {
listen 443 ssl;
server_name localhost;
ssl_certificate server.cert;
ssl_certificate_key server.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;
}
}
5.4.9.验证
5.5.反向代理系统调优
5.5.1.反向代理值Buffer和Cache
Buffer翻译过来是"缓冲",Cache翻译过来是"缓存"。
总结下:
相同点:
两种方式都是用来提供IO吞吐效率,都是用来提升Nginx代理的性能。
不同点:
缓冲主要用来解决不同设备之间数据传递速度不一致导致的性能低的问题,缓冲中的数据一旦此次操作完成后,就可以删除。
缓存主要是备份,将被代理服务器的数据缓存一份到代理服务器,这样的话,客户端再次获取相同数据的时候,
就只需要从代理服务器上获取,效率较高,缓存中的数据可以重复使用,只有满足特定条件才会删除.
5.5.2.Proxy Buffer相关指令
》proxy_buffering :该指令用来开启或者关闭代理服务器的缓冲区;
语法 | proxy_buffering on\ | off; |
---|---|---|
默认值 | proxy_buffering on; | |
位置 | http、server、location |
》proxy_buffers:该指令用来指定单个连接从代理服务器读取响应的缓存区的个数和大小。
语法 | proxy_buffers number size; | |
---|---|---|
默认值 | proxy_buffers 8 4k \ | 8K;(与系统平台有关) |
位置 | http、server、location |
number:缓冲区的个数
size:每个缓冲区的大小,缓冲区的总大小就是number*size
》proxy_buffer_size:该指令用来设置从被代理服务器获取的第一部分响应数据的大小。保持与proxy_buffers中的size一致即可,当然也可以更小。
语法 | proxy_buffer_size size; | |
---|---|---|
默认值 | proxy_buffer_size 4k \ | 8k;(与系统平台有关) |
位置 | http、server、location |
》proxy_busy_buffers_size:该指令用来限制同时处于BUSY状态的缓冲总大小。
语法 | proxy_busy_buffers_size size; | |
---|---|---|
默认值 | proxy_busy_buffers_size 8k\ | 16K; |
位置 | http、server、location |
》proxy_temp_path:当缓冲区存满后,仍未被Nginx服务器完全接受,响应数据就会被临时存放在磁盘文件上,该指令设置文件路径
语法 | proxy_temp_path path; |
---|---|
默认值 | proxy_temp_path proxy_temp; |
位置 | http、server、location |
注意path最多设置三层。
》proxy_temp_file_write_size:该指令用来设置磁盘上缓冲文件的大小。
语法 | proxy_temp_file_write_size size; | |
---|---|---|
默认值 | proxy_temp_file_write_size 8K\ | 16K; |
位置 | http、server、location |
5.5.3.通用网站的配置
根据项目的具体内容进行相应的调节。
proxy_buffering on;
proxy_buffer_size 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
六、Nginx负载均衡
6.1.负载均衡概述
早期的网站流量和业务功能都比较简单,单台服务器足以满足基本的需求,但是随着互联网的发展,业务流量越来越大并且业务逻辑也跟着越来越复杂,单台服务器的性能及单点故障问题
就凸显出来了,因此需要多台服务器进行性能的水平扩展及避免单点故障出现
。那么如何将不同用户的请求流量分发到不同的服务器
上呢?
6.2.负载均衡的原理及处理流程
系统的扩展可以分为纵向扩展
和横向扩展
。
纵向扩展
是从单机的角度出发,通过增加系统的硬件处理能力来提升服务器的处理能力
横向扩展
是通过添加机器来满足大型网站服务的处理能力。
这里面涉及到两个重要的角色分别是"应用集群"和"负载均衡器"
。
应用集群
:将同一应用部署到多台机器上,组成处理集群,接收负载均衡设备分发的请求,进行处理并返回响应的数据。
负载均衡器
:将用户访问的请求根据对应的负载均衡算法
,分发到集群中的一台服务器进行处理。
6.3.负载均衡的作用
- 解决服务器的
高并发
压力,提高应用程序的处理性能。 - 提供
故障转移
,实现高可用。 - 通过添加或减少服务器数量,增强网站的可扩展性。
- 在负载均衡器上进行过滤,可以
提高系统的安全性
。
6.4.负载均衡常用的处理方式
6.4.1.方式一:用户手动选择
这种方式比较原始,只要实现的方式就是在网站主页上面提供不同线路、不同服务器链接方式,让用户来选择自己访问的具体服务器,来实现负载均衡。
6.4.2.方式二:DNS轮询方式
6.4.2.1.DNS
域名系统(服务)协议(DNS)是一种分布式网络目录服务,主要用于域名与 IP 地址的相互转换。
大多域名
注册商都支持对同一个主机名添加多条A记录
,这就是DNS轮询,DNS服务器将解析请求按照A记录的顺序,随机分配到不同的IP上,这样就能完成简单的负载均衡
。DNS轮询的成本非常低,在一些不重要的服务器,被经常使用。
6.4.2.2.为某一个域名添加的IP地址,用2台服务器来做负载均衡
6.4.2.3.验证:
ping www.自己的域名
ping www.baidu.com
清空本地的dns缓存
ipconfig/flushdns
6.4.2.4.DNS负载均衡存在的缺点
我们发现使用DNS来实现轮询,不需要投入过多的成本,虽然DNS轮询成本低廉,但是DNS负载均衡存在明显的缺点。
- 可靠性低
假设一个域名DNS轮询多台服务器,如果其中的一台服务器发生故障,那么所有的访问该服务器的请求将不会有所回应,即使你将该服务器的IP从DNS中去掉,但是由于各大宽带接入商将众多的DNS存放在缓存中,以节省访问时间,导致DNS不会实时更新。所以DNS轮流上一定程度上解决了负载均衡问题,但是却存在可靠性不高的缺点。
- 负载均衡不均衡
DNS负载均衡采用的是
简单的轮询负载算法
,不能区分服务器的差异,不能反映服务器的当前运行状态,不能做到为性能好的服务器多分配请求,另外本地计算机也会缓存已经解析的域名到IP地址的映射
,这也会导致使用该DNS服务器的用户在一定时间内访问的是同一台Web服务器,从而引发Web服务器减的负载不均衡。
负载不均衡
则会导致某几台服务器负荷很低,而另外几台服务器负荷确很高,处理请求的速度慢,配置高的服务器分配到的请求少,而配置低的服务器分配到的请求多。
6.4.3.方式三:四/七层负载均衡
OSI(open system interconnection),叫开放式系统互联模型
,这个是由国际标准化组织ISO指定的一个不基于具体机型、操作系统或公司的网络体系结构。该模型将网络通信的工作分为七层。
- 应用层:为应用程序提供网络服务。
- 表示层:对数据进行格式化、编码、加密、压缩等操作。
- 会话层:建立、维护、管理会话连接。
- 传输层:建立、维护、管理端到端的连接,常见的有TCP/UDP。
- 网络层:
IP寻址
和路由选择
- 数据链路层:控制网络层与物理层之间的通信。
- 物理层:比特流传输。
所谓四层负载均衡
指的是OSI七层模型中的传输层
,主要是基于IP+PORT的负载均衡
实现四层负载均衡的方式:
硬件:F5 BIG-IP、Radware等
软件:LVS、Nginx、Hayproxy等
所谓的七层负载均衡
指的是在应用层
,主要是基于虚拟的URL或主机IP的负载均衡
实现七层负载均衡的方式:
软件:Nginx、Hayproxy等
四层和七层负载均衡
的区别
四层负载均衡数据包是在底层就进行了分发,而七层负载均衡数据包则在最顶端进行分发,所以四层负载均衡的效率比七层负载均衡的要高。
四层负载均衡不识别域名,而七层负载均衡识别域名。
处理四层和七层负载以为其实还有二层、三层负载均衡,二层是在数据链路层基于mac地址来实现负载均衡,三层是在网络层一般采用虚拟IP地址的方式实现负载均衡。
实际环境采用的模式
四层负载(LVS)+七层负载(Nginx)
6.5.Nginx七层负载均衡
Nginx要实现七层负载均衡需要用到proxy_pass代理模块
配置。Nginx默认安装支持这个模块,我们不需要再做任何处理。
Nginx的负载均衡是在Nginx的反向代理基础上把用户的请求根据指定的算法分发到一组【upstream虚拟服务池
】。
6.5.1.Nginx七层负载均衡的指令
upstream指令
该指令是用来定义一组服务器
,它们可以是监听不同端口的服务器,并且也可以是同时监听TCP和Unix socket的服务器。服务器可以指定不同的权重,默认为1。
语法 | upstream name {...} |
---|---|
默认值 | — |
位置 | http |
server指令
该指令用来指定后端服务器的名称和一些参数
,可以使用域名、IP、端口或者unix socket
语法 | server name [paramerters] |
---|---|
默认值 | — |
位置 | upstream |
6.5.2.Nginx七层负载均衡的实现流程
6.5.2.1.服务端设置
server {
listen 9001;
server_name localhost;
default_type text/html;
location /{
return 200 '<h1>192.168.229.131:9001</h1>';
}
}
server {
listen 9002;
server_name localhost;
default_type text/html;
location /{
return 200 '<h1>192.168.229.131:9002</h1>';
}
}
server {
listen 9003;
server_name localhost;
default_type text/html;
location /{
return 200 '<h1>192.168.229.131:9003</h1>';
}
}
6.5.2.2.负载均衡器设置
upstream backend{
server 192.168.229.131:9091;
server 192.168.229.131:9092;
server 192.168.229.131:9093;
}
server {
listen 8083;
server_name localhost;
location /{
proxy_pass http://backend;
}
}
6.5.2.3.访问测试--刷新
http://192.168.229.136:8083/
6.5.3.负载均衡状态
代理服务器在负责均衡调度中的状态有以下几个:
状态 | 概述 |
---|---|
down | 当前的server暂时不参与负载均衡 |
backup | 预留的备份服务器 |
max_fails | 允许请求失败的次数 |
fail_timeout | 经过max_fails失败后, 服务暂停时间 |
max_conns | 限制最大的接收连接数 |
downn【 down表示当前的serve暂时不参与负载】
down:将该服务器标记为永久不可用
,那么该代理服务器将不参与负载均衡
。
upstream backend{
server 192.168.229.131:9001 down;
server 192.168.229.131:9002
server 192.168.229.131:9003;
}
server {
listen 8083;
server_name localhost;
location /{
proxy_pass http://backend;
}
}
该状态一般会对需要停机维护的服务器进行设置。
curl http://192.168.229.136:8083
backup
backup:将该服务器标记为备份服务器
,当主服务器不可用时,将用来传递请求。
upstream backend{
server 192.168.229.131:9001 down;
server 192.168.229.131:9002 backup;
server 192.168.229.131:9003;
}
server {
listen 8083;
server_name localhost;
location /{
proxy_pass http://backend;
}
}
此时需要将9093端口的访问禁止掉来模拟下唯一能对外提供访问的服务宕机以后,backup的备份服务器就要开始对外提供服务,此时为了测试验证,我们需要使用防火墙来进行拦截。
介绍一个工具firewall-cmd
,该工具是Linux提供的专门用来操作firewall的。
查询防火墙中指定的端口是否开放
firewall-cmd --query-port=9001/tcp
如何开放一个指定的端口
firewall-cmd --permanent --add-port=9002/tcp
批量添加开发端口
firewall-cmd --permanent --add-port=9001-9003/tcp
如何移除一个指定的端口
firewall-cmd --permanent --remove-port=9003/tcp
重新加载
firewall-cmd --reload
其中
--permanent表示设置为持久
--add-port表示添加指定端口
--remove-port表示移除指定端口
max_conns
max_conns=number
:用来设置代理服务器同时活动链接的最大数量
,默认为0,表示不限制,使用该配置可以根据后端服务器处理请求的并发量
来进行设置,防止后端服务器被压垮。
max_fails和fail_timeout
max_fails=number:设置允许请求代理服务器失败的次数,默认为1。
fail_timeout=time:设置经过max_fails失败后,服务暂停的时间,默认是10秒。
upstream backend{
server 192.168.229.136:9001 down;
server 192.168.229.136:9002 backup;
server 192.168.229.136:9003 max_fails=3 fail_timeout=15;
}
server {
listen 8083;
server_name localhost;
location /{
proxy_pass http://backend;
}
}
6.5.4.负载均衡策略
除了采用默认的分配方式以外,我们还能采用什么样的负载算法
Nginx的upstream支持如下六种方式的分配算法,分别是:
算法名称 | 说明 |
---|---|
轮询 | 默认方式 |
weight | 权重方式 |
ip_hash | 依据ip分配方式 |
least_conn | 依据最少连接方式 |
url_hash | 依据URL分配方式 |
fair | 依据响应时间方式 |
轮询
轮询是upstream模块负载均衡默认的策略
。每个请求会按时间顺序逐个分配到不同的后端服务器。轮询不需要额外的配置。
upstream backend{
server 192.168.229.131:9001 weight=1;
server 192.168.229.131:9002;
server 192.168.229.131:9003;
}
server {
listen 8083;
server_name localhost;
location /{
proxy_pass http://backend;
}
}
weight轮询【默认为1,weight越大,负载的权重就越大】
weight=number
:用来设置服务器的权重,默认为1
,权重数据越大,被分配到请求的几率越大;
该权重值,主要是针对实际工作环境中不同的后端服务器硬件配置进行调整的,所有此策略比较适合服务器的硬件配置差别比较大的情况。
upstream backend{
server 192.168.229.131:9001 weight=10;
server 192.168.229.131:9002 weight=5;
server 192.168.229.131:9003 weight=3;
}
server {
listen 8083;
server_name localhost;
location /{
proxy_pass http://backend;
}
}
ip_hash
当对后端的多台动态应用服务器做负载均衡时,ip_hash指令
能够将某个客户端IP的请求通过哈希算法
定位到同一台后端服务器上。
这样,当来自某一个IP的用户在后端Web服务器A上登录后,在访问该站点的其他URL,能保证其访问的还是后端web服务器A。
语法 | ip_hash; |
---|---|
默认值 | — |
位置 | upstream |
upstream backend{
ip_hash;
server 192.168.229.131:9001;
server 192.168.229.131:9002;
server 192.168.229.131:9003;
}
server {
listen 8083;
server_name localhost;
location /{
proxy_pass http://backend;
}
}
缺点:ip_hash指令无法保证后端服务器的负载均衡,可能导致有些后端服务器接收到的请求多,有些后端服务器接收的请求少,而且设置后端服务器权重等方法将不起作用。
least_conn
最少连接
,把请求转发给连接数较少的后端服务器。轮询算法
是把请求平均
的转发
给各个后端,使它们的负载大致相同;但是,有些请求占用的时间很长,会导致其所在的后端负载较高。
这种情况下,least_conn这种方式就可以达到更好的负载均衡效果。
upstream backend{
least_conn;
server 192.168.229.131:9001;
server 192.168.229.131:9002;
server 192.168.229.131:9003;
}
server {
listen 8083;
server_name localhost;
location /{
proxy_pass http://backend;
}
}
least_conn
负载均衡策略适合请求处理时间长短不一
造成服务器过载的情况。
url_hash
按访问url的hash结果来分配请求
,使每个url定向到同一个后端服务器,要配合缓存命中来使用
。
同一个资源多次请求,可能会到达不同的服务器上,导致不必要的多次下载,缓存命中率不高,以及一些资源时间的浪费。
而使用url_hash,可以使得同一个url(也就是同一个资源请求)会到达同一台服务器,一旦缓存了资源,再此收到请求,就可以从缓存中读取。
upstream backend{
hash &request_uri;
server 192.168.229.131:9001;
server 192.168.229.131:9002;
server 192.168.229.131:9003;
}
server {
listen 8083;
server_name localhost;
location /{
proxy_pass http://backend;
}
}
访问如下地址:
http://192.168.229.136:8083/a
http://192.168.229.136:8083/b
http://192.168.229.136:8083/c
fair
fair采用的不是内建负载均衡使用的轮换的均衡算法,而是可以根据页面大小、加载时间长短智能的进行负载均衡。如何使用第三方模块的fair负载均衡策略。
upstream backend{
fair;
server 192.168.229.131:9001;
server 192.168.229.131:9002;
server 192.168.229.131:9003;
}
server {
listen 8083;
server_name localhost;
location /{
proxy_pass http://backend;
}
}
6.5.5.添加第三方模块【nginx-upstream-fair
】实现的负载均衡
但是如何直接使用会报错,因为fair属于第三方模块实现的负载均衡。需要添加nginx-upstream-fair
,如何添加对应的模块:
6.5.5.1. 下载nginx-upstream-fair模块
下载地址为:
https://github.com/gnosek/nginx-upstream-fair
6.5.5.2. 将下载的文件上传到服务器并进行解压缩
mkdir -p /nginx/module
cd /nginx/module
unzip nginx-upstream-fair-master.zip
6.5.5.3. 重命名资源
mv nginx-upstream-fair-master fair
6.5.5.4. 使用./configure命令将资源添加到Nginx模块中
./configure --add-module=/nginx/module/fair
./configure --prefix=/usr/local/nginx \
--sbin-path=/usr/local/nginx/sbin/nginx \
--modules-path=/usr/local/nginx/modules \
--conf-path=/usr/local/nginx/conf/nginx.conf \
--error-log-path=/usr/local/nginx/logs/error.log \
--http-log-path=/usr/local/nginx/logs/access.log \
--pid-path=/usr/local/nginx/logs/nginx.pid \
--lock-path=/usr/local/nginx/logs/nginx.lock \
--with-http_gzip_static_module \
--with-http_ssl_module \
--add-module=/nginx/module/fair
6.5.5.5. 编译
make
编译可能会出现如下错误,ngx_http_upstream_srv_conf_t结构中缺少default_port
解决方案:
在Nginx的源码中 src/http/ngx_http_upstream.h,找到ngx_http_upstream_srv_conf_s
,在模块中添加添加default_port属性
# 搜索
find / -name ngx_http_upstream.h
in_port_t default_port
然后再进行make.
6.5.5.6. 更新Nginx
1 将sbin目录下的nginx进行备份
mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginxold
2 将安装目录下的objs中的nginx拷贝到sbin目录
cd objs
cp nginx /usr/local/nginx/sbin
3 更新Nginx
cd ../
make upgrade
6.5.5.7. 编译测试使用Nginx
6.5.56.负载均衡案例
6.5.6.1.案例一:对所有请求实现一般轮询规则的负载均衡
upstream backend{
server 192.168.229.131:9001;
server 192.168.229.131:9002;
server 192.168.229.131:9003;
}
server {
listen 8083;
server_name localhost;
location /{
proxy_pass http://backend;
}
}
6.5.6.2.案例二:对所有请求实现加权轮询规则的负载均衡
upstream backend{
server 192.168.229.131:9001 weight=7;
server 192.168.229.131:9002 weight=5;
server 192.168.229.131:9003 weight=3;
}
server {
listen 8083;
server_name localhost;
location /{
proxy_pass http://backend;
}
}
6.5.6.3.案例三:对特定资源实现负载均衡
upstream videobackend{
server 192.168.229.131:9001;
server 192.168.229.131:9002;
}
upstream filebackend{
server 192.168.229.131:9003;
server 192.168.229.131:9004;
}
server {
listen 8084;
server_name localhost;
location /video/ {
proxy_pass http://videobackend;
}
location /file/ {
proxy_pass http://filebackend;
}
}
6.5.6.4.案例四:对不同域名实现负载均衡
upstream videobackend{
server 192.168.229.131:9001;
server 192.168.229.131:9002;
}
upstream filebackend{
server 192.168.229.131:9003;
server 192.168.229.131:9004;
}
server {
listen 8085;
server_name www.test.cn;
location / {
proxy_pass http://videobackend;
}
}
server {
listen 8086;
server_name www.it.cn;
location / {
proxy_pass http://filebackend;
}
}
6.5.6.5.案例五:实现带有URL重写的负载均衡
upstream backend{
server 192.168.229.131:9001;
server 192.168.229.131:9002;
server 192.168.229.131:9003;
}
server {
listen 80;
server_name localhost;
location /file/ {
rewrite ^(/file/.*) /server/$1 last;
}
location / {
proxy_pass http://backend;
}
}
6.6.Nginx四层负载均衡【 --with-stream 模块】
Nginx在1.9之后,增加了一个stream模块,用来实现四层协议的转发、代理、负载均衡等。
stream模块的用法跟http的用法类似,允许我们配置一组TCP或者UDP等协议的监听,然后通过proxy_pass来转发我们的请求,通过upstream添加多个后端服务,实现负载均衡。
四层协议负载均衡的实现,一般都会用到LVS、HAProxy、F5等,要么很贵要么配置很麻烦,而Nginx的配置相对来说更简单,更能快速完成工作。
6.6.1.添加 --with-stream 模块的支持
Nginx默认是没有编译这个模块的,需要使用到stream模块,那么需要在编译的时候加上--with-stream
。
完成添加--with-stream
的实现步骤:
》将原有/usr/local/nginx/sbin/nginx进行备份
》拷贝nginx之前的配置信息
》在nginx的安装源码进行配置指定对应模块 ./configure --with-stream
》通过make模板进行编译
》将objs下面的nginx移动到/usr/local/nginx/sbin下
》在源码目录下执行 make upgrade进行升级,这个可以实现不停机添加新模块的功能
./configure --prefix=/usr/local/nginx \
--sbin-path=/usr/local/nginx/sbin/nginx \
--modules-path=/usr/local/nginx/modules \
--conf-path=/usr/local/nginx/conf/nginx.conf \
--error-log-path=/usr/local/nginx/logs/error.log \
--http-log-path=/usr/local/nginx/logs/access.log \
--pid-path=/usr/local/nginx/logs/nginx.pid \
--lock-path=/usr/local/nginx/logs/nginx.lock \
--with-http_gzip_static_module \
--with-http_ssl_module \
--with-stream \
--add-module=/nginx/module/fair
6.6.2.Nginx四层负载均衡的指令
stream指令
该指令提供在其中指定流服务器指令的配置文件上下文。和http指令同级。
语法 | stream { ... } |
---|---|
默认值 | — |
位置 | main |
upstream指令
该指令和http的upstream指令是类似的。
6.7.四层负载均衡的案例
6.7.1.需求分析
6.7.2.实现步骤
6.7.3.准备Redis服务器,在一条服务器上准备三个Redis,端口分别是6379,6378
6.7.3.1.下载redis的安装包,redis-7.2.4.tar.gz
redis官网:https://redis.io/download/
# 安装wget工具
yum -y install wget
# 创建自己的redis文件夹
mkdir -p /redis/core
cd /redis/core
# 自己复制的链接地址
wget https://download.redis.io/releases/redis-7.2.4.tar.gz
6.7.3.2.将安装包进行解压缩
tar -zxf redis-4.0.14.tar.gz
6.7.3.3.进入redis的安装包
cd /redis/core/redis-7.2.4
6.7.3.4.使用make和install进行编译和安装
make PREFIX=/usr/local/redis/redis01 install
6.7.3.5.拷贝redis配置文件redis.conf
到/usr/local/redis/redis01/bin目录中
cp redis.conf /usr/local/redis/redis01/bin
6.7.3.6.修改redis.conf配置文件
port 6379 #redis的端口
protected-mode no #需要远程连接,设置为no,取消保护模式
#bind 127.0.0.1 ::1 # 允许redis远程连接,必须注释掉(注释或者改为bind 0.0.0.0)
daemonize yes #后台启动redis设置为yes,开启守护进程模式
appendonly yes #开启redis数据持久化
6.7.3.7.将redis01复制一份为redis02
cd /usr/local/redis
cp -r redis01 redis02
6.7.3.8.将redis02文件文件夹中的redis.conf进行修改
port 6378 #redis的端口
daemonize yes #后台启动redis
6.7.3.9.分别启动,即可获取两个Redis.并查看
ps -ef | grep redis
6.7.3.10.使用Nginx将请求分发到不同的Redis服务器上。
stream {
upstream redisbackend {
server 192.168.229.131:6379;
server 192.168.229.131:6378;
}
server {
listen 81;
proxy_pass redisbackend;
}
}
6.7.4.准备Tomcat服务器.
Tomcat官网:https://tomcat.apache.org/download-80.cgi
6.7.4.1.下载tomcat的安装包,apache-tomcat-8.5.98.tar.gz
# 安装wget工具
yum -y install wget
# 创建自己的tomact文件夹
mkdir -p /tomact/core
cd /tomact/core
# 自己复制的链接地址
wget https://dlcdn.apache.org/tomcat/tomcat-8/v8.5.98/bin/apache-tomcat-8.5.98.tar.gz
6.7.4.2.将安装包进行解压缩
tar -zxf apache-tomcat-8.5.98.tar.gz
6.7.4.3.进入tomcat的bin目录
cd apache-tomcat-8.5.98/bin
./startup.sh
tomcat官网:https://tomcat.apache.org/download-80.cgi
Linux下安装jdk、tomcat:https://blog.csdn.net/qq_45740503/article/details/135609079?spm=1001.2014.3001.5502
6.7.4.4.测试
ps -ef | grep tomcat
6.7.5.nginx.conf配置
stream {
upstream redisbackend {
server 192.168.229.131:6379;
server 192.168.229.131:6378;
}
upstream tomcatbackend {
server 192.168.229.131:8080;
}
server {
listen 81;
proxy_pass redisbackend;
}
server {
listen 82;
proxy_pass tomcatbackend;
}
}
6.7.6.访问测试
七、Nginx缓存集成【ngx_http_proxy_module模块】
ngx_http_proxy_module模块:https://nginx.org/en/docs/http/ngx_http_proxy_module.html
7.1.缓存的概念
缓存就是数据交换的缓冲区(称作:Cache),当用户要获取数据的时候,会先从缓存中去查询获取数据,如果缓存中有就会直接返回给用户,如果缓存中没有,则会发请求从服务器重新查询数据,将数据返回给用户的同时将数据放入缓存,下次用户就会直接从缓存中获取数据。
缓存其实在很多场景中都有用到,比如:
场景 | 作用 |
---|---|
操作系统磁盘缓存 | 减少磁盘机械操作 |
数据库缓存 | 减少文件系统的IO操作 |
应用程序缓存 | 减少对数据库的查询 |
Web服务器缓存 | 减少对应用服务器请求次数 |
浏览器缓存 | 减少与后台的交互次数 |
缓存的优点
- 减少数据传输,节省网络流量,加快响应速度,提升用户体验;
- 减轻服务器压力;
- 提供服务端的高可用性;
缓存的缺点
- 数据的不一致
- 增加成本
Nginx作为web服务器,Nginx作为Web缓存服务器,它介于客户端和应用服务器之间,当用户通过浏览器访问一个URL时,web缓存服务器会去应用服务器获取要展示给用户的内容,将内容缓存到自己的服务器上,当下一次请求到来时,如果访问的是同一个URL,web缓存服务器就会直接将之前缓存的内容返回给客户端,而不是向应用服务器再次发送请求。
web缓存降低了应用服务器、数据库的负载,减少了网络延迟,提高了用户访问的响应速度,增强了用户的体验。
7.2.Nginx的web缓存服务
Nginx是从0.7.48版开始提供缓存功能
。
Nginx是基于Proxy Store来实现的,其原理是把URL及相关组合当做Key,在使用MD5算法对Key进行哈希,得到硬盘上对应的哈希目录路径,从而将缓存内容保存在该目录中。
它可以支持任意URL连接,同时也支持404/301/302这样的非200状态码。
Nginx即可以支持对指定URL或者状态码设置过期时间,也可以使用purge命令来手动清除指定URL的缓存。
7.3.Nginx缓存设置的相关指令
Nginx的web缓存服务
主要是使用ngx_http_proxy_module
模块相关指令集来完成。
proxy_cache_path
该指定用于设置缓存文件的存放路径
语法 | proxy_cache_path path [levels=number] <br/>keys_zone=zone_name:zone_size [inactive=time][max_size=size]; |
---|---|
默认值 | — |
位置 | http |
path:缓存路径地址
,如:
/usr/local/proxy_cache
levels
: 指定该缓存空间对应的目录,最多可以设置3层,每层取值为1|2如 :
levels=1:2 缓存空间有两层目录,第一次是1个字母,第二次是2个字母
举例说明:
MD5[key]通过MD5加密以后的值为 7f138a09169b250e9dcb378140907378
levels=1:2 最终的存储路径为/usr/local/proxy_cache/8/37
levels=2:1:2 最终的存储路径为/usr/local/proxy_cache/78/3/07
levels=2:2:2 最终的存储路径为??/usr/local/proxy_cache/78/73/90
keys_zone
:用来为这个缓存区设置名称和指定大小,如:
keys_zone=MD5:200m 缓存区的名称是MD5,大小为200M,1M大概能存储8000个keys
inactive
:指定缓存的数据多次时间未被访问就将被删除,如:
inactive=1d 缓存数据在1天内没有被访问就会被删除
max_size
:设置最大缓存空间,如果缓存空间存满,默认会覆盖缓存时间最长的资源,如:
max_size=20g
配置实例:
user www;
worker_processes 2;
events {
accept_mutex on; #设置Nginx网络连接序列化,防止多个进程对连接的争抢
multi_accept on; #设置Nginx的worker进程是否可以同时接收多个网络请求
worker_connections 1024; # 设置Nginx单个worker进程最大的连接数
use epoll; #设置Nginx使用的事件驱动模型,使用epoll函数来优化Ngin
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on; # 主要是用来提升网络包的传输效率
tcp_nodelay on; # 提高网络包传输的实时性
keepalive_timeout 65;
proxy_cache_path /usr/local/nginx/proxy_cache levels=2:1 keys_zone=Test:200m inactive=1d max_size=20g;
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
proxy_cache
该指令用来开启或关闭代理缓存
,如果是开启则自定使用哪个缓存区来进行缓存。
语法 | proxy_cache zone_name\ | off; |
---|---|---|
默认值 | proxy_cache off; | |
位置 | http、server、location |
zone_name:指定使用缓存区的名称
proxy_cache_key
该指令用来设置web缓存的key值
,Nginx会根据key值MD5哈希存缓存
。
语法 | proxy_cache_key key; |
---|---|
默认值 | proxy_cache_key $scheme$proxy_host$request_uri; |
位置 | http、server、location |
proxy_cache_valid
该指令用来对不同返回状态码的URL设置不同的缓存时间
语法 | proxy_cache_valid [code ...] time; |
---|---|
默认值 | — |
位置 | http、server、location |
如:
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
为200和302的响应URL设置10分钟缓存,为404的响应URL设置1分钟缓存
proxy_cache_valid any 1m;
对所有响应状态码的URL都设置1分钟缓存
proxy_cache_min_uses
该指令用来设置资源被访问多少次后被缓存
语法 | proxy_cache_min_uses number; |
---|---|
默认值 | proxy_cache_min_uses 1; |
位置 | http、server、location |
proxy_cache_methods
该指令用户设置缓存哪些HTTP方法
语法 | proxy_cache_methods GET\ | HEAD\ | POST; |
---|---|---|---|
默认值 | proxy_cache_methods GET HEAD; | ||
位置 | http、server、location |
默认缓存HTTP的GET和HEAD方法
,不缓存POST方法。
7.4.Nginx缓存设置案例
7.4.1.需求分析
7.4.2.步骤实现
7.4.3.应用服务器【131】的环境准备:启动tomcat并测试
(1)在192.168.229.131服务器上的tomcat的webapps下面添加一个js目录,并在js目录中添加一个jquery-3.7.1.js文件
(2)启动tomcat
(3)访问测试
jquery官网:https://jquery.com/download/
https://code.jquery.com/jquery-3.7.1.js
http://192.168.229.131:8080/js/jquery-3.7.1.js
7.4.4.Nginx的环境准备【136服务器】完成Nginx反向代理配置
http{
upstream backend{
server 192.168.229.131:8080;
}
server {
listen 8080;
server_name localhost;
location / {
proxy_pass http://backend/js/;
}
}
}
7.4.5.缓存状态标记 $upstream_cache_status
$upstream_cache_status包含以下几种状态:
MISS 未命中,请求被传送到后端
HIT 缓存命中
EXPIRED 缓存已经过期请求被传送到后端
UPDATING 正在更新缓存,将使用旧的应答
STALE 后端将得到过期的应答
7.4.6.添加Nginx缓存配置一
http{
proxy_cache_path /usr/local/proxy_cache levels=2:1 keys_zone=Test:200m inactive=1d max_size=20g;
upstream backend{
server 192.168.229.131:8080;
}
server {
listen 8080;
server_name localhost;
location / {
proxy_cache Test;
proxy_cache_key TestKey;
proxy_cache_valid 200 5d;
# 缓存状态标记
add_header nginx-cache "$upstream_cache_status";
proxy_pass http://backend/js/;
}
}
}
7.4.7.添加Nginx缓存配置二
http{
proxy_cache_path /usr/local/proxy_cache levels=2:1 keys_zone=Test:200m inactive=1d max_size=20g;
upstream backend{
server 192.168.229.131:8080;
}
server {
listen 8080;
server_name localhost;
location / {
proxy_cache Test;
#proxy_cache_key TestKey;
proxy_cache_key $scheme$proxy_host$request_uri;#请求的协议 请求的主机 请求的路径
proxy_cache_min_uses 5;# 访问超过5次才缓存
proxy_cache_valid 200 5d;
proxy_cache_valid 404 30s;
proxy_cache_valid any 1m;
# 缓存状态标记
add_header nginx-cache "$upstream_cache_status";
proxy_pass http://backend/js/;
}
}
}
7.5.Nginx缓存的清除
7.5.1.方式一:删除对应的缓存目录
rm -rf /usr/local/nginx/proxy_cache/......
7.5.2.方式二:使用第三方扩展模块 ngx_cache_purge
7.5.2.1.下载ngx_cache_purge模块对应的资源包,并上传到服务器上。
cd /nginx/module
wget http://labs.frickle.com/files/ngx_cache_purge-2.3.tar.gz
7.5.2.2.对资源文件进行解压缩
tar -zxf ngx_cache_purge-2.3.tar.gz
7.5.2.3.修改文件夹名称,方便后期配置
mv ngx_cache_purge-2.3 purge
7.5.2.4.查询Nginx的配置参数
nginx -V
7.5.2.5.进入Nginx的安装目录,使用./configure进行参数配置
./configure --add-module=/nginx/module/purge
./configure --prefix=/usr/local/nginx \
--sbin-path=/usr/local/nginx/sbin/nginx \
--modules-path=/usr/local/nginx/modules \
--conf-path=/usr/local/nginx/conf/nginx.conf \
--error-log-path=/usr/local/nginx/logs/error.log \
--http-log-path=/usr/local/nginx/logs/access.log \
--pid-path=/usr/local/nginx/logs/nginx.pid \
--lock-path=/usr/local/nginx/logs/nginx.lock \
--with-http_gzip_static_module \
--with-http_ssl_module \
--with-stream \
--add-module=/nginx/module/fair \
--add-module=/nginx/module/purge
7.5.2.6.使用make进行编译
make
7.5.2.7.将nginx安装目录的nginx二级制可执行文件备份
mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginxold
7.5.2.8.将编译后的objs中的nginx拷贝到nginx的sbin目录下
cp objs/nginx /usr/local/nginx/sbin
7.5.2.9.使用make进行升级
make upgrade
7.5.2.10.在nginx配置文件中进行如下配置
proxy_cache_path /usr/local/nginx/proxy_cache levels=2:1 keys_zone=Test:200m inactive=1d max_size=20g;
upstream backend {
server 192.168.229.131:8080;
}
server {
listen 8080;
server_name localhost;
location / {
proxy_cache Test;
proxy_cache_key TestKey;
#proxy_cache_key $scheme$proxy_host$request_uri;#请求的协议 请求的主机 请求的路径
proxy_cache_valid 200 5d;
proxy_cache_valid 404 30s;
proxy_cache_valid any 1m;
proxy_cache_min_uses 1;# 访问超过1次才缓存
# 缓存状态标记
add_header nginx-cache "$upstream_cache_status";
proxy_pass http://backend/js/;
}
location ~ /purge(/.*) {
proxy_cache_purge Test TestKey;
}
}
7.5.2.11.测试
http://192.168.229.136:8080/jquery-3.7.1.js
http://192.168.229.136:8080/purge/jquery-3.7.1.js
7.6.Nginx设置资源不缓存
思考一个问题就是不是所有的数据都适合进行缓存。
比如说对于一些经常发生变化的数据
。
如果进行缓存的话,就很容易出现用户访问到的数据不是服务器真实的数据。
所以对于这些资源我们在缓存的过程中就需要进行过滤,不进行缓存。
7.6.1.proxy_no_cache
该指令是用来定义不将数据进行缓存的条件。
语法 | proxy_no_cache string ...; |
---|---|
默认值 | — |
位置 | http、server、location |
7.6.2.配置实例
proxy_no_cache $cookie_nocache $arg_nocache $arg_comment;
7.6.3.proxy_cache_bypass
该指令是用来设置不从缓存中获取数据的条件。
语法 | proxy_cache_bypass string ...; |
---|---|
默认值 | — |
位置 | http、server、location |
https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache_bypass
7.6.4.配置实例
proxy_cache_bypass $cookie_nocache $arg_nocache $arg_comment;
上述两个指令都有一个指定的条件
,这个条件可以是多个
,并且多个条件中至少有一个不为空且不等于"0"
,则条件满足成立。
上面给的配置实例是从官方网站获取的,里面使用到了三个变量,分别是$cookie_nocache、$arg_nocache、$arg_comment
7.6.5.$cookie_nocache、\$arg_nocache、$arg_comment
这三个参数分别代表的含义是:
$cookie_nocache
指的是当前请求的cookie中键的名称为nocache对应的值
$arg_nocache和$arg_comment
指的是当前请求的参数中属性名为nocache和comment对应的属性值
7.6.6.案例演示下:
log_format params $cookie_nocache | $arg_nocache | $arg_comment;
server{
listen 8081;
server_name localhost;
location /{
access_log logs/access_params.log params;
add_header Set-Cookie 'nocache=999';
root html;
index index.html;
}
}
7.6.7.案例实现--设置不缓存资源的配置方案
server{
listen 8080;
server_name localhost;
location / {
if ($request_uri ~ /.*\.js$){
set $nocache 1;
}
proxy_no_cache $nocache $cookie_nocache $arg_nocache $arg_comment;
proxy_cache_bypass $nocache $cookie_nocache $arg_nocache $arg_comment;
}
}
7.6.8.nginx_balance_cache.conf
user www;
worker_processes 2;
events {
accept_mutex on; #设置Nginx网络连接序列化,防止多个进程对连接的争抢
multi_accept on; #设置Nginx的worker进程是否可以同时接收多个网络请求
worker_connections 1024; # 设置Nginx单个worker进程最大的连接数
use epoll; #设置Nginx使用的事件驱动模型,使用epoll函数来优化Ngin
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on; # 主要是用来提升网络包的传输效率
tcp_nodelay on; # 提高网络包传输的实时性
keepalive_timeout 65;
proxy_cache_path /usr/local/nginx/proxy_cache levels=2:1 keys_zone=Test:200m inactive=1d max_size=20g;
log_format main $scheme$proxy_host$request_uri;
log_format params $cookie_nocache | $arg_nocache | $arg_comment;
upstream backend {
server 192.168.229.131:8080;
}
server {
listen 8081;
server_name localhost;
location / {
add_header Set-Cookie 'nocache=999';
access_log logs/access_params.log params;
root html;
index index.html;
}
}
server {
listen 8080;
server_name localhost;
location / {
access_log logs/key.log main;
proxy_cache Test;
#proxy_cache_key TestKey;
}
server {
listen 8081;
server_name localhost;
location / {
add_header Set-Cookie 'nocache=999';
access_log logs/access_params.log params;
root html;
index index.html;
}
}
server {
listen 8080;
server_name localhost;
location / {
access_log logs/key.log main;
proxy_cache Test;
#proxy_cache_key TestKey;
proxy_cache_key $scheme$proxy_host$request_uri;#请求的协议 请求的主机 请求的路径
proxy_cache_valid 200 5d;
proxy_cache_valid 404 30s;
proxy_cache_valid any 1m;
proxy_cache_min_uses 1;# 访问超过1次才缓存
if ($request_uri ~ /.*\.js$){
set $nocache 1;
}
proxy_no_cache $nocache $cookie_nocache $arg_nocache $arg_comment;
proxy_cache_bypass $nocache $cookie_nocache $arg_nocache $arg_comment;
# 缓存状态标记
add_header nginx-cache "$upstream_cache_status";
proxy_pass http://backend/js/;
}
location ~ /purge(/.*) {
access_log logs/key.log main;
proxy_cache_purge Test $scheme$proxy_host$request_uri;
}
}
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
八、Nginx实现服务器端集群搭建
8.1.Nginx与Tomcat部署
Nginx在高并发场景和处理静态资源是非常高性能的,但是在实际项目中除了静态资源还有就是后台业务代码模块,一般后台业务都会被部署在Tomcat,weblogic或者是websphere等web服务器上。
那么如何使用Nginx接收用户的请求并把请求转发到后台web服务器?
步骤分析:
1.准备Tomcat环境,并在Tomcat上部署一个web项目
2.准备Nginx环境,使用Nginx接收请求,并把请求分发到Tomat上
8.1.1.环境准备(Tomcat)
8.1.1.1.浏览器访问:
http://192.168.229.131:8080/demo/index.html
8.1.1.2.获取动态资源的链接地址:
http://192.168.229.131:8080/demo/getAddress
8.1.1.3.在Centos上准备一个Tomcat作为后台web服务器
- Tomcat官网地址:https://tomcat.apache.org/
- 下载tomcat,apache-tomcat-8.5.98.tar.gz
wget https://dlcdn.apache.org/tomcat/tomcat-8/v8.5.98/bin/apache-tomcat-8.5.98.tar.gz
- 将tomcat进行解压缩
tar -zxf apache-tomcat-8.5.98.tar.gz
8.1.1.4.准备一个web项目,将其打包为war
1.将资料中的demo.war上传到tomcat8目录下的webapps包下
2.将tomcat进行启动,进入tomcat8的bin目录下
./startup.sh
8.1.1.5.启动tomcat进行访问测试。
静态资源: http://192.168.229.131:8080/demo/index.html
动态资源: http://192.168.229.131:8080/demo/getAddress
8.1.2.环境准备(Nginx)
8.1.2.1.使用Nginx的反向代理,将请求转给Tomcat进行处理。
upstream webservice {
server 192.168.229.131:8080;
}
server{
listen 80;
server_name localhost;
location /demo {
proxy_pass http://webservice;
}
}
user www;
worker_processes 2;
events {
accept_mutex on; #设置Nginx网络连接序列化,防止多个进程对连接的争抢
multi_accept on; #设置Nginx的worker进程是否可以同时接收多个网络请求
worker_connections 1024; # 设置Nginx单个worker进程最大的连接数
use epoll; #设置Nginx使用的事件驱动模型,使用epoll函数来优化Ngin
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on; # 主要是用来提升网络包的传输效率
tcp_nodelay on; # 提高网络包传输的实时性
keepalive_timeout 65;
upstream webservice {
server 192.168.229.131:8080;
}
server {
listen 80;
server_name localhost;
location /demo {
proxy_pass http://webservice;
}
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
8.1.2.2.启动访问测试
8.2.Nginx+Tomcat来实现动静分离
8.2.1.动静分离概念
动静分离
- 动:后台应用程序的业务处理
- 静:网站的静态资源(html,javaScript,css,images等文件)
- 分离:将两者进行分开部署访问,提供用户进行访问。举例说明就是以后所有和静态资源相关的内容都交给Nginx来部署访问,非静态内容则交个类似于Tomcat的服务器来部署访问。
为什么要动静分离?
- Nginx在处理静态资源的时候,效率是非常高的,而且Nginx的并发访问量也是名列前茅,而Tomcat则相对比较弱一些,所以把静态资源交个Nginx后,可以减轻Tomcat服务器的访问压力并提高静态资源的访问速度。
- 动静分离以后,降低了动态资源和静态资源的耦合度。如动态资源宕机了也不影响静态资源的展示。
如何实现动静分离?
- 实现动静分离的方式很多,比如静态资源可以部署到CDN、Nginx等服务器上,动态资源可以部署到Tomcat,weblogic或者websphere上。
8.2.2.需求分析
8.2.3.动静分离实现步骤
8.2.3.1.将demo.war项目中的静态资源都删除掉,重新打包生成一个war包,在资料中有提供。
8.2.3.2.将war包部署到tomcat中,把之前部署的内容删除掉
进入到tomcat的webapps目录下,将之前的内容删除掉
将新的war包复制到webapps下
将tomcat启动
8.2.3.3.在Nginx所在服务器创建如下目录,并将对应的静态资源放入指定的位置
其中index.html页面的内容如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/jquery.min.js"></script>
<script>
$(function(){
$.get('http://192.168.229.136/demo/getAddress',function(data){
$("#msg").html(data);
});
});
</script>
</head>
<body>
<img src="images/logo.png"/>
<h1>Nginx如何将请求转发到后端服务器</h1>
<h3 id="msg"></h3>
<img src="images/mv.png"/>
</body>
</html>
8.2.3.4.配置Nginx的静态资源与动态资源的访问
upstream webservice{
server 192.168.229.131:8080;
}
server {
listen 80;
server_name localhost;
#动态资源访问配置
location /demo {
proxy_pass http://webservice;
}
#静态资源访问配置
location ~/.*\.(png|jpg|gif|js){
root html/web;
gzip on;
}
location / {
root html/web;
index index.html index.htm;
}
}
8.2.3.5.启动测试,访问http://192.168.229.136/index.html
假如某个时间点,由于某个原因导致Tomcat后的服务器宕机了,我们再次访问Nginx,会得到如下效果,用户还是能看到页面,只是缺失了访问次数的统计,这就是前后端耦合度降低的效果,并且整个请求只和后的服务器交互了一次,js和images都直接从Nginx返回,提供了效率,降低了后的服务器的压力。
8.3.Nginx实现Tomcat集群搭建
在使用Nginx和Tomcat部署项目的时候,我们使用的是一台Nginx服务器和一台Tomcat服务器,效果图如下:
那么问题来了,如果Tomcat的真的宕机了,整个系统就会不完整,所以如何解决上述问题,一台服务器容易宕机,那就多搭建几台Tomcat服务器,这样的话就提升了后的服务器的可用性。这也就是我们常说的集群,搭建Tomcat的集群需要用到了Nginx的反向代理和赋值均衡的知识,具体如何来实现?
8.3.1.分析下原理与环境准备
8.3.2.准备3台tomcat,使用端口进行区分[实际环境应该是三台服务器],修改server.ml,将端口修改分别修改为8080,8180,8280
vim tomcat02/conf/server.xml
vim tomcat03/conf/server.xml
8.3.3.启动tomcat并访问测试,
http://192.168.229.131:8080/demo/getAddress
http://192.168.229.131:8180/demo/getAddress
http://192.168.229.131:8280/demo/getAddress
8.3.4.在Nginx对应的配置文件中添加如下内容:
upstream webservice{
server 192.168.229.131:8080;
server 192.168.229.131:8180;
server 192.168.229.131:8280;
}
完成了上述环境的部署,我们已经解决了Tomcat的高可用性,一台服务器宕机,还有其他两条对外提供服务,同时也可以实现后台服务器的不间断更新。
如果是Nginx宕机了呢,那么整套系统都将服务对外提供服务了,这个如何解决?
8.4.Nginx高可用解决方案
针对于上面提到的问题,我们来分析下要想解决上述问题,需要面临哪些问题?
需要两台以上的Nginx服务器对外提供服务,这样的话就可以解决其中一台宕机了,另外一台还能对外提供服务,
但是如果是两台Nginx服务器的话,会有两个IP地址,用户该访问哪台服务器,用户怎么知道哪台是好的,哪台是宕机了的?
8.4.1.Keepalived
使用Keepalived来解决,Keepalived 软件
由 C 编写的,最初是专为 LVS 负载均衡
软件设计的,Keepalived 软件主要是通过 VRRP 协议
实现高可用功能
。
8.4.2.VRRP介绍
VRRP
(Virtual Route Redundancy Protocol)协议,翻译过来为虚拟路由冗余协议
。
VRRP协议将两台或多台路由器设备虚拟成一个设备,对外提供虚拟路由器IP,而在路由器组内部,如果实际拥有这个对外IP的路由器如果工作正常的话就是MASTER,MASTER实现针对虚拟路由器IP的各种网络功能。其他设备不拥有该虚拟IP,状态为BACKUP,处了接收MASTER的VRRP状态通告信息以外,不执行对外的网络功能。当主机失效
时,BACKUP
将接管
原先MASTER
的网络功能。
从上面的介绍信息获取到的内容就是VRRP是一种协议,那这个协议是用来干什么的?
1.选择协议
VRRP可以把一个虚拟路由器的责任动态分配到局域网上的 VRRP 路由器中的一台。
其中的虚拟路由即Virtual路由是由VRRP路由群组创建的一个不真实存在的路由,这个虚拟路由也是有对应的IP地址。
而且VRRP路由1和VRRP路由2之间会有竞争选择,通过选择会产生一个Master路由和一个Backup路由。
2.路由容错协议
Master路由和Backup路由之间会有一个心跳检测,Master会定时告知Backup自己的状态,如果在指定的时间内,
Backup没有接收到这个通知内容,Backup就会替代Master成为新的Master。
Master路由有一个特权就是虚拟路由和后端服务器都是通过Master进行数据传递交互的,
而备份节点则会直接丢弃这些请求和数据,不做处理,只是去监听Master的状态
8.4.3.使用Keepalived的解决方案
8.4.4.环境搭建
8.4.4.1.环境准备
VIP | IP | 主机名 | 主/从 |
---|---|---|---|
192.168.229.136 | keepalived1 | Master | |
192.168.229.222 | |||
192.168.229.137 | keepalived2 | Backup |
8.4.4.2.keepalived的安装
keepalived官网地址:https://keepalived.org/
8.4.4.2.1.步骤1:从官方网站下载keepalived
# 创建keepalived目录,方便管理资源
mkdir -p /keepalived/core
cd /keepalived/core
wget https://keepalived.org/software/keepalived-2.0.20.tar.gz
8.4.4.2.2.步骤2:将压缩文件进行解压缩
tar -zxf keepalived-2.0.20.tar.gz
8.4.4.2.3.步骤3:对keepalived进行配置,编译和安装
cd /keepalived/core/keepalived-2.0.20
# 解决报错
yum -y install libnl libnl-devel
./configure --sysconf=/etc --prefix=/usr/local
make && make install
8.4.4.2.4.报错解决
Use IPv4 devconf : No
Use iptables : Yes
Use libiptc : No
Use libipset : No
Use nftables : No
init type : systemd
Strict config checks : No
Build genhash : Yes
Build documentation : No
*** WARNING - this build will not support IPVS with IPv6. Please install libnl/libnl-3 dev libraries to support IPv6 with IPVS.
# 解决报错
yum -y install libnl libnl-devel
8.4.4.3.keepalived的系统配置文件和系统配置脚本
/etc/keepalived/keepalived.conf
(keepalived的系统配置文件
,我们主要操作的就是该文件)/usr/local/sbin
目录下的keepalived
,是系统配置脚本
,用来启动和关闭keepalived
cd /etc/keepalived
cp /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.bak
vi /etc/keepalived/keepalived.conf
cd /usr/local/sbin
./keepalived -v
8.4.5.Keepalived配置文件介绍
8.4.5.1.打开keepalived.conf配置文件
这里面会分三部,第一部分是global全局配置
、第二部分是vrrp相关配置
、第三部分是LVS相关配置
。
本次主要是使用keepalived实现高可用部署,没有用到LVS
cd /etc/keepalived
vi /etc/keepalived/keepalived.conf
cd /usr/local/sbin
8.4.5.2.global全局配置
global全局部分:
global_defs {
#通知邮件,当keepalived发送切换时需要发email给具体的邮箱地址
notification_email {
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
#设置发件人的邮箱信息
notification_email_from Alexandre.Cassen@firewall.loc
#指定smpt服务地址
smtp_server 192.168.229.1
#指定smpt服务连接超时时间
smtp_connect_timeout 30
#运行keepalived服务器的一个标识,可以用作发送邮件的主题信息
router_id LVS_DEVEL
#默认是不跳过检查。检查收到的VRRP通告中的所有地址可能会比较耗时,设置此命令的意思是,如果通告与接收的上一个通告来自相同的master路由器,则不执行检查(跳过检查)
vrrp_skip_check_adv_addr
#严格遵守VRRP协议。
vrrp_strict
#在一个接口发送的两个免费ARP之间的延迟。可以精确到毫秒级。默认是0
vrrp_garp_interval 0
#在一个网卡上每组na消息之间的延迟时间,默认为0
vrrp_gna_interval 0
}
8.4.5.3.vrrp相关配置
VRRP部分,该部分可以包含以下四个子模块
1. vrrp_script
2. vrrp_sync_group
3. garp_group
4. vrrp_instance
我们会用到第一个和第四个,
#设置keepalived实例的相关信息,VI_1为VRRP实例名称
vrrp_instance VI_1 {
state MASTER #有两个值可选MASTER主 BACKUP备
interface ens33 #vrrp实例绑定的接口,用于发送VRRP包[当前服务器使用的网卡名称]
virtual_router_id 51#指定VRRP实例ID,范围是0-255
priority 100 #指定优先级,优先级高的将成为MASTER
advert_int 1 #指定发送VRRP通告的间隔,单位是秒
authentication { #vrrp之间通信的认证信息
auth_type PASS #指定认证方式。PASS简单密码认证(推荐)
auth_pass 1111 #指定认证使用的密码,最多8位
}
virtual_ipaddress { #虚拟IP地址设置虚拟IP地址,供用户访问使用,可设置多个,一行一个
192.168.229.222 #指定虚拟ip,自己定义的虚拟ip
}
}
8.4.5.4.服务器1配置内容如下:
global_defs {
notification_email {
tom@itcast.cn
jerry@itcast.cn
}
notification_email_from zhaomin@itcast.cn
smtp_server 192.168.229.1
smtp_connect_timeout 30
router_id keepalived1
vrrp_skip_check_adv_addr
vrrp_strict
vrrp_garp_interval 0
vrrp_gna_interval 0
}
vrrp_instance VI_1 {
state MASTER
interface ens33
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.229.222
}
}
8.4.5.5.服务器2配置内容如下:
! Configuration File for keepalived
global_defs {
notification_email {
tom@itcast.cn
jerry@itcast.cn
}
notification_email_from zhaomin@itcast.cn
smtp_server 192.168.229.1
smtp_connect_timeout 30
router_id keepalived2
vrrp_skip_check_adv_addr
vrrp_strict
vrrp_garp_interval 0
vrrp_gna_interval 0
}
vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 51
priority 90
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.229.222
}
}
8.4.5.6.访问测试
8.4.5.6.1. 启动keepalived之前,咱们先使用命令 ip a
,查看192.168.229.136和192.168.229.137这两台服务器的IP情况。
ip a
8.4.5.6.2. 分别启动两台服务器的keepalived
cd /usr/local/sbin
./keepalived
再次通过 ip a
查看ip
ip a
8.4.5.6.3. 当把192.168.229.136服务器上的keepalived关闭后,再次查看ip
ps -ef | grep keepalived
通过上述的测试,我们会发现,虚拟IP(VIP)会在MASTER节点上
,当MASTER节点上的keepalived出问题以后
,因为BACKUP
无法收到MASTER发出的VRRP状态通过信息
,就会直接升为MASTER
。VIP也会"漂移"到新的MASTER
。
8.4.5.6.4.上面测试和Nginx有什么关系?
我们把192.168.229.136
服务器的keepalived再次启动
下,由于它的优先级高
于服务器192.168.229.122的,所有它会再次成为MASTER
,VIP也会"漂移"过去,然后我们再次通过浏览器访问:
http://192.168.229.222/
8.4.5.6.5.解决问题:如何在服务器上让keepalived 的虚拟IP可以网络访问
在宿主机上配置keepalived 启动成功后,创建虚拟IP访问不了
确保防火墙关闭还是访问不了虚拟IP 192.168.229.222
# 增加一条iptables策略,iptables对虚拟服务ip彻底放行
iptables -t nat -A PREROUTING -p tcp -d 虚拟服务ip --dport 80 -j REDIRECT
ip a
systemctl stop firewalld
systemctl status firewalld
iptables -t nat -A PREROUTING -p tcp -d 192.168.229.222 --dport 80 -j REDIRECT
8.4.5.6.6.如果把192.168.229.136服务器的keepalived关闭掉,再次访问相同的地址
效果实现了以后, 我们会发现要想让vip进行切换,就必须要把服务器上的keepalived进行关闭,而什么时候关闭keepalived呢?应该是在keepalived所在服务器的nginx出现问题后,把keepalived关闭掉,就可以让VIP执行另外一台服务器,但是现在这所有的操作都是通过手动来完成的,我们如何能让系统自动判断当前服务器的nginx是否正确启动,如果没有,要能让VIP自动进行"漂移",这个问题该如何解决?
8.4.6.Keepalived之自动切换脚本实现【keepalived之vrrp_script】
keepalived
只能做到对网络故障和keepalived本身的监控
,即当出现网络故障或者keepalived本身出现问题时,进行切换。但是这些还不够,我们还需要监控keepalived所在服务器上的其他业务,比如Nginx,如果Nginx出现异常
了,仅仅keepalived保持正常,是无法完成系统的正常工作的,因此需要根据业务进程的运行状态决定是否需要进行主备切换,这个时候,我们可以通过编写脚本对业务进程进行检测监控
。
实现步骤:
8.4.6.1. 在keepalived配置文件中添加对应的配置像
vrrp_script 脚本名称
{
script "脚本位置"
interval 3 #执行时间间隔3秒
weight -20 #动态调整vrrp_instance的优先级
}
8.4.6.2. 编写脚本
ck_nginx.sh
#!/bin/bash
num=`ps -C nginx --no-header | wc -l` # 计算nginx进程行数
if [ $num -eq 0 ];then # 判断nginx进程行数是否等于0
/usr/local/nginx/sbin/nginx # 等于0启动nginx
sleep 2 # 睡上2秒
if [ `ps -C nginx --no-header | wc -l` -eq 0 ]; then # 再次判断nginx进程行数是否等于0
killall keepalived # 如果报错 杀死keepalived进程
fi
fi
Linux ps命令用于显示当前进程 (process) 的状态。
-C(command) :指定命令的所有进程
--no-header 排除标题
8.4.6.3. 为脚本文件设置权限
chmod 755 ck_nginx.sh
8.4.6.4. 将脚本添加到
vrrp_script ck_nginx {
script "/etc/keepalived/ck_nginx.sh" #执行脚本的位置
interval 2 #执行脚本的周期,秒为单位
weight -20 #权重的计算方式
}
vrrp_instance VI_1 {
state MASTER
interface ens33
virtual_router_id 10
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.229.111
}
track_script {
ck_nginx
}
}
8.4.6.5. 如果效果没有出来,可以使用 tail -f /var/log/messages
查看日志信息,找对应的错误信息。
8.4.6.6. 测试
8.4.6.7. 模拟136Nginx服务器宕机效果测试
8.4.6.8.问题思考:
通常如果master服务死掉后backup会变成master,但是当master服务又好了的时候 master此时会抢占VIP,这样就会发生两次切换对业务繁忙的网站来说是不好的
。所以我们要在配置文件加入 nopreempt 非抢占,但是这个参数只能用于state 为backup,故我们在用HA的时候最好master 和backup的state都设置成backup 让其通过priority来竞争。
九、Nginx制作在线下载站点【模块ngx_http_autoindex_module】
9.1.下载站点
我们先来看一个网站http://nginx.org/download/
这个我们刚开始学习Nginx的时候给大家看过这样的网站,该网站主要就是用来提供用户来下载相关资源的网站
,就叫做下载网站
。
9.2.如何制作一个下载站点:
nginx使用的是模块ngx_http_autoindex_module
来实现的,该模块处理以斜杠("/")结尾的请求,并生成目录列表。
nginx编译的时候会自动加载该模块,但是该模块默认是关闭的
,我们需要使用下来指令来完成对应的配置
9.2.1.autoindex:启用或禁用目录列表输出
语法 | autoindex on\ | off; |
---|---|---|
默认值 | autoindex off; | |
位置 | http、server、location |
9.2.2.autoindex_exact_size:对应HTLM格式,指定是否在目录列表展示文件的详细大小
默认为on,显示出文件的确切大小,单位是bytes。
改为off后,显示出文件的大概大小,单位是kB或者MB或者GB
语法 | autoindex_exact_size on\ | off; |
---|---|---|
默认值 | autoindex_exact_size on; | |
位置 | http、server、location |
9.2.3.autoindex_format:设置目录列表的格式
语法 | autoindex_format html\ | xml\ | json\ | jsonp; |
---|---|---|---|---|
默认值 | autoindex_format html; | |||
位置 | http、server、location |
注意:该指令在1.7.9及以后版本中出现
9.2.4.autoindex_localtime:对应HTML格式,是否在目录列表上显示时间。
默认为off,显示的文件时间为GMT时间。
改为on后,显示的文件时间为文件的服务器时间
语法 | autoindex_localtime on \ | off; |
---|---|---|
默认值 | autoindex_localtime off; | |
位置 | http、server、location |
9.3.资源准备
9.4.Nginx配置方式如下:
location /download{
root /usr/local;
autoindex on;
autoindex_exact_size on;
autoindex_format html;
autoindex_localtime on;
}
XML/JSON格式[一般不用这两种方式]
9.5.下载站点测试成功
十、Nginx的用户认证模块【ngx_http_auth_basic_module模块】
对应系统资源的访问,我们往往需要限制谁能访问,谁不能访问。这块就是我们通常所说的认证部分,认证需要做的就是根据用户输入的用户名和密码来判定用户是否为合法用户,如果是则放行访问,如果不是则拒绝访问。
Nginx对应用户认证
这块是通过ngx_http_auth_basic_module模块
来实现的,它允许通过使用"HTTP基本身份验证"协议验证用户名和密码来限制对资源的访问。默认
情况下nginx是已经安装了该模块
,如果不需要则使用--without-http_auth_basic_module
。
10.1.auth_basic:使用“ HTTP基本认证”协议启用用户名和密码的验证
语法 | auth_basic string\ | off; |
---|---|---|
默认值 | auth_basic off; | |
位置 | http,server,location,limit_except |
开启后,服务端会返回401
,指定的字符串会返回到客户端,给用户以提示信息,但是不同的浏览器对内容的展示不一致。
10.2.auth_basic_user_file:指定用户名和密码所在文件
语法 | auth_basic_user_file file; |
---|---|
默认值 | — |
位置 | http,server,location,limit_except |
指定文件路径,该文件中的用户名和密码的设置,密码需要进行加密。可以采用工具自动生成
10.3.实现步骤:nginx.conf添加如下内容
location /download{
root /usr/local;
autoindex on;
autoindex_exact_size on;
autoindex_format html;
autoindex_localtime on;
auth_basic 'please input your auth';
auth_basic_user_file htpasswd;
}
10.4.使用htpasswd
工具生成用户名和密码
yum install -y httpd-tools
htpasswd -c /usr/local/nginx/conf/htpasswd username //创建一个新文件记录用户名和密码
htpasswd -b /usr/local/nginx/conf/htpasswd username password //在指定文件新增一个用户名和密码
htpasswd -D /usr/local/nginx/conf/htpasswd username //从指定文件删除一个用户信息
htpasswd -v /usr/local/nginx/conf/htpasswd username //验证用户名和密码是否正确
10.5.测试
上述方式虽然能实现用户名和密码的验证,但是所有的用户名和密码信息都记录在文件里面,如果用户量过大的话,这种方式就显得有点麻烦,这时候我们就得通过后台业务代码来进行用户权限的校验。
十一、Nginx的扩展模块【ngx_lua模块环境准备】
Nginx是可扩展的,可用于处理各种使用场景。使用Lua扩展Nginx的功能。
ngx_lua模块概念
:淘宝开发的ngx_lua模块通过将lua解释器集成进Nginx,可以采用lua脚本实现业务逻辑,由于lua的紧凑、快速以及内建协程,所以在保证高并发服务能力的同时极大地降低了业务逻辑实现成本。
11.1.方式一:lua-nginx-module
11.1.1. LuaJIT是采用C语言编写的Lua代表的解释器
官网地址为:http://luajit.org/
git下载:https://github.com/LuaJIT/LuaJIT/tags
在官网上找到对应的下载地址:http://luajit.org/download/LuaJIT-2.0.5.tar.gz
在centos上使用wget来下载:
mkdir -p /lua/core
cd /lua/core
wget http://luajit.org/download/LuaJIT-2.0.5.tar.gz
将下载的资源进行解压:
tar -zxf LuaJIT-2.0.5.tar.gz
进入解压的目录:
cd LuaJIT-2.0.5
执行编译和安装:
make PREFIX=/usr/local/luajit
make install
测试:
luajit -v
11.1.2.下载lua-nginx-module
下载地址:https://github.com/openresty/lua-nginx-module/tags
11.1.2.1.在centos上使用wget来下载:
wget https://github.com/openresty/lua-nginx-module/archive/refs/tags/v0.10.14.tar.gz
11.1.2.2.将下载的资源进行解压:
tar -zxf lua-nginx-module-0.10.14.tar.gz
11.1.2.3.更改目录名:
mv lua-nginx-module-0.10.14 lua-nginx-module
11.1.2.4.导入环境变量
告诉Nginx去哪里找luajit
vi /etc/profile
export LUAJIT_LIB=/usr/local/lib
export LUAJIT_INC=/usr/local/include/luajit-2.0
source /etc/profile
11.1.2.5.进入Nginx的目录执行如下命令:
./configure --prefix=/usr/local/nginx \
--sbin-path=/usr/local/nginx/sbin/nginx \
--modules-path=/usr/local/nginx/modules \
--conf-path=/usr/local/nginx/conf/nginx.conf \
--error-log-path=/usr/local/nginx/logs/error.log \
--http-log-path=/usr/local/nginx/logs/access.log \
--pid-path=/usr/local/nginx/logs/nginx.pid \
--lock-path=/usr/local/nginx/logs/nginx.lock \
--with-http_gzip_static_module \
--with-http_ssl_module \
--with-stream \
--add-module=/nginx/module/fair \
--add-module=/nginx/module/purge \
--add-module=/nginx/module/lua-nginx-module
11.1.2.6.安装
make && make install
11.1.2.7.如果启动Nginx出现如下错误:
error while loading shared libraries: libluajit-5.1.so.2: cannot open shared object file: No such file or directory
解决方案:
设置软链接,使用如下命令
ln -s /usr/local/lib/libluajit-5.1.so.2 /lib64/libluajit-5.1.so.2
11.1.2.8.如果启动Nginx出现以下错误信息
[root@localhost sbin]# ./nginx
nginx: [warn] lua_load_resty_core is deprecated (the lua-resty-core library is required since ngx_lua v0.10.16) in /usr/local/nginx/conf/nginx.conf:13
nginx: [alert] detected a LuaJIT version which is not OpenResty's; many optimizations will be disabled and performance will be compromised (see https://github.com/openresty/luajit2 for OpenResty's LuaJIT or, even better, consider using the OpenResty releases from https://openresty.org/en/download.html)
nginx: [alert] failed to load the 'resty.core' module (https://github.com/openresty/lua-resty-core); ensure you are using an OpenResty release from https://openresty.org/en/download.html (reason: module 'resty.core' not found:
no field package.preload['resty.core']
no file './resty/core.lua'
no file '/usr/local/luajit/share/luajit-2.0.5/resty/core.lua'
no file '/usr/local/share/lua/5.1/resty/core.lua'
no file '/usr/local/share/lua/5.1/resty/core/init.lua'
no file '/usr/local/luajit/share/lua/5.1/resty/core.lua'
no file '/usr/local/luajit/share/lua/5.1/resty/core/init.lua'
no file './resty/core.so'
no file '/usr/local/lib/lua/5.1/resty/core.so'
no file '/usr/local/luajit/lib/lua/5.1/resty/core.so'
no file '/usr/local/lib/lua/5.1/loadall.so'
no file './resty.so'
no file '/usr/local/lib/lua/5.1/resty.so'
no file '/usr/local/luajit/lib/lua/5.1/resty.so'
no file '/usr/local/lib/lua/5.1/loadall.so') in /usr/local/nginx/conf/nginx.conf:71
这个问题到git上面看了 ,https://github.com/openresty/lua-nginx-module/issues/1509
就是在nginx.conf 中的 http{}模块中加入下面这行代码:lua_load_resty_core off;但是检查的时候发现这命令已经废弃
分析原因:因为lua-nginx-module是来自openrestry,错误中提示的resty.core是openrestry的核心模块,对其下的很多函数进行了优化等工作。以前的版本默认不会把该模块编译进去,所以需要使用的话,我们得手动安装,或者禁用就可以。但是最新的lua-nginx-module模块已经强制性安装了该模块,所以此处因为缺少resty模块导致的报错信息。使用低版本lua-nginx-module-0.10.14方可解决
解决方案有两个:一种是下载对应的模块,另一种则是禁用掉restry模块
,禁用的方式为:在nginx.conf
的http模块设置 lua_load_resty_core off来禁用
http{
lua_load_resty_core off;
}
11.1.2.9.干脆直接用openresty
nginx: [alert] detected a LuaJIT version which is not OpenResty's;
many optimizations will be disabled and performance will be compromised
(see https://github.com/openresty/luajit2 for OpenResty's LuaJIT or, even better,
consider using the OpenResty releases from https://openresty.org/en/download.html)
让我不要用这个luajit版本,可以用openresty提供的luajit优化版本,或者干脆直接用openresty
卸载luajit官网版本,下载openresty提供的luajit优化版本
11.1.2.10.make报错修改ngx_http_lua_headers_in.c文件
‘ngx_http_headers_in_t’没有名为‘cookies’的成员
In file included from /usr/include/dlfcn.h:25:0,
from src/os/unix/ngx_linux_config.h:58,
from src/core/ngx_config.h:26,
from /nginx/module/lua-nginx-module/src/ddebug.h:11,
from /nginx/module/lua-nginx-module/src/ngx_http_lua_headers_in.c:10:
/nginx/module/lua-nginx-module/src/ngx_http_lua_headers_in.c:162:18: 错误:‘ngx_http_headers_in_t’没有名为‘cookies’的成员
offsetof(ngx_http_headers_in_t, cookies),
^
make[1]: *** [objs/addon/src/ngx_http_lua_headers_in.o] 错误 1
make[1]: 离开目录“/nginx/core/nginx-1.24.0”
make: *** [build] 错误 2
vi /nginx/module/lua-nginx-module/src/ngx_http_lua_headers_in.c
11.1.2.11.测试
在nginx.conf下配置如下内容:
location /lua{
default_type 'text/html';
content_by_lua 'ngx.say("<h1>HELLO,LUA</h1>")';
}
配置成功后,启动nginx,通过浏览器进行访问,如果获取到如下结果,则证明安装成功。
11.2.方式二:OpenRestry
11.2.1.概述
OpenResty是由淘宝工程师开发的,所以其官方网站(http://openresty.org/)我们读起来是非常的方便。OpenResty是一个基于Nginx与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。所以本身OpenResty内部就已经集成了Nginx和Lua,所以我们使用起来会更加方便。
11.2.2.下载OpenResty:
https://openresty.org/download/openresty-1.25.3.1.tar.gz
11.2.3.使用wget下载:
mkdir -p /openresty/core
cd /openresty/core
wget https://openresty.org/download/openresty-1.25.3.1.tar.gz
11.2.4.解压缩:
tar -zxf openresty-1.25.3.1.tar.gz
11.2.5.进入OpenResty目录:
cd openresty-1.25.3.1
11.2.6.编译和安装
./configure
make && make install
cd nginx-1.25.3
sh ./configure --prefix=/usr/local/openresty/nginx \
--with-cc-opt='-O2' \
--add-module=../ngx_devel_kit-0.3.3 \
--add-module=../echo-nginx-module-0.63 \
--add-module=../xss-nginx-module-0.06 \
--add-module=../ngx_coolkit-0.2 \
--add-module=../set-misc-nginx-module-0.33 \
--add-module=../form-input-nginx-module-0.12 \
--add-module=../encrypted-session-nginx-module-0.09 \
--add-module=../srcache-nginx-module-0.33 \
--add-module=../ngx_lua-0.10.26 \
--add-module=../ngx_lua_upstream-0.07 \
--add-module=../headers-more-nginx-module-0.37 \
--add-module=../array-var-nginx-module-0.06 \
--add-module=../memc-nginx-module-0.20 \
--add-module=../redis2-nginx-module-0.15 \
--add-module=../redis-nginx-module-0.3.9 \
--add-module=../rds-json-nginx-module-0.16 \
--add-module=../rds-csv-nginx-module-0.09 \
--add-module=../ngx_stream_lua-0.0.14 \
--with-ld-opt='-Wl,-rpath,/usr/local/openresty/luajit/lib' \
--with-stream --without-pcre2 --with-stream_ssl_module --with-stream_ssl_preread_module --with-http_ssl_module
11.2.7.进入OpenResty的目录,找到nginx:
cd /usr/local/openresty/nginx/
11.2.8.在conf目录下的nginx.conf添加如下内容
location /lua{
default_type 'text/html';
content_by_lua 'ngx.say("<h1>HELLO,OpenRestry</h1>")';
}
11.2.9.在sbin目录下启动nginx
11.2.10.通过浏览器访问测试
11.2.11.设置环境变量
vim /etc/profile
# openresty
export PATH=$PATH:/usr/local/openresty/nginx/sbin
# 输入下面命令让设置的环境变量生效
source /etc/profile
# 查看版本信息
nginx -V
11.2.12.openresty安装成系统服务
# 创建脚本
vi /usr/lib/systemd/system/openresty.service
# 重新加载系统服务
systemctl daemon-reload
服务脚本内容
[Unit]
Description=openresty web service
Documentation=https://openresty.org/cn/
After=network.target
[Service]
Type=forking
PIDFile=/usr/local/openresty/nginx/logs/nginx.pid
ExecStartPre=/usr/local/openresty/nginx/sbin/nginx -t -c /usr/local/openresty/nginx/conf/nginx.conf
ExecStart=/usr/local/openresty/nginx/sbin/nginx
ExecReload=/usr/local/openresty/nginx/sbin/nginx -s reload
ExecStop=/usr/local/openresty/nginx/sbin/nginx -s stop
PrivateTmp=true
[Install]
WantedBy=default.target
[Unit]:服务的说明
Description:描述服务
After:描述服务类别
[Service]服务运行参数的设置
Type=forking是后台运行的形式ExecStartpre是检查配置文件
ExecStart为服务的具体运行命令
ExecReload为重启命令
ExecStop为停止命令
PrivateTmp=True表示给服务分配独立的临时空间
注意:[Service]的启动、重启、停止命令全部要求使用绝对路径
[Install]运行级别下服务安装的相关设置,可设置为多用户,即系统运行级别为3
11.2.13.openresty常用命令
# 启动服务
systemctl start openresty
#停止
systemctl stop openresty
#重启
systemctl restart openresty
#重新加载配置文件
systemctl reload openresty
# 查看nginx状态
systemctl status openresty
# 开机启动
systemctl enable openresty.service
# 查看nginx是否启动
ps -ef | grep openresty
十二、ngx_lua的使用
指令执行的顺序
使用Lua编写Nginx脚本的基本构建块是指令。指令用于指定何时运行用户Lua代码以及如何使用结果。下图显示了执行指令的顺序
。
解释下*的作用
*:无 , 即 xxx_by_lua ,指令后面跟的是 lua指令
*:_file,即 xxx_by_lua_file 指令后面跟的是 lua文件
*:_block,即 xxx_by_lua_block 在0.9.17版后替换init_by_lua_file
init_by_lua*
该指令在每次Nginx重新加载配置时执行,可以用来完成一些耗时模块的加载,或者初始化一些全局配置。
init_worker_by_lua*
该指令用于启动一些定时任务,如心跳检查、定时拉取服务器配置等。
set_by_lua*
该指令只要用来做变量赋值,这个指令一次只能返回一个值,并将结果赋值给Nginx中指定的变量。
rewrite_by_lua*
该指令用于执行内部URL重写或者外部重定向,典型的如伪静态化URL重写,本阶段在rewrite处理阶段的最后默认执行。
access_by_lua*
该指令用于访问控制。例如,如果只允许内网IP访问。
content_by_lua*
该指令是应用最多的指令,大部分任务是在这个阶段完成的,其他的过程往往为这个阶段准备数据,正式处理基本都在本阶段。
header_filter_by_lua*
该指令用于设置应答消息的头部信息。
body_filter_by_lua*
该指令是对响应数据进行过滤,如截断、替换。
log_by_lua*
该指令用于在log请求处理阶段,用Lua代码处理日志,但并不替换原有log处理。
balancer_by_lua*
该指令主要的作用是用来实现上游服务器的负载均衡器算法
ssl_certificate_by_*
该指令作用在Nginx和下游服务开始一个SSL握手操作时将允许本配置项的Lua代码。
需求:
http://192.168.229.136?name=张三&gender=1
Nginx接收到请求后,根据gender传入的值,如果gender传入的是1,则在页面上展示
张三先生,如果gender传入的是0,则在页面上展示张三女士,如果未传或者传入的不是1和2则在页面上展示张三。
实现代码
location /getByGender {
default_type 'text/html';
#set_by_lua
set_by_lua $param "
-- 获取请求url上的参数对应值 name gender
local uri_args = ngx.req.get_uri_args()
local name = uri_args['name']
local gender = uri_args['gender']
-- 条件判断 if gender 1 先生 0 女生
if gender == '1' then
return name..'先生'
elseif gender == '0' then
return name..'女士'
else
return name
end
";
header_filter_by_lua "
ngx.header.aaa='bbb'
";
charset utf-8;
return 200 $param;
}
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
location /getByGender {
default_type 'text/html';
#set_by_lua
set_by_lua $param "
-- 获取请求url上的参数对应值 name gender
local uri_args = ngx.req.get_uri_args()
local name = uri_args['name']
local gender = uri_args['gender']
-- 条件判断 if gender 1 先生 0 女生
if gender == '1' then
return name..'先生'
elseif gender == '0' then
return name..'女士'
else
return name
end
";
charset utf-8;
return 200 $param;
}
location /lua{
default_type 'text/html';
content_by_lua 'ngx.say("<h1>HELLO,OpenRestry</h1>")';
}
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
测试
http://192.168.229.136/getByGender?name=TOM&gender=0
http://192.168.229.136/getByGender?name=TOM&gender=1
十三、ngx_lua操作Redis
13.1.介绍
Redis
在系统中经常作为数据缓存
、内存数据库使用
,在大型系统中扮演着非常重要的作用。
在Nginx核心系统中,Redis是常备组件。
Nginx支持3种方法访问Redis,分别是HttpRedis模块
、HttpRedis2Module
、lua-resty-redis库
。
这三种方式中HttpRedis模块提供的指令少,功能单一,适合做简单缓存,HttpRedis2Module模块
比HttpRedis模块操作更灵活,功能更强大。
而Lua-resty-redis库
是OpenResty
提供的一个操作Redis的接口库,可根据自己的业务情况做一些逻辑处理,适合做复杂的业务逻辑。
13.2.lua-resty-redis环境准备
13.2.1.准备一个Redis环境【安装Redis】
连接地址
host= 192.168.229.137
port=6379
13.2.2.准备对应的API
lua-resty-redis提供了访问Redis的详细API,包括创建对接、连接、操作、数据处理等。这些API基本上与Redis的操作一一对应。
(1)redis = require "resty.redis"
(2)new
创建一个Redis对象,遇到错误时,redis为nil,err为错误描述信息
语法: redis,err = redis:new(),创建一个Redis对象。
(3)connect
语法:ok,err=redis:connect(host,port[,options_table]),设置连接Redis的连接信息。
ok:连接成功返回 1,连接失败返回nil
err:返回对应的错误信息
(4)set_timeout
语法: redis:set_timeout(time) ,设置请求操作Redis的超时时间。
(5)close
语法: ok,err = redis:close(),关闭当前连接,成功返回1,失败返回nil和错误信息
(6)redis命令对应的方法
在lua-resty-redis中,所有的Redis命令都有自己的方法,方法名字和命令名字相同,只是全部为小写。
13.2.3.步骤
-- 引入Redis对应的接口对象
-- 创建一个Redis对象
-- 设置超时时间
-- 获取连接
-- 往Redis中存储数据
-- 从Redis中获取数据
-- 关闭连接
13.2.4.效果实现
location / {
default_type "text/html";
content_by_lua_block{
local redis = require "resty.redis" -- 引入Redis对应的接口对象
local redisObj = redis:new() -- 创建一个Redis对象
redisObj:set_timeout(1000) -- 设置超时时间1s
local ok,err = redisObj:connect("192.168.229.137",6379) -- 设置redis连接信息
if not ok then -- 判断是否连接成功
ngx.say("failed to connection redis",err)
return
end
ok,err = redisObj:set("username","TOM")-- 往Redis中存储数据
if not ok then -- 判断是否存入成功
ngx.say("failed to set username",err)
return
end
local res,err = redisObj:get("username") -- 从redis中获取数据
ngx.say(res) -- 将数据写会消息体中
redisObj:close() -- 关闭连接
}
}
13.2.5.运行测试效果
http://192.168.229.136/testRedis
十四、ngx_lua操作Mysql
14.1.介绍
MySQL是一个使用广泛的关系型数据库
。在ngx_lua中,MySQL有两种访问模式,分别是使
(1)用ngx_lua模块和lua-resty-mysql
模块:这两个模块是安装OpenResty时默认安装
的。
(2)使用drizzle_nginx_module(HttpDrizzleModule)模块:需要单独安装,这个库现不在OpenResty中。
14.2.lua-resty-mysql
lua-resty-mysql是OpenResty开发的模块,使用灵活、功能强大,适合复杂的业务场景,同时支持存储过程的访问。
14.3.使用lua-resty-mysql实现数据库的查询
14.3.1.准备一个Mysql环境【安装Mysql】
host: 192.168.229.137
port: 3306
username:root
password:123456
14.3.2.创建一个数据库表及表中的数据
create database nginx_db;
use nginx_db;
create table users(
id int primary key auto_increment,
username varchar(30),
birthday date,
salary double
);
insert into users(id,username,birthday,salary) values(null,"TOM","1988-11-11",10000.0);
insert into users(id,username,birthday,salary) values(null,"JERRY","1989-11-11",20000.0);
insert into users(id,username,birthday,salary) values(null,"ROWS","1990-11-11",30000.0);
insert into users(id,username,birthday,salary) values(null,"LUCY","1991-11-11",40000.0);
insert into users(id,username,birthday,salary) values(null,"JACK","1992-11-11",50000.0);
14.3.3.数据库连接四要素:
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://192.168.200.111:3306/nginx_db
username=root
password=123456
14.4.API学习
(1)引入"resty.mysql"模块
local mysql = require "resty.mysql"
(2)new
创建一个MySQL连接对象,遇到错误时,db为nil,err为错误描述信息
语法: db,err = mysql:new()
(3)connect
尝试连接到一个MySQL服务器
语法:ok,err=db:connect(options),options是一个参数的Lua表结构,里面包含数据库连接的相关信息
host:服务器主机名或IP地址
port:服务器监听端口,默认为3306
user:登录的用户名
password:登录密码
database:使用的数据库名
(4)set_timeout
设置子请求的超时时间(ms),包括connect方法
语法:db:set_timeout(time)
(5)close
关闭当前MySQL连接并返回状态。如果成功,则返回1;如果出现任何错误,则将返回nil和错误描述。
语法:db:close()
(6)send_query
异步向远程MySQL发送一个查询。如果成功则返回成功发送的字节数;如果错误,则返回nil和错误描述
语法:bytes,err=db:send_query(sql)
(7)read_result
从MySQL服务器返回结果中读取一行数据。res返回一个描述OK包或结果集包的Lua表,语法:
res, err, errcode, sqlstate = db:read_result()
res, err, errcode, sqlstate = db:read_result(rows) :rows指定返回结果集的最大值,默认为4
如果是查询,则返回一个容纳多行的数组。每行是一个数据列的key-value对,如
{
{id=1,username="TOM",birthday="1988-11-11",salary=10000.0},
{id=2,username="JERRY",birthday="1989-11-11",salary=20000.0}
}
如果是增删改,则返回类上如下数据
{
insert_id = 0,
server_status=2,
warning_count=1,
affected_rows=2,
message=nil
}
返回值:
res:操作的结果集
err:错误信息
errcode:MySQL的错误码,比如1064
sqlstate:返回由5个字符组成的标准SQL错误码,比如42000
14.5.步骤
-- 引入resty.mysql
-- 创建连接对象 new
-- 建立连接 传入数据库连接的相关信息
-- 判断是否连接成功
-- 设置超时时间 set_timeout
-- 发送SQL语句
-- 读取返回的结果,并且把结果输出到页面
-- 关闭连接
14.6.效果实现--查询单个数据
location /{
content_by_lua_block{
local mysql = require "resty.mysql"
local db = mysql:new()
local ok,err = db:connect{
host="192.168.200.111",
port=3306,
user="root",
password="123456",
database="nginx_db"
}
db:set_timeout(1000)
db:send_query("select * from users where id =1")
local res,err,errcode,sqlstate = db:read_result()
ngx.say(res[1].id..","..res[1].username..","..res[1].birthday..","..res[1].salary)
db:close()
}
}
14.7.测试
http://192.168.229.136/testMysql
14.8.查询多行数据并显示
db:send_query("select * from users")
-- 读取返回的结果,并且把结果输出到页面
local res,err,errcode,sqlstate = db:read_result()
for i,v in ipairs(res) do
ngx.say(v.id..","..v.username..","..v.birthday..","..v.salary.."<br>")
end
14.8.问题
1.如何获取返回数据的内容
2.如何实现查询多条数据
3.如何实现数据库的增删改操作
14.9.使用lua-cjson处理查询结果--返回JSON字符串
read_result()得到的结果res都是table类型,要想在页面上展示,就必须知道table的具体数据结构才能进行遍历获取。处理起来比较麻烦,接下来我们介绍一种简单方式cjson,使用它就可以将table类型的数据转换成json字符串,把json字符串展示在页面上即可。具体如何使用?
14.9.1.引入cjson
local cjson = require "cjson"
14.9.2.调用cjson的encode方法进行类型转换
cjson.encode(res)
14.9.3.使用
location /{
content_by_lua_block{
local mysql = require "resty.mysql"
local cjson = require "cjson"
local db = mysql:new()
local ok,err = db:connect{
host="192.168.200.111",
port=3306,
user="root",
password="123456",
database="nginx_db"
}
db:set_timeout(1000)
db:send_query("select * from users")
local res,err,errcode,sqlstate = db:read_result()
ngx.say(cjson.encode(res))
db:close()
}
}
14.9.4.测试
14.9.5.cjson定义为全局变量--防止重复代码
init_by_lua_block{
cjson = require "cjson" -- 引入cjson
}
server {
listen 80;
server_name localhost;
location /testMysql {
default_type "text/html";
content_by_lua_block{
-- 引入cjson
-- local cjson = require "cjson"
-- 引入resty.mysql
local mysql = require "resty.mysql"
-- 创建连接对象 new
local db = mysql:new()
-- 建立连接 传入数据库连接的相关信息
local ok,err = db:connect{
host = "192.168.229.137",
port = 3306,
user = "root",
password = "123456",
database = "nginx_db"
}
if not ok then -- 判断是否连接成功
ngx.say("faild to connect mysql",err)
return
end
-- 设置超时时间 set_timeout
db:set_timeout(1000)
-- 发送SQL语句
db:send_query("select * from users")
-- 读取返回的结果,并且把结果输出到页面
local res,err,errcode,sqlstate = db:read_result()
-- ngx.say(res[1].id..","..res[1].username..","..res[1].birthday..","..res[1].salary)
--[[for i,v in ipairs(res) do
ngx.say(v.id..","..v.username..","..v.birthday..","..v.salary.."<br>")
end--]]
ngx.say(cjson.encode(res))
-- 关闭连接
db:close()
}
}
14.10.lua-resty-mysql实现数据库的增删改
14.10.1.优化send_query和read_result
本方法是send_query和read_result组合的快捷方法。
语法:
res, err, errcode, sqlstate = db:query(sql[,rows])
14.10.2.优化代码
location /{
content_by_lua_block{
local mysql = require "resty.mysql"
local db = mysql:new()
local ok,err = db:connect{
host="192.168.229.137",
port=3306,
user="root",
password="123456",
database="nginx_db",
max_packet_size=1024,
compact_arrays=false
}
db:set_timeout(1000)
local res,err,errcode,sqlstate = db:query("select * from users")
--local res,err,errcode,sqlstate = db:query("insert into users(id,username,birthday,salary) values(null,'zhangsan','2020-11-11',32222.0)")
--local res,err,errcode,sqlstate = db:query("update users set username='lisi' where id = 6")
--local res,err,errcode,sqlstate = db:query("delete from users where id = 6")
db:close()
}
}
14.10.3.新增
14.10.4.修改
14.10.5.删除
14.11.lua_mysql_redis_nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
init_by_lua_block{
cjson = require "cjson" -- 引入cjson
}
server {
listen 80;
server_name localhost;
location /testMysql {
default_type "text/html";
content_by_lua_block{
-- 引入cjson
-- local cjson = require "cjson"
-- 引入resty.mysql
local mysql = require "resty.mysql"
-- 创建连接对象 new
local db = mysql:new()
-- 建立连接 传入数据库连接的相关信息
local ok,err = db:connect{
host = "192.168.229.137",
port = 3306,
user = "root",
password = "123456",
database = "nginx_db"
}
if not ok then -- 判断是否连接成功
ngx.say("faild to connect mysql",err)
return
end
-- 设置超时时间 set_timeout
db:set_timeout(1000)
-- 发送SQL语句
-- db:send_query("select * from users")
-- 读取返回的结果,并且把结果输出到页面
-- local res,err,errcode,sqlstate = db:read_result()
-- 查询
-- local sql = "select * from users"
-- 新增
-- local sql = "insert into users(username,birthday,salary) values ('zhangsan','2024-12-12',3334)"
-- 修改
-- local sql = "update users set username = 'lisi' where id = 6"
-- 删除
local sql = "delete from users where id = 6"
local res,err,errcode,sqlstate = db:query(sql)
-- ngx.say(res[1].id..","..res[1].username..","..res[1].birthday..","..res[1].salary)
--[[for i,v in ipairs(res) do
ngx.say(v.id..","..v.username..","..v.birthday..","..v.salary.."<br>")
end--]]
ngx.say(cjson.encode(res))
-- 关闭连接
db:close()
}
}
location /testRedis {
default_type "text/html";
content_by_lua_block{
-- 引入Redis对应的接口对象
local redis = require "resty.redis"
-- 创建一个Redis对象
local redisObj = redis:new()
-- 设置超时时间
redisObj:set_timeout(1000)
-- 获取连接
local ok,err = redisObj:connect("192.168.229.137",6379)
if not ok then
ngx.say("faild to connect redis",err)
return
end
-- 往Redis中存储数据
ok,err = redisObj:set("username","ROSE")
if not ok then
ngx.say("faild to connect username",err)
return
end
-- 从Redis中获取数据
local res,err = redisObj:get("username")
ngx.say(res)
-- 关闭连接
redisObj:close()
}
}
location /getByGender {
default_type 'text/html';
#set_by_lua
set_by_lua $param "
-- 获取请求url上的参数对应值 name gender
local uri_args = ngx.req.get_uri_args()
local name = uri_args['name']
local gender = uri_args['gender']
-- 条件判断 if gender 1 先生 0 女生
if gender == '1' then
return name..'先生'
elseif gender == '0' then
return name..'女士'
else
return name
end
";
header_filter_by_lua "
ngx.header.aaa='bbb'
";
charset utf-8;
return 200 $param;
}
location /lua{
default_type 'text/html';
content_by_lua 'ngx.say("<h1>HELLO,OpenRestry</h1>")';
}
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
十五、综合小案例---使用ngx_lua模块完成Redis缓存预热。
15.1.准备一张表(users)【上面】
15.2.浏览器输入如下地址
http://191.168.229.137?username=TOM
15.3.从表中查询出符合条件的记录,此时获取的结果为table类型
15.4.使用cjson将table数据转换成json字符串
15.5.将查询的结果数据存入Redis中
15.6.代码
init_by_lua_block{
redis = require "resty.redis"
mysql = require "resty.mysql"
cjson = require "cjson"
}
location /{
default_type "text/html";
content_by_lua_block{
--获取请求的参数username
local param = ngx.req.get_uri_args()["username"]
--建立mysql数据库的连接
local db = mysql:new()
local ok,err = db:connect{
host="192.168.200.111",
port=3306,
user="root",
password="123456",
database="nginx_db"
}
if not ok then
ngx.say("failed connect to mysql:",err)
return
end
--设置连接超时时间
db:set_timeout(1000)
--查询数据
local sql = ""
if not param then
sql="select * from users"
else
sql="select * from users where username=".."'"..param.."'"
end
local res,err,errcode,sqlstate=db:query(sql)
if not res then
ngx.say("failed to query from mysql:",err)
return
end
--连接redis
local rd = redis:new()
ok,err = rd:connect("192.168.200.111",6379)
if not ok then
ngx.say("failed to connect to redis:",err)
return
end
rd:set_timeout(1000)
--循环遍历数据
for i,v in ipairs(res) do
rd:set("user_"..v.username,cjson.encode(v))
end
ngx.say("success")
rd:close()
db:close()
}
}
15.7.测试结果
15.8.修改某个值测试redis
15.9.完整代码
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
init_by_lua_block{
mysql = require "resty.mysql"
redis = require "resty.redis"
cjson = require "cjson"
}
server {
listen 80;
server_name localhost;
location / {
default_type "text/html";
content_by_lua_block{
-- 获取传入的参数
local param = ngx.req.get_uri_args()["username"] -- 获取请求的参数username
-- 建立mysql数据库的连接
local db = mysql:new()
local ok,err = db:connect{
host="192.168.229.137",
port=3306,
user="root",
password="123456",
database="nginx_db"
}
if not ok then
ngx.say("faild connect to mysql:",err)
return
end
db:set_timeout(1000) --设置连接超时时间
local sql = "" --查询数据
if not param then
sql = "select * from users"
else
sql = "select * from users where username =".."'"..param.."'"
end
local res,err,errcode,sqlstate = db:query(sql)
if not res then
ngx.say("faild to query from mysql:",err)
return
end
-- 连接redis
local rd = redis:new()
ok,err = rd:connect("192.168.229.137",6379)
if not ok then
ngx.say("faild connect to redis:",err)
return
end
rd:set_timeout(1000)
for i,v in ipairs(res) do
rd:set("user_"..v.username,cjson.encode(v)) -- cjson转换为JSON字符串存储到redis
end
ngx.say("success")
rd:close()
db:close()
}
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
评论