负载均衡集群(未完)
负载均衡集群(未完)
方小葱 发表于1年前
负载均衡集群(未完)
  • 发表于 1年前
  • 阅读 39
  • 收藏 0
  • 点赞 0
  • 评论 0

腾讯云 技术升级10大核心产品年终让利>>>   

#高可用与高性能

首先要明晰两个概念:高可用和高性能,高可用和高性能在某些“方法论”或者实现上有类似的地方,但是其解决的问题和侧重点有所不同:

高可用关注的是“持续可用问题”,我知道这是废话,那么何为“可用”,简单的的说“部分服务器挂了依然还能为用户提供服务”。衡量可用度有一个简单的指标:可用性,他是一个百分百比,具体为:在一段时间内服务器(组)正常提供服务的时间/总的时间100。如果你的服务器(组)在93%的情况下是正常的,我们可以认为系统可用性为93%,当然对于单台服务器或者组还有其他指标参数,比如宕机时间(平均故障间隔时间),故障率等。 以下是github的状态页面:https://status.github.com 上面显示了系统可用性和网站的其他指标,可以作为用户的参考。

高性能侧重于“规模”问题,当你的计算量非常大的时候,比如需要处理的数据量(请求量)非常大,或者解题步骤非常多或者繁杂的时候的时候我们为了节省时间,提供更优质的服务需要考虑高性能问题;

我们假设程序和系统已经到最大优化,此时高性能依赖于服务器或者CPU的“堆叠(集群)”,一台服务器可以服务100人,两台服务器可以200人,当然这是理想情况。

而高可用依赖于容错机制,比如失败之后采取什么措施,部分服务不可用之后的熔断措施等,当然备份也是高可用的一个具体措施(包括数据备份),哪怕是冷备:有的银行在采购的时候同样的设备会买两套,一套放在仓库里晾着,生怕天灾人祸而供货商货或者生产商不在继续生产该型号的设备,都是保证系统高可用的一周手段。

##高性能和高可用的交叉点: 1,增加或者增强设备是相同的手段 我们需要增加设备来实现其中一套设备挂了还能使用另一套的方式来实现高可用(个人觉得备机,无论是热备还是冷备,是高可用的必要条件);同样增加设备,如果你能保证两套设备同时工作分担任务,他便能增加系统的性能(我觉得吞吐量或者处理能力这些词更适合这个场景) 2,机制或者方法的交叉点 综合而言高可用一般有两种机制 a,保险丝熔断机制,这种机制在系统出现问题的时候将问题系统切出去,一面问题扩大化,航天飞机电路设计的时候大概会采用这种机制,当某一电路出现问题,为了避免问题蔓延需要断开问题系统;软件种也需要这种机制,1,避免数据污染,2.避免请求堆积;这些问题以后可以讨论 b,线路(备份)切换机制 当系统出现异常,将备机自动或者手动切换过来的机制保证高可用的一种手段,切换的速度和精确度是系统可用性的一个标准。同样,在高性能集群,尤其是负载均衡集群种,将不同请求“路由”到不同的服务器也是一个必要的手段。

#高性能集群 高性能集群的方法取决于解决问题的性质,第一,问题(数据规模)是不是可以分解;第二,问题是不是可以分步 第一点关注数据或者规模的水平切分,就是将一块大数据或者一个大问题分解成不同的小问题然后分布到不同的节点处理,之后或许要汇总(这是mapReduce的核心思想),第二点倾向于将问题分成不同的步骤,比如我原本需要先洗菜,然后再炒菜的,但是我得想一想我能不能将洗菜和炒菜一起放在不同的地方做(当然这个例子必然是不行,对吧),这是分布式计算的核心。

高性能集群分负载均衡集群和分布式计算集群;负载均衡集群为了解决规模分解问题,也就是水平切分; 分布式计算主要解决问题分步解决问题(从业务层面上讲);

举个例子:我们假设完成一笔交易需要做一下几件事情:1,收到,并记录用户请求 2,将请求抽象成一个“交易订单”记录到数据库3,交易系统调用外部系统(可以是一个抽象了的金融基础服务,也可以是一个第三方,比如银行的外部服务)完成交易。3,银行或者外部系统通知交易系统,交易系统更新交易状态。4,交易系统同步返回用户,告知交易结果。5,交易系统调用短信服务,通知用户交易结果。

做这些事情的服务器可以是不同的,他们各自完成交易环节的一小部分,组合在一起完成了整个交易的流程。这些服务器实现不同的功能,组合在一起是一个简单的分布式计算系统。分布式计算侧重于业务的垂直切分,侧重于业务层面的抽象和复用。

