一 web服务介绍
1.1Apache经典web服务
1.1.1Apache prefork 模型
预派生模式,有一个主控制进程,然后生成多个子进程,使用select模型,最大并发1024
每个子进程有一个独立的线程响应用户请求
相对比较占用内存,但是比较稳定,可以设置最大和最小进程数
是最古老的一种模式,也是最稳定的模式,适用于访问量不是很大的场景
优点:稳定
缺点:每个用户请求需要对应开启一个进程,占用资源较多,并发性差,不适用于高并发场景
1.1.2 Apache worker 模型
一种多进程和多线程混合的模型
有一个控制进程,启动多个子进程
每个子进程里面包含固定的线程
使用线程程来处理请求
当线程不够使用的时候会再启动一个新的子进程,然后在进程里面再启动线程处理请求,
由于其使用了线程处理请求,因此可以承受更高的并发
优点:相比prefork 占用的内存较少,可以同时处理更多的请求
缺点:使用keepalive的长连接方式,某个线程会一直被占据,即使没有传输数据,也需要一直等待到超
时才会被释放。如果过多的线程,被这样占据,也会导致在高并发场景下的无服务线程可用(该问题在
prefork模式下,同样会发生)
1.1.3 Apache event模型
Apache中最新的模式,2012年发布的apache 2.4.X系列正式支持event 模型,属于事件驱动模型(epoll)每个进程响应多个请求,在现在版本里的已经是稳定可用的模式
它和worker模式很像,最大的区别在于,它解决了keepalive场景下长期被占用的线程的资源浪费问题(某些线程因为被keepalive,空挂在哪里等待,中间几乎没有请求过来,甚至等到超时)
event MPM中,会有一个专门的线程来管理这些keepalive类型的线程
当有真实请求过来的时候,将请求传递给服务线程,执行完毕后,又允许它释放。这样增强了高并发场景下的请求处理能力
缺点:没有线程安全控制
1.2Nginx-高性能的 Web 服务端
Nginx是由1994年毕业于俄罗斯国立莫斯科鲍曼科技大学的同学为俄罗斯rambler.ru公司开发的,开发工作最早从2002年开始,第一次公开发布时间是2004年10月4日,版本号是0.1.0
2019年3月11日F5 与 NGINX达成协议,F5 将收购 NGINX 的所有已发行股票,总价值约为 6.7 亿美元。6.7亿美金约合44.97亿人民币,nginx核心模块代码长度198430(包括空格、注释),所以一行代码约为2.2万人民币
官网地址 www.nginx.org
Nginx历经十几年的迭代更新(https://nginx.org/en/CHANGES), 目前功能已经非常完善且运行稳定,另外Nginx的版本分为开发版、稳定版和过期版,nginx以功能丰富著称,它即可以作为http服务器,也可以作为反向代理服务器或者邮件服务器能够快速的响应静态网页的请求
支持FastCGI/SSL/Virtual Host/URL Rwrite /Gzip / HTTP Basic Auth/http或者TCP的负载均衡(1.9版本以上且开启stream模块)等功能,并且支持第三方的功能扩展。
1.3服务端 I/O 流程
I/O在计算机中指Input/Output, IOPS (Input/Output Per Second)即每秒的输入输出量(或读写次数),是衡量磁盘性能的主要指标之一。IOPS是指单位时间内系统能处理的I/O请求数量,一般以每秒处理的I/O请求数量为单位,I/O请求通常为读或写数据操作请求。
一次完整的I/O是用户空间的进程数据与内核空间的内核数据的报文的完整交换,但是由于内核空间与用户空间是严格隔离的,所以其数据交换过程中不能由用户空间的进程直接调用内核空间的内存数据,而是需要经历一次从内核空间中的内存数据copy到用户空间的进程内存当中,所以简单说I/O就是把数据从内核空间中的内存数据复制到用户空间中进程的内存当中。
服务器的I/O
磁盘I/O
网络I/O : 一切皆文件,本质为对socket文件的读写
1.3.1磁盘 I/O
磁盘I/O是进程向内核发起系统调用,请求磁盘上的某个资源比如是html 文件或者图片,然后内核通过相应的驱动程序将目标文件加载到内核的内存空间,加载完成之后把数据从内核内存再复制给进程内存,如果是比较大的数据也需要等待时间
1.3.2网络 I/O
网络通信就是网络协议栈到用户空间进程的IO就是网络IO
网络I/O 处理过程:
获取请求数据,客户端与服务器建立连接发出请求,服务器接受请求
构建响应,当服务器接收完请求,并在用户空间处理客户端的请求,直到构建响应完成
返回数据,服务器将已构建好的响应再通过内核空间的网络 I/O 发还给客户端
1.4I/O 模型
1.4.1网络 I/O 模型
阻塞型 I/O 模型(blocking IO)
阻塞IO模型是最简单的I/O模型,用户线程在内核进行IO操作时被阻塞
用户线程通过系统调用read发起I/O读操作,由用户空间转到内核空间。内核等到数据包到达后,然
后将接收的数据拷贝到用户空间,完成read操作
用户需要等待read将数据读取到buffer后,才继续处理接收的数据。整个I/O请求的过程中,用户线
程是被阻塞的,这导致用户在发起IO请求时,不能做任何事情,对CPU的资源利用率不够
优点:程序简单,在阻塞等待数据期间进程/线程挂起,基本不会占用 CPU 资源
缺点:每个连接需要独立的进程/线程单独处理,当并发请求量大时为了维护程序,内存、线程切换开销
较apache 的preforck使用的是这种模式。
非阻塞型 I/O 模型 (nonblocking IO)
用户线程发起IO请求时立即返回。但并未读取到任何数据,用户线程需要不断地发起IO请求,直到数据到达后,才真正读取到数据,继续执行。即 “轮询”机制存在两个问题:如果有大量文件描述符都要等,那么就得一个一个的read。这会带来大量的Context Switch(read是系统调用,每调用一次就得在用户态和核心态切换一次)。轮询的时间不好把握。这里是要猜多久之后数据才能到。等待时间设的太长,程序响应延迟就过大;设的太短,就会造成过于频繁的重试,干耗CPU而已,是比较浪费CPU的方式,一般很少直接使用这种模型,而是在其他IO模型中使用非阻塞IO这一特性。
非阻塞:程序向内核发送请I/O求后一直等待内核响应,如果内核处理请求的IO操作不能立即返回IO结果,进程将不再等待,而且继续处理其他请求,但是仍然需要进程隔一段时间就要查看内核I/O是否完成。
多路复用 I/O 型(I/O multiplexing)
多路复用IO指一个线程可以同时(实际是交替实现,即并发完成)监控和处理多个文件描述符对应各自的IO,即复用同一个线程
信号驱动式 I/O 模型 (signal-driven IO)
信号驱动I/O的意思就是进程现在不用傻等着,也不用去轮询。而是让内核在数据就绪时,发送信号通知进程。
异步 I/O 模型 (asynchronous IO)
异步I/O 与 信号驱动I/O最大区别在于,信号驱动是内核通知用户进程何时开始一个I/O操作,而异步I/O是由内核通知用户进程I/O操作何时完成
1.5零拷贝
传统的 Linux 系统的标准 I/O 接口(read、write)是基于数据拷贝的,也就是数据都copy_to_user或者 copy_from_user,这样做的好处是,通过中间缓存的机制,减少磁盘 I/O 的操作,但是坏处也很明显,大量数据的拷贝,用户态和内核态的频繁切换,会消耗大量的 CPU 资源,严重影响数据传输的性能,统计表明,在Linux协议栈中,数据包在内核态和用户态之间的拷贝所用的时间甚至占到了数据包整个处理流程时间的57.1%
零拷贝就是上述问题的一个解决方案,通过尽量避免拷贝操作来缓解 CPU 的压力。零拷贝并没有真正做到“0”拷贝,它更多是一种思想,很多的零拷贝技术都是基于这个思想去做的优化
二nginx架构和安装
2.1nginx源码安装
源码安装需要提前准备标准的编译器,GCC的全称是(GNU Compiler collection),其有GNU开发,并以GPL即LGPL许可,是自由的类UNIX即苹果电脑Mac OS X操作系统的标准编译器,因为GCC原本只能处理C语言,所以原名为GNU C语言编译器,后来得到快速发展,可以处理C++,Fortran,pascal,objective C,java以及Ada等其他语言,此外还需要Automake工具,以完成自动创建Makefile的工作,Nginx的一些模块需要依赖第三方库,比如: pcre(支持rewrite),zlib(支持gzip模块)和openssl(支持ssl模块)等。
官方源码包下载地址:https://nginx.org/en/download.html
安装编译器: dnf install gcc pcre-devel zlib-devel openssl-devel -y
创建nginx用户:useradd -s /sbin/nologin -M nginx
解压压缩包:tar zxf nginx-1.24.0.tar.gz
进入解压后目录
可配置第三方模块:
./configure --prefix=/usr/local/nginx
–user=nginx \ # 指定nginx运行用户
–group=nginx \ # 指定nginx运行组
–with-http_ssl_module \ # 支持https://
–with-http_v2_module \ # 支持http版本2
–with-http_realip_module \ # 支持ip透传
–with-http_stub_status_module \ # 支持状态页面
–with-http_gzip_static_module \ # 支持压缩
–with-pcre \ # 支持正则
–with-stream \ # 支持tcp反向代理
–with-stream_ssl_module \ # 支持tcp的ssl加密
–with-stream_realip_module # 支持tcp的透传ip
–add-module=/root/echo-nginx-module-0.63(这是需要在官网下载的模块文件,可以在nginx配置文件中echo内置变量)
编译并生成软件目录:
make && make instal
验证版本及编译参数:
先编译配置使nginx命令可以任意位置使用:vim ~/.bash_profile
加入export PATH=$PATH:/usr/local/nginx/sbin
刷新配置文件source ~/.bash_profile
nginx -V可以看到版本配置信息
配置启动文件使systemctl可以启动nginx
vim /lib/systemd/system/nginx.service
加入
刷新配置 systemctl daemon-reload
然后就可以使用systemctl控制nginx了
2.2平滑升级和回滚
平滑升级
有时候我们需要对Nginx版本进行升级以满足对其功能的需求,例如添加新模块,需要新功能,而此时
Nginx又在跑着业务无法停掉,这时我们就可能选择平滑升级
先下载新版本nginx并解压 配置 编译
将旧版本nginx备份cd /usr/local/nginx/sbin/
cp nginx nginx.24
将新版本复制过去cp -f /root/nginx/nginx-1.26.1/objs/nginx /usr/local/nginx/sbin
检测下有没有问题 nginx -t
像旧版本nginx发送USR2信号 nginx会启动新的master进程
kill -USR2 旧的nginx进程id
此时ps -aux |grep nginx会看到两个master的和worker的nginx进程
回收旧版本 :kill -WINCH 旧版本nginx进程id
此时验证版本是否更新 nginx -V
回滚
将更新后的nginx备份 cp nginx nginx.26(注意在usr/local/nginx/sbin目录下)
将旧版本文件改回来 mv nginx.24 nginx
kill -HUP 旧的nginx 进程id(平滑升级时旧的)
回收新版本nginx:kill -WINCH 新版本nginx进程id
nginx -V查看版本信息
三Nginx配置文件
主配置文件:nginx.conf
子配置文件: include conf.d/*.conf
3.1新建一个PC web站点
创建目录mkdir /usr/local/nginx/conf.d/
配置主文件vim /usr/local/nginx/conf/nginx.conf
在http模块最后面加入include /usr/local/nginx/conf/conf.d/*.conf;
创建虚拟主机网站配置
vim /usr/local/nginx/conf.d/vhosts.conf
加入
server {
listen 80;
server_name lee.timinglee.org;
location / {
root /data/web/html;
}
}
创建网站目录 mkdir -p /data/web/html;
输入网页信息echo lee.timinglee.org > /data/web/html/index.html;
刷新配置信息nginx -s reload
测试 curl lee.timinglee.org (注意!访问要在主机设解析文件在/etc/hosts里面 格式 ip +域名)
3.2root和alias
在创建web服务时会有root出现,网页绝对路径等于root+location
示例:
server {
listen 80;
server_name lee.timinglee.org;
location / {
root /data/web;
}
location /dirtest { #必须建立/mnt/dirtest才能访问
root /data/web;
}
}
访问第一个location直接 curl lee.timinglee.org/就可以
访问第二个需要curl lee.timinglee.org/dirtest不过该目录必须在web服务器存在并且里面有.html文件
alias:定义路径别名,会把访问的路径重新定义到其指定的路径,文档映射的另一种机制;仅能用于
location上下文,此指令使用较少
示例:
server {
listen 80;
server_name lee.timinglee.org;
location / {
root /data/web/html;
}
location /dirtest { #必须建立/mnt/dirtest才能访问
root data/web/html;
}
location /heihei {
alias /data/web/html/dirtest;
}
访问第三个其实和第二个是相同目录下的html不过第三个访问方式不一样
curl lee.timinglee.org/alias/ 他将dirtest目录重命名成了heihei
3.3精确匹配
在一个server中location配置段可存在多个,用于实现从uri到文件系统的路径映射;
ngnix会根据用户请求的URI来检查定义的所有location,按一定的优先级找出一个最佳匹配,
而后应用其配置在没有使用正则表达式的时候,nginx会先在server中的多个location选取匹配度最
高的一个uri
uri是用户请求的字符串,即域名后面的web文件路径
然后使用该location模块中的正则url和字符串,如果匹配成功就结束搜索,并使用此location处理
此请求。
匹配案例-精确匹配location = /logo.png
匹配案例-区分大小写location ~ /logo.PNG
匹配案例-不区分大小写location ~* /logo.PNG
匹配案例-URI开始location ^~ /images
优先级:
3.4Nginx账户认证功能
htpasswd -cmb /usr/local/nginx/.htpasswd admin lee #-b 表示非交互建立用户认证
创建页面
mkdir /data/web/lee/
echo lee renzheng >/data/web/lee/index.html
编写配置文件
server {
listen 80;
server_name lee.timinglee.org;(主机需要加解析)
location /lee{
root /data/web/lee;
index index.html;
auth_basic “login password”;
auth_basic_user_file “/usr/local/nginx/.htpasswd”;
}
}
测试: curl lee.timinglee.org/lee/ -u admin:lee
3.5自定义错误页面
listen 80;
server_name www.timinglee.org;
error_page 404 /error.html;
location = /error.html {
root /data/web/errorpage;
}
mkdir /data/web/error -p
echo 404 error page >/data/web/errorpage/index.html;
在浏览器访问www.timinglee.org/error.html
或者curl www.timinglee.org/error.html
3.6自定义错误日志
server {
listen 80;
server_name lee.timinglee.org;
error_page 404 /error.html;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location = /error.html {
root /data/web/errorpage;
}
}
#重启nginx并访问不存在的页面进行测试并验证是在指定目录生成新的日志文件
3.7检测文件是否存在
try_files会按顺序检查文件是否存在,返回第一个找到的文件或文件夹(结尾加斜线表示为文件夹),如
果所有文件或文件夹都找不到,会进行一个内部重定向到最后一个参数。只有最后一个参数可以引起一
个内部重定向,之前的参数只设置内部URI的指向。最后一个参数是回退URI且必须存在,否则会出现内
部500错误。
如果不存在页面, 就转到default.html页面
mkdir /data/web/html/error
echo default >/data/web/html/error/default.html
server {
listen 80;
server_name lee.timinglee.org;
root /data/web/html;
error_page 404 /error.html;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
try_files $uri $uri.html /error/default.html;
location = /error.html {
root /data/web/errorpage;
}
}
3.8长连接配置
在主配置文件中http模块加入
第一行 开启长连接后,返回客户端的会话保持时间为60s,单次长连接累计请求达到指定次数请求或65秒就会被断开,第二个数字60为发送给客户端应答报文头部中显示的超时时间设置为60s:如不设置客户端将不显示超时时间。
第二行是同时最大连接数3
在windows测试
telnet www.timinglee.org 80
然后输入
可以看到默认网页内容
3.9作为下载服务器配置
mkdir -p /data/web/download
echo download file > /data/web/download/file
配置服务
vim /usr/local/nginx/conf.d/vhosts.conf
加入
server {
listen 80;
server_name lee.timinglee.org;
root /date/web/html;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
try_files $uri $uri.html /error/default.html;
location = /error.html {
root /web/data/errorpage;
}
location /download {
root /data/web;
autoindex on; #自动索引功能
autoindex_exact_size off; #计算文件确切大小(单位bytes),此为默认值,off只显示大概大小(单位kb、mb、gb)
limit_rate 1042k;
}
}
#重启Nginx并访问测试下载页面
四 Nginx高级配置
4.1Nginx状态页
server {
listen 80;
server_name status.timinglee.org;
root /data/web/html;
index index.html;
location /status {
stub_status;
auth_basic “auth login”;
auth_basic_user_file /usr/local/nginx/.htpasswd;
allow 172.25.254.1;#允许访问的ip
deny all;
}
}
4.2Nginx压缩功能
在主配置文件http模块
加入
第一行#启用或禁用gzip压缩,默认关闭
第二行#压缩比由低到高从1到9,默认为1,值越高压缩后文件越小,但是消耗cpu比较高。基本设定未4或5
第三行#gzip压缩的最小文件,小于设置值的文件将不会压缩
第四行#启用压缩功能时,协议的最小版本,默认HTTP/1.1
第五行#如果启用压缩,是否在响应报文首部插入“Vary: Accept-Encoding”,一般建议打开
第六行#指明仅对哪些类型的资源执行压缩操作;默认为gzip_types text/html,不用显示指定,否则出错
#重启Nginx并访问测试:
[root@client ~]# curl --head --compressed lee.timinglee.org/data/index.html
4.3Nginx变量使用
内置变量
自定义变量(没第三行)
五 Nginx Rewrite
Nginx服务器利用 ngx_http_rewrite_module 模块解析和处理rewrite请求
此功能依靠 PCRE(perl compatible regular expression),因此编译之前要安装PCRE库
rewrite是nginx服务器的重要功能之一,用于实现URL的重写,URL的重写是非常有用的功能
比如它可以在我们改变网站结构之后,不需要客户端修改原来的书签,也无需其他网站修改我们的
链接,就可以设置为访问
另外还可以在一定程度上提高网站的安全性。
官方文档: https://nginx.org/en/docs/http/ngx_http_rewrite_module.html
5.1ngx_http_rewrite_module 模块指令
if
set
break
用于中断当前相同作用域(location)中的其他Nginx配置
与该指令处于同一作用域的Nginx配置中,位于它前面的配置生效
位于后面的 ngx_http_rewrite_module 模块中指令就不再执行
Nginx服务器在根据配置处理请求的过程中遇到该指令的时候,回到上一层作用域继续向下读取配置,、
该指令可以在server块和locationif块中使用
( 注意: )如果break指令在location块中后续指令还会继续执行,只是不执行 ngx_http_rewrite_module
模块的指令,其它指令还会执行
location /break{
default_type text/html;
set $name lee;
echo $name;
break;
set $port $server_port;
echo $port;
}
return
return用于完成对请求的处理,并直接向客户端返回响应状态码,比如:可以指定重定向URL(对于特殊重
定向状态码,301/302等) 或者是指定提示文本内容(对于特殊状态码403/500等),处于此指令后的所有配
置都将不被执行,return可以在server、if 和 location块进行配置
location /return {
default_type text/html;
if ( !-e KaTeX parse error: Expected '}', got '#' at position 57: …w.baidu.com; #̲return 666 "request_filename is not exist";
}
echo “$request_filename is exist”;
}
5.2 rewrite指令
rewrite flag 使用介绍
利用nginx的rewrite的指令,可以实现url的重新跳转,rewrite有四种不同的flag,分别是redirect(临时
重定向302)、permanent(永久重定向301)、break和last。其中前两种是跳转型的flag,后两种是代理型
跳转型指由客户端浏览器重新对新地址进行请求
代理型是在WEB服务器内部实现跳转
临时重定向302
location / {
root /data/web/var;
index index.html;
#rewrite / http://www.sss.org permanent;
rewrite / http://www.sss.org redirect;
}
可以看到重定向到了www.sss.org 不过curl不支持访问重定向内容,可以在浏览器访问内容
这里是302临时重定向
永久重定向301
location / {
root /data/web/var;
index index.html;
#rewrite / http://www.sss.org permanent;
rewrite / http://www.sss.org redirect;
}
可以看到重定向到了www.sss.org 不过curl不支持访问重定向内容,可以在浏览器访问内容
这里是301永久重定向
rewrite中break和last区别
server中有多个location服务
如果在重定向rewrite 后面不是永久活临时而是break的话会直接访问重定向后的位置内容
如果在重定向rewrite 后面不是永久活临时而是last的话会继续访问其他命名和重定向位置相同location服务,执行里面的操作
5.3Nginx防盗链
防盗链基于客户端携带的referer实现,referer是记录打开一个页面之前记录是从哪个页面跳转过来.的标
记信息,如果别人只链接了自己网站图片或某个单独的资源,而不是打开了网站的整个页面,这就是盗
链,referer就是之前的那个网站域名,正常的referer信息有以下几种:
none: #请求报文首部没有referer首部,
#比如用户直接在浏览器输入域名访问web网站,就没有referer信息。
blocked: #请求报文有referer首部,但无有效值,比如为空。
server_names: #referer首部中包含本主机名及即nginx 监听的server_name。
arbitrary_string: #自定义指定字符串,但可使用作通配符。示例: .timinglee.org www.timinglee.
regular expression: #被指定的正则表达式模式匹配到的字符串,要使用开头,例如:..timinglee.com
可以在/usr/local/nginx/logs/acces.log文件查看访问信息
实现防盗链:
server {
listen 80;
server_name lee.timinglee.org;
root /webdata/nginx/timinglee.org/lee;
location /images {
valid_referers none blocked server_names *.timinglee.org ~.baidu.;#有效访问的referer
if ($invalid_referer){
#return 403;
rewrite ^/ http://lee.timinglee.org/daolian.png permanent;#其他的referer永久重定向到其他网页位置
}
}
}
六Nginx反向代理
6.1实现反向代理
6.1.1反向代理单向web服务器
将我们对www.sss.org的访问请求转发至后端服务器处理
vim /usr/local/nginx/conf.d/pc.conf
nginx -s reload
cur www.sss.org
6.1.2指定location实现反向代理
6.1.3缓存跟你
在ngin主配置文件http模块加入
在服务中添加缓存配置
测试
ab -n1000 -c100 http://www.sss.org/static/index.html
总共发1000次连接,并发100个
然后会发现该目录下出现缓存文件
6.2负载均衡
在上一个节中Nginx可以将客户端的请求转发至单台后端服务器但是无法转发至特定的一组的服务器,而
且不能对后端服务器提供相应的服务器状态监测,Nginx 可以基于ngx_http_upstream_module模块提
供服务器分组转发、权重分配、状态监测、调度算法等高级功能
6.2.1反向代理负载均衡(七层)
配置服务2,3,4,5行是算法
测试,注释算法默认轮询调度
6.2.2mysql(四层)
首先在主配置文件最后面重新加一个子配置文件,因为四层我们子配置文件不能再http模块下
在子配置文件中编写
nginx -s reload
准备两台后端服务器装mysql,并且配置mysql_id第一个是1第二个是2
yum install mariadb-server -y
vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]下面加
server-id=20
systemctl start mariadb
mysql -e “grant all on . to s1@‘%’ identified by ‘s1’;”
测试
在nginx服务器也要装mariadb因为要用到mysql命令
yum install mariadb -y