第十五章 Nginx

一、Nginx

1.1 Nginx 相关概念
1.1.1 正向代理

正向代理类似一个跳板机,代理访问外部资源。
比如我们国内访问谷歌,直接访问访问不到,我们可以通过一个正向代理服务器,请求发到代理服,代理服务器能够访问谷歌,这样由代理去谷歌取到返回数据,再返回给我们,这样我们就能访问谷歌了。
正向代理的用途:

  • 访问原来无法访问的资源,如 google;
  • 可以做缓存,加速访问资源;
  • 对客户端访问授权,上网进行认证;
  • 代理可以记录用户访问记录(上网行为管理),对外隐藏用户信息。
    正向代理即是客户端代理, 代理客户端, 服务端不知道实际发起请求的客户端。
1.1.2 反向代理

反向代理(Reverse Proxy)实际运行方式是指以代理服务器来接受 internet 上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给 internet 上请求连接的客户端,此时代理服务器对外就表现为一个服务器。
反向代理的作用:

  • 保证内网的安全,阻止 web 攻击,大型网站,通常将反向代理作为公网访问地址,Web 服务器是内网;
  • 负载均衡,通过反向代理服务器来优化网站的负载。
    反向代理即是服务端代理, 代理服务端, 客户端不知道实际提供服务的服务端。
1.1.3 负载均衡

负载均衡,英文名称为 Load Balance,其含义就是指将负载(工作任务)进行平衡、分摊到多个操作单元上进行运行,例如 FTP 服务器、Web 服务器、企业核心应用服务器和其它主要任务服务器等,从而协同完成工作任务。
负载均衡构建在原有网络结构之上,它提供了一种透明且廉价有效的方法扩展服务器和网络设备的带宽、加强网络数据处理能力、增加吞吐量、提高网络的可用性和灵活性。
负载均衡的主要作用如下:
**- 高并发:**负载均衡通过算法调整负载,尽力均匀的分配应用集群中各节点的工作量,以此提高应用集群的并发处理能力(吞吐量)。
**- 伸缩性:**添加或减少服务器数量,然后由负载均衡进行分发控制。这使得应用集群具备伸缩性。
**- 高可用:**负载均衡器可以监控候选服务器,当服务器不可用时,自动跳过,将请求分发给可用的服务器。这使得应用集群具备高可用的特性。
**- 安全防护:**有些负载均衡软件或硬件提供了安全性功能,如:黑白名单处理、防火墙,防 DDos 攻击等。

软件负载均衡,应用最广泛,无论大公司还是小公司都会使用。
软件负载均衡从软件层面实现负载均衡,一般可以在任何标准物理设备上运行。
软件负载均衡的 主流产品 有:Nginx、HAProxy、LVS。

  • LVS 可以作为四层负载均衡器。其负载均衡的性能要优于 Nginx。
  • HAProxy 可以作为 HTTP 和 TCP 负载均衡器。
  • Nginx、HAProxy 可以作为四层或七层负载均衡器。
    软件负载均衡的优点:
  • 扩展性好:适应动态变化,可以通过添加软件负载均衡实例,动态扩展到超出初始容量的能力。
  • 成本低廉:软件负载均衡可以在任何标准物理设备上运行,降低了购买和运维的成本。
    软件负载均衡的缺点:
  • 性能略差:相比于硬件负载均衡,软件负载均衡的性能要略低一些。
1.1.4 动静分离

动静分离是指在 web 服务器架构中,将静态页面与动态页面或者静态内容接口和动态内容接口分开不同系统访问的架构设计方法,进而提升整个服务访问性能和可维护性。

动静分离从目的实现的角度,大致分为两类:

  1. 纯粹把静态文件独立成单独的域名,放在独立的服务器上,这种是目前主流推崇的方案之一;
  2. 将动态资源和静态资源混合在一起发布,通过 nginx 调度。
1.2 Nginx 安装
1.2.1 yum 源安装

官网地址:http://nginx.org/

  1. 执行 yum install yum-utils -y 命令;
  2. 执行 vi /etc/yum.repos.d/nginx.repo 添加源;
