• 理解Nginx的反向代理与负载均衡


    Nginx 简介

    原文:https://www.imooc.com/article/284807
     

    初次发布

    Nginx (engine x) 是一个高性能的HTTP和反向代理服务,也是一个IMAP/POP3/SMTP服务。Nginx是由伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点(俄文:Рамблер)开发的,第一个公开版本0.1.0发布于2004年10月4日。其将源代码以类BSD许可证的形式发布,因它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名。

    性能概览

    Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行。其特点是占有内存少,并发能力强,Nginx的并发能力在同类型的网页服务器中表现较好。

    与旧版本的Apache不同,Nginx不采用每客户机一线程的设计模型,而是充分使用异步逻辑(这一点与NodeJS采取了相同的做法,支持高并发,Nginx在官方测试的结果中,能够支持五万个平行连接,而在实际的运作中,是可以支持二万至四万个平行链接),削减了上下文调度开销,所以并发服务能力更强。整体采用模块化设计,有丰富的模块库和第三方模块库,配置灵活。

    Nginx的反向代理

    理解反向代理

    要使用Nginx的反向代理的特性,首先就是要理解什么是反向代理,为此我们先从最简单的C/S架构说起,C/S架构,也即是Client-Server的架构。而最简单的C/S架构,也即是以单个节点作为后端Server的C/S架构。

    C/S架构中的单点Server

    在普通的开发当中,单点Server的服务方式非常常见,比如使用Django框架做后台服务的时候,就可以通过简单的run server命令运行起一个临时的服务,接着通过地址就可以访问到这个服务了。当然了,对于Django而言,run server命令只是提供开发周期的调试使用的便捷工具,更一般的情况是通过uWSGI把这个Django服务跑起来,以获取并比run server更好的服务性能。
    此时部署整一个架构图如下:
    图片描述
    对于请求量非常少的服务,这样的部署不会有什么问题,但如果这个服务请求量上来的时候,这样部署的架构就很有问题了。

    首先一个很客观的问题就是,如果单从服务器的物理特性来看,这个服务器就不能支持这么高的请求量。这种情况下,就迫使开发者去把服务迁移到一个CPU更强、内存更高,综合性能更好的服务器。通过更换服务器当然可以解决这个问题,在不考虑成本的条件下,总可以找到性能更好的服务器来替换原来的服务器以支撑服务,但这种理想的条件不在本文考虑范围之内。

    第二个问题就是,如果服务Server单节点发生了故障,就必然会影响整个服务,因为对于众多的Client客户端都是连接的一个Server服务端,如果这个节点不可用了,势必会影响所有使用了客户端的用户。

    为了解决这两个显而易见的问题,就必须提出一种可以横向拓展的部署架构,使得服务可以支撑的请求量可以随着服务的横向拓展而增加。因而就催生了如下的部署架构:

    图片描述

    基于代理的可横向拓展的C/S架构

    在这个部署的架构当中,除了Server节点,还多出了一个叫“Proxy”的节点,那么这个节点是干嘛的呢?
    “Proxy”的这个节点,它把他接收的所有的请求都转发到他后面的Server节点当中,然后等待Server节点处理请求,再从Server节点取回执行结果返回到Client。所以,“Proxy”的这个节点,他实际上不处理任何的请求。
    我们先来看这样子的架构怎么解决了以上的问题,再来思考“Proxy”的这个角色。
    首先是第一个问题,服务器性能不足的问题,这个架构如何解决性能不足的问题呢?在这个架构里面,假设Server节点S1性能到达瓶颈了,不能处理更多的请求了。如果采用上面的这个架构,那么我们可以添加Server节点S2,同时告诉“Proxy”节点,让他把部分原来转发到S1节点的请求转发到我这里来。这样子通过服务分流减少压力的方法就可以解决原来S1节点性能不足的问题了。
    图片描述

    接着是第二个问题,单点服务器挂掉了怎么办。还是考虑Server节点S1和S2,两者所能够提供的服务是一样的,假设某一个时候S1挂掉了,这时如果有“Proxy”节点的存在,并且“Proxy”节点能够察觉到S1挂掉了的话,那么让“Proxy”节点把原来要转发给S1节点的请求转发到S2进行处理就可以了,这样子通过服务冗余的方法就可以解决原来S1突然挂掉影响服务的问题。

    图片描述
    解决了这两个问题,接下来我们再从这两个问题里面“Proxy”的角色来理解什么叫做代理。
    在第一个问题里面,“Proxy”节点通过服务分流的方法来减少S1的压力,对于原来应该被S1服务的,却由于被“Proxy”节点转发而被S2服务的Client而言,Client他并不知道实际上是由S1处理的还是S2处理的,Client拿到的是一个从“Proxy”节点返回的结果,换言之,Client并不知道自己的请求实际上是被哪个处理的,他只需要往“Proxy”节点发送请求就好了,剩下的工作就由“Proxy”节点去解决。
    也就是,“Proxy”节点相当于一个中介,或者说是一个代理,代理Client去寻找实际的Server节点去完成服务。这样子的模式在现实生活也非常常见,在买房子的时候,通常由房产中介帮助你完成和卖者之间的手续,而不需要你亲自去处理这些事情,你只需要协调好自己与中介之间的手续就好了,这里的中介,就和我们的“Proxy”节点所做的工作非常类似。
    同样的,在第二个问题里面,也是相似的理解方式,Client并不需要感知S1是否还能正常工作,Client只需要把请求发送给“Proxy”节点,由它去帮忙处理就可以了。
    因此,这里面的“Proxy”节点,也就是我们的代理节点。

    正向代理与反向代理

    理解了什么是“代理”,离我们理解什么是“反向代理”就只差“反向”两个字了,与“反向”相对的,就是“正向”,本质上来讲,代理都是存在于Client和Server之间,但是由于性质不同,所以也分为这两种。在这一个部分,我们将会学习,什么是反向代理,什么是正向代理。
    直观的以两个例子去理解什么是正向代理和反向代理。假设由A、B和C三人,他们之间存在借钱的关系。
    对于正向代理,理解起来就是:

    1. A需要钱,A知道C由很多钱,想向C借钱
    2. 但是A和C有矛盾,于是A想到通过B去借C借钱
    3. B向C借到钱了,C不知道是A的存在
    4. 这样B就帮助A借到了Z的钱
      在这个过程,B就充当了代理借钱的角色,并且是代替A去借钱的,这样就是正向代理。

    图片描述

    接着是反向代理:

    1. A需要钱,C有很多钱,A不知道C很多钱
    2. A找B借钱
    3. B知道C有很多钱
    4. B向C借钱,并把借到的钱给A,而没有使用自己的钱借给A
    5. A拿到钱以后,以为钱是B的,A不知道C的存在
      在这个过程当中,B也充当了代理借钱的角色,不过这次不是代替A去借的,而是用C的钱借给A的,换言之即是代替C将钱借给了A,这就是反向代理。
      图片描述
      在例子里面,把A换成Client,把C换成Server,就是计算机的例子了。
    两者区别
    1. 服务对象不同
      • 正向代理,代理的是客户端,也就是例子中的A,服务端不知道实际发起请求的客户端
      • 反向代理,代理的是服务端,也就是例子中的C,客户端不知道实际提供服务的服务端

    正向代理
    图片描述

    反向代理

    图片描述

    1. 安全模型不同
      • 正向代理允许客户端通过它访问任意网站并且隐藏客户端自身,因此必须采取安全措施以确保仅为授权的客户端提供服务
      • 反向代理都对外都是透明的,访问者并不知道自己访问的是代理,访问者不知道服务节点的存在,认为处理请求的就是代理节点

    总而言之,正向代理是从客户端的角度出发,服务于局域网用户,以访问非特定的服务,其中最典型的例子就是FQ;反向代理正好与此相反,从服务端的角度出发,服务于所有用户,隐藏实际的服务节点,服务节点的架构对用户透明,以代理节点统一对外服务。

    Nginx配置反向代理

    (文末附完整nginx.conf配置)
    为了演示Server节点, 我们使用Django快速启动一个项目,可以快速验证反向代理的配置是否ok。

    django-admin startproject server1 

    接着我们启动一个内网地址,端口为8080。

    python manage.py runserver 127.0.0.1:8080 

    接着配置Nginx,在Nginx的配置里面,主要是upstream块,和server块。

    upstream httpserver{ server 127.0.0.1:8080; } 

    然后在server块配置转发到upstream。

    location / { proxy_pass http://httpserver; } 

    如此,便完成反向代理的配置,接着通过命令nginx -s reload重新加载配置文件即可。若存在多个Server节点,在upstream域添加多个Server的地址即可。
    我们另起一个django项目,服务启动在8081端口。
    接着更新upstream的配置。

    upstream httpserver{ server 127.0.0.1:8080; server 127.0.0.1:8081; } 

    就可以完成两个节点的反向代理。

    Nginx代理中的负载均衡

    提到Nginx的反向代理,不得不提的就是Nginx的负载均衡,Nginx支持丰富的负载均衡算法,以提高使用Nginx部署的服务的综合性能。
    在介绍负载均衡之前,我们先来看为什么需要负载均衡。

    为什么需要负载均衡

    需要负载均衡的一个最简单的诉求就是由Proxy代理的多个Server节点的性能并不完全相等的,也即是不同Server节点,他们处理请求的速度和容量都不相同,这就要求Proxy在转发的时候,能够因Server而异,给不同Server转发适合其处理性能的请求量,以防Server节点低负载浪费资源,或者过高负载引起宕机。
    其次就是如果没有负载均衡算法,我们就无法避免很多请求被调度到一个Server节点从而把这个Server节点压垮的情况发生,因为我们没有一种机制保证不同Server节点所处理的请求量数均匀的或者是合理的。

    负载均衡的算法

    对服务器性能的考究有很多变量需要去关注:包括CPU的核数和频率、内存的容量速度、网络的质量、内核最大文件描述符、服务器的其他服务影响等等,因此在负载均衡算法上,也是非常丰富的,以下是几种常见的负载均衡算法。

    随机算法

    随机,顾名思义,就是随机概率的调度,每一个请求通过随机算法调度到不同的服务器,若调用量越大,不同服务器处理的请求数就越平均。
    这种算法看是公平的,但是没有考虑到不同节点性能的差异,同时对随机算法也有一定的要求,要求随机算法在大量的随机事件后能够得到一个均匀的随机结果。

    轮询算法

    轮询算法也非常容易理解,请求到来的时候,按顺序把每个请求转发到多个Server节点当中,保证每个服务节点所处理的请求量都是均匀的。
    虽然这种算法很公平,但是没有考虑到不同节点性能的差异。

    最少连接算法

    在多个服务器当中,优先将请求调度到处理连接数少的服务器上,即使每台服务器的处理能力各不相同,也能够在一定程度上降低服务器的负载。
    这种算法能够考虑不同节点性能之间的差异,处理连接数在一定程度上能够反映其性能的差异,不过并非绝对,在一些条件下,其他原因也可限制处理连接数,比如网络性能、带宽压力等等。

    权重轮询算法

    这种算法要求在转发节点配置Server的时候,添加Server节点的权重信息,以表示不同Server节点的处理性能,在转发节点转发请求的时候,将按照权重的大小来分配转发的流量。
    这种算法可以合理的转发请求,开发人员可以按照Server节点的性能参数、部署的服务来修改Server节点的权重,使得每一个Server节点都能够得到最合理的使用。
    当然,除了开发人员手动配置权重以外,更为智能的一种方式是由代理的Server节点主动上报自己的能力,转发节点在接收到相关信息的时候再权衡不同Server节点的能力,按照权重进行转发。这样就不用人工介入,提高效率。不过这种方式对转发节点和Server节点都有一定的要求,需要开发者去开发相关的逻辑。

    使用Nginx配置负载均衡

    理解不同的负载均衡算法以后,接下来就是对Nginx配置负载均衡了。Nginx支持普通轮询算法和权重轮询算法的负载均衡配置。

    轮询算法的负载均衡

    其实基于普通轮询算法的负载均衡,在前面我们已经实现了,只不过当时重点不在负载均衡,所以没有提及。

    upstream httpserver{ server 127.0.0.1:8080; server 127.0.0.1:8081; } 

    这就是轮询算法的负载均衡的配置,在upstream配置块的多个server节点默认都有权重weight=1,也即是每个服务节点权重一样了。

    权重轮询算法的负载均衡

    在普通轮询算法的基础上,我们可以进行权重轮询算法的配置,配置如下:

    upstream httpserver{ server 127.0.0.1:8080 weight=5; # 权重为5 server 127.0.0.1:8081 weight=2; # 权重为2 server 127.0.0.1:8082; # 默认权重为1 } 

    如此添加weight关键字即可,接着你就可以在日志中看到,请求大致会以5:2:1的比例落到三个server中,这就是权重轮询算法的负载均衡。

    总结

    Nginx是一个高性能的部署服务端。支持HTTP部署、代理和反向代理、负载均衡、邮件服务等丰富的功能,是非常出色的一款软件,本文介绍了反向代理和负载均衡的概念,并介绍了使用Nginx配置反向代理和负载均衡的过程,希望看完这篇文章,大家对Nginx和相关概念有进一步的理解。
    最后打个小广告,实战课程《Django 2.0+微信小程序打造个人助手》,除了使用Django和微信小程序这两款热门技术去开发个人助手以外,针对Django的服务高可用部署等知识点也有详细的介绍,感兴趣的同学可以参加学习,我们一起来探讨哦。


    附:最简单Nginx的完整配置

    user www-data;
    worker_processes auto;
    pid /run/nginx.pid;
    events {
            worker_connections 768;
    }
    http {
            ##
            # Basic Settings
            ##
            sendfile on;
            tcp_nopush on;
            tcp_nodelay on;
            keepalive_timeout 65;
            types_hash_max_size 2048;
            include /etc/nginx/mime.types;
            default_type application/octet-stream;
            ##
            # SSL Settings
            ##
            ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
            ssl_prefer_server_ciphers on;
            ##
            # Logging Settings
            ##
            access_log /var/log/nginx/access.log;
            error_log /var/log/nginx/error.log;
            ##
            # Gzip Settings
            ##
            gzip on;
            gzip_disable "msie6";
            include /etc/nginx/conf.d/*.conf;
            include /etc/nginx/sites-enabled/*;
            upstream httpserver {
                    server 127.0.0.1:8080 weight=5;
                    server 127.0.0.1:8081 weight=2;
            }
            server {
                    listen 80;
                    server_name .dongcia.com;
                    charset utf-8;
                    location / {
                           proxy_pass http://httpserver;
                    }
            }
    }

     

  • 相关阅读:
    bzoj 3196/tyvj p1730 二逼平衡树
    AW201 可见的点 (欧拉函数)
    P3912 素数个数
    P1029 最大公约数和最小公倍数问题
    P1835 素数密度
    P2563 [AHOI2001]质数和分解
    P1075 质因数分解
    AW199 余数之和
    AW198 反素数
    AW197 阶乘分解
  • 原文地址:https://www.cnblogs.com/songlin123/p/10950998.html
Copyright © 2020-2023  润新知