nginx
站内链接:
介绍
说明
- 优势和使用场景
快速响应,高扩展性,高可靠性,低内存消耗(10 000 非活跃连接仅有 2.5MB 消耗),单机 10 万并发连接,热部署(重点),自由的 BSD
优秀的事件驱动框架;
适用于传输层上 TCP 对外服务;
- 同类 web 前端服务器:
a. Apache HTTP Server:
优点:
- 成熟稳定:Apache 是最早的 Web 服务器之一,经过多年发展和广泛使用,已经被广泛验证和测试。
- 强大的模块化支持:Apache 具有丰富的模块化架构,可以通过模块添加特定功能和扩展。
- 良好的操作系统兼容性:Apache 可在多个操作系统上运行,包括 Linux、Windows、macOS 等。
缺点:
- 高资源消耗:相对于其他服务器,Apache 的资源消耗较高,特别是在高并发情况下。
- 配置复杂:Apache 的配置文件相对复杂,需要一定的学习和理解成本。
b. Microsoft IIS (Internet Information Services):
优点:
- Windows 集成:IIS 是 Windows 操作系统的一部分,可以无缝集成到 Windows 服务器环境中。
- 易用性:IIS 提供了可视化的管理界面和易于使用的工具,使得配置和管理变得简单。
- 良好的.NET 集成:IIS 对于.NET 应用程序提供了良好的支持,可以直接托管和运行 ASP.NET 应用程序。
缺点:
- 仅适用于 Windows:IIS 只能运行在 Windows 操作系统上,不适用于其他操作系统。
- 可伸缩性限制:相对于一些开源的服务器,IIS 的可伸缩性可能受限,特别是在高负载环境下。
c. Lighttpd (Lightweight HTTP Server):
优点:
- 轻量级高性能:Lighttpd 是一个轻量级的 Web 服务器,具有较低的资源消耗和快速的性能。
- 高并发处理:Lighttpd 采用了异步非阻塞的事件驱动架构,能够高效处理大量并发连接。
- 内存占用低:相对于一些其他服务器,Lighttpd 在内存使用方面较为节省。
缺点:
- 功能较少:与一些其他服务器相比,Lighttpd 的功能相对较少,可能不适用于某些复杂的应用场景。
- 社区支持相对较小:相对于像 Nginx 和 Apache 这样的服务器,Lighttpd 的社区支持相对较小。
d. Caddy Server:
优点:
自动 HTTPS 支持:Caddy Server 内置了自动申请和管理 SSL 证书的功能,使得配置 HTTPS 变得简单。
配置简单:Caddy Server 使用 Caddyfile 作为配置文件,具有易读易写的语法,配置相对简单。 - 插件生态系统:Caddy Server 拥有丰富的插件生态系统,可以通过插件扩展功能。
缺点:
- 商业许可证:Caddy Server 采用 Apache 2.0 许可证,但对于某些商业用途可能需要购买许可证。
- 社区相对较小:相对于像 Nginx 和 Apache 这样的服务器,Caddy Server 的社区相对较小,可能不具备一些特定功能和支持。
e. Nginx:
优点:
- 高性能:Nginx 以其卓越的性能而闻名,能够处理大量并发连接和高负载环境。
- 内存消耗低:相对于一些传统的服务器,Nginx 在内存使用方面较为节省。
- 可扩展性:Nginx 支持高度的并发性和可扩展性,能够轻松应对高负载情况。
- 强大的反向代理和负载均衡功能:Nginx 具有强大的反向代理和负载均衡功能,可用于构建高可用性和高性能的应用架构。
缺点:
- 动态内容处理限制:相对于一些其他服务器,Nginx 在处理动态内容(如 PHP)方面可能有一些限制。
- 学习曲线:Nginx 的配置相对复杂,需要一定的学习和理解成本。
注意, web 静态服务器一般都是支持如下功能: 基于 REST 架构风格,以统一资源描述符(URI)或者统一资源定位符(URL)作为沟通依据,通过 HTTP/HTTPS 来提供网络服务
后端服务器
- java web 框架
以下是 Java 语言下常见的后端应用服务器和 Web 框架,按照使用量进行逆序排列,并以 Markdown 表格的形式呈现。请注意,由于 Java 生态系统的广泛性和不断变化,这里列出的是一部分常见的选择,可能并不包括所有的后端应用服务器和 Web 框架。
框架名 | 使用场景 | 优点 | 缺点 |
---|---|---|---|
Spring Boot | 大型/中型 Web 应用 | 强大的生态系统,广泛应用于企业级开发 | 学习曲线较陡峭,相对较重的配置和开发流程 |
Apache Tomcat | 中型/小型 Web 应用 | 轻量级,易于部署和使用,广泛应用于 Java Web 开发 | 不适用于高并发场景,相对较少的扩展性和性能 |
Eclipse Jetty | 中型/小型 Web 应用 | 轻量级,嵌入式容器,适用于嵌入式和独立应用 | 不适用于高并发场景,相对较少的扩展性和性能 |
WildFly | 大型/中型 Web 应用 | 全面的 Java EE 支持,适用于企业级应用 | 相对较重的内存占用,较慢的启动时间 |
Apache Geronimo | 大型/中型 Web 应用 | Java EE 支持广泛,可扩展性强,适用于企业级应用 | 学习曲线较陡峭,相对较少的开发人员和资源 |
Resin | 中型/小型 Web 应用 | 快速启动时间,低内存占用,适用于小型项目 | 功能相对较少,生态系统相对较小 |
Undertow | 中型/小型 Web 应用 | 轻量级,高性能,适用于嵌入式和独立应用 | 生态系统相对较小,较少的开发人员和资源 |
Play Framework | 大型/中型 Web 应用 | 响应式、高性能,适用于构建可伸缩的 Web 应用 | 学习曲线较陡峭,相对较少的开发人员和资源 |
Micronaut | 中型/小型 Web 应用 | 轻量级、快速启动,适用于构建低延迟的微服务 | 生态系统相对较小,较新的框架,可能缺少某些功能 |
Spring MVC | 中型/小型 Web 应用 | 基于 Spring 框架,广泛应用于 Java Web 开发 | 相对较重的配置和开发流程,较慢的启动时间 |
Grizzly | 中型/小型 Web 应用 | 轻量级,高性能,适用于嵌入式和独立应用 | 较少的开发人员和资源,相对较少的扩展性和功能 |
- python web 框架
以下是 Python 语言下常见的后端应用服务器和 Web 框架,按照使用量进行逆序排列,并以 Markdown 表格的形式呈现:
框架名 | 使用场景 | 优点 | 缺点 |
---|---|---|---|
Django | 大型/中型 Web 应用 | 强大的功能集和完整的开发生态系统 | 学习曲线较陡峭,相对较重的配置和开发流程 |
Flask | 中型/小型 Web 应用 | 简单、轻量级、易于学习和使用 | 功能相对较少,适用于小型项目 |
FastAPI | 中型/小型 Web 应用 | 高性能、现代化的异步支持和 API 快速开发 | 生态系统相对较小,较新的框架,可能缺少某些功能 |
Tornado | 异步 Web 应用 | 高性能、轻量级,非常适合处理大量并发连接 | 学习曲线较陡峭,不适用于传统的请求-响应模式 |
Pyramid | 大型/中型 Web 应用 | 灵活、可扩展,支持多种开发模式和数据库 | 学习曲线较陡峭,相对较少的开发人员和资源 |
Bottle | 小型 Web 应用 | 极简主义,轻量级,适用于小型项目 | 生态系统相对较小,功能相对较少 |
CherryPy | 中型/小型 Web 应用 | 简单、快速启动,自包含的 Web 服务器 | 功能相对较少,生态系统相对较小 |
web2py | 大型/中型 Web 应用 | 完整的开发框架,易于学习和使用 | 学习曲线较陡峭,相对较重的配置和开发流程 |
Falcon | RESTful API 应用 | 极简主义,高性能,适用于构建轻量级 API | 功能相对较少,不适用于复杂的 Web 应用 |
Bottle | 小型 Web 应用 | 极简主义,轻量级,适用于小型项目 | 生态系统相对较小,功能相对较少 |
Quart | 异步 Web 应用 | 基于 Flask,支持异步编程模型 | 生态系统相对较小,较新的框架,可能缺少某些功能 |
Sanic | 异步 Web 应用 | 高性能、轻量级,适用于处理大量并发请求 | 较新的框架,生态系统相对较小 |
TurboGears | 大型/中型 Web 应用 | 全栈框架,集成多个组件和工具 | 生态系统相对较小,较少的开发人员和资源 |
Hug | RESTful API 应用 | 极简主义,易于使用,高性能 | 生态系统相对较小,功能相对较少 |
请注意,以上列出的是一些常见的 Python 后端应用服务器和 Web 框架,具体选择应根据项目需求、团队经验和个人偏好来决定。
插件
基于底层的系统开发商或者服务器开发者,为了提升整个 web 服务器的并发 TCP 连接,在现有的 nginx 模块不能满足业务需求时,采用以下两种方式来提供站点负载:
- 将所有流量反向代理到后方服务器处理,但是必须后端服务器解决阻塞和并发问题,保证和 nginx 同样的高效;
- 开发 nginx 第三方插件,以适应并发需求;
但实际上第三方插件也仅仅起到分流的功能, 实际的流量处理还是会下发到后发的应用服务器进行处理.
命令和目录
命令
- nginx 命令选项说明
1 | -c <path_to_config> 指定一个nginx配置文件,而非缺省的 |
- 启动和停止
启动: sudo which nginx
从容关闭:
1 | ps -ef|grep nginx |
快速关闭:
1 | ps -ef|grep nginx |
平滑升级配置:
1 | nginx -t -c /etc/nginx/nginx.conf |
平滑升级二进制文件:
1 | # 此时会有两个主进程实例,然后旧实例会在处理完旧连接之后关闭 |
- 进程结构
- master:管理 worker 进程,提供命令行服务
- worker:一般数量和 CPU 数量相同,参照 DPDK 开发(SMP),最大化的利用 CPU,其中 worker 之间通过内存共享,原子操作来实现负载均衡
目录和信号
- 目录或配置说明
- conf.d: 扩展配置文件,设置基础目录
- sites-available: 配置虚拟主机的文件,每一個文件代表一個虚拟主机
- sites-enable: 软连接到 sites-available
- 信号: 主进程可接受的信号:
- TERM, INT 快速关闭
- QUIT 从容关闭
- HUP 从容关闭旧进程,重载
- USR1 重新打开日志文件(这个在日志文件操作时有用)
- USR2 平滑升级可执行程序(有用)
- WINCH 从容关闭 worker
worker 进程支持 TERM,INT, QUIT, USER1 信号来进行处理
配置语法
每一个配置项的语法格式: (configure name) (configure value1) (configure value2) ....;
其中各项说明如下:
1 | configure name 必须在相应的模块中支持(回忆下当初的第三方模块开发); |
例如基本的配置: access_log /var/log/nginx/access.log main info;
, 其中access_log
就表示配置命令, 后面的三个字段表示配置值, 其中 info 为日志的 LEVEL, main 表示标签段位置信息.
常见配置项
块配置项
例如下面章节中所述的http配置
就是块配置项
1 | # 1. nginx运行相关的全局配置 |
调试和日志
- 日志配置
log_format
用于定义一个命名日志格式, 该命令日志会在access_log, error_log
中被引用, 例如:
1 | http { |
1 | daemon on/off: # 守护进程 |
环境变量和用户
1 | # 定义环境变量 |
优化性能配置项
1 | # worker进程数, 对于阻塞式调用,应该多配置一些worker,此时单CPU单worker明显不适用,但是cpu切换代价过大 |
事件类配置项
1 | # 是否开启accept负载均衡锁, 某个worker连接数过多(7/8比例),会降低连接,默认打开 |
if 语法
通过使用 nginx 中支持的变量来进行 if 逻辑判断,例如:
1 | if ($host = 'www.unusebamboo.com') { |
http 配置
基本格式
所有的 HTTP 配置项都必须直属于 http 块,server 块,location 块,upstream 块,if 块,即在 HTTP 大括号里面只能有上面的几个内嵌块
1 | http { |
注意, /etc/nginx/conf.d/
目录下的配置就仅仅需要配置 server 即可, 因为他们在 http 中被 include, 这是一个非常重要的点.
主机配置
- 虚拟主机配置, 设置监听端口
1 | # 例如IPV6配置:listen [:]: 8000; SSL配置:listen 443 default_server ssl; |
参数:
1 | default 将所在的server作为整个WEB服务的默认server块,否则会将第一个server块作为默认的server块.即默认虚拟主机 |
- 虚拟服务配置, 其通用配置如下:
1 | # HOST字段和server_name对比, 优先选择完全匹配项,如果匹配不到,使用默认虚拟主机 |
url 匹配
nginx 中 URL 正则匹配规则有点类似命令行正则匹配逻辑, 下面是 chatgpt 关于 nginx url 正则匹配的回答, 由此可以得出其匹配逻辑类似命令行的简单匹配规则
1 | ^ 和 $:表示匹配 URL 开头和结尾。例如,^/hello$ 匹配 URL 为 /hello 的请求。 |
下面就尽可能穷举所有碰到的实例
1 | # 1. 所有路径开头都是/, 这个表示匹配所有 |
location
location 块通过指定特定的模式来与客户端请求的 URL 进行匹配, 其基本语法有如下两种
1 | # 格式: location [指令模式] url匹配模式 {}, 其中指令模式指用于匹配的方式(精确, 前缀, 正则), url匹配模式则类似路由匹配 |
其中 URL 的匹配规则如下:
1 | = 完全或精确匹配 |
例如, 有两个前端项目, 他们各自打包结束之后有自己的css, js, index.html
等目录和文件, 使用场景例如某一个前端项目的帮助文档等. 那么, 对于此类项目如何配置 nginx 确保多个项目共用一个域名呢?
1 | # a. 正式项目地址: ~: 大小写敏感, ^( |
匹配优先级(见 gpt: nginx 配置中 url 匹配优先级?):
- a. URL 匹配的优先级是从上到下依次匹配的, 一旦请求的 URL 地址匹配到某个 location 则会停止匹配
- b. 另外, 若匹配规则过于复杂或过多则可能影响 nginx 的性能, 需要合理规划
但是对于指令模式, 其有优先级, 类似 css 样式的权重一样:
- 权重 1: =精确匹配
- 权重 2:
^~
前缀匹配 - 权重 3:
~
和~*
例如:
1 | # 1. curl -I website.com:8080/document 返回 返回 HTTP/1.1 702 |
路径定位
- root 和 alias
root 方式设置资源路径, 用来指定请求静态资源时的根目录, 可以用来指定 Nginx 服务器的根目录, 配置块:http,server,location,if:
1 | # 查找/opt/web/html/download/路径下文件, 例如url: http://127.0.0.1/download/show.html, 则会找文件 |
alias 方式设置资源路径, 用来指定 URL 路径和文件系统路径的对应关系, 用于指定某个目录作为请求的静态资源所在的根目录, 配置块:location
1 | # 查找/opt/web/html/路径下文件, 例如url: http://127.0.0.1/download/show.html, 则会找文件 |
其中 root 和 alias 的区别, 以请求的 URI/conf/nginx.conf
为例:
1 | # 1. 返回/usr/local/nginx/conf2/目录下的nginx.conf资源 |
其中 alias 直接丢弃 location 中的匹配部分, root 则仅仅是拼接路径, alias 仅仅用在 location 配置块中, 关于 location 见 6.4 节描述.
- index 访问首页配置, 配置块:http, server,location
index 配置项用于设置 Web 服务器默认的索引文件(默认值为 index.html), 若存在该文件则返回, 否则返回文件目录或者 404.
1 | index file1, file2, ...; |
try_files
指令用于在请求的文件不存在时尝试其他文件或路径
它的作用是根据指定的顺序查找指定的文件或路径, 如果找到了其中一个, 则直接返回该文件或路径的内容.
1 | # 配置块:server,location, 其中file 可以是本地文件路径或 URL, uri 是 Nginx 内部的 URL |
try_files 指令只会查找本地文件或内部 URL, 而不会向后端服务器发送请求, 有效的降低了 web 后端服务器负担, 当然, 若是再通过proxy_pass
(7.1 节)反向代理来转发就不一样了.
资源分配
TCP 连接预分配内存池大小
1 | 语法:connection_pool_size size |
HTTP 连接预分配内存池带下:
1 | 语法:request_pool_size size; |
请求和响应
- 超时时间配置
1 | # 1. 读取HTTP header超时时间 |
- keepalive 配置
1 | # keepalive超时时间 |
HTTP 返回码重定向:
1 | 配置块:http, server, location, if |
递归使用 error_page:
1 | 配置块:http, server, location |
MIME 设置
定义 type 到文件扩展名的映射:
1 | 语法:types { ... }; |
默认 MIME 类型
1 | 语法:default_type MIME-type; |
请求限制
按照 HTTP 方法名限制用户请求
1 | 语法:limit_except method1,... {...}; |
Request Body 的最大值
1 | 语法:client_max_body_size size; |
Request 的限速,每秒传输的字节数
1 | 语法:limit_rate speed; |
页面压缩
说明:GUN-zip 压缩技术,减少页面大小,是的用户浏览页面时更快,需要 Browser 和 Server 共同支持,即 Server 压缩,Browser 解压;
1 | # 开启或者关闭 |
反向代理
upstream, proxy_pass, proxy_set_header, proxy_cache, proxy_connect_timeout 等
proxy_pass
proxy_pass
指令用于将客户端的请求转发给另一个服务器进行处理,并将该服务器的响应返回给客户端, 配置块:location, if. 其整个流程如下:
- 代理服务器接口 Request 请求,并将 Request 转发给内部网络中的上游服务器
- 上游服务器将 Response 返回给客户端
其中 reverse prxoy 对外表现为一个代理, 通过这种反向代理实现负载均衡, 提高 Web 服务器的性能和可靠性. proxy_pass
作为反向代理的一部分, 其作用如下:
- 负载均衡:通过反向代理,将客户端的请求分发到多个后端服务器上,以均衡服务器负载,提高应用程序的性能和可靠性。
- 安全防护:通过反向代理,将后端服务器隐藏在防火墙后面,保护后端服务器的安全。
- URL 重写:通过反向代理,将客户端的请求 URL 转换为后端服务器能够处理的 URL 格式,以实现 URL 重写和反向映射等功能。
- 静态文件缓存:通过反向代理,将静态文件缓存在代理服务器上,以提高文件访问速度和服务器性能。
其配置示例如下:
1 | location / { |
其他配置
- 常用配置
1 | # 功能: 指定反向代理服务器使用的 HTTP 请求方法, 默认请求下使用同原始请求相同的HTTP请求方法 |
上面基本配置的实例如下:
1 | location / { |
proxy_redirect
重定向配置, 上游服务器返回重定向或者刷新请求的响应时, 重新修改 URL 和 HTTP 头信息
格式: proxy_redirect [default|off|redirect replacement]
, 其实例如下
1 | location / { |
这样配置之后, 就能确保backend-server
完全对客户透明.
upstream
- upstream 定义后端服务器的地址, 以便反向代理服务器可以将客户端的请求转发给后端服务器处理
格式: upstream name { ... }
, 注意 upstream 仅仅是反向代理的一个组成部分, 其实例如下:
1 | upstream backend { |
proxy_next_upstream
指令用于在发生代理错误时,切换到下一个后端服务器。
语法格式: proxy_next_upstream [error|timeout|invalid_header|http_500|http_502|http_503|http_504|http_404|off]
- error: 当后端服务器返回 500 或 502 错误时切换
- timeout: 表示当与后端服务器的连接超时时切换
- invalid: 不合法响应
- 5xx: 表示当后端服务器返回 5xx 错误时切换
其实例如下:
1 | # 实现功能: proxy_pass将/请求转发到后端服务器backend(负载均衡), proxy_next_upstream则在发生错误或超时时自动切换到下一个upstream中指定的服务器. |
上游服务器
指的是一组相同功能的服务器, 用于处理反向代理服务器接收到的请求, 注意将其同server {}
块语法区分开来.
语法格式: server name1 [parameters]
, 其中name1
可以是域名,IP 地址端口,UNIX 句柄, paramters 有如下的选项:
- weigth=number:上游服务器的权重
- max_fails=number: 转发失败次数上限,超过则剔除
- fail_timeout=time: 转发超时时间
- down: 表示上游服务器永久下线,搭配 ip_hash 使用
- backup: 表示上游服务器仅仅作为备份服务器,所有正常服务器失效时会启动备份,在 ip_hash 存在时,该选项失效
upstream_addr
获取当前请求所要代理的上游服务器的地址, 并通过add_header
返回给客户端
1 | upstream myapp {} |
负载均衡
nginx 负载均衡有两种方式实现:
- ip hash 算法: 对客户端 IP 地址进行哈希计算, 将其映射到不同的服务器上
- 轮询算法(默认): Nginx 会将请求依次发送到每个服务器上, 直到所有服务器都被轮询过一遍, 然后再次开始轮询
其实例如下:
1 | # IP hash算法, 此时不能使用weight权重 |
其他配置
内部变量
1 | $server_name # 虚拟主机名称 |
其命令格式: 关键字 格式名称 格式, 例如:
1 | log_format lagoulog 'v1{|]$remote_addr:$remote_port{|]....' |
White list
设置多个白名单, 以便跨域
1 | set $cors_origin ""; |
Example
文件下载
需求: 访问特定目录, 返回的静态网页直接显示服务器上指定目录的文件列表, 并可以进入特定的目录
配置:
1 | server{ |
另外, 如果服务器不是 https, 可以设置 chrome 确保不自动进行 http 跳转: http 不跳转
多域名
以本博客以前的架构为准,在 2024 年以前我的博客结构如下:
其中 unusebamboo.top 和 blog.unusebamboo.top 都是静态服务(以前不知道为何这样部署),他们的代码都在此 nginx 服务器上,所以不需要做反向代理设置,此时的 nginx 配置如下:
1 | server { |