开源反向代理工具-Nginx

Nginx简介

NGINX 是一种高性能的反向代理服务器、负载均衡器和 HTTP 缓存服务器。它的设计初衷是为了应对高并发和低资源消耗,尤其适合处理大量的短连接请求。NGINX 的高效性能来自其事件驱动架构和异步非阻塞的处理方式。

Nginx工作原理

1.事件驱动模型

Nginx使用的是一种基于事件的异步非阻塞模型,也就是它能够在处理客户端请求时,不会因为等待某个操作(如I/O操作)而阻塞整个进程。相比传统的基于线程或进程的模型(如Apache),这种方式极大地提高了资源利用率。

事件循环:Nginx采用事件驱动机制管理连接,当有事件发生时,它会被通知并执行相应的操作。例如,一个新的客户端连接会触发accept事件,数据的读取会触发read事件。

异步非阻塞:在等待I/O操作时(如从磁盘读取文件或向客户端发送数据),不会阻塞其他操作。即使正在处理大量请求,单个请求的延迟也会尽可能保持较低。

2.Master-Worker多进程架构

Nginx采用了Master-Worker进程模型,Master进程负责管理Worker进程(包括启动、停止和监控等),而Worker进程负责处理实际的客户端请求。

Master进程:负责配置加载、管理Worker进程等。

Worker进程:负责处理客户端的连接。每个Worker进程独立处理请求,并且它们之间不共享任何状态。通过这种设计,NGINX能够在不锁住资源的情况下处理大量并发请求。

3.反向代理和负载均衡

Nginx主要用于反向代理服务器,即它会接收客户端的请求,转发到后端服务器,并将后端服务器的响应返回给客户端。这使得NGINX成为一个强大的负载均衡器,可以将流量分配给多个后端服务器,以实现更高的可用性和扩展性。

反向代理:Nginx接受客户端请求,将请求转发给后端服务器,并返回后端服务器的响应。

负载均衡算法:它支持多种负载均衡策略,比如轮询(RoundRobin)、权重轮询(Weighted Round Robin)、IP 哈希(IP Hash)、最少连接(LeastConnections)以及第三方模块提供的Fair、URL Hash等。

4.高并发处理

Nginx由于其事件驱动模型和多进程架构,特别适合处理高并发连接。例如,在高并发场景下,Nginx可以在一个工作进程中处理成千上万的连接,而不会因为线程或进程上下文切换导致性能下降。

5.静态资源缓存

Nginx还可以作为一个静态内容服务器,特别擅长处理静态资源如图片、CSS、JavaScript文件的缓存。通过缓存策略,它可以极大地减少后端服务器的负载,并提升整体的响应速度。

6.模块化设计

Nginx支持高度模块化,用户可以根据需求选择或编写自定义的模块。例如,使用SSL模块处理HTTPS请求,或者使用Gzip模块进行压缩等。

Nginx执行流程

在 NGINX 中,处理客户端请求时,它的执行顺序主要遵循以下几个阶段。NGINX 的执行流程是基于事件驱动的,因此它对请求的处理遵循模块化的方式。每个请求会经过一系列预定义的阶段,确保请求按照正确的顺序被处理。

1.接收请求

NGINX通过其事件驱动的架构接收到客户端请求。此时,主进程负责接收连接,并将请求分配给一个可用的工作进程(Worker)。请求被交给Worker后,进入请求处理流程。

2.选择服务器块(server block)

NGINX首先会在配置文件中根据客户端请求的主机名和端口号,查找最合适的server块来处理请求。如果请求中包含了匹配的server_name和listen端口,NGINX将确定使用哪个server块来继续处理请求。

>按照listen指令和server_name指令来匹配。

>如果没有明确匹配的server_name,则使用default的server块。

3.选择位置块(location block)

在确定了合适的server块后,NGINX接下来会根据请求的URI路径,查找最匹配的location块。location匹配返回顺序如下(重要):

精确匹配

如果使用=符号开头的location,表示精确匹配整个URI。

这种匹配优先级最高,如果找到,则立即使用该location,并停止进一步的匹配。

location = / {

处理根路径的请求

}

