[关闭]
@dungan 2022-11-25T02:56:26.000000Z 字数 8707 阅读 621

Nginx

反向代理与负载均衡

在了解负载均衡之前先了解一组概念 !

集群

什么是集群

集群是为了解决高并发问题,由一组相互独立的计算机组成的一个较大的计算机服务系统!

集群的分类

负载均衡集群和高可用集群是互联网常用的集群架构模式!

负载均衡集群

负载均衡的原理是通过一个前端负载均衡器将请求分发到后端的一组服务器,常见的组件有 nginx,LVS,Haproxy!

高可用集群

一般指的是集群中任意节点失效的情况下,该节点的所有任务能够自动转义到其他正常的节点,本质上为了从故障中尽快恢复系统可用,采用的是主从架构,高可用集群常用于不易实现负载均衡的应用(例如主从数据库,主从负载均衡器,主从缓存服务器);常见的组件有 Keepalived,Heartbeat!

nginx 反向代理

nginx 的反向代理主要通过 ngx_http_proxy_module 模块的 proxy_pass 实现,用于把用户的请求转发给后面的服务器节点或者 upstream 服务器池!

  1. location /a/ {
  2. proxy_pass http://www.a.com;
  3. }
  4. location /b/ {
  5. proxy_pass http://www.b.com;
  6. }

搭建测试环境

新建一个虚拟主机

  1. # test.com.conf
  2. server {
  3. listen 80;
  4. server_name test.com;
  5. access_log /data/wwwlogs/172.16.0.18_nginx.log combined;
  6. index index.html index.htm index.php;
  7. root /data/wwwroot/test.com;
  8. }

这个虚拟主机指向的目录下面只有一个 index.html

  1. test.com/
  2. └── index.html # 内容为 index-tcl.com

反向代理与正向代理

概括起来,正向代理是简单的转发用户请求,反向代理则是会接受用户请求后,代理用户访问后面的服务器!

Nginx 代理相关指令说明

  • proxy_pass:转发用户请求给代理。
  • proxy_set_header:设置请求后端服务器的 header 头。
  • client_body_buffer_size:指定客户端请求主体缓冲区大小。
  • proxy_connect_timeout:代理与后端服务器的连接超时时间。
  • proxy_send_timeout:等待后端服务器传输完数据的时间,超过这个时间将会断开连接。
  • proxy_read_timeout:等待后端服务器响应超时时间。
  • proxy_buffers:指定了从被代理服务器到来的应答,本地将用多少和多大的缓冲区读取,默认这个参数等于分页大小,根据环境的不同可能是4K, 8K或16K,这取决于平台。
  • proxy_buffer_size:指定将用多大的缓冲区来读取从被代理服务器到来应答的第一部分,通常来说在这个部分中包含一个小的应答头,默认的缓冲区大小为proxy_buffers指令中的每块大小。
  • proxy_busy_buffers_size:设置系统很忙时可以使用的 proxy_buffers,官方推荐大小为 proxy_buffers * 2。
  • proxy_temp_path:设置临时文件的存储位置。
  • proxy_temp_file_write_size:设置临时文件的大小。
  • proxy_max_temp_file_size : 设置所有临时文件的总的大小。
  • proxy_cache_path:设置缓存数据存储的位置。
  • proxy_cache_min_uses:设置相同的请求达到几次后对该请求进行缓存,默认为1。
  • proxy_cache_key:设置缓存的 key,一般是请求 url 的 hash。
  • proxy_cache_bypass:设置不从缓存读取数据。
  • proxy_cache_use_stale:设置当请求无法被后端服务器处理时,返回 nginx 中的历史缓存。
  • proxy_cache_valid:设置 http状态码的缓存时间,例如
    • proxy_cache_valid 200 302 10m; 表示响应状态码为200 302时,10分钟有效。
    • proxy_cache_valid any 1d; #所有的状态都缓存1天。

示例

