网站首页 >> 建站技术 >> 正文
标题

Nginx实战:缓存、压缩、黑白名单。。常用Nginx运维指南!推荐!

kmwl520   2024-04-16 10:14:07   23℃   0
内容
前言

Nginx是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。


它由伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点开发,并以类BSD许可证的形式发布。

Nginx因其稳定性、丰富的功能集、简单的配置文件和低系统资源的消耗而闻名。

其特点是占有内存少,并发能力强,在同类型的网页服务器中表现较好。

Nginx是目前负载均衡技术中的主流方案,几乎绝大部分项目都会使用它。

Nginx与Redis相同,都是基于多路复用模型构建出的产物,因此它与Redis同样具备资源占用少、并发支持高的特点,在理论上单节点的Nginx同时支持5W并发连接,而实际生产环境中,硬件基础到位再结合简单调优后确实能达到该数值。

接下来本文将讲解下nginx相关配置使用以及文末会讲到Nginx相关性能优化问题。

1.反向代理-负载均衡

Nginx负载均衡是指利用Nginx将网络请求分发到多个服务器上,以便平衡服务器的负载,提高网络服务的可用性和可扩展性。Nginx实现负载均衡的几种主要策略有:

轮询(Round Robin):Nginx默认负载均衡算法,每个请求按时间顺序逐一分配到不同的后端服务器。如果后端某台服务器死机,自动剔除故障系统,使用户访问不受影响。

upstream backend {
server bk1.com;
server bk2.com;

}
server {
location / {
proxy_pass http://backend;  
}
}

加权轮询:根据服务器的性能和配置,为每台服务器配置不同的权重值。权重高的服务器将处理更多的请求,而权重低的服务器则处理较少的请求。如下:bk1跟bk2会以1:2的比例分配请求。

upstream backend {
server bk1.com weight=1;
server bk2.com weight=2;
}
server {
location / {
proxy_pass http://backend;  
}
}

Hash:根据客户端的IP地址或请求的URL进行哈希计算,将请求分配到固定的后端服务器。这种方式可以保证同一客户端的请求将被分配到同一台服务器处理。

upstream backend {
ip_hash;
server bk1.com weight=3;
server bk2.com weight=1;
}
#需要安装第三方模块ngx_http_upstream_hash_module,hash_method为使用的加密算法
upstream backend {
hash $request_uri;
server bk1.com weight=3;
server bk2.com weight=1;
hash_method crc32;
}
server {
location / {
proxy_pass http://backend;  
}
}

FAIL(第三方):需编译安装第三方模块 ngx_http_upstream_fair_module
比 weight、ip_hash更加智能的负载均衡算法,fair算法可以根据页面大小和加载时间长短智能地进行负载均衡,也就是根据后端服务器的响应时间 来分配请求,响应时间短的优先分配。Nginx本身不支持fair,如果需要这种调度算法,则必须安装upstream_fair模块.

upstream backend {
fair;
server bk1.com weight=1;
server bk2.com weight=2;
}
server {
location / {
proxy_pass http://backend;  
}
}

最少连接数法(Least Connections):将请求分配到连接数最少的服务器,可以平衡服务器的负载,提高网络服务的可用性和可扩展性。

upstream backend {
least_conn;
server bk1.com weight=1;
server bk2.com weight=2;
}
server {
location / {
proxy_pass http://backend;  
}
}

2.Nginx请求分发原理

监听和接收请求:Nginx服务器会监听特定的端口,等待客户端的请求到来。一旦收到请求,Nginx会首先对请求进行一些基本的处理。

匹配配置文件:Nginx有一个非常强大的配置系统,可以根据不同的URL路径、请求方法等因素进行匹配。一旦找到匹配的配置,Nginx就会按照该配置进行处理。

后端服务器选择:在匹配的配置中,通常会有一个或多个上游服务器(Upstream)的定义。这些上游服务器就是实际处理请求的后端服务器。Nginx会根据配置的负载均衡策略(如轮询、IP哈希、最少连接等)从上游服务器中选择一个。

