什么是nginx?
- 是一个高性能的负载均衡服务器,处理并发能力强、效率高
- 内存消耗小:开启10nginx服务才占150M内存。
- 运行时间长:即使运行数月也不需要重新启动,还能在不间断服务的情况下进行软件版本的升级
nginx模块讲解
nginx主要分为三个模块:全局块
、events块
、http块
。
其中http块又由server块
、location块
、upstream块
组成
# 全局块:定义影响全局的配置,如用户、worker进程数量、错误日志等
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768; # 每个worker进程的最大连接数
}
http {
# http块:定义HTTP服务器的配置,如mime类型、日志、压缩等
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 on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
# server块:定义虚拟主机的配置,每个server块代表一个虚拟主机
server {
listen 80; # 监听端口
server_name example.com; # 服务器域名
# location块:定义URL匹配的处理规则
location / {
root /var/www/html; # 根目录
index index.html index.htm; # 默认文件
}
location /images/ {
root /var/www/data; # 指定目录
}
# 配置反向代理
location /proxy/ {
proxy_pass http://backend_servers; # 转发到后端服务器池
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
# 定义后端服务器池
upstream backend_servers {
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}
}
全局块
主要定义一些全局属性。如worker进程数、日志等全局属性
user www-data; # 定义运行NGINX进程的用户
worker_processes auto; # 自动检测并设置worker进程数
pid /run/nginx.pid; # 定义存储进程ID文件的位置
include /etc/nginx/modules-enabled/*.conf; # 包含额外的模块配置
events块
主要定义nginx的worker进程的最大连接数
events {
worker_connections 768; # 每个worker进程的最大连接数
}
http块
定义所有与http服务(服务/应用)的相关配置;如连接超时时间。可以包含多个server块,每个server代表一个服务
http {
include /etc/nginx/mime.types; # 包含mime类型定义
default_type application/octet-stream; # 默认的mime类型
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 on; # 启用高效文件传输模式
tcp_nopush on; # 提高TCP传输效率
tcp_nodelay on; # 减少TCP延迟
keepalive_timeout 65; # 连接保持的超时时间
types_hash_max_size 2048; # 提高mime类型的哈希表大小
include /etc/nginx/conf.d/*.conf; # 包含额外的配置文件
include /etc/nginx/sites-enabled/*; # 包含虚拟主机配置文件
server块
定于一个服务的相关配置。一个server块包含多个location块。每个location定义特定URL的处理规则。
server {
listen 80; # 监听80端口
server_name example.com; # 定义虚拟主机的域名
location / {
root /var/www/html; # 定义根目录
index index.html index.htm; # 默认文件
}
location /images/ {
root /var/www/data; # 定义/images/路径的目录
}
location /proxy/ {
proxy_pass http://backend_servers; # 配置反向代理
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
upstream块
定义和管理后端服务器,用于负载均衡和反向代理
upstream backend_servers {
server backend1.example.com; # 定义后端服务器1
server backend2.example.com; # 定义后端服务器2
server backend3.example.com; # 定义后端服务器3
}
}
worker进程
nginx采用的是多进程架构;主要由一个主进程(master process)和多个worker进程组成,每个worker进程互相隔离,单独处理请求。
主进程
- 负责管理(启动、停止)所有worker进程,同时将请求路由分发给worker进程
- 读取和验证配置文件
- 处理系统相关级别工作(如重载配置,重启服务)
worker进程
- 各个worker进程相互隔离,独立处理客户端请求。
- 每个woker进程只有一个线程来进行工作。采用异步、非阻塞的事件驱动模型来处理连接和请求
流程:
- 启动:nginx启动时,主进程加载全局配置信息,并启动对应数量的worker进程
- 请求处理:客户端请求到达时,主进程将请求分发worker进程,worker根据连接请求转发到目标服务中。
示例配置解释
# 全局块
user www-data; # 定义运行NGINX进程的用户
worker_processes auto; # 自动设置worker进程数量,通常设置为CPU核心数
pid /run/nginx.pid; # 定义存储主进程ID文件的位置
events {
worker_connections 768; # 每个worker进程的最大连接数
}
连接:表示TCP或者websocket连接(nginx支持websocket)。连接的超时时间在http块中定义
http {
# 全局配置
keepalive_timeout 65; # 保持连接的超时时间为65秒
keepalive_requests 100; # 每个连接最多处理100个请求
}
异步非阻塞事件处理机制
为什么都说nginx的性能高,其实nginx内部是采用多进程架构+异步非阻塞事件处理机制。
线程一直持续工作,减少了大量的CPU上下文切换。
异步非阻塞事件处理机制:
线程是进程的执行单元,线程获取CPU使用权就会执行任务(代码)。但是线程在执行过程因为某些情况会放弃CPU使用权,进入阻塞状态。
- 示例1 线程执行I/O(网络I/O)任务时,线程会阻塞放弃CPU使用权,并等待I/O任务完成,重新等待CPU调用。
- 示例2 线程获取锁资源时,会进行阻塞放弃CPU使用权,直到当前线程获取锁后,再次等待CPU调度。
这两个实例中,线程在执行过程中都会阻塞,会偷懒,不再往后执行相关代码,直到阻塞消失(I/O完成,获取到锁)。在这种情况下 线程执行任务会非常慢。 那有没有一种办法 让线程一直工作不让线程阻塞(偷懒)。这种办法就叫做 异步非阻塞事件处理机制
假设当前有多个请求进入到同一个worker进程中。
异步非阻塞:当第一个请求被处理时,线程不会一直等待该请求结果,而是直接处理其它请求,当第一个请求完成接收到结果后,线程再来处理该请求。这样可以更好地利用系统资源,提高处理效率。
详细步骤:
- 当有多个请求同时发送时,nginx的主进程会将请求分发不同worker进程或者是同一个worker进程进行处理
- worker进程都有一个循环监听事件,一个单独的线程,线程请求发送给目标服务,就会立马处理其它请求
- 当目标服务处理完成请求后,会响应给nginx(具体worker进程),循环监听事件监听到了响应,就会告知线程处理响应。这样就会提高线程的执行效率.
- 根据相关配置,关闭连接。
总结:请求会分发给多个worker进程,实际上同一时间还是有多个线程处理请求(并发处理请求)。只不过这些线程来自不同的进程,又因为线程不会休息,新的请求进来时很快就被处理,执行效率快,所以并发能力也会提高。
nginx监听规则
在server模块经常能看到这个属性:listen
、server_name
server {
listen 80; # NGINX监听80端口
server_name example.com;
location /image/{
root /home/image/;
expires 30d;
}
# 定义所有请求的处理规则
location / {
# 将请求转发到目标网站
proxy_pass http://testServer.com:8848;
# 设置代理请求的头部信息
# 将请求的Host头部信息设置为客户端请求中的Host
proxy_set_header Host $host;
# 将客户端的IP地址传递给目标服务器
proxy_set_header X-Real-IP $remote_addr;
# 将客户端的真实IP地址包含在请求的X-Forwarded-For头部中
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
listen:表示监听的端口,通常为nginx所在服务器的端口
server_name:表示监听的IP/域名,通常为nginx所在服务器
在我们前端应用中,通常是指定具体的后端服务器IP进行交互,如testServer.com:8848/list。
但是部署到nginx后,项目是不需要指定后端服务器,nginx根据url会自动将请求路由到后端服务器。如下:
发送请求 example.com:80/image/xx.jpg 。就会从nginx所在服务器的/home/image/ 目录下找
发送请求 example.com:80/list;就会转发给testServer.com服务器。url就变成了testServer.com:8848/list
正向代理
代理对象是 客户端
;当客户端想要访问某一网站(服务器)时,nginx就会代理客户端去发送请求,同时隐藏客户端IP地址。
流程:
- 发送请求要目标网站(服务器)时,nginx会拦截请求并生成代理服务器,由它去与目标网站进行交互
- 代理服务器将请求发送给目标网站
- 目标网站返回响应给代理服务器
- 代理服务器返回给客户端
在服务器角度,与我交互的是代理服务器,所以我并不知道客户端的IP地址
示例:客户端通过监听端口
发送请求到 example.com 网站,就会生成代理服务器与服务器进行交互,同时可以选择是否隐藏真实IP地址。
# 定义代理服务器监听的端口
server {
listen 8080;
# 定义所有请求的处理规则
location / {
# 将请求转发到目标网站
proxy_pass http://example.com;
# 设置代理请求的头部信息
# 将请求的Host头部信息设置为客户端请求中的Host
proxy_set_header Host $host;
# 将客户端的IP地址传递给目标服务器
proxy_set_header X-Real-IP $remote_addr;
# 将客户端的真实IP地址包含在请求的X-Forwarded-For头部中
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
反向代理
代理对象是 服务器
;一个大的网站,通常会有多个服务器来处理请求,保证服务的高可用性。nginx就代理这些服务器,当检测到有请求要进入到网站时,就会为网站生成一个代理服务器,并根据负载均衡策略决定将请求路由到哪个服务器中。
流程:
- 客户端发送请求给目标网站,nginx会生成代理服务器
- nginx根据负载均衡策略,决定将请求路由到具体服务器中。同时隐藏真实服务器IP
- 服务器处理请求并将响应结果返回给代理服务器。
- 代理服务器将响应结果放回给客户端。
在客户端角度,与我交互的是代理服务器,我并不知道请求路由到哪个具体的服务器(IP)中
示例:
一个大型网站有很多后端服务器处理用户请求,通过反向代理服务器分发请求以提高性能和安全性
# 定义代理服务器监听的端口
server {
listen 80;
# 定义所有请求的处理规则
location / {
# 将请求转发到后端服务器池
proxy_pass http://backend_servers;
# 设置代理请求的头部信息
# 将请求的Host头部信息设置为客户端请求中的Host
proxy_set_header Host $host;
# 将客户端的IP地址传递给后端服务器
proxy_set_header X-Real-IP $remote_addr;
# 将客户端的真实IP地址包含在请求的X-Forwarded-For头部中
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
# 定义后端服务器池
upstream backend_servers {
# 定义多个后端服务器
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}
反向代理通常会使用 upstream
指令来定义和管理后端服务器。
其实在上方反向代理示例中,也有使用正向代理来代理客户端。
正向、反向代理区别:从nginx配置文件
中来看就是是否使用了 upstream
指令
nginx解决跨域
nginx采用CORS策略来跨域。
server {
listen 80;
server_name example.com;
location / {
# 允许所有来源的跨域请求
add_header Access-Control-Allow-Origin *;
# 允许指定的请求方法
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, HEAD";
# 允许携带认证信息
add_header Access-Control-Allow-Credentials true;
# 允许指定的请求头字段
add_header Access-Control-Allow-Headers "Authorization, Origin, X-Requested-With, Content-Type, Accept";
# 设置预检请求的有效期
add_header Access-Control-Max-Age 3600;
# 配置处理请求的指令
}
}
负载均衡
轮询
每个客户端的请求有序的转发到不同的服务器中,默认是轮询
权重论询
就如某一个服务器比其他服务器更好,我就让客户端的请求多转发到这个服务器中,weight代表权重
在nginx.conf中的配置:
第一步:在http全局块添加负载均衡的服务器列表
第二步:在server块中的location中设置它的映射规则
想要加权重,可在服务器列表中加weight
server 192.168.17.129:8080 weight=5;
server 192.168.17.129:8081 weight=10;
这样8080的服务器处理的量就多一倍
最小连接
下一个连接会被路由到连接数最小的服务器中
IP哈希
每个请求按访问IP的hash结果进行路由,这样每个客户端固定一个后端服务器。
实际中,不考虑使用该方法
动静分离
简单来说就是把动态资源(请求)跟静态资源(图片)分开,分别部署到不同服务器中。
好处:静态资源由nginx处理,减少了后端服务器的负载,提高了响应速度。同时后端服务器只需要处理动态请求即可。
示例:静态资源部署到nginx所在服务器中
url为/image/xx.jpg时就会从/var/www/image/目录下获取
server {
listen 80;
server_name example.com;
# 处理静态文件
location /image/ {
root /var/www/image/;
expires 30d;
}
# 处理动态请求
location / {
proxy_pass http://backend_server;
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_set_header X-Forwarded-Proto $scheme;
}
}
upstream backend_server {
server 127.0.0.1:8080; # 后端服务器地址
}
为什么说nginx处理静态资源就快,而处理动态快呢
这是项目的静态资源都部署在nginx所在的服务器上,所以nginx读取静态资源就非常快。
而处理动态资源,需要解析请求,将请求转发到目标服务器。同时涉及到负载均衡策略等问题。目标服务器返回响应给nginx时还要将响应数据返回给客户端。这一过程非常的繁琐,所消耗的资源也比处理静态资源时多。
限流规则
- 基于连接数限流
- 基于每秒的请求数限流
注:nginx的限流是作用在目标服务器,而不是nginx服务本身。
基于连接数限流
说明:某个客户端IP与nginx发起的连接数超过了阈值,那么超出的连接将会被nginx拒绝。防止某个客户端ip地址与nginx的连接数过载。
http {
# 定义连接限制的共享内存区域,10m是内存大小
limit_conn_zone $binary_remote_addr zone=addr:10m;
server {
listen 80;
server_name example.com;
# 限制每个 IP 地址最多允许 10 个连接
limit_conn addr 10;
location / {
# 配置处理请求的指令
}
}
}
使用 limit_conn_zone 指令定义了一个共享内存区域,用于存储连接限制的状态信息。$binary_remote_addr 是一个 NGINX 变量,表示客户端的 IP 地址,zone=addr:10m 指定了共享内存区域的名称为 addr,大小为 10MB。
每个客户端与nginx进行交互,都会进行一个TCP连接,后续的请求都会复用这个连接,连接过了超时时间后就会销毁。
连接超时时间设置:
http {
keepalive_timeout 30s; # 设置连接超时时间为 30 秒
server {
listen 80;
server_name example.com;
location / {
# 配置处理请求的指令
}
}
}
基于每秒的请求数限流
说明:每秒最多处理多少个请求
http {
# 定义请求速率限制的共享内存区域,10m是内存大小,rate=10r/s表示每秒允许的请求速率
limit_req_zone $binary_remote_addr zone=req_zone:10m rate=10r/s;
server {
listen 80;
server_name example.com;
# 每秒最多允许 10 个请求,突发量不超过 20 个,10-20之间的请求会延迟处理,超过20的请求会直接拒绝。
limit_req zone=req_zone burst=20 nodelay;
location / {
# 配置处理请求的指令
}
}
}
nginx的基于请求数量限流是根据令牌桶算法实现的。
参考文章:限流:计数器、漏桶、令牌桶 三大算法的原理与实战(史上最全)
高可用主备模式
我们是无法确定一个软件是一直运行下去的,所有当nginx坏了的时候,我们需要设置另外一个nginx来完善工作,这里需要下载keepalived来管理nginx,当keppalived检测到主nginx坏了,就会启用备用nginx
参考链接:Nginx配置参数详解
全文参考连接:
Nginx面试题(总结最全面的面试题!!!)
本站资源均来自互联网,仅供研究学习,禁止违法使用和商用,产生法律纠纷本站概不负责!如果侵犯了您的权益请与我们联系!
转载请注明出处: 免费源码网-免费的源码资源网站 » Nginx
发表评论 取消回复