请求 1ocalhost 时将其代理到 test.com;

  1. server {
  2. listen 80;
  3. server_name default;
  4. access_log off;
  5. index index.html index.htm index.php;
  6. root /data/wwwroot/default;
  7. include /usr/local/nginx/conf/rewrite/none.conf;
  8. #error_page 404 /404.html;
  9. #error_page 502 /502.html;
  10. location / {
  11. proxy_pass http://test.com;
  12. proxy_set_header name tcl;
  13. }
  14. }

保存文件后重载配置 nginx -s reload

  1. [root@VM_0_17_centos vhost]# curl localhost
  2. index-test.com
  3. # 输出了 index-test.com,说明反向代理设置成功了!

nginx 负载均衡

nginx 负载均衡由 ngx_http_upstream_module 模块实现,基于 url 转发请求被称为第七层(应用层)负载均衡,而基于 tcp 转发请求则被称为第四层(传输层)负载均衡!

搭建测试环境

这里准备三台服务器

  1. # 192.168.109.136.conf
  2. server {
  3. listen 80;
  4. server_name 192.168.109.136;
  5. access_log /data/wwwlogs/192.168.109.136_nginx.log combined;
  6. index index.html index.htm index.php;
  7. root /data/wwwroot/master.com;
  8. }
  9. # 172.16.0.19.conf
  10. server {
  11. listen 80;
  12. server_name 192.168.109.137;
  13. access_log /data/wwwlogs/192.168.109.137_nginx.log combined;
  14. index index.html index.htm index.php;
  15. root /data/wwwroot/slave1.com;
  16. }
  17. # 172.16.0.20.conf
  18. server {
  19. listen 80;
  20. server_name 192.168.109.138;
  21. access_log /data/wwwlogs/192.168.109.138_nginx.log combined;
  22. index index.html index.htm index.php;
  23. root /data/wwwroot/slave2.com;
  24. }

这三个虚拟主机指向的目录下面只有一个 index.html

  1. slave1.com/
  2. └── index.html # 内容为 index-slave1
  3. slave2.com/
  4. └── index.html # 内容为 index-slave2
  5. master.com/
  6. └── index.html # 内容为 index-master

基本的负载均衡配置如下

  1. upstream backend {
  2. ip_hash;
  3. server backend1.example.com weight=5;
  4. server backend2.example.com:8080 fail_timeout=5s;
  5. server unix:/tmp/backend3;
  6. server backup1.example.com:8080 backup;
  7. }
  8. server {
  9. location / {
  10. proxy_pass http://backend;
  11. # 保留代理之前的host
  12. # proxy_set_header Host $host;
  13. # 将客户端真实的ip地址转发给后端服务器,不然后端服务器记录的是代理的ip!
  14. # proxy_set_header X-real-ip $remote_addr;
  15. # 在多级代理的情况下,记录每次代理之前的客户端真实ip
  16. # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  17. # 表示客户端真实的协议(http还是https)
  18. # proxy_set_header X-Forwarded-Proto $scheme;
  19. # 指定修改被代理服务器返回的响应头中的location头域跟refresh头域数值
  20. # proxy_redirect default;
  21. }
  22. }

upstream 模块支持的代理方式有:proxy_pass,fast-cgi_pass,memcached_pass !

nginx 常见的负载均衡策略

当你有了一组服务器后,接下来就该考虑的是如何把客户端的请求转发给这些服务器,这种转发策略就是 nginx 的负载均衡策略!

负载均衡策略一般有两种:

  • 静态:负载均衡器会根据自身设定的规则进行分配,不需要考虑后端节点服务器的情况,例如 rr(普通的轮询),wrr(加权轮询),ip_hash!
  • 动态:负载均衡器会根据后端节点的当前状态来决定是否分发请求,比如连接少的和响应时间短的会优先获得请求,这类负载均衡策略有 least_conn,fair!

