nginx简介
前言
本文主要介绍nginx的配置文件及使用场景
什么是nginx?
nginx(engine x
)是一款高性能的http 服务器/反向代理web服务器及电子邮件(IMAP/POP3)代理服务器。由俄罗斯的程序设计师Igor Sysoev所开发,官方测试nginx能够支支撑5万并发链接,并且cpu、内存等资源消耗却非常低,运行非常稳定。而tomcat支持5百并发。
能干什么?
- 反向代理
- 负载均衡
- 动静分离
- 高可用
1.2安装
-
docker pull nginx # docker中拉取镜像
-
docker run -d -p 80:80 --name nginx docker.io/nginx #运行 80是容器外端口 后面80是容器内部端口
-
docker exec -it nginx bash #进入容器内部
-
docker cp 容器id:/etc/nginx/nginx.conf /usr/data/nginx/conf/ # 复制配置文件到宿主机 (前提创建好要复制到的文件夹)
-
docker cp 容器id:/etc/nginx/conf.d/default.conf /usr/data/nginx/conf.d/ #同上
-
docker stop nginx #停止运行容器
-
docker rm nginx #删除容器
-
docker run -p 80:80 --name nginx --privileged=true -v /usr/data/nginx/html:/usr/share/nginx/html -v /usr/data/nginx/logs:/var/log/nginx -v /usr/data/nginx/conf/nginx.conf:/etc/nginx/nginx.conf -v /usr/data/nginx/conf.d:/etc/nginx/conf.d -d docker.io/nginx #启动容器 并挂载文件
说明:
-v 是将’:'后面的容器内的文件挂载到宿主机上,也就是说用宿主机的配置来代替容器内的配置,更改宿主机的配置相当于是改容器内的配置,这样的话假如容器被删除了,也不会丢失我们的配置文件。
一些常用命令
docker exec -it 容器name bash
退出容器
#############容器内部命令
exit
ctrl+P+Q
cat 可以查看文件
查看nginx的版本号
./nginx -v
关闭nginx
./nginx -s stop
启动nginx
./nginx
重新加载nginx
./nginx -s reload
###################容器外命令
查看进程
ps -ef|grep nginx
1.3解析配置文件
- 1、全局块:配置影响nginx全局的指令。一般有运行nginx服务器的用户组,nginx进程pid存放路径,日志存放路径,配置文件引入,允许生成worker process数等。
- 2、events块:配置影响nginx服务器或与用户的网络连接。有每个进程的最大连接数,选取哪种事件驱动模型处理连接请求,是否允许同时接受多个网路连接,开启多个网络连接序列化等。
- 3、http块:可以嵌套多个server,配置代理,缓存,日志定义等绝大多数功能和第三方模块的配置。如文件引入,mime-type定义,日志自定义,是否使用sendfile传输文件,连接超时时间,单连接请求数等。
- 4、server块:配置虚拟主机的相关参数,一个http中可以有多个server。
- 5、location块:配置请求的路由,以及各种页面的处理情况。
nginx.conf
##################全局块#################
#定义nginx运行的用户或用户组
user nginx;
#nginx进程数,建议设置为等于CPU总核数 越大,可以支持的并发数量就越多。
worker_processes 1;
#全局错误日志定义 类型 [debug | info | notice | warn | error | crit]
error_log /var/log/nginx/error.log warn;
# 进程pid文件 位置
pid /var/run/nginx.pid;
########################events块##########
events {
#单进程支持的最大连接数目
worker_connections 1024;
}
###############http块###############
http {
#文件扩展名与文件类型映射表
include /etc/nginx/mime.types;
#默认文件类型
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
#定义本虚拟主机的访问日志
access_log /var/log/nginx/access.log main;
#开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on,如
#果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。注意:
#如果图片显示不正常把这个改成off。
sendfile on;
#此选项允许或禁止使用socke的TCP_CORK的选项,此选项仅在使用sendfile的时候使用
#tcp_nopush on;
#连接超时时间 单位秒
keepalive_timeout 65;
#是否开启gzip压缩输出
#gzip on;
#gzip_disable "msie6"; #IE6不使用gzip
#gzip_vary on; #设置为on会在Header里增加 "Vary: Accept-Encoding"
#gzip_proxied any; #代理结果数据的压缩
#gzip_comp_level 6; #gzip压缩比(1~9),越小压缩效果越差,但是越大处理越慢,所以一般取中间值
#gzip_buffers 16 8k; #获取多少内存用于缓存压缩结果
#gzip_http_version 1.1; #识别http协议的版本
#gzip_min_length 1k; #设置允许压缩的页面最小字节数,超过1k的文件会被压缩
#gzip_types application/javascript text/css; #对特定的MIME类型生效,js和css文件会被压缩
#加载配置文件default.conf
include /etc/nginx/conf.d/*.conf;
}
default.conf
#################server块#############
server {
#监听的是容器内部的端口
listen 80;
listen [::]:80;
#域名 可以设置多个,需空格隔开
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
##########################location块##################
#对 “/” 启用反向代理
location / {
# '/' 相当于容器/usr/share/nginx/html目录下,
#一般会把这个目录挂载到容器外,如上面/usr/data/nginx/html ,
#所以只需要把html页面放入这个目录,就可以通过 域名:端口/文件名 进行访问啦啦
root /usr/share/nginx/html;
#默认的首页文件, 多个用空格分开
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
#出错对应的http状态码时,用50x.html页面回应用户。
error_page 500 502 503 504 /50x.html;
#访问50x.html
location = /50x.html {
# 去这个目录下找50x.html页面
root /usr/share/nginx/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
location
配置格式
location [ 空格 | = | ~ | ~* |^~|!~ | !~* ] /uri/ {}
- = 开头:表示精确匹配
- ~ 开头:表示区分大小写的正则匹配
- ~* 开头:表示不区分大小写的正则匹配
- ^~ 开头:注意这不是一个正则表达式,它的目的是优于正则表达式的匹配;如果该location是最佳匹配,则不再进行正则表达式检测。
- !~ && !~*:表示区分大小写不匹配的正则和不区分大小写的不匹配的正则
- /uri/:普通字符串匹配
- / 绝对路径根目录匹配, 如果没有其它匹配,任何请求都会匹配到
匹配搜索优先级
(location =) > (location 完整路径) > (location ^~ 路径) > (location ~,~* 正则顺序) > (location
部分起始路径) > (/)
有无'/'
1、没有/
location /abc/def 可用匹配/abc/defgh请求,也可以匹配/abc/def/gh请求
2、有/
location /abc/def/ 只能匹配/abc/def/anything请求
举例说明
location = / {
#规则A
}
location = /login {
#规则B
}
location ^~ /static/ {
#规则C
}
location ~ \.(gif|jpg|png|js|css)$ {
#规则D,注意:是根据括号内的大小写进行匹配。括号内全是小写,只匹配小写
}
location ~* \.(gif|jpg|png|js|css)$ {
#规则E
}
location !~ \.xhtml$ {
#规则F
}
location !~* \.xhtml$ {
#规则G
}
location / {
#规则H
}
###################################前提监听端口为80
访问根目录/, 比如http://localhost/ 将匹配规则A
访问 http://localhost/login 将匹配规则B,http://localhost/register 则匹配规则H
访问 http://localhost/static/a.html 将匹配规则C
访问 http://localhost/a.gif, http://localhost/b.jpg 将匹配规则D和规则E,但是规则D顺序优先,规则E不起作用, 而 http://localhost/static/c.png 则优先匹配到 规则C
访问 http://localhost/a.PNG 则匹配规则E, 而不会匹配规则D,因为规则E不区分大小写。
访问 http://localhost/a.xhtml 不会匹配规则F和规则G,
http://localhost/a.XHTML不会匹配规则G,(因为!)。规则F,规则G属于排除法,符合匹配规则也不会匹配到,所以想想看实际应用中哪里会用到。
访问 http://localhost/category/id/1111 则最终匹配到规则H,因为以上规则都不匹配,这个时候nginx转发请求给后端应用服务器,比如FastCGI(php),tomcat(jsp),nginx作为方向代理服务器存在。
proxy_pass的几种情况
#下面情况都由http://192.168.0.105/uri/test.html进行访问
location /uri/{
proxy_pass http://127.0.0.1:8080/;
}
代理到URL:http://127.0.0.1:8080/test.html
少个'/'
location /uri/{
proxy_pass http://127.0.0.1:8080;
}
代理到URL:http://127.0.0.1:8080/uri/test.html
location /uri/{
proxy_pass http://127.0.0.1:8080/html/;
}
代理到URL:http://127.0.0.1:8080/html/test.html
少个'/'
location /uri/{
proxy_pass http://127.0.0.1:8080/html;
}
代理到URL:http://127.0.0.1:8080/htmltest.html
1.4反向代理
暴露的是代理服务器地址,隐藏了真实服务器 IP 地址。
![](https://gitee.com/codelnn/ImageHosting/raw/master/image/nginx反向代理.png)
此情况仅限tomcat也在同一docker容器中运行
由于tomcat是在docker中运行的,因此这个proxy_pass 这个IP不能写成localhost和127.0.0.1,需写成这个容器在docker中的IP或者docker的IP。但如果tomcat直接在linux系统运行,则可以写localhost。(有点玄学,有时候docker的IP可以成功,但有些时候只能容器在docker的IP才能成功 ----好像关闭虚拟机防火墙就使用docker的IP了)
查看容器在docker中的IP
![](https://i-blog.csdnimg.cn/blog_migrate/511d75d9814f8b2754ae7db5d0bf3d31.png)
查看docker容器的IP
![](https://i-blog.csdnimg.cn/blog_migrate/34df6d3e05635c04cf0b1f91da04b191.png)
反向代理 通过www.zzf.com可以访问到tomcat的首页
![](https://gitee.com/codelnn/ImageHosting/raw/master/image/nginx反向代理4.png)
注意:如果把静态资源放在root下面,需要进入nginx.conf里面把user改成root。这种情况需要把容器内的/images目录进行挂载到宿主机的root目录下的images文件。
![](https://gitee.com/codelnn/ImageHosting/raw/master/image/nginx图片路径设置.png)
1.5负载均衡
增加服务器的数量,然后将请求分发到各个服务器上,将原先请求集中到单个服务器上的情况改为将请求分发到多个服务器上,将负载分发到不同的服务器,也就是我们所说的负载均衡。
例子:在http模块中加入
upstream myserver{
server 172.17.0.1:8080;
server 172.17.0.1:8081;
}
location /{
proxy_pass http://myserver;
}
分配策略
1、轮询(默认)每一个请求按时间顺序逐一分配到不同的后台服务器,如果后台服务器down掉,能自动删除。
2、weight:代表权重,默认为1,权重越高被分配的客户端越多。
upstream myserver{
server 172.17.0.1:8080 weight=4;
server 172.17.0.1:8081 weight=6;
}
3、ip_hash:每个请求按访问ip的hash结果分配,这样每个访客访问一个后台服务器;可以解决session的问题
upstream myserver{
ip_hash; #保证每个访客固定访问一个后端服务器
server 172.17.0.1:8080;
server 172.17.0.1:8081;
}
4、least_conn:在一些要求需要更长的时间才能完成的应用情况下, 最少连接可以更公平地控制应用程序实例的负载。使用最少连接负载均衡,nginx不会向负载繁忙的服务器上分发请求,而是将请求分发到负载低的服务器上。
upstream myserver{
least_conn; #把请求转发给连接数较少的后端服务器
server 172.17.0.1:8080;
server 172.17.0.1:8081;
}
5、fair(第三方):根据响应时间来分配,响应时间越短越先分配。
upstream myserver{
server 172.17.0.1:8080;
server 172.17.0.1:8081;
fair; #实现响应时间短的优先分配
}
6、url_hash(第三方):按访问url的hash结果来分配请求,使每一个url定向到同一个后端服务器,要配合缓存命中来使用。
upstream myserver{
hash $request_uri; #实现每个url定向到同一个后端服务器
server 172.17.0.1:8080;
server 172.17.0.1:8081;
}
1.6动静分离
为了加快网站的解析速度,可以把动态页面和静态页面由不同的服务器来解析,加快解析速度。降低原来单个服务器的压力。
![](https://gitee.com/codelnn/ImageHosting/raw/master/image/nginx动静分离.png)
两种方法:
一种是纯粹把静态文件独立成单独的域名,放在独立的服务器上,也是目前主流推崇的方案;
另外一种方法就是动态跟静态文件混合在一起发布,通过 nginx 来分开。通过 location指定不同的后缀名实现不同的请求转发。通过 expires 参数设置,可以使浏览器缓存过期时间,减少与服务器之间的请求和流量。
第一种
-
修改本机的host文件
192.168.0.105 img.codelnn.com 192.168.0.105 www.zzf.com
-
然后将我们的图片上传到宿主机挂载nginx的html目录中
-
在
/usr/data/nginx/conf.d
文件夹中添加配置文件img.conf对图片进行反向代理
server {
listen 80;
server_name img.codelnn.com; #修改域名
location /img/ {
root /usr/share/nginx/html; #代理到html文件夹中
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
-
在
/usr/data/nginx/conf.d
文件夹中添加配置文件tomcat.conf对图片进行反向代理server { listen 80; server_name www.zzf.com; location / { proxy_pass http://172.17.0.2:8080; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } }
第二种
server {
listen 80;
server_name www.zzf.com;
location / {
root /usr/share/nginx/html;
index index.html;
}
# 所有静态请求都由nginx处理,存放目录为html
location ~ .(gif|jpg|jpeg|png|bmp|swf|css|js)$ {
root /usr/share/nginx/html;
}
# 所有动态请求都转发给tomcat处理
location ~ .(jsp|do)$ {
proxy_pass http://172.17.0.2:8080;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root e:wwwroot;
}
}
1.7高可用
在Keepalived + Nginx高可用负载均衡架构中,keepalived负责实现High-availability (HA) 功能控制前端机VIP(虚拟网络地址),当有设备发生故障时,热备服务器可以瞬间将VIP自动切换过来,实际运行中体验只有2秒钟切换时间,DNS服务可以负责前端VIP的负载均衡。nginx负责后端web服务器的负载均衡,将客户端的请求按照一定的算法转发给后端处理,后端将响应直接返回给客户端。
![](https://i-blog.csdnimg.cn/blog_migrate/828199e32a2ac2ad111ec9c3a9b3d41a.png)
原理
MASTER、BACKUP两台服务器均通过keepalived软件把ens33网卡绑上一个虚拟IP(VIP)地址192.168.32.88,此VIP当前由谁承载着服务就绑定在谁的ens33上,当MASTER发生故障时,BACKUP会通过/etc/keepalived/keepalived.conf文件中设置的心跳时间advert_int 1检查,无法获取MASTER正常状态的话,BACKUP会瞬间绑定VIP来接替MASTER的工作,当MASTER恢复后keepalived会通过priority(权重参数:值越大优先使用)参数判断优先权将虚拟VIP地址192.168.32.88重新绑定给MASTER的ens33网卡。
安装keepalived
yum install keepalived -y
主机
编辑配置文件keepalived.conf 文件路径:/etc/keepalived/keepalived.conf
!Configuration File for keepalived
global_defs {
notification_email {
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc #定义利用什么邮箱发送邮件
smtp_server smtp.163.com #定义邮件服务器信息
smtp_connect_timeout 30 #定义邮件发送超时时间
router_id 192.168.0.105 #(重点参数)局域网keppalived主机身份标识信息(每台唯一)
script_user root #添加运行健康检查脚本的用户
enable_script_security #添加运行健康检查脚本的组
}
vrrp_script chk_http_port {
script "/etc/keepalived/nginx_check.sh" #表示将一个脚本信息赋值给变量
interval 2 #检测脚本执行的间隔
weight -20 #监测失败,则相应的vrrp_instance的优先级会减少20个点
}
vrrp_instance VI_1 {
state MASTER #keepalived角色描述信息,备份服务器上将 MASTER 改为 BACKUP
interface ens33 #将虚拟ip用于那块网卡
virtual_router_id 51 #主、备机的 virtual_router_id 必须相同
priority 100 #主、备机取不同的优先级,主机值较大,备份机值较小
advert_int 1 #主服务器组播包发送间隔时间
authentication { # 主备主机之间的认证表示信息
auth_type PASS #采用明文认证机制
auth_pass 1111 #编写明文密码
}
virtual_ipaddress {
192.168.0.110 #设置虚拟ip地址信息,此参数备节点设置和主节点相同
}
track_script {
chk_http_port #调用执行脚本
}
}
添加检查nginx的脚步nginx_check.sh 文件路径:/etc/keepalived/nginx_check.sh
#!/bin/bash
# 传入容器名称
containerName=`nginx`
currTime=`date +"%Y-%m-%d %H:%M:%S"`
# 查看进程是否存在
exist=`docker inspect --format '{{.State.Running}}' ${containerName}`
if [ "${exist}" != "true" ]; then
systemctl stop keepalived.service #杀死所有keepalived服务进程
# 记录
echo "${currTime} docker容器宕机,容器名称:${containerName}" >> /etc/dockerlog/docker_monitor.log
fi
注意:一定要给这个脚本文件可执行权限(看到变成可执行的颜色),执行命令:chmod u+x /etc/keepalived/nginx_check.sh
备用机
需要修改的地方
router_id 192.168.0.105 #ip地址
state MASTER #keepalived角色描述信息,备份服务器上将 MASTER 改为 BACKUP
containerName=nginx #容器名字不要相同
启动服务
systemctl start keepalived.service
注意:
虚拟ip网段要和real server 真实ip的网络地址一致,比如 192.168.0.105,那么虚拟ip必须是 192.168.0.* ,否则虚拟ip无法访问
关闭master中的keepalived ,backup的虚拟ip才会进行绑定。
![](https://i-blog.csdnimg.cn/blog_migrate/1a76671f5dc5d37fc7a4861729ae3c9f.png)
1.8nginx原理
![](https://gitee.com/codelnn/ImageHosting/raw/master/image/nginx原理.png)
![](https://gitee.com/codelnn/ImageHosting/raw/master/image/nginx原理2.png)
处理流程
1.首先,master 进程接受到信号(如nginx -s reload)后启动,读取配置文件,建好需要listen的socket后,然后
再fork出多个woker进程,这样每个work进程都可以去accept这个socket
2.当一个client连接到来时,所有accept的work进程都会受到通知,但只有一个进程可以accept成功,其它的则会
accept失败,Nginx提供了一把共享锁accept_mutex来保证同一时刻只有一个work进程在accept连接,从而解决惊群问
题
3.当一个worker进程accept这个连接后,就开始读取请求,解析请求,处理请求,产生数据后,再返回给客户端,最后才
断开连接,这样一个完成的请求就结束了
4.一个worker进程可以同时处理多个请求,每个worker进程只有一个主线程,而是采用异步非阻塞的方式来处理并发请
求。比如同时有多个http request的时候,worker主线程与第一条request建议连接将其处理转发给下游fast cgi后,
并不会挂起等待,而是立马处理下一条,可以理解轮询处理。与多线程相比,这种事件处理方式是有很大的优势的,不需要
创建线程,每个请求占用的内存也很少,没有上下文切换,事件处理非常的轻量级。并发数再多也不会导致无谓的资源浪费
(上下文切换),更多的并发数,只是会占用更多的内存而已。因此nginx 是非常适合处理高并发请求的。
惊群现象:惊群效应就是当一个fd的事件被触发时,所有等待这个fd的线程或进程都被唤醒。一般都是socket的accept()会导致惊群,很多个进程都block在server socket的accept(),一但有客户端进来,所有进程accept()都会返回,但是只有一个进程会读到数据,就是惊群。
愿有前程可奔赴 亦有岁月可回首。