假设我们发现交易系统单机无法应付目前的交易量,我们需要对相同的交易系统部署两份(或者多份),让这个两份系统协同完成规模庞大的交易请求,此时他们将组成一组功能或者业务相同的交易负载均衡系统集群。

#正文 以上是准备工作,本文主要讨论“高性能集群”中的“负载均衡集群”,以及常规场景

#何为负载均衡以及为何需要负载均衡 如果看了上面的准备概述,我觉得就没有必要概念性的解释负载均衡了,我们举个例子; 一家网站,为用户提供新闻资讯服务,刚起步的时候只有几百用户,我们从成本出发准备一台虚拟机就能解决问题;但是随着网站访问量的增加,服务器资源耗今,用户反馈访问缓慢;需要两台或者更多的机器才能提供相同质量的服务,此时最节省成本的做法是再买2台机器(这相比于优化程序优化系统的成本要小的多,得到的收益也可能会好得多);3台服务器分担请求,理论上速度可以比原来快2倍。 那么问题来了:如何做?如何让一部分用户使用服务器A,另一部分用户使用服务器B或者

##负载均衡集群的难题(以下其实都是一个问题): ###均衡问题 我们有两台一模一样的服务器,我们更多的是希望于两台服务器分担相同量的工作,而不是一台服务器很忙,而另两台台服务器很空闲。这往往很难,均衡问题不仅仅取决于使用的方法或者策略,更取决于你对问题的预判,还有对现实问题的妥协。唯一的做法是不断的调整,积累经验逐步调优。 最基本也是最简单的均衡策略是:随机,当然还有轮询,基于后端最少使用或者人为权重; a.随机(Random): 不考虑实际情况,将问题或者请求随机的抛给两台服务器,就像跑硬币实验一样,访问量越高,就越均衡。 b.轮询(Round Robin): 不考虑后端服务器的实际情况,ABCABCABCABCABC。。。的方式依次给A,B,C三台服务器。 c.最少使用(LeastUse/LeastActive) 服务器选择相对空闲的机器最为下一个请求的处理者。这相对要复杂一些,因为实现这个策略需要负载设备和ABC三台台服务器通信,得到AB和C的资源使用情况,当然对每个后端的服务维护一个简单的计数器,调度最小活跃的机器也是一个很好的办法。 d.人为权重 本质上和随机没什么区别只是加入了人为因子(我们可以理解随机策略往往得不到理想中均衡,需要人为设置一些因子作为调整,从而得到一个相对均衡) e.Hash、 使用hash或者一致性hash也是一种很好策略。 f.等。

###路由问题 路由或者线路切换问题是负载均衡的核心;(如何根据业务(这很重要)来实现路由策略是一个很大的难题;这需要考虑上面的“均衡问题”以及下面的“高可用当机均衡问题”,总而言之理由要做的不仅仅是简单的线路上的问题。) 当然这里但讲线路切换问题: 线路切换往往依赖于网络

a.基于解析服务 采用中间人模式,比如: 请求往往不会直接到达前置服务器,更多的时候我们使用DNS,他是一个中间人的角色,通过解析一个域名获得前置服务器的具体IP,随后再直接基于解析出来的IP地址;再比如dubbo的负载我们可以认为是借助一个中间人(注册中心)

b.物理线路切换 简单粗暴的将网线拔下来,插在另一台相同服务器上是简单粗暴解决可用性的一个好方法;然而你不可能做到一秒钟内插拔200次甚至更多;当然你可以说我在光纤种使用不同长度的波,或者无线网络,我基于不同的频段或者频道来做(实际上这种方式并不能很好的用于此种场景);就目前而言物理层线路切换的代价太高了。

c.三层、四层的转发 多数情况下基于IP层的转发是效率相对最好也是最普遍,基本硬件负载或者基于IPVS(LVS)的负载 只需解析重新封装三到四层的协议,他不会产生产生流量,也不需要维护两份连接句柄(七层转发种会提到),如果基于LVS软负载,基于linux net filter实现的转发,只需在linux内核层工作,避免了内核层和用户层的内存拷贝所带来的开销,甚至一台廉价的戴尔PC服务器就能稳定的到达10W的connection,没有足够的资金购买硬件负载,而访问量极高的系统建议采用此种方式。