带^~的前缀匹配

^~表示如果某个前缀匹配成功,不再进行正则表达式匹配,即优先匹配前缀。

这是用来指示NGINX优先使用前缀匹配而不是正则匹配的方式。

location ^~ /static/ {

匹配所有以/static/开头的URI,并停止继续查找正则表达式匹配

}

正则表达式匹配

正则表达式匹配用于更加复杂的匹配规则。正则匹配在前缀匹配之后进行。

~用于大小写敏感的正则表达式匹配。

~*用于大小写不敏感的正则表达式匹配。
正则表达式从上到下匹配,不同的正则表达式在Nginx配置文件中的出现顺序,会影响匹配结果。

location ~ \.php$ {

匹配所有以.php结尾的请求 (大小写敏感)

}

location ~* \.(jpg|jpeg|png)$ {

匹配所有以.jpg, .jpeg, .png结尾的请求 (大小写不敏感)

}

前缀匹配(常规匹配)

NGINX默认情况下按前缀匹配。即URI以某个字符串开头,匹配定义的location块。
NGINX会找到最长的前缀匹配,所以常规匹配在****Nginx 配置文件中没有先后顺序要求。

location /images/ {

处理以 /images/ 开头的所有请求,不包括/images/1/

}

location /images/1/ {

处理以/images/1/开头的所有请求

}

通用匹配

如果没有其他location块匹配到URI,/会作为兜底匹配项。这是最通用的匹配,表示匹配所有请求。

location / {

匹配所有没有被其他 location 块处理的请求

}

4.处理重写规则(rewrite directives)

如果在server或location块中有rewrite指令,Nginx将在此时执行重写规则,改变URI并可能重新选择一个合适的location。重写规则允许修改请求的URI或跳转到其他处理方式。

5.处理访问控制

在处理完重写后,NGINX会检查任何访问控制相关的配置,比如IP限制、允许/禁止访问的规则(allow和deny指令)。如果请求被拒绝,NGINX会返回相应的错误响应。

6.处理代理或静态文件

根据location块的配置,NGINX可能会执行不同的操作,如:

静态文件处理:如果请求的是静态文件,NGINX会直接从文件系统中读取并返回该文件。

反向代理:如果proxy_pass配置存在,NGINX会将请求转发给后端服务器,并将后端的响应返回给客户端。

FastCGI/uwsgi等应用层处理:如果配置了FastCGI、uwsgi等,NGINX会将请求转发给这些处理器。

7.执行过滤器

NGINX可能会对响应进行多种过滤处理,比如:压缩响应数据(如启用了gzip)、添加或修改响应头信息、其他响应内容的处理。这些过滤器按照一定的顺序执行,确保响应在返回客户端之前被适当修改。

8.发送响应

在完成请求处理后,NGINX将结果返回给客户端。响应可以是:来自后端服务器的动态内容;从缓存或文件系统中获取的静态内容;错误页面(如404或500)等。

9.记录日志

最后,Nginx会根据配置将请求的处理结果记录到访问日志中(如access_log和error_log),便于后续分析和排错。

Nginx常用配置

1.反向代理负载均衡

轮询(Round Robin),默认算法,将请求依次分发到每台服务器

upstream backend {

server backend1.example.com;

server backend2.example.com;

}

server {

location /api {

proxy_pass http://backend/api ;

}

}

权重轮询(Weighted Round Robin),根据权重分配请求,权重越高,分配的请求越多

upstream backend {

server backend1.example.com weight=3;

server backend2.example.com weight=1;

}

server {

location /api {

proxy_pass http://backend/api ;

}

}

IP 哈希(IP Hash),根据客户端的IP地址进行哈希计算,将请求分发到固定的服务器上

upstream backend {

ip_hash;

server backend1.example.com;

server backend2.example.com;

}

server {

location /api {

proxy_pass http://backend/api ;

}

}

最少连接数(Least Connections),将请求分发到当前连接数最少的服务器上

upstream backend {

least_conn;

server backend1.example.com;

server backend2.example.com;

}

server {

location /api {

proxy_pass http://backend/api ;

}

}