java 复制代码
   [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. 执行 yum-config-manager --enable nginx-stable 命令。
  2. 执行 yum install nginx 命令安装 Nginx。
java 复制代码
安装目录
| 类型                     | 路径              |
| ---------------------------- | --------------------- |
| nginx.conf配置文件(安装目录) | /etc/nginx/nginx.conf |
| Nginx启动脚本                | /etc/sysconfig/nginx  |
| Nginx log目录                | /var/log/nginx        |
| Nginx pid文件                | /var/run/nginx.pid    |
1.2.2 手动编译安装
  1. 执行 yum install -y wget 命令,更新 wget ;
  2. 执行 wget http://nginx.org/download/nginx-1.14.0.tar.gz 命令下载 Nginx ;
  3. 执行 tar -zxvf nginx-1.14.0.tar.gz 解压 nginx ;
  4. 执行 yum install -y gcc-c++ pcre pcre-devel zlib zlib-devel 命令安装 gcc 环境;
  5. 执行 ./configure 配置;
  6. 执行 make && make install 命令安装 nginx 。
  7. 执行 yum install -y tree 命令安装 tree;
  8. `tree` 通过树形结果查看当前目录结构。
1.3 Nginx 常用命令
1.3.1 启动服务
java 复制代码
# 默认会加载 /usr/local/conf/nginx.conf 配置文件
/usr/local/nginx/sbin/nginx

# 指定加载配置文件启动
/usr/local/nginx/sbin/nginx -c conf/nginx.conf

# 启动nginx同时将进程ID写入指定pid文件
/usr/local/nginx/sbin/nginx -g "pid /usr/local/nginx/nginx.pid;"
1.3.2 停止服务
java 复制代码
# 停止nginx服务
/usr/local/nginx/sbin/nginx -s quit

/usr/local/nginx/sbin/nginx -s stop

# 指定pid文件停止服务
/usr/local/nginx/sbin/nginx -g "pid logs/nginx.pid;" -s quit

/usr/local/nginx/sbin/nginx -g "pid logs/nginx.pid;" -s stop

# 查看进程编号
ps -ef | grep nginx   

# 从容停止nginx
kill -quit 进程编号

# 快速停止nginx
kill -term 进程编号

# 强制结束进程
kill -9 进程编号
1.3.3 重新加载
java 复制代码
# 验证nginx.conf配置文件的语法
/usr/local/nginx/sbin/nginx -t

# 重新加载
/usr/local/nginx/sbin/nginx -s reload
# 或者执行 kill -hup
kill -hup master进程编号

# 查看nginx版本
/usr/local/nginx/sbin/nginx -v
1.4 Nginx 核心配置文件

Nginx.conf 的位置: /usr/local/nginx/conf/nginx.conf

1.4.1 配置文件介绍
  1. 每行配置的结尾需要加上分号。
  2. 如果配置项值中包括语法符号,比如空格符,那么需要使用单引号或双引号括住配置项值,否则 Nginx 会报语法错误。
  3. "#"注释符
  4. 单位简写
  • K 或者 k 千字节(KiloByte,KB)
  • M 或者 m 兆字节(MegaByte,MB)
  • ms(毫秒),s(秒),m(分钟),h(小时),d(天),w(周,包含 7 天),M(月,包含 30 天),y(年,包含 365 天)
1.4.2 main 段
java 复制代码
# 用于设置master进程启动后,fork出的worker进程运行在哪个用户和用户组下
#user  nobody;
# 指定工作衍生进程数(一般等于CPU的总核数或总核数的两倍,两个四个CPU,就设置8)
worker_processes  1;
# 指定错误日志存放的路径,错误日志记录级别可选 [debug | info | notice | warn | error | crit ]
#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;
# 指定 pid 存放的路径
#pid        logs/nginx.pid;

# 指定文件描述符数量
worker_rlimit_nofile 512000;
1.4.3 events 段
java 复制代码
events {
	# 使用的网络I/O模型,Linux推荐使用epoll模式 FreeBSD推荐使用kqueue模型
	use epoll;
	# 单个woker进程支持的最大连接数
    worker_connections  1024;
}
1.4.4 http 段
1.5 Nginx 虚拟主机配置
  1. 创建对应的文件夹
  2. 分别在这三个文件夹中放入对应的资源文件,我们随便放入一个 html 页面即可(能区别即可)
  3. 修改 nginx.conf 配置文件,添加三个 server 配置
java 复制代码
   server {
           listen       80;
   		# 虚拟主机配置
           server_name  bbs.gupao.com;
   
           #charset koi8-r;
   
           #access_log  logs/host.access.log  main;
   		# 虚拟主机对应的服务的资源地址
   		root   /usr/local/nginx/bbs;
           location / {
               index  index.html index.htm;
           }
   
           #error_page  404              /404.html;
   
           # redirect server error pages to the static page /50x.html
           #
           error_page   500 502 503 504  /50x.html;
           location = /50x.html {
               root   html;
           } 
       }
  1. 修改客户的 host 文件
  2. 测试
1.6 Nginx location 匹配规则
1.6.1 location 匹配规则

location 会尝试根据用户请求中的 URI 来匹配上面的/uri 表达式,如果可以匹配,就选择 location{}块中的配置来处理用户请求。当然,匹配方式是多样的,location 的匹配规则。
location [=|`~`|`~`*] /uri/ { ... }

java 复制代码
> ~      #波浪线表示执行一个正则匹配,区分大小写
>
> ~*     #表示执行一个正则匹配,不区分大小写
>
> =      #进行普通字符精确匹配
1.6.2 URI 匹配模式

location 的指令分为两种匹配模式

  1. 普通字符串匹配: 以=开头或者没有带正则引导符号(`~`)规则
  2. 2.正则匹配:以(`~`)开头或者(~*)开头的表示正则匹配
1.6.3 普通匹配模式
java 复制代码
location / {
    root   html;
    index  index.html index.htm;
}
location /demo {
    root   html;
    index  demo.html;
}

> 匹配规则:
>
> location 不是严格匹配,而是一个"前缀匹配"过程,所以在上面那个案例中,两个 location 都能够匹配,但是普通匹配会遵循一个最长匹配规则,也就是上面的请求中,最终 uri 会匹配到长度最大 location。也就是/demo

1.6.4 精准匹配模式

在普通匹配模式中,还可以细分出一种叫精准匹配模式,也就是通过等于号直接来匹配的,精准模式的优先级要比普通模式高!

java 复制代码
location =/demo {
    root  html; 
    index gp.html;
}
location /demo {
   root   html;
   index  demo.html;
}
1.6.5 正则匹配模式
java 复制代码
location ~* \.(jpg|png|css|js|gif)$ {
    root html/images;
}
1.6.6 匹配的优先级
  1. 首先看有没有精准匹配,如果有,则停止匹配过程。
  2. 判断普通命中,如果有多个命中,"记录"下最长的命中结果(记录但不结束)。
  3. 继续判断正则表达式,按配置里的正则表达式顺序为准,由上到下开始匹配,一旦匹配成功一个,立即返回结果并结束。
  • 普通命中,顺序无关,因为按照命中长短来确定。
  • 正则命中,顺序有关系,因为是从前往后命中。
1.6.7 实际使用的建议
  • 第一个必选规则
java 复制代码
  location  =/ {
      proxy_pass http://tomcat:8080/index
  }
  • 第二个必选规则是处理静态文件请求,这是 nginx 作为 http 服务器的强项;有两种配置模式,目录匹配或后缀匹配,任选其一或搭配使用。
java 复制代码
  location ^~ /static/ {
      root /webroot/static/;
  }
  
  location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ {
      root /webroot/res/;
  }
  • 第三个规则就是通用规则,用来转发动态请求到后端应用服务器非静态文件请求就默认是动态请求,自己根据实际把握。
java 复制代码
  location / {
      proxy_pass http://tomcat:8080/
  }
1.7 Nginx 应用
1.7.1 反向代理
  • 语法操作
java 复制代码
  server{
     listen 80;
     server_name localhost;
     location / {
         proxy_pass http://192.168.12.1:8081;
     }
  }
  • 修改请求方式
java 复制代码
  server{
     listen 80;
     server_name localhost;
     location / {
         proxy_pass http://192.168.12.1:8081;
         proxy_method POST;
     }
  }
  • 获取真实 IP
java 复制代码
  server{
  		listen 80;
  		server_name localhost;
  		location / {
  			proxy_pass http://192.168.12.1:8081;
  			proxy_method POST;
  			proxy_set_header Host $host;
  			#获取客户端的ip地址设置到header中
  			proxy_set_header X-Real-IP $remote_addr;        
  			#获取所有转发请求的ip信息列表
  			proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;   
  		}
  	}
1.7.2 负载均衡

网络负载均衡的大致原理是利用一定的分配策略将网络负载平衡地分摊到网络集群的各个操作单元上,使得单个重负载任务能够分担到多个单元上并行处理,使得大量并发访问或数据流量分担到多个单元上分别处理,从而减少用户的等待响应时间。
upstream 是 Nginx 的 HTTP Upstream 模块,这个模块通过一个简单的调度算法来实现客户端 IP 到后端服务器的负载均衡。

- upstream 块

java 复制代码
  upstream gupao{
  server 192.168.12.1:8081; 
  server 192.168.12.1:8082; 
  server 192.168.12.1:8083; 
  }

- server 块
语法:server address [parameters] server 必选。
address 也必选,可以是主机名、域名、ip,也可以指定端口号。
parameters 是可选参数,可以是如下参数:

  • down:表示当前 server 已停用。
  • backup:表示当前 server 是备用服务器,只有其它非 backup 后端服务器都挂掉了或者很忙才会分配到请求。
  • weight:表示当前 server 负载权重,权重越大被请求几率越大。默认是 1max_fails 和fail_timeout 一般会关联使用,如果某台 server 在 fail_timeout 时间内出现了 max_fails 次连接失败,那么 Nginx 会认为其已经挂掉了,从而在 fail_timeout 时间内不再去请求它,fail_timeout 默认是 10s,max_fails 默认是 1,即默认情况是只要发生错误就认为服务器挂掉了,如果将 max_fails 设置为 0,则表示取消这项检查。

    - 负责均衡策略
    轮询(默认)每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器 down 掉,能自动剔除。

    ip_hash: 每个请求按访问 ip 的 hash 结果分配,这样每个访客固定访问一个后端服务器,可以解决 session 的问题。

    权重:即可以指定轮询比率,weight 和访问几率成正比,主要应用于后端服务器异质的场景下。
1.7.3 动静分离
1.7.3.1 动静分离
java 复制代码
server{
   listen 80;
   server_name localhost;
   location / {
       proxy_pass http://192.168.12.1;
       proxy_set_header Host $host;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_send_timeout 60s;
       proxy_read_timeout 60s;
       proxy_connect_timeout 60s;
   }
   location ~ .*\.(gif|jpg|ico|png|css|svg|js)$ {
       root static;
   }
}
1.7.3.2 缓存处理

Etag:对象的标志值,就一个对象而言,文件被修改,Etag 也会修改。

java 复制代码
location ~ .*\.(jpg|jpeg|gif|bmp|png|js|css|ico)$ {
   root static;
   expires 1d;
}
1.7.3.3 优化压缩

Gzip on|off 是否开启 gzip 压缩
Gzip_buffers 4 16k #设置 gzip 申请内存的大小,作用是按指定大小的倍数申请内存空间。4 16k 代表按照原始数据大小以 16k 为单位的 4 倍申请内存。
Gzip_comp_level[1-9] 压缩级别, 级别越高,压缩越小,但是会占用 CPU 资源。
Gzip_disable #正则匹配 UA 表示什么样的浏览器不进行 gzip。
Gzip_min_length #开始压缩的最小长度(小于多少就不做压缩),可以指定单位,比如 1k。
Gzip_http_version 1.0|1.1 表示开始压缩的 http 协议版本。
Gzip_proxied (nginx 做前端代理时启用该选项,表示无论后端服务器的 headers 头返回什么信息,都无条件启用压缩)。
Gzip_type text/pliain,application/xml 对 那 些 类 型 的 文 件 做 压 缩 (conf/mime.conf)。
Gzip_vary on|off 是 否 传 输 gzip 压 缩 标 识 ; 启 用 应 答 头 "Vary:
Accept-Encoding";给代理服务器用的,有的浏览器支持压缩,有的不支持,所以避免浪费不支持的也压缩,所以根据客户端的 HTTP 头来判断,是否需要压缩。
gzip on;
gzip_min_length 5k;
gzip_buffers 4 16k;
gzip_comp_level 3;
gzip_types application/javascript image/jpeg;
gzip_vary on;
> 最后注意:
>
> 1. 图片、mp3 这样的二进制文件,没必要做压缩处理,因为这类文件压缩比很小,压缩过程会耗费 CPU 资源。
> 2. 太小的文件没必要压缩,因为压缩以后会增加一些头信息,反而导致文件变大。
> 3. Nginx 默认只对 text/html 进行压缩 ,如果要对 html 之外的内容进行压缩传输,我们需要手动来配置。

1.7.4 Nginx 原理分析
1.7.4.1 Nginx 进程模型分析
  • 多进程方式
  • 多线程方式
  • 同步方式
  • 异步方式
1.7.4.2 Nginx 原理


1.7.4.3 worker 进程是如何处理请求?


相关推荐
2301_7722042821 小时前
Linux 驱动开发:杂项设备驱动与自动设备号管理
linux·运维·驱动开发
黄昏晓x21 小时前
Linux----缓冲区
linux·运维·服务器
2501_9011478321 小时前
学习笔记:单调递增数字求解的迭代优化与工程实践
linux·服务器·笔记·学习·算法
2501_924878731 天前
AdAgent 能力成熟度模型:从 L1 自动化到 L5 自主增长引擎
运维·自动化
寄存器漫游者1 天前
Linux 软件编程 命令、内核与 Shell
linux·运维·服务器
Kaede61 天前
服务器硬件防火墙和软件防火墙的区别
运维·服务器
qinyia1 天前
通过本地构建解决Cartographer编译中absl依赖缺失问题
linux·运维·服务器·mysql·ubuntu
萧曵 丶1 天前
Docker 面试题
运维·docker·容器
七牛云行业应用1 天前
3.5s降至0.4s!Claude Code生产级连接优化与Agent实战
运维·人工智能·大模型·aigc·claude
小草cys1 天前
鲲鹏920服务器安装openEuler后无法联网,但物理网线已连接
运维·服务器·openeuler