d.七层转发 所谓的七层协议,就是应用层协议(有的书上会说五层 what ever/),开发常用的HTTP协议就是第七层的协议,mysql服务器或者redis自己实现的协议也是第七层协议;使用NGX或者HTTPD解析七层协议,然后rewrite是目前主流的解决办法;理由很简单:设置简单,维护方便,可自定义程度高。相比于LVS我相信绝大多数系统工程师对NGX会更加熟悉一些,这就带来了设置接单维护成本低,出了问题好解决;相比第三四层的协议,七层可以得到最大灵活度,解析HTTP协议获得URL获得用户传递过来某一个参数(比如sessionid等),简单的脚本或者正则就能定义个性化的转发策略。同样MYSQL proxy,AMIBA这种代理中间件通过解析MYSQL协议获得发送的SQL,通过简单的脚本语言(比如mysql 使用lua...)可以很灵活的更具SQL的内容来确定具体的后方服务器,比如读写分离; 七层转发会产生流量的,同时七层代理服务器需要维护前后两个连接句柄(收到用户请求产生并维持一个服务连接,同时作为客户端向后端服务发起请求是另外一个连接),这种转发模式一般在用户层实现,系统需要将内核层的数据拷贝到用户空间,完成解析和处理,再将用户空间的数据拷贝到内核空间,由linux的网络子系统转发,所以我们说他会产生流量,相比三四层的转发其代价就要高很多。

e.基于客户端的路由 我们在客户端实现请求具体去哪一个服务器,通过配置一个服务器集群列表或者从“名字服务器”查找和下载这个列表,然后由客户端决定具体选择哪条线路的路由。redis官方的“哨兵”方案就是这种模式。

综述:DNS轮询属于中间人模式,dubbo同样采用中间人方式;三四七层转发属于代理模式(proxy);基于用户选择实际上是讲路由的功能放到客户端实现,比如淘宝的数据中间件等采用了这种模式(dubbo是向注册中心获取服务提供者列表并且存储的,策略在注册中心实现,同样服务器提供者的负载策略也不完全取决于服务的消费者);选择四层转发(交换)还是七层不仅仅取决于性能需求,更多的还是取决于功能需求,比如你的系统要求通过URL的某个关键字或者参数来决定具体线路的,你可能就必须得选择“七层设备”来做代理了。

###代理模式的单点问题 上面简单的讲负载均衡的方案或者方式归纳了一下;其中的代理转发模式会存在“单点故障问题”,比如最简单前置服务器为NGX,后面有两台TOMCAT服务器,当前置NGX当机或者出现问题的时候,服务必然会中断。那么我们应该怎么解决这个问题呢?

其中的一个答案是VIP(虚IP),虚拟IP的方案是基于VRRP协议(虚拟路由冗余协议)的,它将局域网中的多台设备(路由)虚拟成一个设备,以一主多从的形式工作。常用的开源方案是KeepAlived,从名字上大概可以看出keepAliveD接管一个对外的虚拟IP,并在多台设备之间维持心跳。 以下是网上的图片很简单的说明了这个方案:

另一个答案是:中间人模式,比如基于DNS的切换

###负载均衡的高可用以及当机均衡问题 理想情况下使用均衡策略慢慢优化,可以得到一个相对满意的结果,可世事难料,突然有一天B服务器挂了,如果不做任何事情你可能会损失1/3的页面请求,实际上此时我们需要将这部分的请求重新定位的好的A和C服务器,选择一个好的策略或者算法避免将请求过于集中的切换到单台服务器(这可能会一下拖垮那台服务器)是一个重要的问题;我将其称为“当机再均衡问题”;假设B挂了,我们通过合理的算法将请求定位到AC服务器,系统勉强可以支撑,此时我们的工程师将B服务器修复,重新加入集群,2台服务器又回到了原来的三台服务器的状态,这依然需要“再次均衡”不是吗?

#通用的负载均衡方案

一般而言常用四层协议相对单一(注意基于四层交换设备不能理解四层以上的协议) ##LVS+KeepAlived 其中LVS负责四层转发并维持会话(通过检索会话表和标记来维持会话连接,避免发往相同地方的数据包走不同的线路),而KeepAliveD则负责接管虚拟IP和维持心跳;

##HAProxy+KeepAlived 其中HAProxy负责四层或者七层的转发,而keepAlived负责接管虚拟IP和维持心跳;HAProxy是常用负载均衡方案,相比于LVS而言HaProxy工作在用户层,提供更多更丰富的功能;

而七层协议相对就丰富了,各个软件根据自己的功能需求可以实现自己的七层协议; 常用的七层协议包括邮件协议,HTTP协议,FTP,对于各个关系数据库或者非关系数据库一般也都有自己的协议。要理解和解析这些协议才能完成七层转发。

常用的HTTP代理包括市场上多数的硬件负载,NGX等web服务器;

