负载均衡的原理(垂直扩展 Scale Up、横向扩展 Scale Out)

转自:码农翻身(微信号:coderising)算法

这是1998年一个普通的上午。编程

一上班,老板就把张大胖叫进了办公室,一边舒服地喝茶一边发难:“大胖啊,咱们公司开发的这个网站,如今怎么愈来愈慢了? ”浏览器

还好张大胖也注意到了这个问题,他早有准备,一脸无奈地说: “唉,我昨天检查了一下系统,如今的访问量已经愈来愈大了,不管是CPU,仍是硬盘、内存都不堪重负了,高峰期的响应速度愈来愈慢。”缓存

顿了一下,他试探地问道:“老板,能不能买个好机器? 把如今的‘老破小’服务器给替换掉。我据说IBM的服务器挺好的,性能强劲,要不来一台?”服务器

(码农翻身注:这叫垂直扩展 Scale Up)微信

“好你个头,你知道那机器得多贵吗?! 咱们小公司,用不起啊!” 抠门的老板马上否决。网络

“这…” 大胖表示黔驴技穷了。负载均衡

“你去和CTO Bill 商量下, 明天给我弄个方案出来。”jsp

老板无论过程,只要结果。编程语言

一、隐藏真实服务器

大胖悻悻地去找Bill。

他将老板的指示声情并茂地作了传达。

Bill笑了:“我最近也在思考这件事,想和你商量一下,看看能不能买几台便宜的服务器,把管理系统多部署几份,横向扩展(Scale Out)一下。 ”

横向扩展? 张大胖心中寻思着,若是把系统部署到几个服务器上,用户的访问请求就能够分散到各个服务器,那单台服务器的压力就小得多了。

“但是,” 张大胖问道 ,“机器多了,每一个机器一个IP, 用户可能就迷糊了,到底访问哪个?”

clipboard.png
“确定不能把这些服务器暴露出去,从客户角度看来,最好是只有一个服务器。” Bill 说道。

张大胖眼前一亮, 忽然有了主意:“有了!咱们有个中间层啊,对,就是DNS,咱们能够设置一下,让咱们网站的域名映射到多个服务器的IP,用户面对的是咱们系统的域名,而后咱们能够采用一种轮询的方式, 用户1的机器作域名解析的时候,DNS返回IP1, 用户2的机器作域名解析的时候,DNS返回IP2… 这样不就能够实现各个机器的负载相对均衡了吗?”

clipboard.png
Bill 思考片刻,发现了漏洞:“这样作有个很要命的问题,因为DNS这个分层的系统中有缓存,用户端的机器也有缓存,若是某个机器出故障,域名解析仍然会返回那个出问题机器的IP,那全部访问该机器的用户都会出问题, 即便咱们把这个机器的IP从DNS中删除也不行, 这就麻烦了。”

张大胖确实是没想到这个缓存带来的问题, 他挠挠头:“那就很差办了。”

二、偷天换日

“要不咱们本身开发一个软件实现负载均衡怎么样?” Bill另辟蹊径。

为了展现本身的想法, 他在白板上画了一张图, “看到中间那个蓝色服务器没有,咱们能够把它称为Load Balancer (简称LB), 用户的请求都发给他,而后它再发给各个服务器。”

clipboard.png
张大胖仔细审视这个图。

Load Balancer 简称LB, 有两个IP,一个对外(115.39.19.22),一个对内(192.168.0.100)。用户看到的是那个对外的IP。后面的真正提供服务的服务器有三个,称为RS1, RS2,RS3,他们的网关都指向LB。

“可是怎么转发请求呢?嗯,用户的请求究竟是什么东西?” 张大胖迷糊了。

“你把计算机网络都忘了吧? 就是用户发过来的数据包嘛! 你看这个层层封装的数据包,用户发了一个HTTP的请求,想要访问咱们网站的首页,这个HTTP请求被放到一个TCP报文中,再被放到一个IP数据报中, 最终的目的地就是咱们的Load Balancer(115.39.19.22)。”

