文章目录
- 一、基础篇
- 二、进阶篇
- 1.Nginx服务器基础配置
- 2.Nginx配置成系统服务
- 3.Nginx静态资源配置指令
- 4.静态资源优化配置语法
- 5.Nginx静态压缩实战
- 6.静态资源的缓存处理
- 7.Nginx的跨域问题解决
- 8.静态资源防盗链
- 9.Rewrite功能配置
- 10.Nginx反向代理
- 11.Nginx的安全控制
- 12.Nginx的负载均衡
- 13.Nginx缓存集成
- 14.Nginx实现服务器端集群搭建
- 15.Nginx制作下载站点
- 16.Nginx的用户认证模块
- 17.nginx的拓展模块
- 总结
一、基础篇
1. 优点
1.速度更快、并发更高
2.配置简单拓展性强
3.高可靠性
4.热部署
5.成本低,BSD许可证
2.常用功能模块
1.静态资源部署
2.Rewrite地址重写(正则表达式)
3.反向代理
4.负载均衡(轮询、加权轮询、ip_hash、url_hash、fair)
5.web缓存
6.环境部署(高可用的环境)
7.用户认证模块
3.Nginx的核心组成
1.nginx二进制可执行文件
2.nginx.conf配置文件
3.error.log错误日志
4.access.log访问日志记录
4.Nginx安装方式
1).源码简单安装
环境准备
1.GCC编译器
yum install -y gcc
2.PCRE(正则)
yum install -y pcre pcre-devel
3.zlib(压缩算法)
yum install -y zlib zlib-devel
4.OpenSSL
yum install -y openssl openssl-devel
简单安装
1.进入官网查找需要下载版本链接地址
wget http://nginx.org/download/nginx-1.20.1.tar.gz
2.将下载的资源进行包管理
mkdir -p nginx/core
mv nginx-1.20.1.tar.gz nginx/core/
3.解压缩
tar -zvxf nginx-1.20.1.tar.gz
4.进入资源文件执行configure
./configure
5.编译
make
6.安装
make install
7.验证
默认安装路径在 /usr/local/nginx/
进入安装目录的sbin下执行 ./nginx
访问本机ip出现Welcome to nginx!
2).yum安装
官方安装步骤:http://nginx.org/en/linux_packages.html#RHEL-CentOS
3).源码复杂安装
这种方式和简单安装配置不同的地方在第一步,通过 ./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
4).nginx卸载
1.关闭nginx进程
./nginx -s stop
2.将安装的nginx删除
rm -rf nginx
3.将安装包之前的编译环境清除掉(进入configure文件目录执行)
make clean
5.Nginx目录说明
fastcgi.conf:fastcgi相关配置文件
fastcgi.conf.default:fastcgi.conf的备份文件
fastcgi_params:fastcgi的参数文件
fastcgi_params.default:fastcgi的参数备份文件
scgi_params:scgi的参数文件
scgi_params.default:scgi的参数备份文件
uwsgi_params:uwsgi的参数文件
uwsgi_params.default:uwsgi的参数备份文件
mime.types:记录的是HTTP协议中的Content-Type的值和文件后缀名的对应关系
mime.types.default:mime.types的备份文件
nginx.conf:这个是Nginx的核心配置文件,将要学习的重点
nginx.conf.default:nginx.conf的备份文件
koi-utf、koi-win、win-utf这三个文件都是与编码转换映射相关的配置文件,用来将一种编码转换成另一种编码
html:存放nginx自带的两个静态的html页面
50x.html:访问失败后的失败页面
index.html:成功访问的默认首页
logs:记录入门的文件,当nginx服务器启动后,这里面会有 access.log
error.log 和nginx.pid三个文件出现。
sbin:是存放执行程序文件nginx
nginx是用来控制Nginx的启动和停止等相关的命令。
5.Nginx服务信号控制
6.Nginx服务命令行控制
此方式是通过Nginx安装目录下的sbin下的可执行文件nginx来进行Nginx状态的控制,
我们可以通过nginx -h 来查看都有哪些参数可以用:
-?和-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的配置文件路径,(默认为: conf/nginx.conf)
-g:用来补充Nginx配置文件,向Nginx服务指定启动时应用全局的配置
7.Nginx服务器版本平滑升级
1.将1.14.2版本的sbin目录下的nginx进行备份
2.将Nginx1.16.1安装目录编译后(make执行但是不执行make install)的objs目录下的nginx文件,拷贝到原来/usr/local/nginx/sbin 目录下
1).使用服务信号升级
3.发送信号USR2给Nginx的1.14.2版本对应的master进程
4.发送信号QUIT给Nginx的1.14.2版本对应的master进程
5.查看是否成功./nginx -v
2).使用make命令升级
3.进入到新版本安装目录,执行make upgrade
4.查看是否成功./nginx -v
8.Nginx核心配置文件结构
nginx.conf配置文件中默认有三大块:全局块、events块、http块 http块中可以配置多个server块,每个server块又可以配置多个location块。1).全局块
1.user 用户名 [组名]
默认nobody
用于配置运行nginx服务器的worker进程的用户和用户组
2.master_process on|off
默认on
用来指定是否开启工作进程。
3.worker_processes num/auto
默认1
用于配置Nginx生成工作进程的数量,这个是Nginx服务器实现并发处理服务的关键所在。理论上来说workder process的值越大,
可以支持的并发处理量也越多,但事实上这个值的设定是需要受到来自服务器自身的限制,建议将该值和服务器CPU的内核数保存一致。
4.daemon on|off
默认on
设定Nginx是否以守护进程的方式启动。
5.pid 文件路径
默认为:/usr/local/nginx/logs/nginx.pid
用来配置Nginx当前master进程的进程号ID存储的文件路径。
6.error_log 文件路径 [日志级别]
默认为error_log logs/error.log error;
用来配置Nginx的错误日志存放路径
位置:全局块、http、server、location
其中日志级别的值有:
debug|info|notice|warn|error|crit|alert|emerg,翻译过来为
测试 |信息|通知 |警告|错误 |临界|警报 |紧急,这块建议不要设
置成info以下的等级,因为会带来大量的磁盘I/O消耗,影响Nginx的性
能。
7.include 文件路径
无默认值
include:用来引入其他配置文件,使Nginx的配置更加灵活
位置:any
2).events块
1.accept_mutex on|off
默认值 on
用来设置Nginx网络连接序列化(这个配置主要可以用来解决常说的"惊群"问题。大致意思是在某一个时刻,
客户端发来一个请求连接,Nginx后台是以多进程的工作模式,也就是说有多个worker进程会被同时唤醒,
但是最终只会有一个进程可以获取到连接,如果每次唤醒的进程数目太多,就会影响Nginx的整体性能。
如果将上述值设置为on(开启状态),将会对多个Nginx进程接收连接进行序列号,一个个来唤醒接收,就防止了多个进程对连接的争抢。)
2.multi_accept on|off
默认值off
用来设置是否允许同时接收多个网络连接(如果multi_accept被禁止了,nginx一个工作进程只能同时接受一个新的连接。
否则,一个工作进程可以同时接受所有的新连接。)
3.worker_connections number
默认值512
用来配置单个worker进程最大的连接数(这里的连接数不仅仅包括和前端用户建立的连接数,
而是包括所有可能的连接数。另外,number值不能大于操作系统支持打开的最大文件句柄数量。)
4.use method
默认值根据操作系统定这里是epoll
用来设置Nginx服务器选择哪种事件驱动来处理网络消息(此处所选择事件处理模型是Nginx优化部分的一个重要内容,
method的可选值有select/poll/epoll/kqueue等,之前在准备centos环境的时候,我们强调过要使用
linux内核在2.6以上,就是为了能使用epoll函数来优化Nginx。)
3).http块
1.定义MIME-Type
我们都知道浏览器中可以显示的内容有HTML、XML、GIF等种类繁多的文件、媒体等资源,浏览器为了区分这些资源,就需要使用MIME-Type。所以说MIME Type是网络资源的媒体类型。Nginx作为web服务器,也需要能够识别前端请求的资源类型。
在Nginx的配置文件中,默认有两行配置
include mime.types;
default_type application/octet-stream;
include mime.types,相当于把mime.types文件中MIMT类型与相关类型文件的文件
后缀名的对应关系加入到当前的配置文件中。
default_type用来配置Nginx响应前端请求默认的MIME类型
默认值default_type text/plain;
位置http、server、location
2.自定义服务日志
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
3.sendfile:用来设置Nginx服务器是否使用sendfile()传输文件,该属性可以大大提高Nginx处理静态资源的性能
语法 sendfile on|off;
默认值 sendfile off;
位置 http、server、location
4.keepalive_timeout:用来设置长连接的超时时间。
语法 keepalive_timeout time;
默认值 keepalive_timeout 75s;
位置 http、server、location
5.keepalive_requests:用来设置一个keep-alive连接使用的次数。
语法 keepalive_requests number;
默认值 keepalive_requests 100;
位置 http、server、location
3.server块和location块
待补充
二、进阶篇
1.Nginx服务器基础配置
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块 结束##
}
##http块 end##
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.Nginx配置成系统服务
把Nginx应用服务设置成为系统服务,方便对Nginx服务的启动和停止等
相关操作,具体实现步骤:
1.在/usr/lib/systemd/system 目录下添加nginx.service,内容如下:
vim /usr/lib/systemd/1 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
2.添加完成后如果权限有问题需要进行权限设置
chmod 755 /usr/lib/systemd/system/nginx.service
3.使用系统命令来操作Nginx服务
启动: systemctl start nginx
停止: systemctl stop nginx
重启: systemctl restart nginx
重新加载配置文件: systemctl reload nginx
查看nginx状态: systemctl status nginx
开机启动: systemctl enable nginx
3.Nginx静态资源配置指令
1).listen指令
listen:用来配置监听端口
语法 | listen address[:port] [default_server]…; listen port [default_server]…; |
---|---|
默认值 | listen *:80 |
位置 | server |
常用设置:
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。
2).server_name指令
server_name:用来设置虚拟主机服务名称。
语法 | server_name name …;name可以提供多个中间用空格分隔 |
---|---|
默认值 | server_name “”; |
位置 | server |
关于server_name的配置方式有三种,分别是:
-
精确匹配
如:server { listen 80; server_name www.itcast.cn www.itheima.cn; ... }
-
通配符匹配
server_name中支持通配符"*",但需要注意的是通配符不能出现在域名的中间,只能出现在首段或尾段,如:server { listen 80; server_name *.itcast.cn www.itheima.*; # www.itcast.cn abc.itcast.cn www.itheima.cn ... }
-
正则表达式匹配
server_name中可以使用正则表达式,并且使用~ 作为正则表达式字符串的开始标记。
配置如下:server{ listen 80; server_name ~^www\.(\w+)\.com$; default_type text/plain; return 200 $1 ..; } 注意 ~后面不能加空格,括号可以取值如$1
匹配执行顺序
由于server_name指令支持通配符和正则表达式,因此在包含多个虚拟
主机的配置文件中,可能会出现一个名称被多个虚拟主机的
server_name匹配成功,当遇到这种情况,当前的请求交给谁来处理
呢?
匹配执行顺序
No1:准确匹配server_name
No2:通配符在开始时匹配server_name成功
No3:通配符在结束时匹配server_name成功
No4:正则表达式匹配server_name成功
No5:被默认的default_server处理,如果没有指定默认找第一个server
3).location指令
用来设置请求的url
语法 | location [ = | ~ | ~* | ^~ |@ ] uri{…} |
---|---|
默认值 | - |
位置 | server,location |
匹配执行顺序
uri变量是待匹配的请求字符串,可以不包含正则表达式,也可以包含正则表达式,那么nginx服务器在搜索匹配location的时候,是先使用不包含正则表达式进行匹配,找到一个匹配度最高的一个,然后在通过包含正则表达式的进行匹配,如果能匹配到直接访问,匹配不到,就使用刚才匹配度最高的那个location来处理请求。
- 不带符号
不带符号,要求必须以指定模式开始server { listen 80; server_name 127.0.0.1; location /abc{ default_type text/plain; return 200 "access success"; } } 以下访问都是正确的 http://192.168.200.133/abc http://192.168.200.133/abc?p1=TOM http://192.168.200.133/abc/ http://192.168.200.133/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";
}
}
- 其他的见error_page指令
a.设置请求资源的目录root / alias
root:设置请求的根目录
path为Nginx服务器接收到请求以后查找资源的根目录路径。
语法 | root path; |
---|---|
默认值 | root html; |
位置 | http、server、location |
alias:用来更改location的URI
path为修改后的根路径。
语法 | alias path; |
---|---|
默认值 | - |
位置 | location |
root的处理结果是: root路径+location路径
alias的处理结果是:使用alias路径替换location路径
alias是一个目录别名的定义,root则是最上层目录的含义。
如果location路径是以/结尾,则alias也必须是以/结尾,root没有要求
b.index指令
index:设置网站的默认首页
语法 | index file…; |
---|---|
默认值 | index index.html; |
位置 | http、server、location |
index后面可以跟多个设置,如果访问的时候没有指定具体访问的资源,则会依次进行查找,找到第一个为止。
4)error_page指令
error_page:设置网站的错误页面
语法 | error_page code … [=[response]] uri;; |
---|---|
默认值 | - |
位置 | http、server、location… |
举例说明
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...';
}
}
4.可选项=[response] 的作用是用来将相应代码更改为另外一个并返回
server{
error_page 404 =200 /50x.html;
location =/50x.html{
root html;
}
}
这样的话,当返回404找不到对应的资源的时候,在浏览器上可以看到,
最终返回的状态码是200,这块需要注意下,编写error_page后面的内
容,404后面需要加空格,200前面不能加空格
4.静态资源优化配置语法
Nginx对静态资源如何进行优化配置。这里从三个属性配置进行优化:
sendfile on; # 减少了2次拷贝喝内核切换
tcp_nopush on; # 提升效率
tcp_nodelay on; # 提升试试性
sendfile,用来开启高效的文件传输模式。
tcp_nopush:该指令必须在sendfile打开的状态下才会生效,主要是用来提升网络包的传输’效率’
tcp_nodelay:该指令必须在keep-alive连接开启的情况下才生效,来提高网络包传输的’实时性’
经过刚才的分析,“tcp_nopush"和”tcp_nodelay“看起来是"互斥的”,那么为什么要将这两个值都打开,这个大家需要知道的是在linux2.5.9以后的版本中两者是可以兼容的,三个指令都开启的好处是,sendfile可以开启高效的文件传输模式,tcp_nopush开启可以确保在发送到客户端之前数据包已经充分“填满”, 这大大减少了网络开销,并加快了文件发送的速度。 然后,当它到达最后一个可能因为没有“填满”而暂停的数据包时,Nginx会忽略tcp_nopush参数, 然后,tcp_nodelay强制套接字发送数据。由此可知,TCP_NOPUSH可以与TCP_NODELAY一起设置,它比单独配置TCP_NODELAY具有更强的性能。
5.Nginx静态压缩实战
1).Gzip模块配置指令
接下来所学习的指令都来自ngx_http_gzip_module模块,该模块会在
nginx安装的时候内置到nginx的安装环境中,也就是说我们可以直接使
用这些指令。
- gzip指令:该指令用于开启或者关闭gzip功能
语法 | gzip on|off; |
---|---|
默认值 | gzip off; |
位置 | http、server、location… |
只有该指令为打开状态,下面的指令才会生效
- gzip_types指令:该指令可以根据响应页的MIME类型选择性地开启Gzip压缩功能(可以使用"*"代表所有)
语法 | gzip_types mime-type …; |
---|---|
默认值 | gzip_types text/html; |
位置 | http、server、location… |
- gzip_comp_level指令:该指令用于设置Gzip压缩程度,级别从1-9,1表示要是程度最低,要是效率最高,9刚好相反,压缩程度最高,但是效率最低最费时间。(一般是6)
语法 | gzip_comp_level level; |
---|---|
默认值 | gzip_types 1; |
位置 | http、server、location… |
- gzip_vary指令:该指令用于设置使用Gzip进行压缩发送是否携带“Vary:Accept-Encoding”头域的响应头部。主要是告诉接收方,所发送的数据经过了Gzip压缩处理。
语法 | gzip_vary on|off; |
---|---|
默认值 | gzip_vary off; |
位置 | http、server、location… |
前端控制台会出现 Vary: Accept-Encoding
- gzip_buffers指令:该指令用于处理请求压缩的缓冲区数量和大小。
语法 | gzip_buffers number size; |
---|---|
默认值 | gzip_buffers 32 4k |
位置 | http、server、location… |
其中number:指定Nginx服务器向系统申请缓存空间个数,size指的是每个缓存空间的大小。主要实现的是申请number个每个大小为size的内存空间。这个值的设定一般会和服务器的操作系统有关,所以建议此项不设置,使用默认值即可。
- gzip_disable指令:针对不同种类客户端发起的请求,可以选择性地开启和关闭Gzip功能。
语法 | gzip_disable regex …; |
---|---|
默认值 | — |
位置 | http、server、location… |
regex:根据客户端的浏览器标志(user-agent)来设置,支持使用正则表达式。指定的浏览器标志不使用Gzip.该指令一般是用来排除一些明显不支持Gzip的浏览器。
IE1~6版本屏蔽此功能:gzip_disable 1 "MSIE [1-6]\.";
- gzip_http_version指令:针对不同的HTTP协议版本,可以选择性地开启和关闭Gzip功能。
语法 | gzip_http_version 1.0|1.1; |
---|---|
默认值 | gzip_http_version 1.1; |
位置 | http、server、location… |
该指令是指定使用Gzip的HTTP最低版本,该指令一般采用默认值即可。
- gzip_min_length指令:该指令针对传输数据的大小,可以选择性地开启和关闭Gzip功能
语法 | gzip_min_length length; |
---|---|
默认值 | gzip_min_length 20; |
位置 | http、server、location… |
Gzip压缩功能对大数据的压缩效果明显,但是如果要压缩的数据比较小的化,可能出现越压缩数据量越大的情况,因此我们需要根据响应内容的大小来决定是否使用Gzip功能,响应页面的大小可以通过头信息中的Content-Length 来获取。但是如何使用了Chunk编码动态压缩,该指令将被忽略。建议设置为1K或以上。
- gzip_proxied指令:该指令设置是否对服务端返回的结果进行Gzip压缩。
语法 | gzip_proxied off|expired|no-cache|nostore|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 - 无条件
启用压缩
2).Gzip压缩功能的实例配置
gzip on; #开启gzip功能
gzip_types *; #压缩源文件类型,根据具体的访问资源类型设定
gzip_comp_level 6; #gzip压缩级别
gzip_min_length 1024; #进行压缩响应页面的最小长度,contentlength
gzip_buffers 4 16K; #缓存空间大小
gzip_http_version 1.1; #指定压缩响应所需要的最低HTTP请求版本
gzip_vary on; #往头信息中添加压缩标识
gzip_disable "MSIE [1-6]\."; #对IE6以下的版本都不进行压缩
gzip_proxied off; #nginx作为反向代理压缩服务端返回数据的条件
以上配置在很多地方可能都会用到,所以我们可以将这些内容抽取到一个配置文件中nginx_gzip.conf,然后通过include指令把配置文件再次加载nginx.conf配置文件中,方法使用。
3).Gzip和sendfile共存问题
前面在讲解sendfile的时候,提到过,开启sendfile以后,在读取磁盘上的静态资源文件的时候,可以减少拷贝的次数,可以不经过用户进程将静态文件通过网络设备发送出去,但是Gzip要想对资源压缩,是需要经过用户进程进行操作的。所以如何解决两个设置的共存问题。可以使用ngx_http_gzip_static_module模块的gzip_static指令来解决。
a.gzip_static指令
gzip_static: 检查与访问资源同名的.gz文件时,response中以gzip相关的header返回.gz文件的内容。
语法 | gzip_static on | off | always;; |
---|---|
默认值 | gzip_static off; |
位置 | http、server、location… |
b.添加模块到Nginx的实现步骤
添加上述命令后,会报一个错误, unknown directive"gzip_static" 主要的原因是Nginx默认是没有添加ngx_http_gzip_static_module模块。如何来添加?
-
查询当前Nginx的配置参数 nginx -V
-
将nginx安装目录下sbin目录中的nginx二进制文件进行更名(备份作用防止添加失败恢复)
-
进入Nginx的安装目录
-
执行make clean清空之前编译的内容
-
使用configure来配置参数
--with-http_gzip_static_module此模块前要加上nginx -V当前已配置参数 ./configure --with-http_gzip_static_module
-
使用make命令进行编译
-
将objs目录下的nginx二进制执行文件移动到nginx安装目录下的sbin目录中
-
执行更新命令 make upgrade
c.gzip_static测试使用
使用gzip命令对资源进行压缩在访问就可以啦
6.静态资源的缓存处理
1).浏览器缓存执行流程
HTTP协议中和页面缓存相关的字段,我们先来认识下:
header | 说明 |
---|---|
Expires | 缓存过期的日志和时间 |
Cache-Control | 设置和缓存相关的配置信息 |
Last-Modified | 请求资源最后修改时间 |
ETag | 请求变量的实体标签的当前值,比如文件的MD5值 |
流程
1. 用户首次请求,客户端无对应缓存数据,需发送request请求来获取数据
2. 服务端接收到请求后,响应200并在响应头上附上对应资源及缓存信息
3. 当用户再次访问相同资源时,判断缓存是否过期(Expires),无过期则从缓存种获取数据展示给用户
4. 如果Expires过期,需判断缓存文件是否发生过变化,判断标准为Last-Modified和ETag
5. 若判断结果未发生变化,服务端返回304,直接从缓存文件种获取数据
6. 如果发生了变化,需重新从服务端获取数据
2).浏览器缓存相关指令
Nginx需要进行缓存相关设置,就需要用到如下的指令:
expires指令
该指令用来控制页面缓存的作用。可以通过该指令控制HTTP应答中的“Expires"和”Cache-Control"
语法 | expires [modified] time; expires epoch|max|off; |
---|---|
默认值 | expires off; |
位置 | http、server、location… |
time:可以整数也可以是负数,指定过期时间,如果是负数,Cache-Control则为no-cache,如果为整数或0,则Cache-Control的值为maxage=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:默认不缓存。
add_header指令
add_header指令是用来添加指定的响应头和响应值。
语法 | add_header name value [always]; |
---|---|
默认值 | - |
位置 | http、server、location… |
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> 响应最大Age值
Cache-control: s-maxage=<seconds> 公共缓存服务器响应的最大Age值
7.Nginx的跨域问题解决
1).浏览器的同源策略
浏览器的同源策略:是一种约定,是浏览器最核心也是最基本的安全功
能,如果浏览器少了同源策略,则浏览器的正常功能可能都会受到影
响。
同源: 协议、域名(IP)、端口相同即为同源
2).跨域问题
有两台服务器分别为A,B,如果从服务器A的页面发送异步请求到服务器B获取数据,如果服务器A和服务器B不满足同源策略,则就会出现跨域问题。
3).解决方案
使用add_header指令,该指令可以用来添加一些头信息
语法 | add_header name value [always]; |
---|---|
默认值 | - |
位置 | http、server、location… |
此处用来解决跨域问题,需要添加两个头信息,一个是
Access-Control-Allow-Origin , Access-Control-Allow-Methods
Access-Control-Allow-Origin: 直译过来是允许跨域访问的源地址信息,可以配置多个(多个用逗号分隔),也可以使用* 代表所有源
Access-Control-Allow-Methods:直译过来是允许跨域访问的请求方式,值可以为 GET POST PUT DELETE...,可以全部设置,也可以根据需要设置,多个用逗号分隔
举例
8.静态资源防盗链
1).什么是静态资源防盗链
资源盗链指的是此内容不在自己服务器上,而是通过技术手段,绕过别人的限制将别人的内容放到自己页面上最终展示给用户。以此来盗取大网站的空间和流量。简而言之就是用别人的东西成就自己的网站。
2).实现原理
了解防盗链的原理之前,我们得先学习一个HTTP的头信息Referer,当浏览器向web服务器发送请求的时候,一般都会带上Referer,来告诉浏览器该网页是从哪个页面链接过来的。
后台服务器可以根据获取到的这个Referer信息来判断是否为自己信任的网站地址,如果是则放行继续访问,如果不是则可以返回403(服务端拒绝访问)的状态信息。
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: 可以支持正则表达式和*的字符串。如果是正则表达式,需要以~开头表示,例如
3).针对目录进行防盗链
场景:图片有很多,该如何批量进行防盗链?
配置如下:
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 ,第三方模块如何实现盗链,如果在Nginx中使用第三方模块的功能,这些我们在后面的Nginx的模块篇再进行详细的讲解。
9.Rewrite功能配置
Rewrite是Nginx服务器提供的一个重要基本功能,是Web服务器产品中几乎必备的功能。主要的作用是用来实现URL的重写。www.jd.com 注意:Nginx服务器的Rewrite功能的实现依赖于PCRE的支持,因此在编译安装Nginx服务器之前,需要安装PCRE库。Nginx使用的是ngx_http_rewrite_module模块来解析和处理Rewrite功能的相关配置。
1).Rewrite相关指令
-
set指令
该指令用来设置一个新的变量。语法 set $variable value; 默认值 - 位置 server、location if variable:变量的名称,该变量名称要用"$"作为变量的第一个字符,且不要与Nginx服务器预设的全局变量同名。 value:变量的值,可以是字符串、其他变量或者变量的组合等。
-
rewrite常用全局变量
变量 说明 args get的请求参数 $http_user_agent 存储用户访问服务器的代理信息,通过浏览器访问记录浏览器的相关版本信息 host 变量存储的是访问服务器的server_name值 document_uri 变量存储的是当前访问地址的URI。比如http://192.168.200.133/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.200.133/server?id=10&name=zhangsan中的"/server?id=10&name=zhangsan" 上述参数还可以在日志文件中使用,这个就要用到前面我们介绍的log_format 指令 log_format main '$remote_addr - $request - $status-$request_uri $http_user_agent'; access_log logs/access.log main;
-
if指令
该指令用来支持条件判断,并根据条件判断结果选择不同的Nginx配置。语法 if (condition){…} 默认值 - 位置 server、location if ($request_method = POST){ return 405; } 注意:此处和Java不太一样的地方是字符串不需要添加引号,并且等号和不等号前后到需要加空格。 使用正则表达式对变量进行匹配,匹配成功返回true,否则返回false。变量与正则表达式之间使用"\~","\~\*","!\~","!\~\*"来连接。 "~"代表匹配正则表达式过程中区分大小写, "~*"代表匹配正则表达式过程中不区分大小写 "!~"和"!~*"刚好和上面取相反值,如果匹配上返回false,匹配不上返回true if ($http_user_agent ~ MSIE){ #$http_user_agent的值中是否包含MSIE字符串,如果包含返回true } 注意:正则表达式字符串一般不需要加引号,但是如果字符串中包含"}"或者是";"等字符时,就需要把引号加上。 判断请求的文件是否存在使用"-f"和"!-f" if (-f $request_filename){ #判断请求的文件是否存在 } 判断请求的目录是否存在使用"-d"和"!-d" 判断请求的目录或者文件是否存在使用"-e"和"!-e" 判断请求的文件是否可执行使用"-x"和"!-x"
-
break指令
该指令用于中断当前相同作用域中的其他Nginx配置。与该指令处于同一作用域的Nginx配置中,位于它前面的指令配置生效,位于后面的指令配置无效。并且break还有另外一个功能就是终止当前的匹配并把当前的URI在本location进行重定向访问处理。语法 break; 默认值 - 位置 server、location、if -
return指令
该指令用于完成对请求的处理,直接向客户端返回。在return后的所有Nginx配置都是无效的。语法 return code [text]; return code URL; return URL; 默认值 - 位置 server、location、if code:为返回给客户端的HTTP状态代理。可以返回的状态代码为0~999的任意HTTP状态代理 text:为返回给客户端的响应体内容,支持变量的使用 URL:为返回给客户端的URL地址
6.rewrite指令
该指令通过正则表达式的使用来改变URI。可以同时存在一个或者多个指令,按照顺序依次对URL进行匹配和处理。
语法 | rewrite regex replacement [flag]; |
---|---|
默认值 | - |
位置 | server、location、if |
regex:用来匹配URI的正则表达式
replacement:匹配成功后,用于替换URI中被截取内容的字符串。如果该字符串是以"http://"或者"https://"开头的,则不会继续向下对URI进行其他处理,而是直接返回重写后的URI给客户端。
flag:用来设置rewrite对URI的处理行为,可选值有如下:
last:终止继续在本location块中处理接收到的URI,并将此处重写的URI作为一个新的URI,使用各location块进行处理。该标志将重写后的URI重写在server块中执行,为重写后的URI提供了转入到其他location块的机会。
break:将此处重写的URI作为一个新的URI,在本块中继续进行处理。该标志将重写后的地址在当前的location块中执行,不会将新的URI转向其他的location块。
redirect:将重写后的URI返回给客户端,状态码为302,指明是临时重定向URI,主要用在replacement变量不是以"http://"或者"https://"开头的情况。
permanent:将重写后的URI返回给客户端,状态码为301,指明是永久重定向URI,主要用在replacement变量不是以"http://"或者"https://"开头的情况。
6.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;
2).Rewrite相关案例
a.域名跳转
- nginx.conf 配置
- 跳转配置
- 注意:需在/etc/hosts下添加域名解析
b.域名镜像
镜像网站指定是将一个完全相同的网站分别放置到几台服务器上,并分别使用独立的URL进行访问。其中一台服务器上的网站叫主站,其他的为镜像网站。镜像网站和主站没有太大的区别,可以把镜像网站理解为主站的一个备份节点。可以通过镜像网站提供网站在不同地区的响应速度。镜像网站可以平衡网站的流量负载、可以解决网络宽带限制、封锁等。
为其中某一个子目录下的资源做镜像(在location块中配置rewrite功能)
c.独立域名
一个完整的项目包含多个模块,比如购物网站有商品搜索模块、商品详情模块和购物车模块等,那么我们如何为每一个模块设置独立的域名。
d.目录自动添加“/”
通过http://127.0.0.1:8000/heima 和通过http://127.0.0.1:8000/heima/ 访问的区别?
如果不加斜杠,Nginx服务器内部会自动做一个301的重定向,重定向的地址会有一个指令叫server_name_in_redirect on|off;来决定重定向的地址:
如果该指令为on
重定向的地址为: http://server_name:8082/目录名/;
http://localhost:8082/heima/
如果该指令为off
重定向的地址为: http://原URL中的域名:8082/目录名/;
http://127.0.0.1:8082/heima/
注意server_name_in_redirect指令在Nginx的0.8.48版本之前默认都是
on,之后改成了off,所以现在我们这个版本不需要考虑这个问题
e.合并目录(搜索引擎优化(SEO))
搜索引擎优化(SEO)是一种利用搜索引擎的搜索规则来提高目的网站在有关搜索引擎内排名的方式。我们在创建自己的站点时,可以通过很多中方式来有效的提供搜索引擎优化的程度。其中有一项就包含URL的目录层级一般不要超过三层,否则的话不利于搜索引擎的搜索也给客户端的输入带来了负担,但是将所有的文件放在一个目录下又会导致文件资源管理混乱并且访问文件的速度也会随着文件增多而慢下来,这两个问题是相互矛盾的,那么使用rewrite如何解决上述问题?
举例,网站中有一个资源文件的访问路径时/server/11/22/33/44/20.html,也就是说20.html存在于第5级目录下,如果想要访问该资源文件,客户端的URL地址就要写成http://127.0.0.1/server/11/22/33/44/20.html ,
这样http://127.0.0.1:8083/server-11-22-33-44-20.html就能访问到了
f.防盗链
防盗链之前我们已经介绍过了相关的知识,在rewrite中的防盗链和之前
将的原理其实都是一样的,只不过通过rewrite可以将防盗链的功能进行
完善下,当出现防盗链的情况,我们可以使用rewrite将请求转发到自定
义的一张图片和页面,给用户比较好的提示信息。下面我们就通过根据
文件类型实现防盗链的一个配置实例:
location /images {
root html;
valid_referers none blocked www.baidu.com;
if ($invalid_referer){
#return 403;
rewrite ^/ /images/forbidden.png break;
}
}
10.Nginx反向代理
1)反向代理概述
关于正向代理和反向代理,我们在前面的章节已经通过一张图给大家详细的介绍过了,简而言之就是正向代理代理的对象是客户端,反向代理代理的是服务端,这是两者之间最大的区别。
Nginx即可以实现正向代理,也可以实现反向代理。
2)正向代理简单应用
服务器ip 192.168.44.128:80
代理服务器ip 192.168.44.129:82
客户端ip 192.168.44.1
a.服务端设置
b.使用客户端访问服务端,打开日志查看结果
c.代理服务器设置:
d.在客户端配置代理服务器(ip改为192.168.44.129),端口为上面设置的82
e.设置完成后,再次通过浏览器访问服务端
通过对比,上下两次的日志记录,会发现虽然我们是客户端访问服务
端,但是如果使用了代理,那么服务端能看到的只是代理发送过去的请
求,这样的化,就使用Nginx实现了正向代理的设置。
3)反向代理的配置语法
Nginx反向代理模块的指令是由ngx_http_proxy_module 模块进行解析,该模块在安装Nginx的时候已经自己加装到Nginx中了,接下来我们把反向代理中的常用指令一一介绍下:
a.proxy_pass
该指令用来设置被代理服务器地址,可以是主机名称、IP地址加端口号形式。
语法 | proxy_pass URL; |
---|---|
默认值 | - |
位置 | location |
URL:为要设置的被代理服务器地址,包含传输协议( http , https:// )、
主机名称或IP地址加端口号、URI等要素。
在编写proxy_pass的时候,后面的值要不要加"/"?
server{
listen 80;
server_name localhost;
location /server{
#proxy_pass http://192.168.200.146;
proxy_pass http://192.168.200.146/;
}
}
当客户端访问 http://localhost/server/index.html这个时候,
第一个proxy_pass就变成了 http://localhost/server/index.html
第二个proxy_pass就变成了 http://localhost/index.html效果就不一样了。
b.proxy_set_header
该指令可以更改Nginx服务器接收到的客户端请求的请求头信息,然后将新的请求头发送给代理的服务器
语法 | proxy_set_header field value; |
---|---|
默认值 | proxy_set_header Host $proxy_host; proxy_set_header Connection close; |
位置 | http、server、location |
需要注意的是,如果想要看到结果,必须在被代理的服务器上来获取添
加的头信息。
被代理服务器:[192.168.200.146]
server {
listen 8080;
server_name localhost;
default_type text/plain;
return 200 $http_username;
}
代理服务器:[192.168.200.133]
server {
listen 8080;
server_name localhost;
location /server {
proxy_pass
http://192.168.200.146:8080/;
proxy_set_header username TOM;
}
}
c.proxy_redirect
该指令是用来重置头信息中的"Location"和"Refresh"的值
语法 | proxy_redirect redirect replacement; proxy_redirect default; proxy_redirect off; |
---|---|
默认值 | proxy_redirect default; |
位置 | http、server、location |
服务端[192.168.200.146]
server {
listen 8081;
server_name localhost;
if (!-f $request_filename){
return 302 http://192.168.200.146;
}
}
代理服务端[192.168.200.133]
server {
listen 8081;
server_name localhost;
location / {
proxy_pass http://192.168.200.146:8081/;
proxy_redirect http://192.168.200.146 http://192.168.200.133;
}
}
proxy_redirect redirect replacement;
redirect:目标,Location的值
replacement:要替换的值
proxy_redirect default;
default;
将location块的uri变量作为replacement,
将proxy_pass变量作为redirect进行替换
proxy_redirect off;
关闭proxy_redirect的功能
4)nginx反向代理实战
服务器1,2,3存在两种情况
第一种情况: 三台服务器的内容不一样。
第二种情况: 三台服务器的内容是一样。
a. 如果服务器1、服务器2和服务器3的内容不一样,那我们可以根据用户请求来分发到不同的服务器。
- 代理服务器
- 服务端
b.如果服务器1、服务器2和服务器3的内容是一样的,该如何处理?
11.Nginx的安全控制
安全隔离:通过代理分开了客户端到应用程序服务器端的连接,实现了安全措施。在反向代理之前设置防火墙,仅留一个入口供代理服务器访问。
1)使用SSL对流量进行加密
HTTPS是一种通过计算机网络进行安全通信的传输协议。它经由HTTP进行通信,利用SSL/TLS建立全通信,加密数据包,确保数据的安全性。
SSL(Secure Sockets Layer)安全套接层
TLS(Transport Layer Security)传输层安全
上述这两个是为网络通信提供安全及数据完整性的一种安全协议,TLS和SSL在传输层和应用层对网络连接进行加密。
Nginx要想使用SSL,需要满足一个条件即需要添加一个模块–withhttp_ssl_module ,而该模块在编译的过程中又需要OpenSSL的支持,这个我们之前已经准备好了。
a.Nginx添加SSL的支持
完成 --with-http_ssl_module 模块的增量添加
1.将原有/usr/local/nginx/sbin/nginx进行备份
2.拷贝nginx之前的配置信息
3.在nginx的安装源码进行配置指定对应模块 ./configure --with-http_ssl_module
4.通过make模板进行编译
5.将objs下面的nginx移动到/usr/local/nginx/sbin下
6.在源码目录下执行 make upgrade进行升级,这个可以实现不停机添加新模块的功能
make upgrade问题解决:http://blog.chinaunix.net/uid-29380389-id-4308436.html
b.Nginx的SSL相关指令
ssl:该指令用来在指定的服务器开启HTTPS,可以使用 listen 443 ssl,这种方式更通用些。
语法 | ssl on | off; |
---|---|
默认值 | off |
位置 | http、server |
ssl_certificate:为当前这个虚拟主机指定一个带有PEM格试证书的证书。
语法 | ssl_ceritificate_key file; |
---|---|
默认值 | - |
位置 | http、server |
ssl_session_cache:该指令用来配置用于SSL会话的缓存
语法 | ssl_sesion_cache off|none|[builtin[:size]][shared:name:size] |
---|---|
默认值 | 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支持的格式
ssl_prefer_server_ciphers:该指令指定是否服务器密码优先客户端密码
语法 | ssl_perfer_server_ciphers on|off; |
---|---|
默认值 | ssl_perfer_server_ciphers off; |
位置 | http、server |
c. 生成证书
方式一:使用阿里云/腾讯云等第三方服务进行购买。
方式二:使用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
d. 开启SSL实例
坑1:nginx -t 失败
错误:nginx:SSL: error:140AB18F:SSL routines:SSL_CTX_use_certificate:ee key too small
原因:版本问题,私钥长度不能设置成1024位,必须2048位。不然再最后启动nginx时会出如下错误。需重新生成证数
坑2:配置完成重新启动后服务器拒绝链接,443端口无监听
解决:必须用此命令关闭在重启 nginx -s stop
2)反向代理系统调优
反向代理值Buffer和Cache
Buffer翻译过来是"缓冲",Cache翻译过来是"缓存"。
总结如下:
相同点:
两种方式都是用来提供IO吞吐效率,都是用来提升Nginx代理的性能。
不同点:
缓冲主要用来解决不同设备之间数据传递速度不一致导致的性能低的问题,缓冲中的数据一旦此次操作完成后,就可以删除。
缓存主要是备份,将被代理服务器的数据缓存一份到代理服务器,这样的话,客户端再次获取相同数据的时候,就只需要从代理服务器上获取,效率较高,缓存中的数据可以重复使用,只有满足特定条件才会删除.
a. 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_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 |
通用网站的配置
proxy_buffering on;
proxy_buffer_size 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
12.Nginx的负载均衡
1)负载均衡原理及处理流程
系统的扩展可以分为纵向扩展和横向扩展。
纵向扩展是从单机的角度出发,通过增加系统的硬件处理能力来提升服务器的处理能力
横向扩展是通过添加机器来满足大型网站服务的处理能力。
这里面涉及到两个重要的角色分别是"应用集群"和"负载均衡器"。
应用集群:将同一应用部署到多台机器上,组成处理集群,接收负载均衡设备分发的请求,进行处理并返回响应的数据。
负载均衡器:将用户访问的请求根据对应的负载均衡算法,分发到集群中的一台服务器进行处理。
2)负载均衡的作用
- 解决服务器的高并发压力,提高应用程序的处理性能。
- 提供故障转移,实现高可用。
- 通过添加或减少服务器数量,增强网站的可扩展性。
- 在负载均衡器上进行过滤,可以提高系统的安全性。
3)负载均衡常用的处理方式
a.方式一:用户手动选择
这种方式比较原始,只要实现的方式就是在网站主页上面提供不同线路、不同服务器链接方式,让用户来选择自己访问的具体服务器,来实现负载均衡。
a.方式二:DNS轮询
原理:一个域名对应多个IP,访问会进行DNS解析再轮询(但有dns缓存的限制可以使用ipconfig/flushdns清空)
优点:成本低
缺点:
- 可靠性低:假设一个域名DNS轮询多台服务器,如果其中的一台服务器发生故障,那么所有的访问该服务器的请求将不会有所回应,即使你将该服务器的IP从DNS中去掉,但是由于各大宽带接入商将众多的DNS存放在缓存中,以节省访问时间,导致DNS不会实时更新。所以DNS轮流上一定程度上解决了负载均衡问题,但是却存在可靠性不高的缺点。
- 负载均衡不均衡:DNS负载均衡采用的是简单的轮询负载算法,不能区分服务器的差异,不能反映服务器的当前运行状态,不能做到为性能好的服务器多分配请求,另外本地计算机也会缓存已经解析的域名到IP地址的映射,这也会导致使用该DNS服务器的用户在一定时间内访问的是同一台Web服务器,从而引发Web服务器减的负载不均衡。
负载不均衡则会导致某几台服务器负荷很低,而另外几台服务器负荷确很高,处理请求的速度慢,配置高的服务器分配到的请求少,而配置低的服务器分配到的请求多。
c.方式三:四/七层负载均衡
所谓四层负载均衡指的是OSI七层模型中的传输层,主要是基于IP+PORT的负载均衡
实现四层负载均衡的方式:
硬件:F5 BIG-IP、Radware等
软件:LVS、Nginx、Hayproxy等
所谓的七层负载均衡指的是在应用层,主要是基于虚拟的URL或主机IP的负载均衡
实现七层负载均衡的方式:
软件:Nginx、Hayproxy等
四层和七层负载均衡的区别
1.四层负载均衡数据包是在底层就进行了分发,而七层负载均衡数据包则在最顶端进行分发,所以四层负载均衡的效率比七层负载均衡的要高。
2.四层负载均衡不识别域名,而七层负载均衡识别域名。
实际环境采用的模式
四层负载(LVS)+七层负载(Nginx)
4)Ngxinx七层负载均衡
Nginx要实现七层负载均衡需要用到proxy_pass代理模块配置。Nginx默认安装支持这个模块,我们不需要再做任何处理。Nginx的负载均衡是在Nginx的反向代理基础上把用户的请求根据指定的算法分发到一组【upstream虚拟服务池】。
a. Nginx七层负载均衡的指令
upstream指令:该指令是用来定义一组服务器,它们可以是监听不同端口的服务器,并且也可以是同时监听TCP和Unix socket的服务器。服务器可以指定不同的权重,默认为1。
语法 | upstream name {…} |
---|---|
默认值 | - |
位置 | http |
该指令用来指定后端服务器的名称和一些参数,可以使用域名、IP、端口或者unix socket
语法 | server name [paramerters] |
---|---|
默认值 | - |
位置 | http |
b.Nginx七层负载均衡的实现流程
服务端设置192.168.44.128:
负载均衡器设置192.168.44.129:
5)负载均衡状态
代理服务器在负责均衡调度中的状态有以下几个:
状态 | 概述 |
---|---|
down | 当前的server暂时不参与负载均衡 |
backup | 预留的备份服务器 |
max_fails | 允许请求失败的次数 |
fail_timeout | 经过max_fails失败后, 服务暂停时间 |
max_conns | 限制最大的接收连接数 |
1.down:将该服务器标记为永久不可用,那么该代理服务器将不参与负载均衡。
该状态一般会对需要停机维护的服务器进行设置。
2.backup:将该服务器标记为备份服务器,当主服务器不可用时,将用来传递请求。
此时需要将9003端口的访问禁止掉来模拟下唯一能对外提供访问的服务宕机以后,backup的备份服务器就要开始对外提供服务,此时为了测试验证,我们需要使用防火墙来进行拦截。
防火墙操作指令
查询防火墙中指定的端口是否开放
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表示移除指定端口
3.max_conns=number:用来设置代理服务器同时活动链接的最大数量,默认为0,表示不限制,使用该配置可以根据后端服务器处理请求的并发量来进行设置,防止后端服务器被压垮。
4.max_fails和fail_timeout
max_fails=number:设置允许请求代理服务器失败的次数,默认为1。
fail_timeout=time:设置经过max_fails失败后,服务暂停的时间,默认是10秒。
这里请求3次(9003服务器均失败跳转到备用服务器9002)后,15秒内再次访问始终请求的是9002的服务器.,之后才会访问9003的服务器
6)负载均衡策略
介绍完Nginx负载均衡的相关指令后,我们已经能实现将用户的请求分发到不同的服务器上,那么除了采用默认的分配方式以外,我们还能采用什么样的负载算法?
Nginx的upstream支持如下六种方式的分配算法,分别是:
算法名称 | 说明 |
---|---|
轮询 | 默认方式 |
weight | 权重方式 |
ip_hash | 根据ip分配方式 |
least_conn | 依据最少连接方式 |
url_hash | 依据URL分配方式 |
fair | 依据响应时间方式(智能) |
a. 轮询
是upstream模块负载均衡默认的策略。每个请求会按时间顺序逐个分配到不同的后端服务器。轮询不需要额外的配置。(默认weight=1)
upstream backend{
server 192.168.200.146:9001 weight=1;
server 192.168.200.146:9002;
server 192.168.200.146:9003;
}
server {
listen 8083;
server_name localhost;
location /{
proxy_pass http://backend;
}
}
b. weight加权【加权轮询】
weight=number:用来设置服务器的权重,默认为1,权重数据越大,被分配到请求的几率越大;该权重值,主要是针对实际工作环境中不同的后端服务器硬件配置进行调整的,所有此策略比较适合服务器的硬件配置差别比较大的情况。
upstream backend{
server 192.168.200.146:9001 weight=10;
server 192.168.200.146:9002 weight=5;
server 192.168.200.146:9003 weight=3;
}
server {
listen 8083;
server_name localhost;
location /{
proxy_pass http://backend;
}
}
c. ip_hash
当对后端的多台动态应用服务器做负载均衡时,ip_hash指令能够将某个客户端IP的请求通过哈希算法定位到同一台后端服务器上。这样,当来自某一个IP的用户在后端Web服务器A上登录后,在访问该站点的其他URL,能保证其访问的还是后端web服务器A。
语法 | ip_hash |
---|---|
默认值 | ip_hash |
位置 | upstream |
upstream backend{
ip_hash;
server 192.168.200.146:9001;
server 192.168.200.146:9002;
server 192.168.200.146:9003;
}
server {
listen 8083;
server_name localhost;
location /{
proxy_pass http://backend;
}
}
需要额外多说一点的是使用ip_hash指令无法保证后端服务器的负载均衡,可能导致有些后端服务器接收到的请求多,有些后端服务器接收的请求少,而且设置后端服务器权重等方法将不起作用。
d. least_conn
最少连接,把请求转发给连接数较少的后端服务器。轮询算法是把请求平均的转发给各个后端,使它们的负载大致相同;但是,有些请求占用的时间很长,会导致其所在的后端负载较高。这种情况下,least_conn这种方式就可以达到更好的负载均衡效果。
upstream backend{
least_conn;
server 192.168.200.146:9001;
server 192.168.200.146:9002;
server 192.168.200.146:9003;
}
server {
listen 8083;
server_name localhost;
location /{
proxy_pass http://backend;
}
}
此负载均衡策略适合请求处理时间长短不一造成服务器过载的情况。
e. url_hash
按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,要配合缓存命中来使用。同一个资源多次请求,可能会到达不同的服务器上,导致不必要的多次下载,缓存命中率不高,以及一些资源时间的浪费。而使用url_hash,可以使得同一个url(也就是同一个资源请求)会到达同一台服务器,一旦缓存住了资源,再此收到请求,就可以从缓存中读取。
upstream backend{
hash &request_uri;
server 192.168.200.146:9001;
server 192.168.200.146:9002;
server 192.168.200.146:9003;
}
server {
listen 8083;
server_name localhost;
location /{
proxy_pass http://backend;
}
}
f. fair
fair采用的不是内建负载均衡使用的轮换的均衡算法,而是可以根据页面大小、加载时间长短智能的进行负载均衡。那么如何使用第三方模块的fair负载均衡策略。
upstream backend{
fair;
server 192.168.200.146:9001;
server 192.168.200.146:9002;
server 192.168.200.146:9003;
}
server {
listen 8083;
server_name localhost;
location /{
proxy_pass http://backend;
}
}
但是如何直接使用会报错,因为fair属于第三方模块实现的负载均衡。需要添加nginx-upstream-fair ,如何添加对应的模块:
-
下载nginx-upstream-fair模块
下载地址为: https://github.com/gnosek/nginx-upstream-fair
-
将下载的文件上传到服务器并进行解压缩
-
使用./configure命令将资源添加到Nginx模块中(要加上之前nginx -V里的内容)
./configure --add-module=/root/nginx-upstream-fair-master
-
编译
make 编译可能会出现如下错误,ngx_http_upstream_srv_conf_t结构中缺少default_port 解决方案 在Nginx的源码中 src/http/ngx_http_upstream.h,找到ngx_http_upstream_srv_conf_s ,在模块中添加添加default_port属性 in_port_t default_port
然后再执行make
-
更新Nginx
将sbin目录下的nginx进行备份 将安装目录下的objs中的nginx拷贝到sbin目录 更新Nginx(使用make upgrade) 如果最后一步出现报错,则用备份的nginx重启后在执行就ok
如果是yum安装nginx参考一下网址进行添加模块:
https://blog.youkuaiyun.com/qq_24027457/article/details/89161730
7)负载均衡案例
a. 案例一:对所有请求实现一般轮询规则的负载均衡
upstream backend{
server 192.168.200.146:9001;
server 192.168.200.146:9002;
server 192.168.200.146:9003;
}
server {
listen 8083;
server_name localhost;
location /{
proxy_pass http://backend;
}
}
b. 案例二:对所有请求实现加权轮询规则的负载均衡
upstream backend{
server 192.168.200.146:9001 weight=7;
server 192.168.200.146:9002 weight=5;
server 192.168.200.146:9003 weight=3;
}
server {
listen 8083;
server_name localhost;
location /{
proxy_pass http://backend;
}
}
c. 案例三:对特定资源实现负载均衡
upstream videobackend{
server 192.168.200.146:9001;
server 192.168.200.146:9002;
}
upstream filebackend{
server 192.168.200.146:9003;
server 192.168.200.146:9004;
}
server {
listen 8084;
server_name localhost;
location /video/ {
proxy_pass http://videobackend;
}
location /file/ {
proxy_pass http://filebackend;
}
}
d. 案例四:对不同域名实现负载均衡
upstream itcastbackend{
server 192.168.200.146:9001;
server 192.168.200.146:9002;
}
upstream itheimabackend{
server 192.168.200.146:9003;
server 192.168.200.146:9004;
}
server {
listen 8085;
server_name www.itcast.cn;
location / {
proxy_pass http://itcastbackend;
}
}
server {
listen 8086;
server_name www.itheima.cn;
location / {
proxy_pass http://itheimabackend;
}
}
e. 案例五:实现带有URL重写的负载均衡
upstream backend{
server 192.168.200.146:9001;
server 192.168.200.146:9002;
server 192.168.200.146:9003;
}
server {
listen 80;
server_name localhost;
location /file/ {
rewrite ^(/file/.*) /server/$1 last;
}
location /server {
proxy_pass http://backend;
}
}
8)Nginx四层负载均衡
Nginx在1.9之后,增加了一个stream模块,用来实现四层协议的转发、代理、负载均衡等。stream模块的用法跟http的用法类似,允许我们配置一组TCP或者UDP等协议的监听,然后通过proxy_pass来转发我们的请求,通过upstream添加多个后端服务,实现负载均衡。
四层协议负载均衡的实现,一般都会用到LVS、HAProxy、F5等,要么很贵要么配置很麻烦,而Nginx的配置相对来说更简单,更能快速完成工作。
9)添加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进行升级,这个可以实现不停机添加新模块的功能
10)Nginx四层负载均衡的指令
a. stream指令
该指令提供在其中指定流服务器指令的配置文件上下文。和http指令同级。
语法 | stream{…} |
---|---|
默认值 | - |
位置 | main(http同级) |
b. upstream指令
该指令和http的upstream指令是类似的。
11)四层负载均衡的案例
a. 需求分析
b. 实现
-
在192.168.44.128上部署2个redis,端口分别是6379,6378
上传redis的安装包, redis-4.0.14.tar.gz 将安装包进行解压缩 tar -zxf 1 redis-4.0.14.tar.gz 进入redis的安装包 cd redis-4.0.14 使用make和install进行编译和安装(prefix后跟安装路径) make PREFIX=/usr/local/redis/redis01 install 拷贝redis配置文件redis.conf 到/usr/local/redis/redis01目录中 cp redis.conf /usr/local/redis/redis01 修改redis.conf配置文件 port 6379 #redis的端口 daemonize yes #后台启动redis bind 0.0.0.0 #所有主机都能访问 将redis01复制一份为redis02 cp -r redis01 redis02 将redis02文件文件夹中的redis.conf进行修改 port 6378 #redis的端口 daemonize yes #后台启动redis bind 0.0.0.0 #所有主机都能访问 启动redis redis01/bin/redis-server redis01/redis.conf redis02/bin/redis-server redis02/redis.conf 进入redis设置值测试 redis01/bin/redis-cli -h 192.168.44.128 -p 6378 set text 6378text redis01/bin/redis-cli -h 192.168.44.128 -p 6379 set text 6379text
-
在192.168.44.128上部署tomcat,端口默认8080
上传tomcat的安装包 将安装包进行解压缩(/usr/local/tomcat下) tar -zxf apache-tomcat-8.5.70 进入tomcat的bin目录启动 cd apache-tomcat-8.5.70/bin ./startup 直接访问ip:8080出现默认页面
-
在192.168.44.129上配置nginx.conf
stream { upstream redisbackend { server 192.168.44.128:6379; server 192.168.44.128:6378; } upstream tomcatbackend { server 192.168.44.128:8080; } server { listen 81; proxy_pass redisbackend; } server { listen 82; proxy_pass tomcatbackend; }
}
13.Nginx缓存集成
1)缓存的概念
缓存就是数据交换的缓冲区(称作:Cache),当用户要获取数据的时候,会先从缓存中去查询获取数据,如果缓存中有就会直接返回给用户,如果缓存中没有,则会发请求从服务器重新查询数据,将数据返回给用户的同时将数据放入缓存,下次用户就会直接从缓存中获取数据。
缓存的优点:
- 减少数据传输,节省网络流量,加快响应速度,提升用户体验;
- 减轻服务器压力;
- 提供服务端的高可用性;
缓存的缺点:
- 数据的不一致
- 增加成本
本次课程注解讲解的是Nginx,Nginx作为web服务器,Nginx作为Web缓存服务器,它介于客户端和应用服务器之间,当用户通过浏览器访问一个URL时,web缓存服务器会去应用服务器获取要展示给用户的内容,将内容缓存到自己的服务器上,当下一次请求到来时,如果访问的是同一个URL,web缓存服务器就会直接将之前缓存的内容返回给客户端,而不是向应用服务器再次发送请求。web缓存降低了应用服务器、数据库的负载,减少了网络延迟,提高了用户访问的响应速度,增强了用户的体验。
2)Nginx缓存原理
Nginx是从0.7.48版开始提供缓存功能。Nginx是基于Proxy Store来实现的,其原理是把URL及相关组合当做Key,在使用MD5算法对Key进行哈希,得到硬盘上对应的哈希目录路径,从而将缓存内容保存在该目录中。它可以支持任意URL连接,同时也支持404/301/302这样的非200状态码。Nginx即可以支持对指定URL或者状态码设置过期时间,也可以使用purge命令来手动清除指定URL的缓存。
3)Nginx缓存设置的相关指令
Nginx的web缓存服务主要是使用ngx_http_proxy_module 模块相关指令集来完成,接下来我们把常用的指令来进行介绍下。
proxy_cache_path
该指定用于设置缓存文件的存放路径
语法 | proxy_cache_path path [levels=number] keys_zone=zone_name:zone_size [inactive=time] [max_size=size]; |
---|---|
默认值 | - |
位置 | http |
path:缓存路径地址,如:
/usr/1 local/proxy_cache
levels: 指定该缓存空间对应的目录,最多可以设置3层,每层取值为1|2
如 :
levels=1:2 缓存空间有两层目录,第一次是1个字母,第二次是2个字母
举例说明:
itheima[key]通过MD5加密以后的值为
43c8233266edce38c2c9af0694e2107d
levels=1:2 最终的存储路径为/usr/local/proxy_cache/d/07
levels=2:1:2 最终的存储路径为/usr/local/proxy_cache/7d/0/21
levels=2:2:2 最终的存储路径为/usr/local/proxy_cache/7d/10/e2
keys_zone:用来为这个缓存区设置名称和指定大小,如:
keys_zone=itcast:200m 缓存区的名称是itcast,大小为200M,1M大概能存储8000个keys
inactive:指定缓存的数据多次时间未被访问就将被删除,如:
inactive=1d 缓1 存数据在1天内没有被访问就会被删除
max_size:设置最大缓存空间,如果缓存空间存满,默认会覆盖缓存时间最长的资源,如:
max_size=20g
配置实例:
http{
proxy_cache_path /usr/local/proxy_cache
keys_zone=itcast:200m levels=1:2:1 inactive=1d
max_size=20g;
}
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方法。
4)Nginx缓存设置案例
a. 需求分析
b. 步骤实现
- 应用服务器192.168.44.128服务器部署tomcat,并在tomcat的webapps下面添加一个js目录,并在js目录中添加一个npn.js文件
- 192.168.44.128:8080/js/npn.js可正常访问
- 设置反向代理代理(代理服务器192.168.44.129)
- nginx完成缓存配置
5)Nginx缓存的清除
方式一:删除对应的缓存目录
针对全部缓存
rm -rf /usr/local/proxy_cache/.....
方式二:使用第三方拓展模块 ngx_cache_purge
- 安装升级第三方模块ngx_cache_purge
- 配置
访问http://192.168.44.129:8080/purge/npm.js即可清除缓存
6)Nginx设置资源不缓存
前面咱们已经完成了Nginx作为web缓存服务器的使用。但是我们得思考一个问题就是不是所有的数据都适合进行缓存。比如说对于一些经常发生变化的数据。如果进行缓存的话,就很容易出现用户访问到的数据不是服务器真实的数据。所以对于这些资源我们在缓存的过程中就需要进行过滤,不进行缓存。
Nginx也提供了这块的功能设置,需要使用到如下两个指令:
proxy_no_cache
该指令是用来定义不将数据进行缓存的条件
语法 | proxy_no_cache string …; |
---|---|
默认值 | - |
位置 | http、server、location |
配置实例
proxy_no_cache $cookie_nocache $arg_nocache $arg_comment;
proxy_cache_bypass
该指令是用来设置不从缓存中获取数据的条件。
语法 | proxy_cache_bypass string …; |
---|---|
默认值 | - |
位置 | http、server、location |
配置实例
proxy_cache_bypass $cookie_nocache $arg_nocache $arg_comment;
上述两个指令都有一个指定的条件,这个条件可以是多个,并且多个条件中至少有一个不为空且不等于"0",则条件满足成立。(或关系有一个为真即成立)上面给的配置实例是从官方网站获取的,里面使用到了三个变量,分别是$cookie_nocache、$arg_nocache、$arg_comment
这三个参数分别代表的含义是:
$cookie_nocache
指的是当前请求的cookie中键的名称为nocache对应的值
$arg_nocache和$arg_comment
指的是当前请求的参数中属性名为nocache和comment对应的属性值
当前仅为测试这3个参数
访问对应日志
设置资源不缓存的配置方案
14.Nginx实现服务器端集群搭建
1)Nginx与tomcat部署
前面课程已经将Nginx的大部分内容进行了讲解,我们都知道了Nginx在高并发场景和处理静态资源是非常高性能的,但是在实际项目中除了静态资源还有就是后台业务代码模块,一般后台业务都会被部署在Tomcat,weblogic或者是websphere等web服务器上。那么如何使用Nginx接收用户的请求并把请求转发到后台web服务器?
环境准备tomcat
web项目放如webapps下,启动访问测试
静态资源: http://192.168.44.128:8080/demo/index.html
动态资源: http://192.168.44.128:8080/demo/getAddress
环境准备(Nginx)
使用反向代理,配置如下:
upstream webservice {
server 192.168.44.128:8080;
}
server{
listen 80;
server_name localhost;
location /demo {
proxy_pass http://webservice;
}
}
2)Nginx实现动静分离
什么是动静分离?
动:后台应用程序的业务处理
静:网站的静态资源(html,javaScript,css,images等文件)
分离:将两者进行分开部署访问,提供用户进行访问。举例说明就是以后所有和静态资源相关的内容都交给Nginx来部署访问,非静态内容则交个类似于Tomcat的服务器来部署访问。
为什么要动静分离?
前面我们介绍过Nginx在处理静态资源的时候,效率是非常高的,而且Nginx的并发访问量也是名列前茅,而Tomcat则相对比较弱一些,所以把静态资源交个Nginx后,可以减轻Tomcat服务器的访问压力并提高静态资源的访问速度。
动静分离以后,降低了动态资源和静态资源的耦合度。如动态资源宕机了也不影响静态资源的展示。
如何实现动静分离?
实现动静分离的方式很多,比如静态资源可以部署到CDN、Nginx等服务器上,动态资源可以部署到Tomcat,weblogic或者websphere上。本次课程只要使用Nginx+Tomcat来实现动静分离。
a. 需求分析
b. 动静分离实现步骤
-
将demo.war项目中的静态资源都删除掉,重新打包生成一个war包,在资料中有提供。
-
将war包部署到tomcat中,把之前部署的内容删除掉
进入到tomcat的webapps目录下,将之前的内容删除掉 将新的war包复制到webapps下 将tomcat启动
-
在Nginx所在服务器创建如下目录,并将对应的静态资源放入指定的位置
其中html页面如下<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="js/jquery.min.js"></script> <script> $(function(){ $.get('/demo/getAddress',function(data){ $("#msg").html(data); }); }); </script> </head> <body> <img src="images/logo.png"> <h3 id="msg"></h3> <img src="images/mv.png"> </body> </html>
-
配置Nginx的静态资源与动态资源的访问
假如某个时间点,由于某个原因导致Tomcat后的服务器宕机了,我们再次访问Nginx,会得到如下效果,用户还是能看到页面,只是缺失了访问次数的统计,这就是前后端耦合度降低的效果,并且整个请求只和后的服务器交互了一次,js和images都直接从Nginx返回,提供了效率,降低了后的服务器的压力。
3)Nginx实现Tomcat集群搭建
在使用Nginx和Tomcat部署项目的时候,我们使用的是一台Nginx服务器和一台Tomcat服务器,效果图如下:
那么问题来了,如果Tomcat的真的宕机了,整个系统就会不完整,所以如何解决上述问题,一台服务器容易宕机,那就多搭建几台Tomcat服务器,这样的话就提升了后的服务器的可用性。这也就是我们常说的集群,搭建Tomcat的集群需要用到了Nginx的反向代理和赋值均衡的知识,具体如何来实现?我们先来分析下原理
环境准备
- 准备3台tomcat,使用端口进行区分[实际环境应该是三台服务器],修改server.ml,将端口修改分别修改为8080,8180,8280
- 启动tomcat并访问测试
- 在Nginx对应的配置文件中添加如下内容:
4)Nginx高可用解决方案
好了,完成了上述环境的部署,我们已经解决了Tomcat的高可用性,一台服务器宕机,还有其他两条对外提供服务,同时也可以实现后台服务器的不间断更新。但是新问题出现了,上述环境中,如果是Nginx宕机了呢,那么整套系统都将服务对外提供服务了,这个如何解决?
针对于上面提到的问题,我们来分析下要想解决上述问题,需要面临哪些问题?
需要两台以上的Nginx服务器对外提供服务,这样的话就可以解决其中一台宕机了,另外一台还能对外提供服务,但是如果是两Nginx服务器的话,会有两个IP地址,用户该访问哪台服务器,用户怎么知道哪台是好的,哪台是宕机了的?
a. Keepalived
使用Keepalived来解决,Keepalived 软件由 C 编写的,最初是专为 LVS负载均衡软件设计的,Keepalived 软件主要是通过 VRRP 协议实现高可用功能。
b. VRRP介绍
VRRP(Virtual Route Redundancy Protocol)协议,翻译过来为虚拟路由冗余协议。VRRP协议将两台或多台路由器设备虚拟成一个设备,对外提供虚拟路由器IP,而在路由器组内部,如果实际拥有这个对外IP的路由器如果工作正常的话就是MASTER,MASTER实现针对虚拟路由器IP的各种网络功能。其他设备不拥有该虚拟IP,状态为BACKUP,处了接收MASTER的VRRP状态通告信息以外,不执行对外的网络功能。当主机失效时,BACKUP将接管原先MASTER的网络功能。
从上面的介绍信息获取到的内容就是VRRP是一种协议,那这个协议是用来干什么的?
- 选择协议
VRRP可以把一个虚拟路由器的责任动态分配到局域网上的 VRRP 路由器中的一台。其中的虚拟路由即Virtual路由是由VRRP路由群组创建的一个不真实存在的路由,这个虚拟路由也是有对应的IP地址。而且VRRP路由1和VRRP路由2之间会有竞争选择,通过选择会产生一个Master路由和一个Backup路由。 - 路由容错协议
Master路由和Backup路由之间会有一个心跳检测,Master会定时告知Backup自己的状态,如果在指定的时间内,Backup没有接收到这个通知内容,Backup就会替代Master成为新的Master。Master路由有一个特权就是虚拟路由和后端服务器都是通过Master进行数据传递交互的,而备份节点则会直接丢弃这些请求和数据,不做处理,只是去监听Master的状态
用了Keepalived后,解决方案如下:
c. 环境搭建
-
环境准备
vip ip 主机名 主从 - 192.168.44.129 test129.cn master 192.168.44.200 - - - - 192.168.44.130 test130.cn backup -
keepalived的安装
步骤1:从官方网站下载keepalived,官网地址 https://keepalived.org/ 步骤2:将下载的资源上传到服务器 keepalived-2.0.20.tar.gz 步骤3:创建keepalived目录,方便管理资源 mkdir keepalived 步骤4:将压缩文件进行解压缩,解压缩到指定的目录 tar -zxf keepalived-2.0.20.tar.gz -C keepalived/ 步骤5:对keepalived进行配置,编译和安装 cd keepalived/keepalived-2.0.20 ./configure --sysconf=/etc --prefix=/usr/local make && make install
安装完成后,有两个文件需要我们认识下,一个是/etc/keepalived/keepalived.conf (keepalived的系统配置文件,我们主要操作的就是该文件),一个是/usr/local/sbin目录下的keepalived ,是系统配置脚本,用来启动和关闭keepalived。
d. Keepalived配置
打开keepalived.conf配置文件
这里面会分三部,第一部分是global全局配置、第二部分是vrrp相关配置、第三部分是LVS相关配置。 本次课程主要是使用keepalived实现高可用部署,没有用到LVS,所以我们重点关注的是前两部分。
主192.168.44.129:
! Configuration File for keepalived
# global全局部分
global_defs {
# 通知邮件,当keepalived发送切换时需要发email给具体的邮箱地址
notification_email {
xxx@xx.com
}
# 设置发件人的邮箱信息
notification_email_from xxx@xx.com
# 指定smpt服务地址
smtp_server smtp.qq.com
# 指定smpt服务连接超时时间
smtp_connect_timeout 30
# 运行keepalived服务器的一个标识,可以用作发送邮箱的主题信息
router_id 129test.cn
# 默认不是跳过检查。检查接收到的vrrp通告中的所有地址可能会比较耗时,设置此命令的意思是,如果通告与接收的上一个通告>来自相同的master路由器,则不执行检查(跳过检查)
vrrp_skip_check_adv_addr
# 严格遵守vrrp协议
vrrp_strict
# 在一个接口发送的两个免费APP之间的延迟。可以精确到毫秒级。默认是0
vrrp_garp_interval 0
# 在一个网卡上每组na消息之间的延迟时间,默认为0
vrrp_gna_interval 0
}
# vrrp部分,该部分可以包含以下四个子模块 vrrp_script vrrp_sync_group garp_group vrrp_instance,这里用到1、4
# 自动检测nginx是否正常运行脚本 脚本名称ck_nginx
vrrp_script ck_nginx{
# 脚本位置
script "/etc/keepalived/ck_nginx.sh"
# 执行间隔2秒
interval 2
# 动态调整vrrp_instance的优先级keepalived重启后减20
weight -20
}
# 设置keepalived实例的相关信息,VI_1为vrrp实例名称
vrrp_instance VI_1 {
# 有2个值可选 master主 backup备
state BACKUP
# vrrp实例绑定的接口,用于发送vrrp包【当前服务器使用的网卡名称】
interface ens160
# 指定vrrp实例ID,范围是0~255
virtual_router_id 51
# 指定优先级,优先级高的将成为master
priority 100
# 指定发送vrrp通告的间隔,单位是秒
advert_int 1
# 非抢占式
nopreempt
# vrrp之间通信的认证信息
authentication {
# 指定认证方式。pass简单密码认证(推荐)
auth_type PASS
# 指定认证使用的密码,最多8位
auth_pass 1111
}
# 虚拟IP地址,设置虚拟ip地址,供用户访问使用,可设置多个,一行一个
virtual_ipaddress {
192.168.44.200
}
# 配置上面的 vrrp_script ck_nginx 块
track_script{
ck_nginx
}
}
备192.168.44.130:
! Configuration File for keepalived
global_defs {
notification_email {
xxx@xx.com
}
notification_email_from xxx@xx.com
smtp_server smtp.xx.com
smtp_connect_timeout 30
router_id 130test.cn
vrrp_skip_check_adv_addr
vrrp_strict
vrrp_garp_interval 0
vrrp_gna_interval 0
}
vrrp_instance VI_1 {
state BACKUP
interface ens160
virtual_router_id 51
priority 90
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.44.200
}
}
keepalived只能做到对网络故障和keepalived本身的监控,即当出现网络故障或者keepalived本身出现问题时,进行切换。但是这些还不够,我们还需要监控keepalived所在服务器上的其他业务,比如Nginx,如果Nginx出现异常了,仅仅keepalived保持正常,是无法完成系统的正常工作的,因此需要根据业务进程的运行状态决定是否需要进行主备切换,这个时候,我们可以通过编写脚本对业务进程进行检测监控。
上面的vrrp_script脚本配置解决
通常如果master服务死掉后backup会变成master,但是当master服务又好了的时候 master此时会抢占VIP,这样就会发生两次切换对业务繁忙的网站来说是不好的。所以我们要在配置文件加入 nopreempt 非抢占,但是这个参数只能用于state 为backup,故我们在用HA的时候最好master 和backup的state都设置成backup 让其通过priority来竞争。
上面配置文件均已配置
15.Nginx制作下载站点
如何制作一个下载站点:
nginx使用的是模块ngx_http_autoindex_module来实现的,该模块处理以斜杠("/")结尾的请求,并生成目录列表。
nginx编译的时候会自动加载该模块,但是该模块默认是关闭的,我们需要使用下来指令来完成对应的配置
autoindex
启用或禁用目录列表输出(总开关)
语法 | autoindex on|off; |
---|---|
默认值 | autoindex off; |
位置 | http、server、location |
autoindex_exact_size
对应HTLM格式,指定是否在目录列表展示文件的详细大小
默认为on,显示出文件的确切大小,单位是bytes。 改为off后,显示出文件的大概大小,单位是kB或者MB或者GB
语法 | autoindex_exact_size on|off; |
---|---|
默认值 | autoindex_exact_size on; |
位置 | http、server、location |
autoindex_format
设置目录列表的格式
语法 | autoindex_format html|xml|json|jsonp; |
---|---|
默认值 | autoindex_format html; |
位置 | http、server、location |
注意:该指令在1.7.9及以后版本中出现
autoindex_localtime
对应HTML格式,是否在目录列表上显示时间。
默认为off,显示的文件时间为GMT时间。 改为on后,显示的文件时间为文件的服务器时间
语法 | autoindex_localtime on | off; |
---|---|
默认值 | autoindex_localtime off; |
位置 | http、server、location |
配置如下:
坑:重新加载配置文件后依旧是403
解决:资源目录的权限要求是755,资源权限要求是644
16.Nginx的用户认证模块
对应系统资源的访问,我们往往需要限制谁能访问,谁不能访问。这块就是我们通常所说的认证部分,认证需要做的就是根据用户输入的用户名和密码来判定用户是否为合法用户,如果是则放行访问,如果不是则拒绝访问。
Nginx对应用户认证这块是通过ngx_http_auth_basic_module模块来实现的,它允许通过使用"HTTP基本身份验证"协议验证用户名和密码来限制对资源的访问。默认情况下nginx是已经安装了该模块,如果不需要则使用–without-http_auth_basic_module。
该模块的指令比较简单:
auth_basic
使用“ HTTP基本认证”协议启用用户名和密码的验证
语法 | auth_basic string|off; |
---|---|
默认值 | auth_basic off; |
位置 | http、server、location limit_except |
开启后,服务端会返回401,指定的字符串会返回到客户端,给用户以提示信息,但是不同的浏览器对内容的展示不一致。
auth_basic_user_file
指定用户名和密码所在文件
语法 | auth_basic_user_file file; |
---|---|
默认值 | - |
位置 | http、server、location limit_except |
指定文件路径,该文件中的用户名和密码的设置,密码需要进行加密。可以采用工具自动生成
实现步骤:
nginx配置
使用htpasswd工具生成账号密码文件userpasswd
yum install 1 -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 //验证用户名和密码是否正确
坑:访问403或者报错
解决:userpasswd文件权限设置位644
上述方式虽然能实现用户名和密码的验证,但是大家也看到了,所有的用户名和密码信息都记录在文件里面,如果用户量过大的话,这种方式就显得有点麻烦了,这时候我们就得通过后台业务代码来进行用户权限的校验了。
17.nginx的拓展模块
1)lua
a. 概念
Lua是一种轻量、小巧的脚本语言,用标准C语言编写并以源代码形式开发。设计的目的是为了嵌入到其他应用程序中,从而为应用程序提供灵活的扩展和定制功能。
b. 特性
跟其他语言进行比较,Lua有其自身的特点:
(1)轻量级
Lua用标准C语言编写并以源代码形式开发,编译后仅仅一百余千字节,可以很方便的嵌入到其他程序中。
(2)可扩展
Lua提供非常丰富易于使用的扩展接口和机制,由宿主语言(通常是C或C++)提供功能,Lua可以使用它们,就像内置的功能一样。
(3)支持面向过程编程和函数式编程
c. 应用场景
Lua在不同的系统中得到大量应用,场景的应用场景如下:
游戏开发、独立应用脚本、web应用脚本、扩展和数据库插件、系统安全上。
d. Lua的安装
在linux上安装Lua非常简单,只需要下载源码包并在终端解压、编译即可使用。
Lua的官网地址为: https://www.lua.org
-
点击download可以找到对应版本的下载地址,我们本次课程采用的是lua-5.3.5,其对应的资源链接地址为https://www.lua.org/ftp/lua-5.4.1.tar.gz,也可以使用wget命令直接下载:
wget https://www.lua.org/1 ftp/lua-5.4.1.tar.gz
-
编译安装
cd lua-5.4.1 make linux test make install
如果在执行make linux test失败,报如下错误:
说明当前系统缺少libreadline-dev依赖包,需要通过命令来进行安装yum install -y readline-devel
验证是否安装成功
lua -v
e. Lua的语法
Lua和C/C++语法非常相似,整体上比较清晰,简洁。条件语句、循环语句、函数调用都与C/C++基本一致。如果对C/C++不太熟悉的同学来说,也没关系,因为天下语言是一家,基本上理解起来都不会太困难。我们一点点来讲。
① 第一个Lua程序
交互式:Lua交互式编程模式可以通过命令lua -i 或lua来启用
脚本式:
方式一:我们需要一个文件名为 hello.lua,在文件中添加要执行的代码,然后通过命令 lua hello.lua 来执行,会在控制台输出对应的结果。
方式二:
② Lua的注释
单行注释:
--注释内容
多行注释:
--[[
注释内容
注释内容
--]]
如果想取消多行注释,只需要在第一个–之前在加一个-即可,如:
---[[
注释内容
注释内容
--]]
③ 标识符
换句话说标识符就是我们的变量名,Lua定义变量名以一个字母 A 到 Z或 a 到 z 或下划线 _ 开头后加上0个或多个字母,下划线,数字(0到9)。这块建议大家最好不要使用下划线加大写字母的标识符,因为Lua的保留字也是这样定义的,容易发生冲突。注意Lua是区分大小写字母的。
④ 关键字
下列是Lua的关键字,大家在定义常量、变量或其他用户自定义标识符都要避免使用以下这些关键字:
一般约定,以下划线开头连接一串大写字母的名字(比如 _VERSION)被保留用于 Lua 内部全局变量。这个也是上面我们不建议这么定义标识符的原因。
⑤ 运算符
算术运算符:
+ 加法 10+20 -->30
- 减法 20-10 -->10
* 乘法 10*20 -->200
/ 除法 20/10 -->2
% 取余 3%2 -->1
^ 乘幂 10^2 -->100
- 负号 -10 -->-10
关系运算符:
== 等于
~= 不等于
> 大于
< 小于
>= 大于等于
<= 小于等于
逻辑运算符:
and 逻辑与 A and B
or 逻辑或 A or B
not 逻辑非 取反,如果为true,则返回false
其他运算符:
.. 连接两个字符串
# 一元预算法,返回字符串或表的长度
示例:
> "HELLO ".."WORLD" -->HELLO WORLD
> #"HELLO" -->5
⑥ 全局变量&局部变量
在Lua语言中,全局变量无须声明即可使用。在默认情况下,变量总是认为是全局的,如果未提前赋值,默认为nil:
要想声明一个局部变量,需要使用local来声明:
⑦ Lua数据类型
Lua有8个数据类型
nil(空,无效值)
boolean(布尔,true/false)
number(数值)
string(字符串)
function(函数)
table(表)类似python的数组+字典
thread(线程)
userdata(用户数据)
可以使用type函数测试给定变量或者的类型:
print(type(nil)) -->nil
print(type(true)) --> boolean
print(type(1.1*1.1)) --> number
print(type(“Hello world”)) --> string
print(type(io.stdin)) -->userdata
print(type(print)) --> function
print(type(type)) -->function
print(type{}) -->table
print(type(type(X))) --> string
-
nil
nil是一种只有一个nil值的类型,它的作用可以用来与其他所有值进行区分,也可以当想要移除一个变量时,只需要将该变量名赋值为nil,垃圾回收就会会释放该变量所占用的内存。 -
boolean
boolean类型具有两个值,true和false。boolean类型一般被用来做条件判断的真与假。在Lua语言中,只会将false和nil视为假,其他的都视为真,特别是在条件检测中0和空字符串都会认为是真,这个和我们熟悉的大多数语言不太一样。 -
number
在Lua5.3版本开始,Lua语言为数值格式提供了两种选择:integer(整型)和float(双精度浮点型)[和其他语言不太一样,float不代表单精度类型]。
数值常量的表示方式:4 -->4
0.4 -->0.4
4.75e-3 -->0.00475
4.75e3 -->4750不管是整型还是双精度浮点型,使用type()函数来取其类型,都会返回的是number
type(3) -->number
type(3.3) -->number所以它们之间是可以相互转换的,同时,具有相同算术值的整型值和浮 点型值在Lua语言中是相等的
-
string
Lua语言中的字符串即可以表示单个字符,也可以表示一整本书籍。在Lua语言中,操作100K或者1M个字母组成的字符串的程序很常见。
可以使用单引号或双引号来声明字符串
如果声明的字符串比较长或者有多行,则可以使用如下方式进行声明:html = [[ <html> <head> <title>Lua-string</title> </head> <body> <a href="http://www.lua.org">Lua</a> </body> </html> ]]
-
table
table是Lua语言中最主要和强大的数据结构。使用表, Lua 语言可以以一种简单、统一且高效的方式表示数组、集合、记录和其他很多数据结构。 Lua语言中的表本质上是一种辅助数组。这种数组比Java中的数组更加灵活,可以使用数值做索引,也可以使用字符串或其他任意类型的值作索引(除nil外)。
数组(表)的下标默认是从1开始的。
表的索引即可以是数字,也可以是字符串等其他的内容,所以我们也可以将索引更改为字符串来创建(类似于python字典)。
获取方式索引 arr[“X”] 或 arr.X
迭代看下面的for循环更为复杂的表
arr = {“TOM”,X=10,“JERRY”, Y=20,“ROSE”,Z=30}
TOM : arr[1]
10 : arr[“X”] | arr.X
JERRY: arr[2]
20 : arr[“Y”] | arr.Y -
function
在 Lua语言中,函数( Function )是对语句和表达式进行抽象的主要方式。
定义函数的语法为:function functionName(params) end
函数被调用的时候,传入的参数个数与定义函数时使用的参数个数不一致的时候,Lua 语言会通过 抛弃多余参数和将不足的参数设为 nil 的方式来调整参数的个数。
function f(a,b) print(a,b) end f() --> nil nil f(2) --> 2 nil f(2,6) --> 2 6 f(2,6,8) --> 2 6 (8被丢弃)
可变长参数函数
function add(...) a,b,c=... print(a) print(b) print(c) end add(1,2,3) --> 1 2 3
函数返回值可以有多个,这点和Java不太一样
function f(a,b) return a,b end x,y=f(11,22) --> x=11,y=22
-
thread
thread翻译过来是线程的意思,在Lua中,thread用来表示执行的独立线路,用来执行协同程序。 -
userdata
userdata是一种用户自定义数据,用于表示一种由应用程序或C/C++语言库所创建的类型。
⑧ Lua控制结构
Lua 语言提供了一组精简且常用的控制结构,包括用于条件执行的证 以及用于循环的 while、 repeat 和 for。 所有的控制结构语法上都有一个显式的终结符: end 用于终结 if、 for 及 while 结构, until 用于终结repeat 结构。
if then elseif else
function testif(a)
if a>0 then
print("a是正数")
else
print("a是负数")
end
end
while循环
--语法
--[[
while 条件 do
循环体
end
]]
--实现数组的循环
function testWhile()
local i = 1
while i<=10 do
print(i)
i=i+1
end
end
repeat循环
顾名思义, repeat-until语句会重复执行其循环体直到条件为真时结束。 由于条件测试在循环体之后执行,所以循环体至少会执行一次。
--语法
--[[
repeat
循环体
until 条件
]]
--示例
function testRepeat()
local i = 10
repeat
print(i)
i=i-1
until i < 1
end
for循环
- 数值型for循环
--param的值从exp1变化到exp2之前的每次循环会执行 循环体,并在每次循环结束后将步长(step)exp3增加到param上。exp3可选,如果不设置默认为1 --语法 --[[ for param=exp1,exp2,exp3 do 循环体 end ]] --示例 for i = 1,100,10 do print(i) end
- 泛型for循环
--泛型for循环通过一个迭代器函数来遍历所有值,类似于java中的foreach语句。 --i是数组索引值,v是对应索引的数组元素值,ipairs是Lua提供的一个迭代器函数,用来迭代数组,x是要遍历的数组。 --语法 --[[ for i,v in ipairs(x) do 循环体 end ]] -- 示例 arr = {"TOME","JERRY","ROWS","LUCY"} for i,v in ipairs(arr) do print(i,v) end --上面实际输出结果为 --[[ 1 TOM 2 JERRY 3 ROWS 4 LUCY ]] --但是如果将arr的值进行修改为 arr = {"TOME","JERRY","ROWS",1 x="JACK","LUCY"} --同样的代码在执行的时候,就只能看到和之前一样的结果,而其中的x为JACK就无法遍历出来,缺失了数据,如果解决呢? --我们可以将迭代器函数变成pairs,如 for i,v in pairs(arr) do print(i,v) end --上面实际输出结果为 --[[ 1 TOM 2 JERRY 3 ROWS 4 LUCY x JACK ]]
2)ngx_lua模块概念
淘宝开发的ngx_lua模块通过将lua解释器集成进Nginx,可以采用lua脚本实现业务逻辑,由于lua的紧凑、快速以及内建协程,所以在保证高并发服务能力的同时极大地降低了业务逻辑实现成本。
3)ngx_lua模块环境准备
方式一:lua-nginx-module
-
LuaJIT是采用C语言编写的Lua代表的解释器。
官网地址为:http://luajit.org/ 在官网上找到对应的下载地址:http://luajit.org/download/LuaJIT-2.0.5.tar.gz 在centos上使用wget来下载: 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 && make install
-
下载lua-nginx-module
下载地址:https://github.com/openresty/lua-nginx-module/archive/v0.10.16rc4.tar.gz 在centos上使用wget来下载: wget https://github.com/openresty/luanginx-module/archive/v0.10.16rc4.tar.gz 将下载的资源进行解压: tar -zxf lua-nginx-module-0.10.16rc4.tar.gz 更改目录名:mv lua-nginx-module-0.10.16rc4 lua-nginx-module 导入环境变量,告诉Nginx去哪里找luajit export LUAJIT_LIB=/usr/local/lib export LUAJIT_INC=/usr/local/include/luajit-2.0 进入Nginx的目录执行如下命令: ./configure --prefix=/usr/local/nginx --addmodule=../lua-nginx-module make && make install
注意事项:
(1)如果启动Nginx出现如下错误:
解决方案:
设置软链接,使用如下命令ln -s /usr/local/lib/libluajit-5.1.so.2 /lib64/libluajit-5.1.so.2
(2)如果启动Nginx出现以下错误信息
分析原因:因为lua-nginx-module是来自openrestry,错误中提示的resty.core是openrestry的核心模块,对其下的很多函数进行了优化等工作。以前的版本默认不会把该模块编译进去,所以需要使用的话,我们得手动安装,或者禁用就可以。但是最新的lua-nginx-module模块已经强制性安装了该模块,所以此处因为缺少resty模块导致的报错信息。
解决方案有两个:一种是下载对应的模块,另一种则是禁用掉restry模块,禁用的方式为:http{ lua_load_resty_core off; }
-
测试
在nginx.conf下配置如下内容:location /lua{ default_type 'text/html'; content_by_lua 'ngx.say("<h1>HELLO,LUA</h1>")'; }
配置成功后,启动nginx,通过浏览器进行访问,如果获取到结果,则证明安装成功。
方式二:OpenRestry
概述:
前面我们提到过,OpenResty是由淘宝工程师开发的,所以其官方网站(http://openresty.org/)我们读起来是非常的方便。OpenResty是一个基于Nginx与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。所以本身OpenResty内部就已经集成了Nginx和Lua,所以我们使用起来会更加方便。
安装
(1) 下载OpenResty:
https://openresty.org/download/openresty-1.15.8.2.tar.gz
(2)使用wget下载: wget
https://openresty.org/download/openresty-1.15.8.2.tar.gz
(3)解压缩: tar -zxf openresty-1.15.8.2.tar.gz
(4)进入OpenResty目录: cd openresty-1.15.8.2
(5) 执行命令:./configure
(6) 执行命令:make && make install
(7)进入OpenResty的目录,找到nginx:cd /usr/local/openresty/nginx/
(8)在conf目录下的nginx.conf添加如下内容
location /lua{
default_type 'text/html';
content_by_lua 'ngx.say("<h1>HELLO,OpenRestry</h1>")';
}
(9)在sbin目录下启动nginx
(10)通过浏览器访问测试
4)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.44.129?name=tom&gender=1
Nginx接收到请求后,根据gender传入的值,如果gender传入的是1,则在页面上展示
tom先生,如果gender传入的是0,则在页面上展示tom女士,如果未传或者传入的不是1和2则在页面上展示tom。
配置
打开/usr/local/openresty/nginx/conf/nginx.conf 修改后重启
5)nginx_lua操作Redis
Redis在系统中经常作为数据缓存、内存数据库使用,在大型系统中扮演着非常重要的作用。在Nginx核心系统中,Redis是常备组件。Nginx支持3种方法访问Redis,分别是HttpRedis模块、HttpRedis2Module、luaresty-redis库。这三种方式中HttpRedis模块提供的指令少,功能单一,适合做简单缓存,HttpRedis2Module模块比HttpRedis模块操作更灵活,功能更强大。而Lua-resty-redis库是OpenResty提供的一个操作Redis的接口库,可根据自己的业务情况做一些逻辑处理,适合做复杂的业务逻辑。所以本次课程将主要以Lua-resty-redis来进行讲解。
lua-resty-redis环境准备
步骤一:准备一个Redis环境
连接地址
host= 192.168.44.128
port=6379
步骤二:准备对应的API
lua-resty-redis提供了访问Redis的详细API,包括创建对接、连接、操作、数据处理等。这些API基本上与Redis的操作一一对应。
(1)redis = require “resty.redis”
(2)new
语法: 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命令都有自己的方法,方法名字和命令名字相同,只是全部为小写。
步骤三:效果实现
打开配置文件编辑保存重启nginx
/usr/local/openresty/nginx/conf/nginx.conf
步骤四:运行测试效果
6)nginx_lua操作mysql
MySQL是一个使用广泛的关系型数据库。在ngx_lua中,MySQL有两种访问模式,分别是使:
(1)用ngx_lua模块和lua-resty-mysql模块:这两个模块是安装OpenResty时默认安装的。
(2)使用drizzle_nginx_module(HttpDrizzleModule)模块:需要单独安装,这个库现不在OpenResty中。
a. 使用lua-resty-mysql实现数据库的查询
lua-resty-mysql是OpenResty开发的模块,使用灵活、功能强大,适合复杂的业务场景,同时支持存储过程的访问。
步骤一:MYSQL准备
创建一个数据库表及表中的数据。
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(username,birthday,salary) values("TOM","1988-11-11",10000.0);
insert into users(username,birthday,salary) values("JERRY","1989-11-11",20000.0);
insert into users(username,birthday,salary) values("ROWS","1990-11-11",30000.0);
insert into users(username,birthday,salary) values("LUCY","1991-11-11",40000.0);
insert into users(username,birthday,salary) values("JACK","1992-11-11",50000.0);
数据库连接四要数:
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://192.168.44.129:3306/nginx_db
username=root
password=
步骤二: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
步骤三:效果实现
b. 使用lua-cjson处理查询结果
通过上述的案例学习,read_result()得到的结果res都是table类型,要想在页面上展示,就必须知道table的具体数据结构才能进行遍历获取。处理起来比较麻烦,接下来我们介绍一种简单方式cjson,使用它就可以将table类型的数据转换成json字符串,把json字符串展示在页面上即可。具体如何使用?
步骤一:引入cjson
local cjson 1 = require "cjson"
步骤二:调用cjson的encode方法进行类型转换
cjson.encode(res)
步骤三:效果实现
c. lua-resty-mysql实现数据库的增删改
优化send_query和read_result(本方法是send_query和read_result组合的快捷方法。)
语法:
res, err, errcode, sqlstate = db:query(sql[,rows])
d. 综合小案例
使用ngx_lua模块完成Redis缓存预热。
分析:
(1)先得有一张表(users)
(2)浏览器输入如下地址 http://191.168.200.133?1 username=TOM
(3)从表中查询出符合条件的记录,此时获取的结果为table类型
(4)使用cjson将table数据转换成json字符串
(5)将查询的结果数据存入Redis中
实现:
总结
提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。