Fair,第三方模块,智能负载均衡算法,根据后端服务器的响应时间和负载情况来分配请求。与传统的轮询算法不同,Fair策略会优先将请求分配给响应时间较短、负载较轻的服务器,从而提高整体系统的性能和响应速度

upstream backend {

fair;

server backend1.example.com;

server backend2.example.com;

}

server {

location /api {

proxy_pass http://backend/api ;

}

}

URL Hash,第三方模块,通过对请求的URL进行哈希计算,将请求分配到特定的服务器上。这种策略特别适用于需要提高缓存命中率的场景

upstream backend {

hash $request_uri;

server backend1.example.com;

server backend2.example.com;

}

server {

location /api {

proxy_pass http://backend/api ;

}

}

2.日志输出

输出格式

Nginx的日志输出为JSON格式是一个常见的需求,因为JSON格式的日志便于日志管理工具(如 ELK Stack)解析和分析。为了让Nginx以JSON格式输出日志,可以按照以下步骤配置:

备份并编辑Nginx配置文件(通常是 /etc/nginx/nginx.conf

修改 log_format 指令,将其格式化为 JSON 格式

http {

log_format json_combined escape=json '{'

'"time_local": "$time_local",'

'"remote_addr": "$remote_addr",'

'"remote_user": "$remote_user",'

'"request": "$request",'

'"status": "$status",'

'"body_bytes_sent": "$body_bytes_sent",'

'"http_referer": "$http_referer",'

'"http_user_agent": "$http_user_agent",'

'"http_x_forwarded_for": "$http_x_forwarded_for",'

'"request_time": "$request_time",'

'"upstream_response_time": "$upstream_response_time",'

'"upstream_addr": "$upstream_addr",'

'"upstream_status": "$upstream_status",'

'"host": "$host"'

'}';

access_log /var/log/nginx/access.log json_combined;

}

输出字段

Nginx默认的日志输出字段太少,不便于排查问题,流量分析等,我们可以添加输出的字段,例如:

$host:请求主机头字段,否则为服务器名称

$upstream_status:记录上游服务器返回的HTTP状态码

$upstream_addr:记录处理请求的上游服务器的地址

$upstream_response_time:记录从上游服务器接收到响应的时间

$http_x_forwarded_for: 客户端的真实ip(非常有用,根据返回的ip层级数量,可以筛选安全攻击事件)

$server_addr:服务器地址,在完成一次系统调用后可以确定这个值

$server_name:服务器名称

$server_port:请求到达服务器的端口号

$request_uri:包含请求参数的原始URI

$http_user_agent:客户端agent信息

$request_body:记录POST请求的body内容,这对于调试和监控非常有帮助

3.重写功能

rewrite

Nginx的rewrite指令用于基于正则表达式修改请求的URI。它可以在serverlocationif块中使用,并支持多种标志(flags)来控制重写行为,以下是一些关键知识点和配置示例:

rewrite [pattern] [replacement] [flags];

pattern:要匹配的URI模式可以使用正则表达式。

replacement:重写后的URI。

flags:控制重写行为的标志如last、break、redirect、permanent等。

其中几种flags的说明如下:

last :停止处理当前的重写规则,并重新发起一个新的请求来匹配新的location。这意味着重写后的URL会被重新解析并匹配新的location块。
break :停止处理当前的重写规则,但不会重新发起新的请求。这意味着重写后的URL不会被重新解析,只会在当前的location块内继续处理。
redirect :返回302临时重定向。
permanent:返回301永久重定向。

两个示例

location /old-url/ {

rewrite ^/old-url/(.*)$ /new-url/$1 permanent;

}

#将所有以/old-url开头的请求重写为/new-url开头,并返回301永久重定向
if ($http_user_agent ~* "iPhone") {

rewrite ^(.*)$ /mobile$1 break;

}

#iPhone用户的请求进行重写为/mobile开头

return

Nginx的return指令用于立即返回一个HTTP状态码和可选的响应体。它可以在serverlocation块中使用,常用于简单的重定向或返回特定的状态码:

server {

listen 80;

server_name example.com;

return 301 https://server_namerequest_uri;

}

#将所有HTTP请求重定向到HTTPS,并返回301永久重定向

缓存控制

浏览器缓存控制

浏览器缓存可以通过设置HTTP头部字段来实现,主要包括强缓存和协商缓存

强缓存指的是浏览器在缓存有效期内直接从缓存中读取资源,而不与服务器进行任何通信。可以通过以下指令配置:

location / {

expires 30d; # 设置缓存时间为30天

add_header Cache-Control "public, max-age=2592000"; # 30天的秒数

}

协商缓存指的是浏览器在每次请求资源时,都会向服务器确认资源是否更新。常用的HTTP头部字段包括Last-Modified和ETag

location / {

add_header Last-Modified $date_gmt;

add_header ETag $request_uri;

if_modified_since exact;

etag on;

}

代理缓存控制

Nginx还可以作为反向代理服务器缓存后端服务器的响应。首先,定义缓存的路径和一些参数:

proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m use_temp_path=off;

#/data/nginx/cache:缓存文件存储的路径。

#levels=1:2:缓存目录的层级结构,防止单个目录中包含过多文件。

#keys_zone=my_cache:10m:定义一个共享内存区域,用于存储缓存键和元数据。

#max_size=10g:缓存的最大大小。

#inactive=60m:未被访问的缓存项在60分钟后会被删除。

#use_temp_path=off:将缓存文件直接写入最终目录,避免不必要的数据复制

然后,在需要缓存的location块中启用代理缓存:

server {

listen 80;

server_name example.com;

location / {

proxy_cache my_cache;

proxy_pass http://backend_server;

proxy_set_header Host $host;

proxy_set_header X-Real-IP $remote_addr;

proxy_cache_valid 200 302 10m;

proxy_cache_valid 404 1m;

proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;

}

}

#proxy_cache my_cache:启用之前定义的缓存区域。

#proxy_pass http://backend_server:将请求转发到后端服务器。

#proxy_set_header:设置一些头部信息。

#proxy_cache_valid:定义不同响应状态码的缓存时间。

#proxy_cache_use_stale:在后端服务器出现错误或超时时,使用过期的缓存内容。

访问控制

Nginx提供了强大的访问控制功能,可以通过 allowdeny指令来基于IP地址进行访问控制。通过这些指令,你可以允许或禁止特定IP地址或IP段访问你的Nginx服务器资源。allowdeny可以在httpserverlocation 块中使用,以下是几个示例

location /admin {

deny all; # 禁止所有 IP 访问

allow 192.168.1.1; # 允许特定 IP 访问

}
location / {

allow all; # 允许所有 IP 访问

deny 192.168.1.100; # 禁止特定 IP 访问

}
http {

allow 192.168.1.0/24; # 全局允许指定 IP 段访问

deny all; # 全局禁止其他 IP 访问

}

相关推荐
小安运维日记7 分钟前
CKA认证 | Day3 K8s管理应用生命周期(上)
运维·云原生·容器·kubernetes·云计算·k8s
小han的日常34 分钟前
接口自动化环境搭建
运维·自动化
小扳36 分钟前
Docker 篇-Docker 详细安装、了解和使用 Docker 核心功能(数据卷、自定义镜像 Dockerfile、网络)
运维·spring boot·后端·mysql·spring cloud·docker·容器
运维小文40 分钟前
服务器硬件介绍
运维·服务器·计算机网络·缓存·硬件架构
是安迪吖1 小时前
nfs服务器
运维·服务器
鱼骨不是鱼翅1 小时前
模拟回显服务器
运维·服务器
Elastic 中国社区官方博客2 小时前
使用真实 Elasticsearch 进行更快的集成测试
大数据·运维·服务器·数据库·elasticsearch·搜索引擎·集成测试
舞动CPU8 小时前
linux c/c++最高效的计时方法
linux·运维·服务器
皮锤打乌龟8 小时前
(干货)Jenkins使用kubernetes插件连接k8s的认证方式
运维·kubernetes·jenkins
钰@9 小时前
小程序开发者工具的network选项卡中有某域名的接口请求,但是在charles中抓不到该接口
运维·服务器·小程序