转发请求:选定了后端服务器后,Nginx会将请求转发给选定的服务器。这个过程中,Nginx会处理一些网络层的细节,如TCP粘包/拆包、连接管理等问题。

接收响应:后端服务器处理完请求后,会将响应返回给Nginx。Nginx再次处理这个响应,例如进行压缩、缓冲等操作,然后将响应返回给客户端。

记录日志:在整个过程中,Nginx还会进行详细的日志记录,包括请求的详细信息、后端服务器的响应状态等,用于监控和故障排查。

3.Nginx动静分离

nginx动静分离它的核心思想是将静态页面与动态页面或者静态内容接口和动态内容接口分开,部署在不同的系统上,以提高整个服务器的处理性能和可维护性。

实现动静分离的方法主要有两种:一种是将静态资源独立部署在独立的服务器上,也就是有独立的域名存放。另一种方法则是将动态和静态资源混合在一起发布,通过Nginx来进行区分。

静态资源独立部署好理解,将动态和静态资源混合在一起发布则是动态和静态资源通过一个服务器或者nginx请求访问,如:

#动态接口
location /api {
rewrite ^/api/(.*)$ /$1 break;
proxy_pass http://127.0.0.1:8081;
proxy_set_header Host $Host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header REMOTE-HOST $remote_addr;
add_header X-Cache $upstream_cache_status;

proxy_connect_timeout 30s;
proxy_read_timeout 86400s;
proxy_send_timeout 30s;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
#静态资源
location / {
root /home/blog/fronted/dist;
index  index.html index.htm;
try_files $uri $uri/ /index.html /index.php;
}

在我们使用nginx的过程中,不管是说接口传输数据还是静态资源数据,如果说数据的大小越小,那是不是传输的速度是不是更快?

使用的宽带流量是不是也会随之减少?

还有个比较重要的点是资源压缩后会减少服务器的CPU和内存使用,因为解压缩操作需要消耗CPU资源。对于那些同时处理大量请求的服务器来说,减轻服务器负载可以提高其整体性能和稳定性,这样用户体验也会随之变强。

http{
# 开启压缩
gzip on;
# 哪些可以被压缩
gzip_types text/plain text/css application/xml text/javascript image/jpeg image/gif image/png;

# Gzip压缩程度,级别从1-9,1表示压缩程度最低,压缩效率最高,9刚好相反,压缩程度最高,但是效率最低最费时间(因为压缩需要cpu进行计算)
gzip_comp_level 6;
# 在头部中添加Vary: Accept-Encoding(建议开启)
#这个指令使得Nginx根据客户端的HTTP头来判断是否需要压缩,避免浪费不支持的也压缩
gzip_vary on;
# 处理压缩请求的缓冲区数量和大小
# 当 Nginx 对请求的响应进行 gzip 压缩时,它会使用内存缓冲区来存储压缩数据
# 指令通常有两个参数,size:指定每个缓冲区的大小,number:指定要使用的缓冲区的数量
# 这个设置可以帮助优化压缩操作,特别是在处理大文件或大量小文件时。
# 如果您发现 Nginx 由于内存问题而频繁地写入磁盘,
# 可能需要调整此设置。但请注意,增加缓冲区的大小也会增加内存的使用量。因此,需要根据实际的服务器配置和需求进行适当的调整
gzip_buffers 16 8k;
# 这个指令可以根据客户端的浏览器标志(user-agent)来设置,支持使用正则表达式。指定的浏览器标志不使用Gzip
# 低版本的IE浏览器不支持压缩
gzip_disable "MSIE [1-6]\.";
# 用于设置进行 gzip 压缩的响应的最小字节数。当一个响应的长度小于 gzip_min_length
# 指定的值时,Nginx 将不会对该响应进行 gzip 压缩,因为较小的响应通常不值得进行压缩
gzip_min_length 2k;
# 用于控制是否允许在代理请求上使用 gzip 压缩。当 Nginx 作为反向代理时,
# 这个指令可以用来指定哪些后端服务器应该或不应该进行压缩
gzip_proxied off;
}

5.缓存

对于性能优化而言,nginx加入缓存机制是一种可以大幅度提升性能的一种可靠方案。nginx缓存其主要的优点主要有:
提高性能:通过缓存静态内容,Nginx可以减轻后端服务器的负载,提高网站的响应速度和吞吐量。这对于处理大量并发请求非常有效,可以显著提升用户体验。

节省带宽:对于一些不经常变化的内容,如图片、静态页面等,缓存可以避免重复从后端服务器获取,从而节省带宽,降低网络流量。

降低延迟:由于缓存可以存储已经获取的内容,当再次需要这些内容时,可以直接从缓存中快速读取,避免了再次向服务器请求的时间延迟,提高了响应速度。

防止重复请求:当用户再次访问相同的内容时,如果该内容已经被缓存,Nginx可以直接提供缓存的内容,而不需要再次向后端服务器发送请求。这可以避免不必要的网络流量和服务器负载。

提高可用性:当后端服务器出现故障或网络问题时,Nginx仍然可以从缓存中提供内容,保证网站的正常运行,提高系统的可用性。

可配置性强:Nginx提供了丰富的缓存配置选项,可以根据实际需求进行灵活的配置。例如,可以设置缓存的过期时间、缓存大小等,以满足不同的需求。

proxy_cache_path:代理缓存的路径。

path:缓存的路径地址。

levels:缓存存储的层次结构,最多允许三层目录。

use_temp_path:是否使用临时目录。

keys_zone:指定一个共享内存空间来存储热点Key(1M可存储8000个Key)。

inactive:设置缓存多长时间未被访问后删除(默认是十分钟)。

max_size:允许缓存的最大存储空间,超出后会基于LRU算法移除缓存,Nginx会创建一个Cache manager的进程移除数据,也可以通过purge方式。

manager_files:manager进程每次移除缓存文件数量的上限。

manager_sleep:manager进程每次移除缓存文件的时间上限。

manager_threshold:manager进程每次移除缓存后的间隔时间。

loader_files:重启Nginx载入缓存时,每次加载的个数,默认100。

loader_sleep:每次载入时,允许的最大时间上限,默认200ms。

loader_threshold:一次载入后,停顿的时间间隔,默认50ms。

purger:是否开启purge方式移除数据。

purger_files:每次移除缓存文件时的数量。

purger_sleep:每次移除时,允许消耗的最大时间。

purger_threshold:每次移除完成后,停顿的间隔时间。

语法:proxy_cache_path path [levels=levels] [use_temp_path=on|off] keys_zone=name:size [inactive=time] [max_size=size] [manager_files=number] [manager_sleep=time] [manager_threshold=time] [loader_files=number] [loader_sleep=time] [loader_threshold=time] [purger=on|off] [purger_files=number] [purger_sleep=time] [purger_threshold=time];

是的,你没有看错,就是这么长....,解释一下每个参数项的含义:

proxy_cache:开启或关闭代理缓存,开启时需要指定一个共享内存区域。

zone为内存区域的名称,即上面中keys_zone设置的名称。

语法:proxy_cache zone | off;

proxy_cache_key:定义如何生成缓存的键。

string为生成Key的规则,如schemeproxy_host$request_uri。

语法:proxy_cache_key string;

proxy_cache_valid:缓存生效的状态码与过期时间。

code为状态码,time为有效时间,可以根据状态码设置不同的缓存时间。

例如:proxy_cache_valid 200 302 30m;

语法:proxy_cache_valid [code ...] time;

proxy_cache_min_uses:设置资源被请求多少次后被缓存。

number为次数,默认为1。

语法:proxy_cache_min_uses number;

proxy_cache_use_stale:当后端出现异常时,是否允许Nginx返回缓存作为响应。

error为错误类型,可配置timeout|invalid_header|updating|http_500...。

语法:proxy_cache_use_stale error;

proxy_cache_lock:对于相同的请求,是否开启锁机制,只允许一个请求发往后端。

语法:proxy_cache_lock on | off;

proxy_cache_lock_timeout:配置锁超时机制,超出规定时间后会释放请求。

proxy_cache_lock_timeout time;

proxy_cache_methods:设置对于那些HTTP方法开启缓存。

method为请求方法类型,如GET、HEAD等。

语法:proxy_cache_methods method;

proxy_no_cache:定义不存储缓存的条件,符合时不会保存。

string为条件,例如cookienocachearg_nocache $arg_comment;

语法:proxy_no_cache string...;

proxy_cache_bypass:定义不读取缓存的条件,符合时不会从缓存中读取。

和上面proxy_no_cache的配置方法类似。

语法:proxy_cache_bypass string...;

add_header:往响应头中添加字段信息。

语法:add_header fieldName fieldValue;

$upstream_cache_status:记录了缓存是否命中的信息,存在多种情况:

MISS:请求未命中缓存。

HIT:请求命中缓存。

EXPIRED:请求命中缓存但缓存已过期。

STALE:请求命中了陈旧缓存。

REVALIDDATED:Nginx验证陈旧缓存依然有效。

UPDATING:命中的缓存内容陈旧,但正在更新缓存。

BYPASS:响应结果是从原始服务器获取的。

PS:这个和之前的不同,之前的都是参数项,这个是一个Nginx内置变量。

http{
# 设置缓存的目录,并且内存中缓存区名为hot_cache,大小为128m,
# 三天未被访问过的缓存自动清楚,磁盘中缓存的最大容量为2GB。
proxy_cache_path /soft/nginx/cache levels=1:2 keys_zone=hot_cache:128m inactive=3d max_size=2g;

server{
location / {
# 使用名为nginx_cache的缓存空间
proxy_cache hot_cache;
# 对于200、206、304、301、302状态码的数据缓存1天
proxy_cache_valid 200 206 304 301 302 1d;
# 对于其他状态的数据缓存30分钟
proxy_cache_valid any 30m;
# 定义生成缓存键的规则(请求的url+参数作为key)
proxy_cache_key $host$uri$is_args$args;
# 资源至少被重复访问三次后再加入缓存
proxy_cache_min_uses 3;
# 出现重复请求时,只让一个去后端读数据,其他的从缓存中读取
proxy_cache_lock on;
# 上面的锁超时时间为3s,超过3s未获取数据,其他请求直接去后端
proxy_cache_lock_timeout 3s;
# 对于请求参数或cookie中声明了不缓存的数据,不再加入缓存
proxy_no_cache $cookie_nocache $arg_nocache $arg_comment;
# 在响应头中添加一个缓存是否命中的状态(便于调试)
add_header Cache-status $upstream_cache_status;
}
}
}

6.IP白名单黑名单

在当下互联网爆炸的时代,有时候往往避免不了被某些人做一些恶意攻击,如:DDos或者恶意爬虫之类的。通过将可疑或已知的攻击源列入黑名单,可以有效地减少不必要的访问和潜在的风险。

nginx实现黑名单白名单主要通过allow、deny配置项来实现:

allow xxx.xxx.xxx.xxx; # 允许指定的IP访问,实现白名单。
deny xxx.xxx.xxx.xxx; # 禁止指定的IP访问,实现黑名单。

如果指定的ip太多的话,可以在单独的nginx conf文件中配置,在include进去。

如:ip.conf,然后再主的nginx .conf中include

allow xxx.xxx.xxx.xxx;
allow xxx.xxx.xxx.xxx;
allow xxx.xxx.xxx.xxx;
allow xxx.xxx.xxx.xxx;
....
deny xxx.xxx.xxx.xxx;
deny xxx.xxx.xxx.xxx;
deny xxx.xxx.xxx.xxx;
deny xxx.xxx.xxx.xxx;
....
http{
# 屏蔽所有IP
include ip.conf;
server{
location xxx {
# 某个location才屏蔽或者放开
include ip.conf;
}
}
}

其次,你也可以使用第三方模块ngx_http_geo_module或者ngx_http_geo_module按地区或者国家进行屏蔽。

7.跨域问题

Nginx的跨域问题主要涉及到浏览器的同源策略和CORS(跨源资源共享)机制。

同源策略是浏览器安全机制的一部分,它要求请求的来源必须与当前网页的协议、域名和端口三者之间全部相同。如果请求的来源与当前网页不同源,浏览器会阻止该请求,以防止潜在的安全风险。

location / {
# 允许跨域请求,自定义变量$http_origin,*表示所有
add_header 'Access-Control-Allow-Origin' *;
# 允许携带cookie请求
add_header 'Access-Control-Allow-Credentials' 'true';
# 允许跨域请求的方法:GET,POST,OPTIONS,PUT
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT';
# 允许请求时携带的头部信息,*表示所有
add_header 'Access-Control-Allow-Headers' *;
# 允许发送按段获取资源的请求
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
# 一定要有!!!否则Post请求无法进行跨域!
# 在发送Post跨域请求前,会以Options方式发送预检请求,服务器接受时才会正式请求
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
# 对于Options方式的请求返回204,表示接受跨域请求
return 204;
}
}