#负载均衡常用场景 ##前置WEB服务的负载均衡 一般指接入服务器,比如静态页面服务器,接入代理服务器等的负载均衡 通常对NGX这种接入服务器做集群需要在其前面加入一个四层或者七层代理,使用上面所说的通用方案是比较好的选择,当然你也可以将NGX作为NGX的七层代理(在NGX前面再放一个NGX),形成一个树形的结构(当然我没试过那么做,印象当中NGX+NGX的方案只在为了数据转发问题的情况出现过,大概是机房A的服务器作为接入,转发到B的接入服务器,个人觉得不是一个负载均衡的常规手段)。

##业务服务器的负载均衡 这里的业务服务器一般指完成一定业务功能和逻辑服务组件,比如tomcat、jetty等,我们需要在这些业务服务器前面加一个Proxy来作把控全局: ###NGX+业务服务器 比如nginx/apache httpd+tomcat/jetty等。ngx作为前置接入,基于七层的NGX或者HTTPD是一个很好的选择。 ##Redis的负载均衡 常规的基于四层的 ###单机Redis无法满足业务需求的两种情况 1,性能无法满足(这里通常指响应速度),一般采用复制+负载均衡的方式实现这种业务需求场景 2,容量无法满足,我们知道Redis将数据放在内存当中,而实际上内存大小是有限的,比如一台服务器64G的内存,而实际上我们的数据量达到了128G左右,我们忽略系统和软件运行所占的内存开销,128G的数据无法放到64G的单机上去,必须分布到2台甚至3台服务器上去,这些服务器上的数据是不一样的,并不能简单的通过复制来实现,这个时候我们需要对数据“分块”,将部分数据放到A,其他数据放到B。 基本的由第一种情况导致的问题我们可以使用复制+通用七层,七层,客户端实现等方式来实现负载均衡;而第二种情况相对要复杂一些,我们也可以通过七层或者客户端实现路由算法的方式来实现数据的分布存储问题。 a,haproxy+KeepAliveD b,twemproxy:推特开发的代理服务器,基于七层转发,同时支持redis和memcached协议。可使用KeepAlived来解决代理的点单问题。

##MYSQL负载均衡 MYSQ,其实任何数据存储方案都面临上面Redis一节种提到的两个问题,对于数据库来说,更多被提到的是分表分库,这是基于业务讨论的,一般简单只是为了满足访问性能的需求实现的“同构”的方案先对简单,一般的叫法是读写分离,该方案的核心思想是讲读数据和写数据分离,以避免锁带来的开销,其实现的基本思路是复制(主从复制); 除了通用的基于四层的负载均衡方案(HAProxy/LVS),我们还可以使用一些中间件来完成MySQL的负载均衡,通常更业务挂钩的情况下我们都会选择七层转发作为,我们知道MYSQL有自己的协议,对于

a,关于MYSQL集群和分布式问题 mysql提供ndb引擎,这是一个分布式的存储引擎,相比于简单的同构集群(比如读写分离等)

b,分库分表问题 随着业务规模的增加

c,关于复制: 数据库的复制多数采用二进制日志的方式,也有按照快照的复制方法,相比而言各有各的优势,比如你通过updage语句(update xxx where id < 10000)我们假设这条语句更新了10000条数据,如果通过顺序的日志的方式来实现,我们在同步从服务器的时候只需要发送和处理一条一句,而通过快照的方式我们则需要将这10000条数据(至少是diff部分)发送到

复制的通信一般采用推(push)或者拉(pull)的方式,两者的区别在于谁是主动一方,以及实时性问题。采用推的方式可以简单的理解为主服务器上数据发生变化主动推送到从服务器上。拉的方式则是每个一段时间完成一次同步。

##应用程序的负载均衡 每种语言有自己的实现,这里讲一下dubbo的负载均衡。 dubbo的核心是registery,这相当于一个目录查找服务,提供服务的组件向注册中心注册自己的服务,消费服务的组件向注册中心询问服务提供者的位置。 dubbo是分层设计的,每一层解决不同的问题,详细的设计图可以再官方文档上找到,dubbo实现负载均衡的层是cluster这一层实现,该层的主要目标是为上层提供一个通用的统一的界面,实现负载均衡在上层的透明。对于用户来说相同的服务可以在不同的机器上部署多分,同时用户可以通过简单配置来实现负载策略,我们也可以通过实现LoadBalance相关接口来定制自己的负载策略,而ZK的一致性hash算法可以解决服务的单点问题

共有 人打赏支持
粉丝 27
博文 6
码字总数 15977
×
方小葱
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: