文章目录
前言
在入门之前先抛出几个问题进行思考,后面会进行解答
- Nginx是什么?
- 正向代理和反向代理?
- 为什么要使用负载均衡?
- Nginx的负载均衡模式有哪些?它的实现原理是什么?
- 如果代理的服务器宕机了 Nginx 会如何处理?
- Nginx 的缓存功能是如何使用的?
- Nginx 失败会重试吗?
Nginx是什么?
Nginx(发音为"engine-x")是一个高性能的开源Web服务器和反向代理服务器。
Nginx具有以下主要特点:
- 高性能:Nginx采用了高效的事件驱动架构和多进程/多线程工作模式,能够高效处理大量并发请求,适用于高流量的网站和应用程序。
- 反向代理:Nginx可以作为反向代理服务器,将客户端的请求转发给多个后端服务器,并将后端服务器的响应返回给客户端。
- 负载均衡:Nginx内置了负载均衡功能,可以根据不同的负载均衡算法将请求分发给多个后端服务器,提高系统的可靠性和性能。
- 静态文件服务:Nginx擅长处理静态文件,可以快速、高效地提供静态文件的访问,减轻动态处理的负载。
- HTTPS和SSL支持:Nginx支持HTTPS和SSL/TLS协议,能够提供安全的加密通信。
- 可扩展性:Nginx具有良好的模块化架构,支持丰富的第三方模块和插件,可以根据需要进行功能扩展和定制。
由于其出色的性能和功能特点,Nginx被广泛应用于各种Web应用场景,包括高流量的网站、Web应用程序、反向代理、负载均衡、缓存加速、媒体流服务等。
正向代理和反向代理?
正向代理: 由于某种**原因,我们并不能直接访问Google,那么我们可以借助歪PIN来实现,这就是一个简单的正向代理的例子。这里你能够发现,正向代理“代理”的是客户端,而且客户端是知道目标的,而目标是不知道客户端是通过歪PIN访问的。
反向代理: 当我们在外网访问百度的时候,其实会进行一个转发,代理到内网去,这就是所谓的反向代理,即反向代理“代理”的是服务器端,而且这一个过程对于客户端而言是透明的。
为什么要使用负载均衡?
之所以需要使用负载均衡是因为,如果我们使用的是一台服务器,那么在高峰期时很多用户就需要排队等待系统响应,因为一台服务器能处理的并发数是固定的。例如,一个 Tomcat 在默认情况下只能开启 150 个线程(Tomcat 8.5.x 版本)来处理并发任务,如果并发数超过了最大线程数,那么新来的请求就只能排队等待处理了,如下图所示:
然而如果有负载均衡的话,我们就可以将所有的请求分配到不同的服务器上。假如 1 台服务器可以处理 2000 个请求,那么 5 台服务器就可以处理 10000 个请求了,这样就大大提高了系统处理业务的能力,如下图所示:
Nginx的负载均衡模式有哪些?它的实现原理是什么?
知道了负载均衡的好处之后,我们来看下 Nginx 负载均衡的功能。
Nginx 主要的负载均衡策略(内置的负载均衡)有以下四种:
- 轮询策略(默认负载均衡策略)
- 最少连接数负载均衡策略
- ip-hash 负载均衡策略
- 权重负载均衡策略
1. 轮询策略
轮询负载策略是指每次将请求按顺序轮流发送至相应的服务器上,它的配置示例如下所示:
http {
upstream myapp1 {
server srv1.example.com;
server srv2.example.com;
server srv3.example.com;
}
server {
listen 80;
location / {
proxy_pass http://myapp1;
}
}
}
在以上实例中,当我们使用“ip:80/”访问时,请求就会轮询的发送至上面配置的三台服务器上。
Nginx 可以实现 HTTP、HTTPS、FastCGI、uwsgi、SCGI、memcached 和 gRPC 的负载均衡。
2. 最少连接数负载均衡
此策略是指每次将请求分发到当前连接数最少的服务器上,也就是 Nginx 会将请求试图转发给相对空闲的服务器以实现负载平衡,它的配置示例如下:
upstream myapp1 {
least_conn;
server srv1.example.com;
server srv2.example.com;
server srv3.example.com;
}
3. 加权负载均衡
此配置方式是指每次会按照服务器配置的权重进行请求分发,权重高的服务器会收到更多的请求,这就相当于给 Nginx 在请求分发时加了一个参考的权重选项,并且这个权重值是可以人工配置的。因此我们就可以将硬件配置高,以及并发能力强的服务器的权重设置高一点,以更合理地利用服务器的资源,它配置示例如下:
upstream myapp1 {
server srv1.example.com weight=3;
server srv2.example.com;
server srv3.example.com;
}
以上配置表示,5 次请求中有 3 次请求会分发给 srv1,1 次请求会分发给 srv2,另外 1 次请求会分发给 srv3。
4. ip-hash 负载均衡
以上三种负载均衡的配置策略都不能保证将每个客户端的请求固定的分配到一台服务器上。假如用户的登录信息是保存在单台服务器上的,而不是保存在类似于 Redis 这样的第三方中间件上时,如果不能将每个客户端的请求固定的分配到一台服务器上,就会导致用户的登录信息丢失。因此用户在每次请求服务器时都需要进行登录验证,这样显然是不合理的,也是不能被用户所接受的,所以在特殊情况下我们就需要使用 ip-hash 的负载均衡策略。
ip-hash 负载均衡策略可以根据客户端的 IP,将其固定的分配到相应的服务器上,它的配置示例如下:
upstream myapp1 {
ip_hash;
server srv1.example.com;
server srv2.example.com;
server srv3.example.com;
}
实现原理
Nginx 的实现原理是,首先客户端通过访问域名地址发出 HTTP 请求,访问的域名会被 DNS 服务器解析为 Nginx 的 IP 地址,然后将请求转发至 Nginx 服务器,Nginx 接收到请求之后会通过 URL 地址和负载均衡的配置,匹配到配置的代理服务器,然后将请求转发给代理服务器,代理服务器拿到请求之后将处理结果返回给 Nginx,Nginx 再将结果返回给客户端,这样就完成了一次正常的 HTTP 交互。
如果代理的服务器宕机了 Nginx 会如何处理?
健康检测
被代理的服务器出现宕机的情况,如果被 Nginx 发现,那么 Nginx 就会将其自动标识为不可用,并且在一段时间内会禁止入站的请求访问到该服务器上。
而这个发现服务器宕机的过程就是健康检测的功能了。Nginx 的健康检测分为两种类型,主动检测和被动检测,默认的非商用 Nginx 采用的是被动检测。
所谓的被动检测是指只有访问了该服务器之后发现服务器不可用了,才会将其标识为不可用,并且在一定时间内禁止请求分发到该服务器上,而不是主动以一定的频率去检查服务器是否可用。
健康检测有两个重要参数 max_fails 和 fail_timeout。
fail_timeout 定义了健康检查的执行时长,而 max_fails 表示服务不可用的最大尝试次数,当一定时间内(此时间由 fail_timeout 定义),发生了一定次数的服务器不响应的事件(此次数由 max_fails 定义),那么 Nginx 就会将该服务器标识为不可用的服务器,并且在一定时间内禁止请求分发到该服务器。默认情况下 max_fails 设置为 1,当它设置为 0 时表示禁用此服务器的运行状况检查,它的配置示例如下:
upstream cluster{
server srv1.example.com max_fails=2 fail_timeout=10s;
server srv2.example.com max_fails=2 fail_timeout=10s;
}
以上配置表示,如果 10s 内发生了两次服务不可用的情况就会将该服务器标识为不可用的状态。
当服务器被标识为不可用时,只有达到了 fail_timeout 定义的时间后,才会进行再一次的健康请求检测。
而主动健康检测的实现方案有两种,一种是使用商用的 Nginx Plus 来配置主动健康检测,另一种是使用开源的第三方模块 nginx_upstream_check_module 来实现主动健康检测。
Nginx Plus 和 nginx_upstream_check_module 模块的主动健康检查配置大体都是一样的,它的配置示例如下:
upstream backend {
server srv1.example.com;
server srv2.example.com;
check interval=3000 rise=1 fall=3 timeout=2000 type=http;
check_http_send "HEAD /status HTTP/1.0\r\n\r\n";
check_http_expect_alive http_2xx http_3xx;
}
其中,check_http_send 表示发送请求的内容,而 check_http_expect_alive 是服务器正常情况下的响应状态码,如果后端服务器的响应状态包含在此配置中,则说明是健康的状态。
Nginx 的缓存功能是如何使用的?
我们可以开启 Nginx 的静态资源缓存,将一些不变的静态文件,比如图片、CSS、JS 等文件进行缓存,这样在客户端访问这些资源时就不用去访问服务器了,因此响应的速度就可以大幅提升,并且节省了宝贵的服务器资源。
Nginx 开启缓存需要在 http 节点中配置 proxy_cache_path 信息,以及 server 节点中配置要缓存资源的后缀名,它的配置示例如下:
http {
// 忽略其他的配置信息......
proxy_cache_path /data/cache levels=1:2 keys_zone=nuget-cache:20m max_size=50g inactive=1d;
include nginx_proxy.conf;
server {
listen 80;
server_name srv1.example.com;
location ~ .*\.(gif|jpg|png|css|js)(.*) { # 要缓存的文件的后缀
access_log off;
add_header Cache-Control "public,max-age=24*3600";
proxy_pass http://localhost:8080;
}
}
}
其中,proxy_cache_path 配置的是缓存的目录信息,以及缓存的保存时间 inactive,还有缓存的大小等信息;而“access_log off”表示关闭日志功能,proxy_pass 表示当第一次没有缓存时的请求地址,之后便会将访问到的资源缓存起来。
Nginx 失败会重试吗?
Nginx本身不会自动重试失败的请求。当Nginx接收到请求时,它会尝试将请求代理到后端服务器或处理请求的上游服务器。如果后端服务器或上游服务器在处理请求时返回错误响应(例如502、504等),Nginx会将该错误响应传递给客户端。
不过可以通过配置Nginx来实现请求重试的行为。Nginx提供了一些模块和指令,可以处理请求失败的情况。
-
使用
proxy_next_upstream
指令:这个指令用于配置Nginx在与后端服务器通信时遇到错误时的行为。可以设置它来指定Nginx在遇到错误时应该尝试的上游服务器的列表,并设置重试次数。例如,以下配置将Nginx在遇到502错误时重试3次:location / { proxy_pass http://backend; proxy_next_upstream error timeout; proxy_next_upstream_tries 3; } ```
-
使用
proxy_connect_timeout
和proxy_read_timeout
指令:通过设置这些指令,可以调整Nginx与后端服务器建立连接和读取响应的超时时间。如果超时发生,Nginx可以选择重试请求或返回错误响应。 -
使用第三方模块:Nginx生态系统中有一些第三方模块可用于实现更高级的请求重试功能,例如
ngx_http_retry_module
。这些模块可以提供更多的控制权和灵活性,以实现特定的重试逻辑。
不过我们需要注意: 请求重试可能对服务器负载和性能产生影响,特别是在面对高并发请求时。因此,在实施请求重试策略时,请考虑服务器的负载能力和性能要求。
最好根据我们的具体需求和环境来评估是否需要配置请求重试,并根据实际情况进行调整。