8.防盗链

防盗链主要用于防止未经授权的第三方网站直接获取或链接到你的资源,保护你的网站资源不被非法利用。

valid_referers:这个指令用于指定允许访问资源的来源域名或URL。

可以设置具体的域名、IP地址或URL字符串,也可以使用通配符来匹配多个来源。

如果请求的来源不在valid_referers指定的范围内,Nginx将返回403错误。其值有

none:表示接受没有Referer字段的HTTP请求访问。

blocked:表示允许http://或https//以外的请求访问。

server_names:资源的白名单,这里可以指定允许访问的域名。

string:可自定义字符串,支配通配符、正则表达式写法。

if ($invalid_referer):这个指令用于检查请求的来源是否符合valid_referers的设置。

如果不符合,则执行相应的操作,如返回403错误或重定向到其他页面。

location /img/ {
valid_referers none blocked bk1.com;
if ($invalid_referer) {
return 403;
}
}

9.大文件上传

Nginx中,可以使用client_max_body_size指令来限制客户端请求体的最大尺寸,以避免因文件过大而导致的问题。

server {
listen 80;
server_name bk1.com;
location /upload {
client_max_body_size 10m;  # 限制请求主体为10MB  
...
}
}

10.https配置

Nginx可以配置SSL证书来实现网站的安全传输。