clipboard.png
(注: 客户发给LB的数据包, 没有画出数据链路层的帧)

“可是这个数据包一看就是发给Load Balancer的, 怎么发给后面的服务器?”

Bill 说: “能够偷天换日,好比Load Balancer想把这个数据包发给RS1(192.168.0.10), 就能够作点手脚,把这个数据包改为这样, 而后这个IP数据包就能够转发给RS1去处理了。”

clipboard.png
(LB动了手脚,把目的地IP和端口改成RS1的)

“RS1处理完了,要返回首页的HTML,还要把HTTP报文层层封装:” 张大胖明白怎么回事了:

clipboard.png
(RS1处理完了,要发送结果给客户端)

“因为LB是网关,它还会收到这个数据包,它就能够再次施展手段,把源地址和源端口都替换为本身的,而后发给客户就能够了。”

clipboard.png
(LB再次动手脚,把源地址和端口改为本身的, 让客户端毫无察觉)

张大胖总结了一下数据的流向:
客户端 --> Load Balancer --> RS --> Load Balancer --> 客户端

他兴奋地说:“这招瞒天过海真是妙啊,客户端根本就感觉不到后面有好几台服务器在工做,它一直觉得只有Load Balancer在干活。”

Bill此刻在思考Load Balancer 怎么样才能选取后面的各个真实的服务器, 能够有不少种策略,他在白板上写到:

轮询: 这个最简单,就是一个挨一个轮换。
加权轮询: 为了应对某些服务器性能好,可让他们的权重高一点,被选中的概率大一点。
最少链接: 哪一个服务器处理的链接少,就发给谁。
加权最少链接:在最少链接的基础上,也加上权重

还有些其余的算法和策略,之后慢慢想。

三、四层仍是七层?

张大胖却想到了另一个问题: 对于用户的一个请求来讲,可能会被分红多个数据包来发送,若是这些数据包被咱们的Load Balancer发到了不一样的机器上,那就彻底乱套了啊! 他把本身的想法告诉了Bill。
Bill说:“这个问题很好啊,咱们的Load Balancer必须得维护一个表,这个表须要记录下客户端的数据包被咱们转发到了哪一个真实的服务器上, 这样当下一个数据包到来时,咱们就能够把它转发到同一个服务器上去。”

“看来这个负载均衡软件须要是面向链接的,也就是OSI网络体系的第4层, 能够称为四层负载均衡”Bill作了一个总结。

“既然有四层负载均衡,那是否是也能够搞个七层的负载均衡啊?” 张大胖突发奇想。

“那是确定的,若是咱们的Load Balancer把HTTP层的报文数据取出来,根据其中的URL,浏览器,语言等信息,把请求分发到后面真实的服务器去,那就是七层的负载均衡了。不过咱们现阶段先实现一个四层的吧,七层的之后再说。”

Bill 吩咐张大胖组织人力把这个负载均衡软件给开发出来。

张大胖不敢怠慢,因为涉及到协议的细节问题,张大胖还买了几本书:《TCP/IP详解》 卷一,卷二,卷三, 带着人快速复习了C语言, 而后开始疯狂开发。

四、责任分离

三个月后,Load Balancer的初版开发出来了,这是运行在Linux上的一个软件, 公司试用了一下,管理系统运行流畅,感受还真是不错,仅仅用几台便宜的服务器就能够实现负载均衡了。

老板看到没花多少钱就解决了问题,很是满意,给张大胖所在的开发组发了1000块钱奖金,组织你们出去搓了一顿。

张大胖他们看到老板很抠门,虽略有不满,可是想到经过这个软件的开发,学到了不少底层的知识,尤为是TCP协议,也就忍了。

