在入门之前先抛出几个问题进行思考,后面会进行解答
Nginx(发音为"engine-x")是一个高性能的开源Web服务器和反向代理服务器。
Nginx具有以下主要特点:
由于其出色的性能和功能特点,Nginx被广泛应用于各种Web应用场景,包括高流量的网站、Web应用程序、反向代理、负载均衡、缓存加速、媒体流服务等。
正向代理: 由于某种**原因,我们并不能直接访问Google,那么我们可以借助歪PIN来实现,这就是一个简单的正向代理的例子。这里你能够发现,正向代理“代理”的是客户端,而且客户端是知道目标的,而目标是不知道客户端是通过歪PIN访问的。
反向代理: 当我们在外网访问百度的时候,其实会进行一个转发,代理到内网去,这就是所谓的反向代理,即反向代理“代理”的是服务器端,而且这一个过程对于客户端而言是透明的。
之所以需要使用负载均衡是因为,如果我们使用的是一台服务器,那么在高峰期时很多用户就需要排队等待系统响应,因为一台服务器能处理的并发数是固定的。例如,一个 Tomcat 在默认情况下只能开启 150 个线程(Tomcat 8.5.x 版本)来处理并发任务,如果并发数超过了最大线程数,那么新来的请求就只能排队等待处理了,如下图所示:
然而如果有负载均衡的话,我们就可以将所有的请求分配到不同的服务器上。假如 1 台服务器可以处理 2000 个请求,那么 5 台服务器就可以处理 10000 个请求了,这样就大大提高了系统处理业务的能力,如下图所示:
知道了负载均衡的好处之后,我们来看下 Nginx 负载均衡的功能。
Nginx 主要的负载均衡策略(内置的负载均衡)有以下四种:
轮询负载策略是指每次将请求按顺序轮流发送至相应的服务器上,它的配置示例如下所示:
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 的负载均衡。
此策略是指每次将请求分发到当前连接数最少的服务器上,也就是 Nginx 会将请求试图转发给相对空闲的服务器以实现负载平衡,它的配置示例如下:
upstream myapp1 {
least_conn;
server srv1.example.com;
server srv2.example.com;
server srv3.example.com;
}
此配置方式是指每次会按照服务器配置的权重进行请求分发,权重高的服务器会收到更多的请求,这就相当于给 Nginx 在请求分发时加了一个参考的权重选项,并且这个权重值是可以人工配置的。因此我们就可以将硬件配置高,以及并发能力强的服务器的权重设置高一点,以更合理地利用服务器的资源,它配置示例如下:
upstream myapp1 {
server srv1.example.com weight=3;
server srv2.example.com;
server srv3.example.com;
}
以上配置表示,5 次请求中有 3 次请求会分发给 srv1,1 次请求会分发给 srv2,另外 1 次请求会分发给 srv3。
以上三种负载均衡的配置策略都不能保证将每个客户端的请求固定的分配到一台服务器上。假如用户的登录信息是保存在单台服务器上的,而不是保存在类似于 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 采用的是被动检测。
所谓的被动检测是指只有访问了该服务器之后发现服务器不可用了,才会将其标识为不可用,并且在一定时间内禁止请求分发到该服务器上,而不是主动以一定的频率去检查服务器是否可用。
健康检测有两个重要参数 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 的静态资源缓存,将一些不变的静态文件,比如图片、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 表示当第一次没有缓存时的请求地址,之后便会将访问到的资源缓存起来。