通过安装SSL证书,Nginx可以将传统的http协议升级为https协议,提供加密保护,确保数据传输的安全性。

server
{
listen 80;
listen 443 ssl http2;
server_name bk1.com;
# 打开SSL加密传输
ssl on;
if ($server_port !~ 443){
rewrite ^(/.*)$ https://$host$1 permanent;
}
#HTTP_TO_HTTPS_END
# 证书文件目录
ssl_certificate    /www/server/panel/vhost/cert/study-tenant/fullchain.pem;
# 服务器私钥
ssl_certificate_key    /www/server/panel/vhost/cert/study-tenant/privkey.pem;
# 服务器支持的TLS版本
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
# TLS握手时,服务器采用的密码套件
ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
# 停止通信时,加密会话的有效期,在该时间段内不需要重新交换密钥
ssl_session_timeout 10m;
}

11.性能优化相关

开启长连接配置:启用HTTP/1.1持久连接:在Nginx的配置文件中,找到http块,添加以下配置项。

http {
...
proxy_http_version 1.1;
proxy_set_header Connection "";
...
}

proxy_http_version 1.1;启用了HTTP/1.1持久连接。

proxy_set_header Connection "";禁用了Nginx向代理服务器发送的Connection头部,确保不会覆盖代理服务器设置的持久连接。