但是好景不长,张大胖发现这个Load Balancer存在这瓶颈:全部的流量都要经过它,它要修改客户发来的数据包, 还要修改发给客户的数据包。

网络访问还有个极大的特色,那就是请求报文较短而响应报文每每包含大量的数据。这是很容易理解的,一个HTTP GET请求短得可怜,但是返回的HTML倒是极长,这就进一步加重了Load Balancer修改数据包的工做。

张大胖赶忙去找Bill ,Bill说:“这确实是个问题,咱们把请求和响应分开处理吧,让Load Balancer只处理请求,让各个服务器把响应直接发给客户端,这样瓶颈不就消除了吗?”

“怎么分开处理?”

“首先让全部的服务器都有同一个IP, 咱们把他称为VIP吧(如图中115.39.19.22)。”

clipboard.png
张大胖经过初版Load Balancer的开发,积累了丰富的经验。

他问道:“你这是把每一个实际服务器的loopback都绑定了那个VIP, 不过有问题啊,这么多服务器都有一样的IP , 当IP数据包来的时候,到底应该由哪一个服务器来处理?”

“注意,IP数据包实际上是经过数据链路层发过来的,你看看这个图。”

clipboard.png
张大胖看到了客户端的HTTP报文再次被封装储层TCP报文,端口号是80, 而后IP数据报中的目的地是115.39.19.22(VIP)。

图中的问号是目的地的MAC地址, 该怎么获得呢?

对, 是使用ARP协议,把一个IP地址(115.39.19.22)给广播出去,而后具备此IP机器就会回复本身的MAC地址。 可是如今有好几台机器都有同一个IP(115.39.19.22), 怎么办?

Bill 说道:“咱们只让Load Balancer 响应这个VIP地址(115.39.19.22)的ARP请求,对于RS1,RS2,RS3, 抑制住对这个VIP地址的ARP响应,不就能够惟一地肯定Load Balancer了? ”

原来如此!张大胖恍然大悟。

既然Load Balancer获得了这个IP数据包, 它就能够用某个策略从RS1, RS2,RS3中选取一个服务器,例如RS1(192.168.0.10),把IP数据报原封不动, 封装成数据链路层的包(目的地是RS1的MAC地址),直接转发就能够了。

clipboard.png
RS1(192.168.0.10)这个服务器收到了数据包,拆开一看,目的地IP是115.39.19.22,是本身的IP, 那就能够处理了。

处理完了之后,RS1能够直接响应发回给客户端,彻底不用再经过Load Balancer。由于本身的地址就是115.39.19.22。

对于客户端来讲,它看到的仍是那个惟一的地址115.39.19.22, 并不知道后台发生了什么事情。

Bill补充到:“因为Load Balancer 根本不会修改IP数据报,其中的TCP的端口号天然也不会修改,这就要求RS1, RS2,RS3上的端口号必须得和Load Balancer一致才行。”

像以前同样,张大胖总结了一下数据的流向:

客户端 --> Load Balancer --> RS --> 客户端

Bill 说道:“怎么样? 这个办法还能够吧?”

张大胖又想了想,这种方式彷佛没有漏洞,而且效率很高,Load Balancer只负责把用户请求发给特定的服务器就万事大吉了, 剩下的事由具体的服务器来处理,和它没有关系了。

他高兴地说:“不错,我着手带人去实现了。”

后记: 本文所描述的,其实就是著名开源软件LVS的原理,上面讲的两种负载均衡的方式,就是LVS的NAT和DR。

LVS是章文嵩博士在1998年5月成立的自由软件项目,如今已是Linux内核的一部分。想一想那时候我还在不亦乐乎地折腾我的网页,学会安装和使用Linux 没多久 , 服务器端开发也仅限于ASP,像LVS这种负载均衡的概念压根就没有据说过。

编程语言能够学,差距也能弥补,可是这种境界和眼光的差距,简直就是巨大的鸿沟,难以跨越啊!

相关文章
相关标签/搜索