rr(轮询 round-robin):每个请求按时间顺序逐一分配到不同的后端服务器,如果后端某台服务器宕机,故障系统被自动剔除,使用户访问不受影响!

  1. upstream test {
  2. server 192.168.109.137;
  3. server 192.168.109.138;
  4. }

权重(weight):指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况!

  1. upstream test {
  2. server 192.168.109.137 weight=1;
  3. server 192.168.109.138 weight=9;
  4. # 基于权重的策略,那么10次一般只会有9次会访问到172.16.0.19,而有1次会访问到172.16.0.18
  5. }

ip_hash:每个请求按访问IP的hash结果分配,这样来自同一个IP的访客固定访问一个后端服务器,有效解决了动态网页存在的session共享问题!

  1. upstream test {
  2. ip_hash;
  3. server 192.168.109.137;
  4. server 192.168.109.138;
  5. }

least_conn:优先发送给那些接受请求少的,目的是为了让请求分发得更平衡些!

  1. upstream test {
  2. least_conn;
  3. server 192.168.109.137;
  4. server 192.168.109.138;
  5. }

fair:按后端服务器的响应时间来分配请求,响应时间短的优先分配;Nginx本身是不支持fair的,如果需要使用这种调度算法,必须下载 Nginx 的 upstream_fair 模块!

  1. upstream test {
  2. fair;
  3. server 192.168.109.137;
  4. server 192.168.109.138;
  5. }

url_hash:按访问 url 的 hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效;Nginx本身是不支持 url_hash 的,如果需要使用这种调度算法,必须安装 Nginx hash 软件包!

在upstream中加入hash语句,server语句中不能写入weight等其他的参数,hash_method是使用的hash算法!

  1. upstream test {
  2. hash $request_uri;
  3. hash_method crc32;
  4. server 192.168.109.137;
  5. server 192.168.109.138;
  6. }

Nginx 负载均衡相关的参数说明

  • down:假如有一台主机是出了故障,或者下线了,要暂时移出,那可以把它标为down,表示请求是会略过这台主机的。
  • backup:backup是指备份的机器,相对于备份的机器来说,其他的机器就相当于主要服务器,只要当主要服务器不可用的时候,才会用到备用服务器。
  • weight:服务器的权重,默认每台主机的权重都是1,配置高的服务器可以适当给大点。
  • max_fails:表示的是尝试连接后端主机失败的次数,默认为1,即请求一次失败后就换到下台主机。
  • fail_timeout:在 max_fails 定义的失败次数后,距离下次检查的间隔时间,默认是10s。

注意:ip_hash 下不能设置 backup 和 weight!

示例

我们在 192.168.109.136 这台机器上做负载均衡。

demo1:轮询

  1. # 192.168.109.136.conf
  2. upstream test {
  3. server 192.168.109.137;
  4. server 192.168.109.138;
  5. }
  6. location / {
  7. proxy_pass http://test;
  8. }

测试

  1. [root@centos default]# curl localhost
  2. index-slave1
  3. [root@centos default]# curl localhost
  4. index-slave2
  5. [root@centos default]# curl localhost
  6. index-slave1
  7. # 可以看到按照轮询策略进行负载均衡成功了!

demo2:权重

  1. # 192.168.109.136.conf
  2. upstream test {
  3. server 192.168.109.137 weight=1;
  4. server 192.168.109.138 weight=9;
  5. }
  6. location / {
  7. proxy_pass http://test;
  8. }

测试

  1. [root@centos default]# curl localhost
  2. index-slave2
  3. [root@centos default]# curl localhost
  4. index-slave2
  5. [root@centos default]# curl localhost
  6. index-slave2
  7. [root@centos default]# curl localhost
  8. # 可以看到调整 192.168.109.138 的权重后一直输出的是 slave2!

demo3:当一台 down 掉后启用备用机

  1. upstream test {
  2. server 192.168.109.137 backup;
  3. server 192.168.109.138 down;
  4. }
  5. location / {
  6. proxy_pass http://test;
  7. }