配置keep-alive参数:在Nginx的配置文件中,找到需要启用长连接的代理服务器的配置块(通常是location块),添加以下配置项:

location / {
...
proxy_http_version 1.1;
proxy_set_header Connection "";
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;
proxy_keepalive 1;
proxy_connect_timeout 600;
proxy_send_timeout 600;
proxy_read_timeout 600;
...
}

proxy_http_version 1.1;启用了HTTP/1.1持久连接。

proxy_set_header Connection "";禁用了Nginx向代理服务器发送的Connection头部。

proxy_keepalive 1;启用了长连接。其他参数如proxy_connect_timeout、proxy_send_timeout和proxy_read_timeout等可以根据实际需要进行调整。

开启0拷贝:在Nginx中开启零拷贝,可以通过配置sendfile指令来实现。

零拷贝是一种优化技术,可以避免在数据传输过程中进行不必要的拷贝操作,从而提高数据传输的效率。

location / {
...
sendfile on;
...
}

通过将sendfile指令设置为on,可以启用Nginx的零拷贝功能。

Nginx将会使用sendfile系统调用,将文件内容直接从内核空间传输到网络套接字,避免了在用户空间和内核空间之间的数据拷贝。

开启无延迟或多包共发机制:tcp_nodelay参数可以控制Nagle算法的行为。

