当前位置: 首页 > 科技观察

关于高性能负载均衡架构,这些知识点大部分人都不知道!

时间:2023-03-14 13:37:59 科技观察

单个服务器再优化,硬件再好,也总会有性能天花板。当单台服务器的性能不能满足业务需求时,就需要设计高性能的集群来提高系统的整体处理性能。高性能集群的本质很简单,通过增加更多的服务器来提高系统的整体计算能力。由于计算本身的一个特性:相同的输入数据和逻辑,无论在哪个服务器上执行,都应该得到相同的输出。因此,高性能集群设计的复杂性主要体现在任务分配部分。需要设计合理的任务分配策略,将计算任务分配给多台服务器执行。高性能集群的复杂性主要体现在需要增加任务分配器,为任务选择合适的任务分配算法。对于任务分发器,比较流行和通用的术语是“负载均衡器”。但这个名字有些误导,会让人下意识地认为任务分配的目的是让各个计算单元的负载保持均衡状态。事实上,任务分配不仅仅考虑计算单元的负载均衡。不同的任务分配算法有不同的目标。有的是基于负载的考虑,有的是基于性能(吞吐量,响应时间)的考虑,有的是基于业务的考虑。.考虑到“负载均衡”已经成为事实上的标准术语,我这里也用“负载均衡”代替“任务分配”,但请记住,负载均衡不仅仅是为了计算单元的负载达到均衡状态。负载均衡的分类常见的负载均衡系统包括三种类型:DNS负载均衡、硬件负载均衡和软件负载均衡。DNS负载均衡DNS是最简单、最常见的负载均衡方法,一般用于实现地理级别的均衡。比如北方用户访问北京机房,南方用户访问深圳机房。DNS负载均衡的本质是DNS可以解析同一个域名,返回不同的IP地址。比如同样是www.baidu.com,北方用户解析后得到的地址是61.135.165.224(这是北京机房的IP),南方用户解析后得到的地址是14.215.177.38(这是深圳机房的IP)。下面是一个简单的DNS负载均衡示意图:DNS负载均衡实现简单,成本低,但也存在粒度太粗,负载均衡算法少等缺点。仔细分析优缺点后,优点如下:简单、成本低:负载均衡工作交给DNS服务器,不需要自己开发和维护负载均衡设备。就近访问,提高访问速度:DNS解析可以根据请求源IP解析到离用户最近的服务器地址,可以加快访问速度,提高性能。缺点包括:更新不及时:DNS缓存需要很长时间。修改DNS配置后,由于缓存的原因,很多用户会继续访问修改前的IP。这样访问就会失败,达不到负载均衡的目的。并且还会影响用户正常使用服务。可扩展性差:DNS负载均衡的控制权在域名提供商,无法根据业务特点为其做更多的定制化功能和扩展特性。分配策略比较简单:DNS负载均衡支持的算法少;无法区分服务器之间的差异(无法根据系统和服务的状态判断负载);它无法感知后端服务器的状态。针对DNS负载均衡的一些不足,一些公司针对延迟和故障敏感的业务,自行实现了HTTP-DNS的功能,即使用HTTP协议实现私有DNS系统。这样的方案与一般的DNS优缺点正好相反。硬件负载均衡硬件负载均衡是通过一个单独的硬件设备来实现负载均衡的功能。这类设备类似于路由器和交换机,可以理解为负载均衡的基础网络设备。目前业界有两种典型的硬件负载均衡设备:F5和A10。这种设备性能强劲,功能强大,但价格也不便宜。一般只有“有钱”的公司才会考虑使用这种设备。普通业务级的公司用不起,二来业务量也没那么大,用这些设备太浪费了。硬件负载均衡的优点是:功能强大:全面支持各级负载均衡,支持完善的负载均衡算法,支持全局负载均衡。性能强大:相比之下,软件负载均衡最高支持10万级并发,硬件负载均衡可以支持100万以上并发。稳定性高:商用硬件负载均衡已经通过良好严格的测试,已经大规模使用,稳定性高。支持安全防护:硬件均衡设备除了负载均衡功能外,还具备防火墙、抗DDoS攻击等安全功能。硬件负载均衡的缺点是:贵:F5最常见的是“马6”,比较好的是“Q7”。可扩展性差:硬件设备可以根据业务进行配置,但不能进行扩展和定制。软件负载均衡软件负载均衡是通过负载均衡软件实现负载均衡功能。常见的有Nginx和LVS。其中Nginx是软件的7层负载均衡,LVS是Linux内核的4层负载均衡。第4层和第7层之间的区别在于协议和灵活性。Nginx支持HTTP和E-mail协议;而LVS是四层负载均衡,和协议无关。几乎所有的应用程序都可以使用,比如聊天、数据库等。软件和硬件的主要区别在于性能,硬件负载均衡性能远高于软件负载均衡性能。Ngxin的性能是万级别的,一般Linux服务器上安装一个Nginx可以达到5万/秒;LVS的性能是10万级别的,据说可以达到80万/秒;秒到800万/秒(数据来源网络,仅供参考,如需使用,请根据实际业务场景进行性能测试)。当然,软件负载均衡最大的优点就是便宜。一台普通的Linux服务器批发价在1万元左右。与F5的价格相比,那就是自行车和宝马的区别。除了使用开源系统做负载均衡,如果业务比较特殊,也可能基于开源系统进行定制(比如Nginx插件),甚至是自研。下面是Nginx的负载均衡架构示意图:软件负载均衡的优点:简单:部署和维护都比较简单。便宜:只需购买Linux服务器并安装软件即可。灵活:可根据业务选择四、七层负载均衡;也可以根据业务方便的进行扩展,比如可以通过Nginx插件实现业务定制功能。其实下面的缺点是和硬件负载均衡相比的,并不是说软件负载均衡就不能用了。性能一般:一个Nginx可以支持5万左右并发。功能不如硬件负载均衡强大。一般不具备防火墙、抗DDoS攻击等安全功能。负载均衡的典型架构我们介绍了三种常见的负载均衡机制:DNS负载均衡、硬件负载均衡和软件负载均衡。每种方法都有一定的优缺点,但并不意味着在实际应用中只能根据它们各自的优缺点结合使用。具体来说,组合的基本原则是:利用DNS负载均衡实现地理级别的负载均衡;硬件负载均衡用于实现集群级别的负载均衡;软件负载均衡用于实现机器级的负载均衡。举一个假设的例子来说明这个组合,如下图所示。整个系统的负载均衡分为三层。地域级负载均衡:www.xxx.com部署在北京、广州、上海机房。当用户访问时,DNS会根据用户所在的地理位置,确定返回哪个机房的IP。图中返回广州机房的IP地址,方便用户访问广州机房。集群级负载均衡:广州机房负载均衡使用F5设备。F5接收到用户请求后,进行集群级别的负载均衡,将用户请求发送到本地三个集群之一。我们假设F5将用户请求发送到Gave“广州集群2”。机器级负载均衡:广州集群2使用Nginx进行负载均衡。Nginx收到用户请求后,将用户请求发送给集群中的某个服务器。服务器处理用户的业务请求并返回业务响应。需要注意的是,上图只是一个例子,一般用于大型业务场景。如果业务量不是那么大,没有必要严格照搬这个架构。比如大学论坛,不需要DNS负载均衡,也不需要F5设备。使用Nginx作为简单的负载均衡就足够了。负载均衡算法负载均衡算法数量众多,可以根据业务特点进行定制开发。抛开细节上的差异,按照算法的预期目标大致可以分为以下几类。任务扁平化分类:负载均衡系统将接收到的任务分发给服务器处理。这里的“平均”可以是绝对数的平均,也可以是比例或权重的平均。负载均衡类:负载均衡系统根据服务器的负载进行分配。这里的负载不一定是通常意义上的“CPU负载”,而是系统当前的压力,可以通过CPU负载来衡量,也可以通过连接数、I/O占用率、网卡吞吐量等来衡量。用于测量系统的压力。最佳性能等级:负载均衡系统根据服务器的响应时间分配任务,将新任务优先分配给响应最快的服务器。Hash类:负载均衡系统根据任务中的某些关键信息进行Hash计算,将具有相同Hash值的请求分配给同一台服务器。常见的主动源地址Hash、目的地址Hash、sessionidhash、用户IDHash等。接下来介绍负载均衡算法及其优缺点。轮询负载均衡系统收到请求后,会依次分配给服务器。轮询是最简单的策略,不需要关注服务器本身的状态。例如:某服务器当前因为触发了程序BUG而陷入死循环,导致CPU负载过高。源源不断地发送它。集群中有32核的新机器,也有16核的旧机器。负载均衡系统也不关心。分配给新旧机器的任务数量是一样的。需要注意的是,负载均衡系统不需要关注“服务器本身的状态”,这里的关键词是“自身”。即只要服务器在运行,运行状态是无关紧要的。但是,如果服务器直接宕机,或者服务器与负载均衡系统断开连接,此时负载均衡系统可以感知到,需要进行相应的处理。例如,从可分配服务器列表中删除服务器显然是不合理的,否则服务器会宕机,任务会继续分配给它。总而言之,“简单”既是轮询算法的优势,也是劣势。加权循环负载均衡系统根据服务器权重分配任务。这里的权重一般是根据硬件配置静态配置的。动态计算会更适合业务,但复杂度会更高。加权轮询是轮询的一种特殊形式,其主要目的是解决不同服务器处理能力不同的问题。例如集群中有32核的新机器和16核的旧机器,理论上我们可以假设新机器的处理能力是旧机器的两倍,负载均衡系统可以基于比例为2:1。将更多任务分配给新机器,以充分利用新机器的性能。Weightedroundrobin解决了roundrobin算法中不能根据服务器配置差异分配任务的问题,但是也存在不能根据服务器状态差异分配任务的问题。最低负载优先级负载平衡系统将任务分配给当前负载最低的服务器。这里的负载可以根据不同的任务类型和业务场景,用不同的指标来衡量。例如:LVS,一种四层网络负载均衡设备,可以通过“连接数”来判断服务器的状态。服务器连接数越大,服务器的压力就越大。Nginx是一个7层网络负载系统,可以通过“HTTP请求数”来判断服务器状态(Nginx内置的负载均衡算法不支持这种方式,需要扩展)。如果我们开发自己的负载均衡系统,可以根据业务特点选择衡量系统压力的指标。如果是CPU密集型,可以通过“CPU负载”来衡量系统压力;如果是I/O密集型,可以通过“I/Oload”来衡量系统压力。负载优先级最低的算法解决了轮询算法中无法感知服务器状态的问题,但由此带来的代价是复杂度很高。例如:最小连接优先级算法要求负载均衡系统统计每台服务器当前建立的连接数。固定连接池方式不适合这种算法。比如LVS可以用这个算法做负载均衡,但是通过连接池连接MySQL集群的负载均衡系统就不适合用这个算法做负载均衡。CPU负载优先级最低的算法需要负载均衡系统以一定的方式收集每台服务器的CPU负载,并根据1分钟的负载或15分钟的负载来判断。没有1分钟肯定比15分钟好或坏这样的事情。不同业务的最佳时间间隔是不同的。如果时间间隔太短,容易造成频繁的波动。如果时间间隔过长,可能会导致峰值到来时响应变慢。最低负载优先级算法基本上可以完美解决轮询算法的不足,因为使用该算法后,负载均衡系统需要感知服务器当前的运行状态。当然,代价是复杂性的巨大增加。通俗地说,轮询可能是一个5行代码就能实现的算法,而最低的负载优先级算法可能需要1000行才能实现,甚至需要负载均衡系统和服务端都需要开发代码。如果最低负载优先级算法本身设计不好,或者不适合业务的运行特点,算法本身就可能成为性能瓶颈,或者导致很多莫名其妙的问题。因此,虽然最低负载优先算法的效果看起来不错,但实际上实际应用场景并没有轮询(包括加权轮询)多。从服务器的角度分配最佳性能负载最低优先级算法,而从客户端角度分配最佳性能优先级算法,将任务首先分配给处理速度最快的服务器,通过这种方式实现对客户端最快的响应。与最低负载优先算法类似,性能优化优先算法本质上是感知服务器的状态,仅以响应时间为外在标准来衡量服务器的状态。因此,最优性能优先算法的问题与最低负载优先算法的问题类似,复杂度很高,主要体现在:负载均衡系统需要收集和分析每个任务的响应时间每个服务器。在场景中,这种收集和统计本身会消耗更多的性能。为了减少这种统计消耗,可以采用抽样的方式进行统计,即不统计所有任务的响应时间,而是对部分任务的响应时间进行抽样,以估算整体任务的响应时间。采样统计虽然可以降低性能消耗,但是进一步增加了复杂度,因为需要确定合适的采样率。如果采样率太低,结果将不准确。采样率过高会消耗性能。一件复杂的事情。不管是全部统计还是抽样统计,都需要选择一个合适的周期:10秒内最好的表现,1分钟内最好的表现,或者5分钟内最好的表现……没有千篇一律的-适合所有周期。根据实际业务进行判断和选择也是一件比较复杂的事情,甚至在系统上线后,还需要不断调优,以达到最优设计。Hash型负载均衡系统根据任务中的某些关键信息进行Hash计算,将具有相同Hash值的请求分配给同一台服务器。这样做的目的主要是为了满足特定的业务需求。例如:Sourceaddresshash将同一源IP地址的任务分配给同一台服务器处理,适用于有事务和会话的业务。例如,当我们通过浏览器登录网上银行时,会产生一个session信息,这个信息是临时的,关闭浏览器后就失效了。网银后台不需要持久化session信息,只需要将session暂时保存在某个服务器上即可,但需要保证session存在期间用户每次访问的都是同一台服务器.这种业务场景可以使用SourceaddressHash来实现。IDHash是将一个ID标识的业务分配给同一台服务器进行处理,这里的ID一般是临时数据的ID(比如sessionid)。比如上面的网银登录例子,也可以通过sessionidhash来达到用户在同一个session中每次都访问同一个服务器的目的。