测试

  1. [root@centos default]# curl localhost
  2. index-slave1
  3. # 可以看到当 192.168.109.138 down 掉后,启用了备用机 192.168.109.137!

nginx buffer

在proxy_buffering 开启的情况下,Nginx将会尽可能的读取所有的upstream端传输的数据到buffer,直到proxy_buffers设置的所有buffer们被写满或者数据被读取完(EOF)。此时nginx开始向客户端传输数据,会同时传输这一整串buffer们。同时如果response的内容很大的话,Nginx会接收并把他们写入到temp_file里去。大小由proxy_max_temp_file_size控制。如果busy的buffer传输完了会从temp_file里面接着读数据,直到传输完毕。

一旦proxy_buffers设置的buffer被写入,直到buffer里面的数据被完整的传输完(传输到客户端),这个buffer将会一直处在busy状态,我们不能对这个buffer进行任何别的操作。所有处在busy状态的buffer size加起来不能超过proxy_busy_buffers_size,所以proxy_busy_buffers_size是用来控制同时传输到客户端的buffer数量的。

nginx 缓存

缓存可以用来降低服务器的负载,实现静态化等功能;
nginx 缓存是通过键值存储的,键是存放在内存中,数据是放到磁盘上,在内存中找一块空间,通过对 url 进行 hash生成缓存的键,这个键所对应的值指向的是磁盘中缓存空间的内容的路径,磁盘上存放缓存的文件!

nginx cache 的配置一般如下

  1. http {
  2. # 在内存中找10M的空间,命名为 cache_zone
  3. proxy_cache_path /data/cache levels=1:2 keys_zone=cache_zone:10m inactive=1d max_size=100m;
  4. server {
  5. listen 80;
  6. server_name www.mytcl.com;
  7. root /data/wwwroot/proxy;
  8. # add_header X-Via $server_addr;
  9. # add_header X-Cache $upstream_cache_status;
  10. location / {
  11. proxy_pass http://121.41.18,56;
  12. # proxy_set_header X-Real-IP $remote_addr;
  13. proxy_cache cache_zone;
  14. #proxy_cache_key $host$uri$is_args$args;
  15. proxy_cache_key $host$uri;
  16. proxy_cache_valid 200 304 301 302 1d; # 注意:该指令必须设置
  17. }
  18. }

指令 proxy_cache_path 用来设置缓存的位置,只能在 http 区块设置,语法如下

  1. proxy_cache_path path [levels=number] keys_zone=zone_name:zone_size [inactive=time] [max_size=size];

指令 proxy_cache_key 它用来指定生成缓存 key 的 url 格式 ,语法如下

  1. # 不考虑 url 参数,相同的 url 写入到同一文件
  2. proxy_cache_key $host$uri;
  3. # 考虑 url 参数生成不同的缓存
  4. proxy_cache_key $host$uri$is_args$args;

proxy_cache_key 默认是$scheme$host$request_uri,但是一般我们会把它设置成:$host$uri$is_args$args 一个完整的url路径!

现在分别在代理服务器和后端服务器的根目录下新建新建 index.html

  1. /data/wwwroot/proxy/
  2. ├── index.html # 内容为 nginx1
  3. /data/wwwroot/back-end
  4. ├── index.html # 内容为 nginx2

浏览器中访问,可以看到代理设置成功

截图中的X-Cache用来标识缓存的状态
- MISS 未命中,请求被传送到后端。
- HIT 缓存命中。
- EXPIRED 缓存已经过期请求被传送到后端。
- UPDATING 正在更新缓存,将使用旧的应答。
- STALE 后端将得到过期的应答。
- BYPASS 缓存被绕过了。

接着我们去缓存所在的目录发现缓存也成功创建了,目录层级符合 levels=1:2 的规则

  1. [root@VM_0_17_centos cache]# tree /data/cache/
  2. /data/cache/
  3. └── a
  4. └── 6f
  5. └── 0fa5edb6a43601ec428e5817185a46fa

参考

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注