Nagle算法是一种拥塞控制算法,用于减少网络中的小包数量,从而提高网络吞吐量。默认情况下Nagle算法是启用的,这意味着在发送小包时会进行延迟,等待更多的数据包组合后再一起发送。

如果项目属于交互性很强的应用,需要快速响应,则可以手动开启tcp_nodelay配置,让应用程序向内核递交的每个数据包都会立即发送出去。

http {
...
tcp_nodelay on;
tcp_nopush on;
...
}

要注意:这两个参数是“互斥”的,如果同时开启,可能会导致性能下降。

如果追求响应速度的应用推荐开启tcp_nodelay参数,如IM、金融等类型的项目。

调整worker:Nginx启动后默认只会开启一个Worker工作进程处理客户端请求,而我们可以根据机器的CPU核数开启对应数量的工作进程,以此来提升整体的并发量支持。

# 自动根据CPU核心数调整Worker进程数量
worker_processes auto;

同时也可以稍微调整一下每个工作进程能够打开的文件句柄数:

# 每个Worker能打开的文件描述符,最少调整至1W以上,负荷较高建议2-3W
worker_rlimit_nofile 20000;

开启CPU亲和机制:在Nginx中开启CPU亲和性机制,可以使用worker_cpu_affinity参数。

该参数用于将worker进程绑定到特定的CPU核心上,以提高进程的执行效率。

如下,将worker进程绑定到第0、1、2和3号CPU核心上:

worker_processes 4;
worker_cpu_affinity 00000001 00000010 00000100 00001000;

开启epoll模型及调整并发连接数:开启epoll模型,可以使用event类型参数,将其设置为epoll。Epoll是一种高效的I/O事件通知机制,适用于高并发连接的情况。

events {
worker_connections 10000;
multi_accept on;
use epoll;
}

worker_connections参数用于设置每个worker进程可以处理的最大并发连接数。

multi_accept参数用于允许多个连接同时进入等待状态,以加速连接的建立。

结尾

在部署和运维Nginx时,建议遵循最佳实践以确保系统的稳定性和安全性。

这包括保持Nginx的版本更新、定期检查和优化配置文件、限制不必要的访问权限、使用防火墙保护服务器以及实施日志管理和监控等措施。


标签
点评

本文暂无评论 - 欢迎您

请填写验证码