背景
在Java系统实现过程中,我们不可避免地会借助大量开源功能组件。然而,这些组件往往功能丰富且体系庞大,官方文档常常详尽至数百页。而在实际项目中,我们可能仅需使用其中的一小部分功能,这就造成了一个挑战:如何在有限的时间和精力下,高效地掌握并使用这些组件的核心功能,以实现投入产出最大化?
针对这一问题,我基于二八原则,整理编写本文。
首先,我会聚焦于组件的常见和核心功能,这些功能通常是我们在日常开发中频繁使用到的,也是构建稳定、高效系统的基石。通过深入了解这些核心功能的使用方法和最佳实践,我们可以确保在关键点上投入足够的精力,从而避免在实际使用中掉入陷阱。
其次,我会以问题为导向,将实用性作为第一要素,对组件的功能进行筛选和整理。这意味着我会优先关注那些在项目中实际需要用到的功能,而对于那些特定场景下才会用到的功能,我会在文中提及但不做详细展开。这样做的好处是,我们可以在保证核心功能得到充分理解的同时,减少不必要的阅读负担,提高学习效率,降低投入成本。
最后,我会注重内容的精炼和易读性。通过简明扼要的文字描述和直观的示例代码,帮助读者快速理解并掌握组件的核心用法。
同时,我也会结合经验指出常见的问题和【注意事项】,以便读者在使用过程中能够规避一些常见的错误和陷阱。
综上所述,通过这个系列的内容整理,我希望能够帮助读者在有限的时间和精力下,高效地掌握并使用这些开源功能组件的核心功能,满足系统实现的需要。
注:部分内容章节由AI辅助生成草稿,我对其进行了复核和修订,修复了有问题和有错误的部分。
理论
Nginx是什么?
Nginx是一个轻量级、高性能的web服务器,支持HTTP、HTTPS、SMTP、POP3 和 IMAP 协议,并可以实现反向代理、负载均衡的功能。
什么是反向代理?
反向代理(Reverse Proxy)是一种服务,它位于一个或多个原始服务(常称为后端服务)之前,接收客户端的请求并将这些请求转发到原始服务。客户端通常不会意识到反向代理的存在,因为它们直接与反向代理进行通信,而反向代理则代表客户端与后端服务进行交互。
反向代理的主要作用包括:
- 负载均衡:反向代理可以将请求分发到多个后端服务,从而实现负载均衡,提高系统的性能和可靠性。
- 安全性增强:通过隐藏后端服务的详细信息,反向代理可以增加系统的安全性,防止后端服务直接暴露给外部。
- SSL/TLS 终端:反向代理可以处理 SSL/TLS 连接,减轻后端服务的加密解密负担,同时可以集中管理 SSL 证书。
- 缓存静态内容:反向代理可以缓存后端服务的静态内容,减少对后端服务的请求次数,加快内容的加载速度。
- 压缩和优化:反向代理可以在将请求转发给后端服务之前或将响应返回给客户端之前,对数据进行压缩或优化。
- 访问控制:反向代理可以实施访问控制策略,例如 IP 过滤、地理定位访问限制等。
- URL 重写:反向代理可以修改请求的 URL,实现 URL 重写,有助于 SEO 优化和重定向。
- 连接管理:反向代理可以管理客户端与后端服务之间的连接,例如保持连接的持久性或断开空闲连接。
- 日志记录和监控:反向代理可以记录请求和响应的日志,便于监控和分析流量模式。
- 故障转移:在后端服务发生故障时,反向代理可以自动将请求转发到健康的服务,提高系统的可用性。
Nginx 和 Apache 是当前市面主流的Web服务容器,具备上述反向代理功能。
Nginx 和 Apache的区别在哪?
Nginx 和 Apache 都是流行的 Web 服务容器,但它们在多个方面存在显著差异:
- 架构和并发处理:
- Nginx 采用异步非阻塞的事件驱动模型,能够处理大量并发连接,适合静态内容和高并发场景。
- Apache 采用同步多进程模型,每个连接对应一个进程,适合处理动态内容,但在高并发情况下可能会遇到性能瓶颈。
- 资源占用:
- Nginx 以其轻量级和低资源占用著称,适合处理静态文件和反向代理。
- Apache 在处理动态内容时资源占用较高,但在动态请求处理方面表现优异。
- 配置和灵活性:
- Nginx 的配置文件简洁,支持正则配置,易于理解和修改。
- Apache 的配置文件复杂,支持目录级别的配置(.htaccess 文件),提供了更高的灵活性。
- 模块化和扩展性:
- Nginx 的模块化设计使其编写模块相对简单,但模块需要从源代码编译。
- Apache 支持动态加载模块,提供了丰富的第三方模块和插件,扩展性更强。
- 负载均衡和反向代理:
- Nginx 内置了负载均衡功能,支持多种负载均衡算法,适合作为反向代理服务器。
- Apache 通过模块化架构和第三方模块实现负载均衡,但配置和管理较为复杂。
- 稳定性和成熟度:
- Nginx 以其高性能和轻量级特点著称,适合高并发和负载压力较大的场景。
- Apache 更为成熟,拥有庞大的开发者社区和丰富的文档资源,适合需要稳定性和功能丰富的场景。
- 市场占有率:
- Nginx 是增长最快的网络服务器,市场份额不断上升,尤其在高流量网站中表现突出。
- Apache 曾经是主流,拥有广泛的用户群体和成熟的技术,已被Nginx超越。
- 适用场景:
- Nginx 适合处理静态内容、反向代理和高并发场景。
- Apache 适合处理动态内容、需要高度定制和灵活性的场景。
- 社区和生态系统:
- Nginx 的社区非常活跃,提供了大量的高性能模块。
- Apache 拥有庞大的开发者社区和丰富的第三方模块。
- 组合使用:
- 许多管理员将 Apache 和 Nginx 结合使用,利用 Nginx 处理静态内容和负载均衡,将动态请求转发给 Apache 处理。
综上所述,选择 Nginx 还是 Apache 应根据具体需求、技术栈和场景来决定。
Nginx的主要作用有哪些?
以下是 Nginx 的一些主要作用:
- 静态内容服务:Nginx 可以高效地提供静态文件,如 HTML、CSS、JavaScript 和图片等。
- 反向代理:Nginx 可以作为反向代理服务,将客户端的请求转发到后端的服务上。
- 负载均衡:Nginx 能够分配请求到多个后端服务,提高应用的可用性和扩展性。
- SSL/TLS 终端:Nginx 支持 SSL/TLS 协议,可以用于终止 SSL 连接,提高安全性。
- 缓存:Nginx 提供了静态内容的缓存机制,可以减少后端服务的负载,提高响应速度。
- 压缩:Nginx 可以对传输的数据进行压缩,减少带宽消耗。
- URL 重写:Nginx 支持 URL 重写规则,可以用于实现 SEO 优化和重定向。
- 访问控制:Nginx 提供了访问控制列表(ACL),可以限制特定 IP 或地理位置的访问。
- 日志记录:Nginx 可以记录访问日志,帮助分析流量和监控访问模式。
- 模块化:Nginx 拥有丰富的模块系统,可以扩展其功能,如使用第三方模块。
- 高并发处理:Nginx 以其高并发处理能力而闻名,适合处理大量并发连接。
- 跨平台:Nginx 可以在多种操作系统上运行,包括 Linux、Unix、BSD、Mac OS X 和 Windows。
- 配置灵活:Nginx 提供了灵活的配置选项,可以根据需求进行定制。
Nginx 的设计哲学是提供少而精的核心功能,并通过模块化扩展来满足特定的需求,这使得它在性能和灵活性方面都非常出色。
主要应用场景有哪些?
web应用容器:对于前后端分离项目,基于vue和react等框架构建的前端项目,往往会选用nginx作为其web应用容器。
负载均衡:在系统架构中作为负载均衡中间件,进行七层协议的转发。
实战
如何下载?
官网下载地址:https://nginx.org/en/download.html
当前最新稳定版本是1.26.1,windows版下载地址:https://nginx.org/download/nginx-1.26.1.zip
无需安装,解压即可,解压后目录如下:
注:下文都以该版本为例进行配置说明。
常用命令有哪些?
nginx 启动
nginx -s stop 停止
nginx -s quit 安全退出
nginx -s reload 重新加载配置文件
nginx -t 验证配置文件是否正确
注:nginx -s reload命令重新加载配置文件,不会中断当前的连接或服务。
配置文件在哪?
Nginx配置文件默认在安装目录下的conf目录下,文件名为nginx.conf,可用文本类查看工具直接打开。
典型配置什么样?
nginx自带了示例配置,如下:
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include 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 logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
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;
}
# 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;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}
示例文件中展示的往往是核心的、常用的参数,下面来具体说一下。
常用参数有哪些?
Nginx 的配置文件通常分为几个部分:全局块、events 块、http 块。其中http 块内部有一个重要节点 server 块,server块中又包含一个重要节点location块,配置结构如下:
main # 全局配置
├── events # 配置网络连接
├── http # 配置代理、缓存、日志等
│ ├── upstream # 配置负载均衡
│ ├── server # 配置虚拟主机,可以有多个 server
│ ├── server
│ │ ├── location # 用于匹配 URI(URL 是 URI 的一种),可以有多个 location
│ │ ├── location
│ │ └── ...
│ └── ...
└── ...
注:
1.上面的main代表根节点的示意,实际并不真实存在。
2.upstream块用于负载均衡,非必须
全局块
位于配置文件的顶层,用来进行全局化配置,如指定运行nginx进程的操作系统用户、配置工作进程数量、指定错误日志的路径以及指定nginx进程的主进程pid存放文件。
user
指定运行 Nginx 工作进程的用户,与文件权限和系统安全性相关,合理配置 user
参数,可以增强 Nginx 服务器的安全性,并确保它能够正确地访问和管理所需的资源。
【参数说明】
- 默认设置:在默认的 Nginx 配置中,
user
可能被设置为nobody
或特定的用户,如www-data
(在某些 Linux 发行版中)。
【注意事项】
- 权限控制:通过指定
user
,可以限制 Nginx 进程对系统资源的访问,因为不同用户具有不同的权限。 - 安全性:以非特权用户运行 Nginx 可以减少潜在的安全风险,因为即使 Nginx 被恶意攻击,攻击者也只能获得该用户的权限。
worker_processes
Nginx的总体架构是有一个主进程负责整体调度和管理,然后开启多个工作进程来干具体的活。
该参数用来指定 Nginx 启动的工作进程数量。这个参数直接影响到 Nginx 服务器并发处理请求的能力。
【参数说明】
- 默认行为:默认情况下,Nginx 配置文件中的
worker_processes
被设置为 1,这意味着只有一个工作进程来处理所有的网络请求。 - 设置建议:通常建议将
worker_processes
的值设置为与 CPU 核心数相等,以便充分利用多核处理器的优势。如果服务器有多个 CPU 或多核心 CPU,可以设置worker_processes
等于 CPU 的核心数。 - 自动检测:可以将
worker_processes
设置为auto
,这样 Nginx 会自动检测当前主机的 CPU 核心数,并启动对应数量的工作进程。
当设置该值为2时,启动nginx服务,从操作系统层面可以看到,实际有3个进程,1个是主进程,另外两个则是工作进程。
建议将该值设置为auto,当服务器增配cpu资源时,nginx可自动检测调整,无需同步调整配置。
error_log
日志对于排除 Nginx 服务问题至关重要,该参数定义错误日志的存放位置和日志级别。
【参数说明】
- 默认值:Nginx 的默认错误日志文件路径在linux下通常是
/var/log/nginx/error.log
,并且默认日志级别是error
,在windows系统下位于程序所在目录的的logs目录。 - 日志级别:可以设置不同的日志级别,包括
debug
、info
、notice
、warn
、error
、crit
、alert
和emerg
。级别越高,记录的信息越少,生产环境中常用的是warn
、error
和crit
这三个级别 。
【注意事项】
- 日志级别说明:
debug
:输出最详细的信息,主要用于调试。info
:提供一般信息,可能包含敏感数据,生产环境不推荐使用。notice
:正常运行时的提醒信息。warn
:警告信息,表示有潜在的问题。error
:错误信息,表示处理请求时出现的问题。crit
:临界信息,表示严重错误。alert
和emerg
:紧急信息,表示非常严重的状况 。
- 在生产环境中,建议根据需要选择合适的日志级别,避免产生过多的日志信息,影响系统性能。
pid
定义 Nginx 主进程的 PID 文件存放路径。PID 文件记录了 Nginx 进程的进程标识符(Process ID),通常用于管理 Nginx 进程,比如重启或停止服务。
【参数说明】
- 默认设置:在默认情况下,Nginx 可能会将 PID 文件放在如
/var/run/nginx.pid
的系统运行目录中,但这可能会因操作系统或安装方式的不同而有所变化,windows下则存放在程序所在目录的的logs目录。
【注意事项】
- 路径选择:指定的路径应该是一个可写目录,并且运行 Nginx 的用户对该文件有读写权限。
- 重启和停止服务:通过 PID 文件,可以方便地使用如
nginx -s stop
或nginx -s reload
命令来控制 Nginx 服务的启动和停止。 - 多实例运行:如果你在同一台服务器上运行多个 Nginx 实例,每个实例的 PID 文件应存放在不同的路径,以避免冲突。
events 块
worker_connections
定义单个工作进程可以打开的最大连接数。
【参数说明】
- 默认值:默认情况下,
worker_connections
被设置为 1024。 - 设置建议:在高并发场景下,可能需要增加此值以允许更多的并发连接。
【注意事项】
- 内存考量:每个连接会占用一定的内存资源。连接数的增加直接影响到内存的使用量,因为每个连接都需要为其分配读写事件和相关数据结构。
- 操作系统限制:操作系统对进程可以打开的文件描述符数量有限制,这通常通过
ulimit -n
命令查看(通常为65536)。Nginx 的worker_rlimit_nofile
指令可以用来设置工作进程打开文件描述符的上限,以避免超出系统限制。 - 性能监控:在调整
worker_connections
参数后,应监控 Nginx 的性能和资源使用情况,确保配置更改达到预期效果,并未对服务器稳定性造成负面影响。 - 错误处理:如果
worker_connections
设置得太低,可能会导致连接数超过限制,从而出现 “connection reset by peer” 错误或在日志中记录警告信息。
【相关参数】
events块下还可以设置一个worker_rlimit_nofile
参数,与worker_connections存在差异:
- worker_connections:
- 这个参数定义了每个工作进程(worker process)可以打开的最大连接数。
- 它是
events
块中的一个指令,用于设置 Nginx 能够同时处理的活动连接数。 worker_connections
的值通常根据服务器的硬件能力(如 CPU 核心数和内存大小)来设定。例如:worker_connections 1024;
表示每个工作进程可以处理的最大连接数为 1024。
- worker_rlimit_nofile:
- 这个参数用于设置每个工作进程可以打开的文件描述符的最大数量。
- 它是
events
块中的一个指令,用于配置文件描述符的限制,这包括套接字连接、文件等。 worker_rlimit_nofile
的值应该设置得比worker_connections
大一些,以确保除了连接之外,Nginx 还有额外的文件描述符用于日志文件、临时文件等。- 例如:
worker_rlimit_nofile 2048;
表示每个工作进程可以打开的最大文件描述符数量为 2048。
区别:
worker_connections
主要关注网络连接的数量,即每个工作进程能够同时处理的客户端连接数。worker_rlimit_nofile
更广泛地关注所有类型的文件描述符,包括网络连接、日志文件、配置文件等。
配置建议:
- 通常建议将
worker_rlimit_nofile
设置为比worker_connections
高一些的值,以确保 Nginx 有足够的文件描述符用于其操作。例如,如果worker_connections
设置为 1024,可以将worker_rlimit_nofile
设置为 2048 或更高。 - 这些参数的设置应基于服务器的硬件规格和预期的负载。在配置时,还需要考虑操作系统级别的文件描述符限制,确保 Nginx 的设置不超过操作系统的限制。
通过合理配置这两个参数,可以优化 Nginx 服务器的性能和资源利用率。
http 块
include mime.types;
这是一句引用指令,引入mime.types文件的内容,没有路径意味着同路径,即nginx根目录下conf目录下有个名字为mime.types的文件,该文件定义了HTTP响应的MIME类型与文件扩展名之间的映射关系,内容如下:
types {
text/html html htm shtml;
text/css css;
text/xml xml;
image/gif gif;
image/jpeg jpeg jpg;
application/javascript js;
application/atom+xml atom;
application/rss+xml rss;
text/mathml mml;
text/plain txt;
text/vnd.sun.j2me.app-descriptor jad;
text/vnd.wap.wml wml;
text/x-component htc;
image/avif avif;
image/png png;
image/svg+xml svg svgz;
image/tiff tif tiff;
image/vnd.wap.wbmp wbmp;
image/webp webp;
image/x-icon ico;
image/x-jng jng;
image/x-ms-bmp bmp;
font/woff woff;
font/woff2 woff2;
application/java-archive jar war ear;
application/json json;
application/mac-binhex40 hqx;
application/msword doc;
application/pdf pdf;
application/postscript ps eps ai;
application/rtf rtf;
application/vnd.apple.mpegurl m3u8;
application/vnd.google-earth.kml+xml kml;
application/vnd.google-earth.kmz kmz;
application/vnd.ms-excel xls;
application/vnd.ms-fontobject eot;
application/vnd.ms-powerpoint ppt;
application/vnd.oasis.opendocument.graphics odg;
application/vnd.oasis.opendocument.presentation odp;
application/vnd.oasis.opendocument.spreadsheet ods;
application/vnd.oasis.opendocument.text odt;
application/vnd.openxmlformats-officedocument.presentationml.presentation
pptx;
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
xlsx;
application/vnd.openxmlformats-officedocument.wordprocessingml.document
docx;
application/vnd.wap.wmlc wmlc;
application/wasm wasm;
application/x-7z-compressed 7z;
application/x-cocoa cco;
application/x-java-archive-diff jardiff;
application/x-java-jnlp-file jnlp;
application/x-makeself run;
application/x-perl pl pm;
application/x-pilot prc pdb;
application/x-rar-compressed rar;
application/x-redhat-package-manager rpm;
application/x-sea sea;
application/x-shockwave-flash swf;
application/x-stuffit sit;
application/x-tcl tcl tk;
application/x-x509-ca-cert der pem crt;
application/x-xpinstall xpi;
application/xhtml+xml xhtml;
application/xspf+xml xspf;
application/zip zip;
application/octet-stream bin exe dll;
application/octet-stream deb;
application/octet-stream dmg;
application/octet-stream iso img;
application/octet-stream msi msp msm;
audio/midi mid midi kar;
audio/mpeg mp3;
audio/ogg ogg;
audio/x-m4a m4a;
audio/x-realaudio ra;
video/3gpp 3gpp 3gp;
video/mp2t ts;
video/mp4 mp4;
video/mpeg mpeg mpg;
video/quicktime mov;
video/webm webm;
video/x-flv flv;
video/x-m4v m4v;
video/x-mng mng;
video/x-ms-asf asx asf;
video/x-ms-wmv wmv;
video/x-msvideo avi;
}
default_type
default_type
主要用于设置默认的 MIME 类型。当 Nginx 收到一个请求,且该请求的文件扩展名在 mime.types
文件中没有对应的 MIME 类型定义时,Nginx 将使用 default_type
指定的类型来处理该文件。
【参数说明】
- 默认值:如果不显式设置
default_type
,则 Nginx 的默认值通常是text/plain
,意味着未明确指定类型的文件将被当作纯文本处理。 - 设置建议:如果希望所有的未知类型文件都被客户端作为二进制流处理,可以设置
default_type application/octet-stream;
,这通常用于强制客户端下载文件而不是尝试打开或显示它们。
access_log
访问日志记录了客户端对服务器的每次请求的详细信息,包括请求的 URL、客户端 IP、请求时间、响应状态码等,这对于分析流量和监控网站活动非常有用。
该参数指定访问日志的存放路径。
【参数说明】
- 默认值:Nginx 的默认访问日志文件路径通常是
/var/log/nginx/access.log
,并且默认日志格式是combined
(Nginx预置格式的一种),这种格式记录了较为详细的信息。 - 日志格式:可以通过
log_format
指令定义日志的格式。常见的格式有default
、combined
、x-forwarded-for
等,也可以自定义格式。 - 配置方法:可以在 Nginx 配置文件的
http
、server
或location
块中设置access_log
。例如:
access_log /path/to/your/access.log combined;
这表示将访问日志记录到指定路径的文件中,并使用 combined
日志格式。
【注意事项】
- 自定义日志格式:除了预置的日志格式外,还可以使用
log_format
指令来自定义日志的格式,例如:
log_format main '$http_x_forwarded_for - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent"';
上面定义了一种新的日志格式,并将其命名为“main”,然后可以指定日志使用这个格式:
access_log /path/to/your/access.log main;
- 日志切割:可以通过设置
access_log
的buffer
参数来控制日志的切割。例如:
access_log /path/to/your/access.log combined buffer=16k flush=1m;
这里 buffer=16k
表示每个缓冲区的大小为 16KB,flush=1m
表示每分钟刷新一次缓冲区,即先将日志写到内存中,然后批量持久化到磁盘,从而提升性能。
- 多日志文件:可以在同一个
server
或location
块中定义多个access_log
,将日志输出到不同的文件或使用不同的格式。 - 优化性能:在高流量的网站上,写入访问日志可能会对性能产生影响。可以通过设置
open_file_cache
指令来优化文件打开操作,减少日志写入的开销。
sendfile
用于指定传输文件的处理模式。当启用 sendfile
时,Nginx 会直接将文件内容从磁盘发送到网络,而不需要将文件内容先读入到缓冲区(内存)中。这可以减少数据复制的开销,提高文件传输效率。使用 sendfile
可以减少内存的使用,并显著提高 Nginx 服务器在传输静态文件时的性能。
【参数说明】
- 默认值:在 Nginx 的默认配置中,
sendfile
参数通常被设置为on
,意味着启用了高效的文件传输方式。 - 设置建议:对于静态文件服务器,建议保持
sendfile
为on
,以提高性能。然而,在某些特定场景下,如需要对文件内容进行处理(例如,SSL 加密或压缩)时,可能需要将其设置为off
。
【注意事项】
- 在某些情况下,如果 Nginx 配置了
sendfile
为on
,但实际并未使用sendfile
系统调用,可能是因为操作系统不支持或配置不当,可以通过 Nginx 的错误日志来检查是否有相关警告。 <font style="color:rgb(6, 6, 7);">sendfile</font>
系统调用在不同的操作系统上支持程度不同。在 Linux 上,<font style="color:rgb(6, 6, 7);">sendfile</font>
是高效的,而在其他系统上可能不是。Windows 版本的 Nginx 支持<font style="color:rgb(6, 6, 7);">sendfile</font>
,但由于 Windows 版本的 Nginx 仅使用<font style="color:rgb(6, 6, 7);">select()</font>
和<font style="color:rgb(6, 6, 7);">poll()</font>
作为连接处理方法,因此可能无法达到与 Linux 版本相同的高性能和可扩展性。<font style="color:rgb(6, 6, 7);">sendfile</font>
参数可以在 Nginx 配置文件的<font style="color:rgb(6, 6, 7);">http</font>
块、<font style="color:rgb(6, 6, 7);">server</font>
块或<font style="color:rgb(6, 6, 7);">location</font>
块中设置。在不同块中的设置将影响不同的配置范围。
tcp_nopush
在 TCP 协议中,数据传输通常是以流的形式进行的,这意味着数据可以被分割成多个包发送。“tcp_nopush” 选项允许开发者控制数据的发送时机,从而优化网络传输的效率。例如,在某些应用中,可能希望将多个小的数据包合并成一个大的数据包发送,以减少网络开销和提高传输效率。使用 “tcp_nopush” 可以推迟数据的发送,直到有足够的数据量再进行发送。
【参数说明】
- 默认值:在 Nginx 的默认配置中,
tcp_nopush
通常被设置为off
,这意味着 tcp_nopush 选项默认是禁用的。 - 设置建议:如果你的应用发送的响应头较小,而响应体较大,启用
tcp_nopush
可以提高性能,因为它允许 Nginx 等待更多的数据被写入缓冲区后再发送,从而减少网络请求的次数。 - 配置方法:可以在 Nginx 配置文件的
http
、server
或location
块中设置tcp_nopush
。
【注意事项】
- 与
sendfile
** 的关系**:tcp_nopush
通常与sendfile
指令一起使用。sendfile
用于加速静态文件的传输,而tcp_nopush
可以进一步优化数据的发送过程。 - 性能影响:启用
tcp_nopush
可能会增加内存的使用量,因为数据在发送前会在缓冲区中停留更长时间。因此,在内存资源受限的环境中使用时需要谨慎。 - 适用场景:
tcp_nopush
适用于静态内容的传输,特别是当文件较大时,可以减少网络往返次数,提高传输效率。 - tcp_nodelay:与tcp_nopush的功能相反,确保数据立即发送而不是等待,这有助于减少网络延迟,默认值为开启。
gzip
用于开启或关闭 Gzip 压缩功能,启用后将帮助减少传输的数据大小,提高页面加载速度。
【参数说明】:
- **默认值: **off,未开启,设置为on打开。
- 配置方法:可以在 Nginx 配置文件的
http
、server
或location
块中设置
【注意事项】
Nginx提供了大量相关参数,具体如下:
- 压缩级别:
通过gzip_comp_level
设置压缩级别,范围从 1 到 9。级别 1 提供最快的压缩速度,而级别 9 提供最佳的压缩率。通常推荐使用级别 3 或 6,以在压缩效果和服务器 CPU 负载之间取得平衡。 - 最小压缩长度:
使用gzip_min_length
指定进行压缩的响应数据的最小字节数。例如,gzip_min_length 1k;
意味着只有超过 1KB 的数据才会被压缩,这有助于避免小文件压缩后体积反而增加。 - 缓冲区设置:
gzip_buffers
定义了用于压缩的缓冲区数量和大小,例如gzip_buffers 4 16k;
指定了 4 个 16KB 的缓冲区。 - HTTP 版本:
gzip_http_version 1.1;
确保即使在 HTTP/1.1 下能进行压缩,因为早期的 HTTP 版本可能不支持 Gzip 压缩。 - 压缩 MIME 类型:
gzip_types
指定了应该被压缩的 MIME 类型。建议包括text/plain
、application/x-javascript
、text/css
等常见类型。 - Vary 响应头:
设置gzip_vary on;
会向响应头中添加 “Vary: Accept-Encoding”,这有助于缓存服务器根据请求头中的 Accept-Encoding 字段缓存不同版本的响应。 - 代理压缩设置:
gzip_proxied
用于作为反向代理时的压缩设置。例如,gzip_proxied expired no-cache no-store private auth;
表示在特定缓存头存在时启用压缩。 - 禁用 Gzip 压缩:
gzip_disable
可以用于指定不需要 Gzip 压缩的 User-Agent。例如,gzip_disable "MSIE [1-6]\.";
可以防止为不支持 Gzip 的旧版 IE 浏览器启用压缩。
通过这些配置,可以确保 Nginx 的 Gzip 压缩功能得到有效利用,从而提升网站的性能和用户体验。
gzip压缩开启前后对比图,效果还是很明显的,如下图:
server 块
在http节点下,可以配置一个或多个server块。
server相当于虚拟主机,即可以通过nginx,实现在一台服务器上部署多个web站点的目的。
listen
- 基本功能:
<font style="color:rgb(6, 6, 7);">listen</font>
指令告诉 Nginx 在指定的端口和(可选的)地址上监听传入的连接请求。
- 默认值:
- 如果没有指定
<font style="color:rgb(6, 6, 7);">listen</font>
参数,Nginx 默认监听端口 80(对于 HTTP)和 443(对于 HTTPS)。
- 如果没有指定
- 配置方法:
<font style="color:rgb(6, 6, 7);">listen</font>
参数通常在<font style="color:rgb(6, 6, 7);">server</font>
块中设置。例如:
server {
listen 80;
server_name example.com;
...
}
- 端口号:
- 必须指定端口号,如
<font style="color:rgb(6, 6, 7);">80</font>
或<font style="color:rgb(6, 6, 7);">443</font>
。端口号是客户端用于连接到服务器的网络端口。
- 必须指定端口号,如
- 地址:
- 可以指定监听的 IP 地址,如
<font style="color:rgb(6, 6, 7);">listen 192.168.1.1:80;</font>
。如果省略地址,Nginx 将监听所有 IPv4 地址。
- 可以指定监听的 IP 地址,如
- IPv6 支持:
- 对于 IPv6 地址,可以使用
<font style="color:rgb(6, 6, 7);">[::]:80</font>
来监听所有 IPv6 地址的指定端口。
- 对于 IPv6 地址,可以使用
- 多个监听端口:
- 可以在同一个
<font style="color:rgb(6, 6, 7);">server</font>
块中使用多个<font style="color:rgb(6, 6, 7);">listen</font>
指令来监听多个端口,或者在不同的<font style="color:rgb(6, 6, 7);">server</font>
块中监听不同的端口。
- 可以在同一个
- SSL/TLS:
- 当使用
<font style="color:rgb(6, 6, 7);">listen</font>
参数监听 443 端口时,通常与 SSL/TLS 配置结合使用,以提供 HTTPS 服务。需要确保配置了正确的 SSL 证书和私钥。
- 当使用
配置示例
监听 IPv4 和 IPv6 地址的 HTTP 和 HTTPS 端口:
server {
listen 80;
listen [::]:80;
server_name example.com;
...
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
...
}
重定向配置
可以使用 <font style="color:rgb(6, 6, 7);">return</font>
指令在 <font style="color:rgb(6, 6, 7);">server</font>
块中重定向 HTTP 请求到 HTTPS。例如:
server {
listen 80;
server_name www.baidu.com;
return 301 https://$server_name$request_uri;
}
这样用户请求地址若为http://www.baidu.com,会自动重定向到https://www.baidu.com。
server_name
用于定义当前 server 块处理的域名或域名列表。
- 基本功能:
server_name
指令用于指定当前 server 块应响应的域名。当一个请求到达 Nginx 时,Nginx 会检查请求的 Host 头部信息,并尝试匹配一个 server 块。
- 语法格式:
server_name
可以包含一个或多个域名,用空格分隔。例如:
server {
server_name example.com www.example.com;
...
}
- 通配符:
- 可以使用
*
作为通配符来匹配任意数量的字符。例如:
- 可以使用
server {
server_name *.example.com;
...
}
这将匹配 blog.example.com
、shop.example.com
等所有以 .example.com
结尾的域名。
- 正则表达式:
- 可以使用
~
或~*
来指定一个正则表达式。~
表示区分大小写的匹配,而~*
表示不区分大小写的匹配。例如:
- 可以使用
server {
server_name ~^www\..+\.example\.com$;
...
}
- ~^: 这表示匹配开始的位置,~是正则表达式的匹配符号,^表示匹配字符串的开始。
- www.: 匹配文字"www.",其中的反斜杠</font>用于转义点.,因为点在正则表达式中是一个特殊字符,表示任意字符,所以我们需要用</font>来告诉它我们想匹配实际的点字符。
- .+: 匹配一个或多个任意字符,.表示任意单个字符,+表示一个或多个前面的字符。
- .example.com: 匹配文字".example.com",同样地,点.被转义了,因为我们需要匹配实际的点字符。
- $: 表示匹配字符串的结尾。
-
默认 server 块:
- 如果没有匹配到任何 server 块,Nginx 会使用一个没有定义
server_name
的默认 server 块来响应请求。
- 如果没有匹配到任何 server 块,Nginx 会使用一个没有定义
-
端口敏感性:
server_name
指令是端口敏感的。如果在同一端口上配置了多个 server 块,每个 server 块都需要明确指定server_name
。
-
重定向:
- 可以使用
server_name
和return
指令实现基于域名的重定向。例如:
- 可以使用
server {
listen 80;
server_name olddomain.com;
return 301 https://newdomain.com$request_uri;
}
基于该点,即使用户在浏览器输入的是http,系统会自动重定向到https,即实现了使用https作为系统统一入口的功能。
- 配置优先级:
- 如果多个 server 块配置了相同的
server_name
,Nginx 会根据配置文件中的顺序选择第一个匹配的 server 块。
- 如果多个 server 块配置了相同的
- 使用场景:
server_name
常用于处理虚拟主机,即一台服务器托管多个域名的情况。每个域名可以有不同的配置,如根目录、日志文件等。
- 配置示例:
- 为不同的域名配置不同的 server 块:
server {
listen 80;
server_name site1.com;
root /path/to/site1;
...
}
server {
listen 80;
server_name site2.com;
root /path/to/site2;
...
}
通过合理使用 server_name
指令,可以实现基于域名的请求路由和处理,为不同的网站提供定制化的服务和配置。
root
用于定义web服务的根目录。这个指令指定了 Nginx 从哪里提供文件,比如 HTML、图片、样式表和脚本文件。
- 基本功能:
root
指令告诉 Nginx 在处理请求时应该从哪个目录提供文件。
- 语法格式:
root
后面直接跟文件系统的路径。例如:
root /path/to/your/root;
路径可以是绝对路径,也可以是相对于 nginx.conf
配置文件所在目录的相对路径。
- 配置位置:
root
可以在http
、server
或location
块中设置。在不同的块中设置会影响不同的配置范围。
- 默认值:
- 如果没有明确设置
root
,Nginx 将使用编译时定义的默认根目录(Nginx所在目录下的html目录)。
- 如果没有明确设置
- 路径解析:
- Nginx 会将
root
指令中的路径与下文中的location
块中定义的 URI 组合,形成完整的文件路径。
- Nginx 会将
- 配置示例:
- 在
server
块中设置根目录:
- 在
server {
listen 80;
server_name example.com;
root /path/to/your/root;
index index.html;
}
- 与 location 结合使用:
root
可以与location
块结合使用,为不同的路径提供不同的根目录。例如:
location /images/ {
root /path/to/images;
}
通过合理配置 root
指令,可以确保 Nginx 服务器正确地提供静态内容,同时提高网站的可维护性和安全性。
index
用于定义在请求特定位置但没有明确指定文件名时,Nginx 应该默认提供哪些文件,即通常所说的默认首页。
- 基本功能:
- 当客户端发起一个对目录的请求,而不是对特定文件的请求时,
index
指令告诉 Nginx 返回哪个文件。
- 当客户端发起一个对目录的请求,而不是对特定文件的请求时,
- 语法格式:
index
后面可以跟一个或多个文件名,用空格分隔。例如:
index index.html index.htm;
Nginx 将按顺序尝试提供这些文件,上述配置将首先尝试提供 index.html
,如果没有找到,再尝试 index.htm
。
- 默认值:
- 如果没有设置
index
指令,Nginx 将默认尝试提供index.html
文件。
- 如果没有设置
- 配置位置:
index
可以在http
、server
或location
块中设置。在location
块中设置时,将覆盖上级块中的设置。
- 配置示例:
- 设置默认首页为
index.html
:
- 设置默认首页为
server {
listen 80;
server_name example.com;
location / {
index index.html;
}
}
通过合理使用 index
指令,可以确保当用户访问网站的根目录或子目录时,能够看到合适的默认页面,从而提供更好的导航体验和网站可用性。
charset
用于指定对特定类型的响应内容应用字符集转换。这通常用于确保发送给客户端的内容具有正确的字符编码。
- 基本功能:
charset
指令定义了响应内容的默认字符编码。当响应内容的Content-Type
头部包含charset
参数时,Nginx 默认不会修改它。如果响应头中只有Content-Type
而没有charset
,Nginx 将添加charset
指令中指定的字符集。
- 配置方法:
charset
可以在http
、server
或location
块中设置。例如:
charset utf-8;
- 指定的字符集应该是有效的字符编码名称,如 `utf-8`、`iso-8859-1` 等。
- 默认值:
- 如果没有设置
charset
指令,Nginx 不会自动添加字符集到响应头中。
- 如果没有设置
- 类型指定:
charset
可以指定为所有响应的默认字符集,或者仅用于特定的 MIME 类型。例如,可以只为text
类型的响应设置字符集:
charset text/plain utf-8;
- 配置示例:
- 为所有响应设置默认字符集:
http {
charset utf-8;
}
- 为特定 MIME 类型设置字符集:
server {
location / {
charset text/html utf-8;
}
}
通过合理配置 charset
参数,可以确保客户端正确解析响应内容的字符编码,避免出现乱码或其他显示问题。这对于国际化站点尤为重要。
error_page
用于定义特定错误代码的自定义响应页面的指令。
- 基本功能:
error_page
指令允许你为特定的 HTTP 错误代码指定一个自定义的错误页面。当发生这些错误时,Nginx 将显示你指定的页面或重定向到你指定的 URL。
- 语法格式:
error_page
的基本语法是指定一个错误代码,后跟一个可选的响应状态码和 URI。例如:
error_page 404 /404.html;
- 错误代码:
- 可以为多种 HTTP 错误代码定义自定义页面,如 404(未找到)、403(禁止访问)、500(内部服务器错误)等。
- 重写响应状态码:
- 在某些情况下,你可能希望在返回自定义错误页面时使用不同的 HTTP 状态码。可以通过在
error_page
指令中指定来实现。例如:
- 在某些情况下,你可能希望在返回自定义错误页面时使用不同的 HTTP 状态码。可以通过在
error_page 404 =200 /custom_404.html;
服务端返回了404响应状态码时,由Nginx重写为200,并重定向到 /404.html
页面。
- 使用变量:
- 自定义错误页面的 URI 中可以使用 Nginx 内置变量,如
$uri
(请求的 URI)和$args
(请求的参数字符串)。
- 自定义错误页面的 URI 中可以使用 Nginx 内置变量,如
- 配置示例:
- 为多个错误代码定义相同的自定义页面:
error_page 404 502 503 /errors/404.html;
- 使用变量定义错误页面:
error_page 404 =200 /not_found?uri=$uri&args=$args;
通过合理使用 error_page
指令,可以提供更友好的用户体验,并且在发生错误时提供更多的上下文信息或重定向用户到更适当的位置。
https
大部分配置跟http都一致,只是监听的默认端口,由80变更为了443,同时增加了证书配置,示例如下:
server {
#SSL 默认访问端口号为 443
listen 443 ssl;
#请填写绑定证书的域名
server_name meet.popsoft.tech;
#证书文件的绝对路径。
ssl_certificate C:\\publish\\cer\\meet.popsoft.tech_bundle.crt;
#私钥文件的绝对路径。
ssl_certificate_key C:\\publish\\cer\\meet.popsoft.tech.key;
#会话时长
ssl_session_timeout 5m;
#协议配置
ssl_protocols TLSv1.2 TLSv1.3;
#配置加密套件,写法遵循 openssl 标准。
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
#优先考虑服务器端的加密套件偏好
ssl_prefer_server_ciphers on;
……
}
注意listen的写法,需要在端口号后加ssl。
ssl_certificate属性指定证书文件的地址。
ssl_certificate_key属性指定证书密钥的地址。
location
核心的指令,用于定义请求的处理规则。
- 基本功能:
location
指令用于匹配请求的 URI(路径部分)或命名位置,并根据匹配结果应用不同的配置。
- 语法格式:
location
后面跟随一个 URI 模式,然后是一个大括号{}
包含的配置块。例如:
location / {
root /path/to/directory;
index index.html;
}
- try_files 指令:
- 尝试按顺序查找并使用列表中的文件来响应客户端的请求,可结合nginx内置变量使用,例如:
location / {
try_files $uri $uri/ /index.html;
}
这个配置将首先尝试提供请求的 URI,如果不存在,再尝试提供 URI 的目录索引,如果还是不存在,最后提供根目录下的 index.html
文件。
- 精确匹配:
- 使用等号
=
后跟 URI 可以进行精确匹配。例如,location = /
仅匹配根路径。
- 使用等号
- 正则表达式匹配:
- 使用波浪线
~
开头表示使用正则表达式匹配 URI。例如:
- 使用波浪线
location ~ \.php$ {
fastcgi_pass backend;
}
~表示这是一个正则表达式匹配,.php是匹配PHP文件的正则表达式,$表示字符串的结尾,确保只有以.php结尾的URL才会被匹配。
- 前缀匹配:
- 没有特殊字符的普通字符串将被视为前缀匹配。例如,
location /images/
将匹配以/images/
开头的任何 URI。
- 没有特殊字符的普通字符串将被视为前缀匹配。例如,
- 通配符匹配:
- 使用星号
*
作为通配符可以匹配任意字符。例如,location /images/*.jpg
匹配/images/
下的任何以.jpg
结尾的文件。
- 使用星号
- 地址重写:
- 使用rewrite指令,可以重写地址,如
location /pro/ {
proxy_pass http://localhost:18080;
rewrite "^/pro/(.*)$" /$1 break ;
}
"^/pro/(.*)$": 这是一个正则表达式,用来匹配URL。
- `^` 表示URL的开始。
- `/pro/` 是一个固定的字符串,表示URL中必须包含 "/pro/"。
- `(.*)` 是一个捕获组,匹配 "/pro/" 后面的任何字符,直到URL的末尾。
- `$` 表示URL的结束。
/$1: 这指定了重写的目标URL。
- `$1` 是一个反向引用,引用了正则表达式中的第一个捕获组(即 `^/pro/(.*)$` 中的 `(.*)`)。这意味着将URL中 "/pro/" 后面的部分替换为原始URL中 "/pro/" 后面的部分。
break: 这个指令告诉服务器在执行完这条规则后停止进一步的重写处理。
这条规则的作用是将所有以 “/pro/” 开头的URL重写为只包含 “/pro/” 后面的部分,然后停止进一步的URL重写处理。
- 配置示例:
- 为静态文件设置根目录:
location /static/ {
root /path/to/static/files;
}
- 为 PHP 文件设置 FastCGI 处理:
location ~ \.php$ {
fastcgi_pass backend;
include fastcgi_params;
}
- 优先级:
- 如果有多个
location
块能够匹配同一个请求,Nginx 将选择具有最高优先级的匹配。优先级顺序为:精确匹配 > 正则表达式匹配 > 通配符匹配 > 前缀匹配。
- 如果有多个
- 嵌套使用:
location
块可以嵌套在其他location
块中,以提供更具体的配置。
通过合理使用 location
指令,可以对不同的请求路径应用不同的处理规则,实现复杂的路由逻辑和内容服务策略。
如何配置负载均衡?
配置负载均衡主要涉及将客户端的请求分发到多个后端服务器上。
负载均衡需要配置一个 upstream
块,该块可以放在http中,也可以放到server块中。
upstream
用于定义负载均衡服务器组的部分,它允许你将客户端请求分发到多个后端服务器上。
- 基本功能:
upstream
块允许你指定一个服务器组,Nginx 将使用这个组中的服务器来处理客户端请求。
- 语法格式:
upstream
块以关键字upstream
开始,后面跟着服务器组的名称,大括号{}
内包含具体的服务器配置。例如:
upstream myapp {
server backend1.example.com;
server backend2.example.com;
}
- 服务器定义:
- 在
upstream
块内,使用server
指令来指定后端服务器的地址和可选的配置参数。
- 在
- 与 location 块结合使用:
- 在
server
块中的location
块里使用proxy_pass
指令来指定请求转发到哪个upstream
组。
- 在
location / {
proxy_pass http://myapp;
}
通过合理配置 upstream
,可以有效地实现请求的负载均衡,提高应用程序的可用性和伸缩性。不同的负载均衡算法适用于不同的场景,因此在选择时需要考虑应用程序的特性和服务器的负载情况。
负载均衡算法有哪些?
Nginx 支持多种负载均衡算法,可以根据不同的策略来分发请求到后端服务器。以下是一些常见的负载均衡算法及其配置方法:
- 轮询(默认):
- 轮询算法是 Nginx 默认的负载均衡方法,按照服务器的顺序轮流分配请求。
- 无需特别配置,只需在
upstream
块中列出所有服务器即可。
- 权重:
- 权重算法允许你为每个服务器指定一个权重值,不指定默认权重值为1,权重越高的服务器将接收更多的请求。
- 在
server
指令中添加weight
参数:
upstream myapp {
server backend1.example.com weight=3;
server backend2.example.com weight=2;
server backend3.example.com weight=1;
}
换个角度看,轮询相当于权重的一种特例,即所有的服务器权重值都是1,所以收到的请求数量也是基本相同的。
- 最少连接:
- 最少连接算法将请求分配给当前活跃连接数最少的服务器。
- 在
upstream
块中添加least_conn
参数:
upstream myapp {
least_conn;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}
- IP 哈希:
- IP 哈希算法根据客户端 IP 地址进行哈希,并将请求定向到同一个服务器,从而会话保持一致。
- 在
upstream
块中添加ip_hash
参数:
upstream myapp {
ip_hash;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}
- URL 哈希:
- URL 哈希算法根据请求的 URL 进行哈希,并将请求定向到同一个服务器。
- 在
upstream
块中添加hash
参数,并在server
指令中添加hash
参数:
upstream myapp {
hash $request_uri;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}
该模式的意义在于,相同的请求都会转发到同一台服务器,结合缓存使用可以提高缓存命中率,提升性能。
- 第三方模块:
- Nginx 社区提供了一些第三方模块,如
ngx_http_upstream_hash
,可以实现更复杂的负载均衡算法。
- Nginx 社区提供了一些第三方模块,如
完整示例
server {
upstream myapp {
server backend1.example.com;
server backend2.example.com;
}
location / {
proxy_pass http://myapp;
}
}
如何实现会话保持?
如系统的身份认证基于session-cookie模式,在集群多节点模式下,如不做会话保持策略,则可能发生用户在A节点登录,后续请求被路由到B服务器,而B服务器中并没有用户的会话数据,从而出现身份认证失败的问题。
针对上述问题,一种比较简便的处理策略就是进行会话保持,即确保某一用户始终路由到某一个固定的后端服务节点,也即上面说的,通过ip_hash的模式来实现。
upstream myapp {
ip_hash;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}
注:通常情况下,短时间内用户的ip地址是固定不变的,因此基于ip的hash算法,计算结果也会固定到某一个后端节点。
如何正常显示ip地址?
通过nginx进行负载均衡时,系统获取客户端ip地址,默认情况下会显示为127.0.0.1或0:0:0:0:0:0:0:1,如下图所示:
需要增加以下配置,使用proxy_set_header指令来将源ip地址传递,如下:
upstream myapp {
server backend1.example.com;
server backend2.example.com;
}
server {
listen 80;
location / {
proxy_pass http://myapp;
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;
}
}
这里有两种场景,一种是请求链路中无代理,通过$remote_addr可以拿到请求的源ip地址,然后通过指令proxy_set_header X-Real-IP
r
e
m
o
t
e
a
d
d
r
,
将
其
放
到
h
t
t
p
h
e
a
d
e
r
中
的
X
−
R
e
a
l
−
I
P
属
性
中
;
另
一
种
是
请
求
链
路
中
有
代
理
,
这
时
候
则
使
用
内
置
变
量
remote_addr,将其放到http header中的X-Real-IP属性中;另一种是请求链路中有代理,这时候则使用内置变量
remoteaddr,将其放到httpheader中的X−Real−IP属性中;另一种是请求链路中有代理,这时候则使用内置变量proxy_add_x_forwarded_for,它包含了原始请求的 X-Forwarded-For
头信息(如果有的话),后面附加了当前客户端的 IP 地址,这样可以确保即使请求经过了多个代理,原始客户端的 IP 地址也不会丢失。
应用系统获取请求源ip地址时,也需要按约定处理,以java为例,代码如下:
/**
* 获取当前请求者IP地址
*
* @return
*/
public static String getRemoteAddr() {
String ip = "";
if (RequestContextHolder.getRequestAttributes() != null) {
ServletRequestAttributes requestAttributes =
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (requestAttributes != null) {
HttpServletRequest request = requestAttributes.getRequest();
ip = request.getHeader("x-forwarded-for");
if (StringUtils.isNotBlank(ip) && !UNKNOWN.equalsIgnoreCase(ip)) {
if (ip.indexOf(COMMA) != -1) {
ip = ip.substring(0, ip.indexOf(","));
}
}
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Real-IP");
}
if (StringUtils.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
}
}
return ip;
}
其处理逻辑就是首先从http的header头中获取x-forwarded-for属性,如存在且不为空,按逗号拆分,取首段,这是源ip地址,后面都是经过的代理的ip地址;如为空,则找X-Real-IP属性,如依旧为空,再调用jdk原始的getRemoteAddr来获取,即尽最大可能获取到用户请求的真实源ip地址。
如何搭建集群?
nginx可以作为后端服务的负载均衡,配置多个节点防止单点故障。不过从整个系统架构视角看,nginx会成为新的单点故障的隐患点。
解决方案就是搭建两个nginx节点,然后配合keepalived,实现nginx集群,提升系统的高可用性。
由于nginx自身高度稳定,访问量有限的中小型应用,可以考虑单节点运行。
502报错如何处理?
问题描述
Nginx 返回 502 Bad Gateway 错误,通常表示作为代理服务器的 Nginx 无法从上游服务器(如后端应用服务器)获取有效的响应。一般发生在压力测试或者高并发系统的生产环境,这时候我们查看后端服务器,会发现有大量tcp连接处于time_wait状态,从而影响了系统的吞吐量和对请求的响应。
原因分析
出现502报错,大多数情况下是由于未使用长连接,所有请求都是短连接,造成tcp连接频繁建立和销毁,而服务器承载tcp连接的数量是有限的。注意这里有个误区,就是很多时候会误以为可用端口数耗光了,实际上单台服务器,可用端口在几万,而可支撑的tcp连接往往只有几千。
按照tcp协议,每个连接四次挥手后,进入time_wait状态,默认需要2分钟后才会彻底销毁,释放连接及端口资源。该值可以通过调整操作系统参数缩短,问题会一定程度上缓解,但不会彻底解决。
解决方案
启用http的长连接功能,复用tcp连接,减少tcp连接创建和销毁的开销,实际上就是将tcp连接池化,一个tcp连接可以复用,为多个http请求提供服务。长连接功能是http1.1新增的功能,http 1.0则只能建立短连接。
对于客户(浏览器)到nginx再到tomcat(后端)的请求,实际是两段。
正常情况下,从浏览器到nginx前半段,走的都是http1.1协议,在请求头中有Connection属性,且其值为keep-alive。
Nginx默认也开启了长连接配置,主要涉及到两个参数:一是keepalive_timeout 参数,定义连接在保持空闲状态时的超时时间,比如设置为65秒,意味着tcp连接如果在65秒内没有收到新的请求后再退出;二是keepalive_requests,定义一个tcp连接上可以服务的最大请求数目,默认值是100,一般情况的请求量也足够用了。
但如果并发量特别大,qps特别高,比如10000qps,即每秒钟有1w请求,而每个tcp连接只能复用100次,意味着有每秒钟有大约100个tcp连接需要销毁和新建,从而查看nginx所在的服务器,会有相当数量的tcp连接因销毁产生的time_wait状态。这种情况下可以考虑适当调高keepalive_requests的值。
对于nginx到后端服务这一段,正常情况下也会使用长连接,但不排除一些特别因素影响导致使用了短连接,比如请求协议走的是http1.0而不是http1.1,或者协议版本是1.1,但请求头中出现了Connection属性,其值还是close等各种奇怪的情况,导致长连接未生效。
nginx这边有几个参数来解决该问题,如下:
http {
server {
upstream backend {
server backend1.example.com;
server backend2.example.com;
# 连接数量
keepalive 30;
}
location / {
proxy_pass http://backend;
# 设置http版本为1.1
proxy_http_version 1.1;
# 去除header中的Connection属性
proxy_set_header Connection "";
}
}
}
一是设置nginx跟后端服务起的连接的复用数量。
在 Nginx 的 upstream
块中,keepalive
指令用于定义与后端服务器连接的复用数量。当设置 keepalive
参数为一个正整数时,Nginx 会尝试与后端服务器保持一定数量的连接处于打开状态,以便快速处理后续的请求。
keepalive 30;
这个配置的含义是,Nginx 将与每个后端服务器保持最多 30 个长连接(persistent connections)。
这些长连接会在不同的请求之间复用,减少连接建立和关闭的开销,从而提高请求处理的效率。这对于动态内容的服务器尤其有用,因为它们可能需要频繁地处理来自同一客户端的多个请求。
二是通过指令强行指定http协议版本以及清除请求头中的Connection属性
对于http协议1.1版本,不需要在header头上传输Connection属性,如果出现了反而会存在问题,所以需要通过proxy_set_header指令去除。
如何部署前端项目?
nginx本身是一个低资源占用,高性能的http web服务容器,可以部署vue、react等实现的前端项目。
部署 Vue 项目到 Nginx 服务器通常涉及以下步骤:
- 构建 Vue 项目:
- 在本地开发环境中运行 Vue 项目构建命令来生成生产环境的构建文件。这通常通过运行以下命令完成:
npm run build
打包完成后前端内容如下:
- 拷贝内容
将第一步打包产生的文件,上传的服务器,有两种做法,一是直接将其放到nginx所在目录的html下,这是nginx的存放站点内容的默认目录,在server块中无需使用root来指定站点目录;二是将其放到服务器任意目录,在server块中通过root指令设置目录。第二种方式更灵活,我们将其拷贝到c:/publish/meet/frontend目录下。
- 配置nginx
server {
#监听端口号
listen 80;
#域名
server_name meet.popsoft.tech;
location / {
root c:/publish/meet/frontend;
index index.html;
try_files $uri $uri/ /index.html;
}
location /pro/ {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://localhost:18080;
rewrite "^/pro/(.*)$" /$1 break ;
}
}
这里的location涉及到两部分,一类是匹配/,用于用户访问前端,通过root指定到vue的发布目录;另一类是匹配/pro/,前端vue访问后端服务都是以pro作为起始,但后端服务没有pro这段,所以通过rewrite指令,去除前缀后再访问后端服务。后端springboot服务暴漏的端口是18080,通过proxy_pass http://localhost:18080来转发。