图解大型网站--负载均衡架构
负载均衡(Load Balancing) 负载均衡建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。
反向代理服务器和负载平衡器是客户端-服务器计算体系结构中的组件。两者都充当客户端和服务器之间的通信的中介,执行提高效率的功能。它们可以实现为专用的专用设备,但是在现代的Web体系结构中,它们越来越多地是在商品硬件上运行的软件应用程序。
基本定义很简单:
一个反向代理接受来自客户端的请求,将其转发到能够满足它的服务器,并返回服务器对客户端的响应。
负载平衡器将进入的客户机请求分配到一组服务器中,在每种情况下将所选服务器的响应返回到适当的客户机。
但是听起来很相似,对不对?两种类型的应用程序都位于客户端和服务器之间,接受前者的请求并传递后者的响应。难怪在什么是反向代理和负载均衡器的问题上存在混淆。为了帮助区分它们,让我们探讨一下它们通常在什么时候以及为什么被部署在一个网站上。
负载均衡
当站点需要多个服务器时,最通常会部署负载均衡器,因为单个服务器无法有效处理大量请求。部署多台服务器还可以消除单点故障,使网站更加可靠。最常见的是,所有服务器都承载相同的内容,并且负载平衡器的工作是分配工作负载,以便最大程度地利用每个服务器的容量,防止任何服务器上的过载并导致对客户端的最快响应。
负载平衡器还可以通过减少客户端看到的错误响应数量来增强用户体验。它通过检测服务器何时停机并将请求从它们转移到组中的其他服务器来实现。在最简单的实现中,负载平衡器通过拦截对常规请求的错误响应来检测服务器的运行状况。应用程序运行状况检查是一种更灵活,更复杂的方法,其中,负载均衡器发送单独的运行状况检查请求,并要求指定的响应类型以使服务器运行正常。
某些负载平衡器提供的另一个有用功能是会话持久性,即将所有请求从特定客户端发送到同一服务器。尽管HTTP从理论上讲是无状态的,但许多应用程序必须存储状态信息只是为了提供其核心功能-类比一下电子商务网站上的购物篮。如果负载平衡器将用户会话中的请求分配到不同的服务器,而不是将所有请求都定向到响应初始请求的服务器,则这些应用程序在负载平衡的环境中表现不佳,甚至可能失败。
反向代理
部署反向代理的另一个原因是Web加速 –减少了生成响应并将其返回给客户端所需的时间。Web加速技术包括:
压缩–在将服务器响应返回给客户端之前(例如,使用
gzip
)进行压缩会减少它们所需的带宽量,从而加快它们在网络上的传输速度。SSL终止 –对客户端和服务器之间的流量进行加密可以保护它穿越Internet等公共网络时的安全。但是解密和加密在计算上可能是昂贵的。通过解密传入的请求并加密服务器响应,反向代理释放了后端服务器上的资源,这些资源随后可用于主要目的,即服务内容。
缓存 –反向代理在将后端服务器的响应返回给客户端之前,将其副本存储在本地。当客户端(或任何客户端)发出相同的请求时,反向代理可以自己从缓存中提供响应,而不是将请求转发到后端服务器。这既减少了对客户端的响应时间,又减少了后端服务器上的负载。
NGINX Plus如何提供帮助?
NGINX Plus和NGINX是高流量网站(例如Dropbox,Netflix和Zynga)使用的同类最佳的反向代理和负载平衡解决方案。全世界有超过4亿个网站依靠NGINX Plus和NGINX来快速,可靠和安全地提供其内容。
NGINX Plus执行上面以及所有以上讨论的所有负载平衡和反向代理功能,从而提高了网站性能,可靠性,安全性和规模。作为基于软件的负载平衡器,NGINX Plus比具有类似功能的基于硬件的解决方案便宜得多。NGINX Plus中全面的负载平衡和反向代理功能使您能够构建高度优化的应用程序交付网络。
有关NGINX Plus如何实现此处描述的功能的详细信息,请查看以下资源:
NGINX Plus的应用程序负载平衡
使用NGINX Plus进行应用程序运行状况检查
NGINX Plus的会话持久性
使用NGINX和NGINX Plus缓解DDoS攻击
压缩和解压缩
HTTP和TCP的 SSL终止
NGINX Plus中的内容缓存
大型网站负载均衡的利器
全局负载均衡系统(GSLB)
内容缓存系统(CDN)
服务器负载均衡系统(SLB)
DNS域名解析的基本过程
最初的负载均衡解决方案(DNS轮询)
优点
基本上无成本,因为往往域名注册商的这种解析都是免费的;
部署方便,除了网络拓扑的简单扩增,新增的Web服务器只要增加一个公网IP即可
缺点
健康检查,如果某台服务器宕机,DNS服务器是无法知晓的,仍旧会将访问分配到此服务器。修改DNS记录全部生效起码要3-4小时,甚至更久;
分配不均,如果几台Web服务器之间的配置不同,能够承受的压力也就不同,但是DNS解析分配的访问却是均匀分配的。用户群的分配不均衡导致DNS解析的不均衡。
会话保持,如果是需要身份验证的网站,在不修改软件构架的情况下,这点是比较致命的,因为DNS解析无法将验证用户的访问持久分配到同一服务器。虽然有一定的本地DNS缓存,但是很难保证在用户访问期间,本地DNS不过期,而重新查询服务器并指向新的服务器,那么原服务器保存的用户信息是无法被带到新服务器的,而且可能要求被重新认证身份,来回切换时间长了各台服务器都保存有用户不同的信息,对服务器资源也是一种浪费。
全局负载均衡系统(GSLB)
优势
数据中心冗余备份
多站点流量优化
确保用户体验
全局负载均衡系统(GSLB)的原理
DNS检查工具网上有很多,感兴趣的可以搜索一下。
内容缓存系统(CDN)
内容缓存系统(CDN)之静态加速
内容缓存系统(CDN)之动态加速
动态加速的特点
智能路由
传输控制协议(TCP)优化
HTTP预载
服务器负载均衡系统
应用背景
访问流量快速增长
业务量不断提高
用户需求
希望获得7×24的不间断可用性及较快的系统反应时间
负载均衡必须满足性能、扩展、可靠性
服务器负载均衡系统三种接入方式
部署方式 |
特点 | 优点 |
缺点 |
串联路由模式 |
比较常见的部署方式 |
|
|
单臂模式 |
最常见的部署方式 |
|
|
DSR |
服务器回程报文不通过负载均衡设备,直接返回给客户端; 延迟短,适合流媒体等对延时要求较高应用 |
|
|
服务器负载均衡系统的常见调度算法
轮询(Round Robin)
加权轮询(Weighted Round Robin)
最少连接(Least Connections)
加权最少连接(Weighted Least Connections)
健康性检查
健康性检查算法的目的:通过某种探针机制,检查服务器群中真实服务器的健康情况,避免把客户端的请求分发给出现故障的服务器,以提高业务的HA能力。
目前常用的健康性检查算法:
Ping(ICMP)
TCP
HTTP
FTP
系统加速
优化功能-SSL加速
优化功能-HTTP压缩
HTTP压缩是在Web服务器和浏览器间传输压缩文本内容的方法。F5 HTTP压缩技术通过具有智能压缩能力的 BIG-IP 系统可缩短应用交付时间并优化带宽。HTTP压缩采用通用的压缩算法压缩HTML、JavaScript或CSS文件。压缩的最大好处就是降低了网络传输的数据量,从而提高客户端浏览器的访问速度。
优化功能-连接复用
优化功能-TCP缓存
会话保持
会话保持-客户端源IP会话保持
会话保持-Cookie会话保持
局限性:
对于非HTTP协议,或者客户端禁用Cookie,无效。
会话保持-URL哈希(Hash)会话保持
哈希会话保持的一个基本概念就是按照某个Hash因子,根据此因子以及后台存在多少台服务器计算得到的结果来选择将请求分配到那台服务器。哈希会话保持的特点是在后台服务器的健康状态不发生改变的时候,每个特定的Hash因子被分配到的服务器是固定的。其最大的优势是哈希会话保持可以没有会话保持表,而仅仅是根据计算的结果来确定被分配到那台服务器,尤其在一些会话保持表查询的开销已经远远大于Hash计算开销的情况下,采用Hash会话保持可以提高系统的处理能力和响应速度。
URL哈希会话保持通常针对后台采用Cache服务器的应用场景,针对URL进行Hash计算,将同一个URL的请求分配到同一台Cache服务器,这样,对后台的Cache服务器群来说,每台Cache服务器上存放的内容都是不一样的,提高Cache服务器的利用率。
故障案例分析
Q&A案例分析(1)-循环跳转
故障现象:
Web服务端对用户访问的URL进行判断,对于非https的请求,重定向到http站点,结果导致用户一直302跳转。
原因分析:
采用了负载均衡SSL加速功能,在服务端看到所有的用户请求都来自于http。
解决方案:
全站启用SSL加速。
Q&A案例分析(2)-用户Session丢失
故障现象:
用户在http站点上提交数据到同域名的https站点,web程序抛出session丢失的异常,用户提交数据失败。
原因分析:
http和https在负载均衡设备上被认为是2个独立的服务,产生2个独立的TCP链接,会命中不同的真实服务器,导致session丢失。
解决方案:
在负载均衡设备上启用基于真实服务器的会话保持。
Q&A案例分析(3)-客户端源IP取不到
故障现象:
原因分析:
解决方案:
负载均衡设备会用用户的外网IP改写x-forwarded-for值,服务端通过获取http协议中request header头的x-forwarded-for值作为用户源IP。IIS日志通过安装插件形式显示用户源IP。
服务器负载均衡设备选型
1、价格因素
硬件设备:F5、 Citrix 、Redware 、A10
软件:LVS、Nginx、Haproxy、zen loadbalance
2、性能
4/7层吞吐量(单位bps)
4/7层新建连接数(单位CPS)
并发连接数
功能模块性能指标(ssl加速、 HTTP压缩、内存Cache)
3、满足真实和未来需求
1)如果确认负载均衡设备对所有应用的处理都是最简单的4层处理,那么理论上选择的负载均衡设备的4层性能稍高于实际性能需求即可。
2)如果确认负载均衡设备对所有应用的处理都是简单的7层处理,那么理论上选择的负载均衡设备的7层性能稍高于实际性能需求即可。
3)如果负载均衡设备处理的应用既有4层的也有7层的,建议按照7层应用的性能来考虑负载均衡设备。
5)如果负载均衡设备有混合的复杂流量处理并且还开启了一些功能模块,那么建议选择的负载均衡设备4/7层性能为真实性能需求的3倍。
6)考虑到设备需要轻载运行才能更加稳定,所以有可能的话在以上基础上再增加30%的性能。
7)如果还要满足未来几年的发展需求,在以上基础上还要留出未来发展所需要增加的性能。
8)不同负载均衡设备厂家由于不同的架构,使得某些设备在复杂环境下可能也表现的比较优秀,这个客户可以对比判断,但总体来说,以上建议适合于所有厂家的设备。
当前大多数的互联网系统都使用了服务器集群技术,集群即将相同服务部署在多台服务器上构成一个集群整体对外提供服务,这些集群可以是Web应用服务器集群,也可以是数据库服务器集群,还可以是分布式缓存服务器集群等。
在实际应用中,在Web服务器集群之前总会有一台负载均衡服务器,负载均衡设备的任务就是作为Web服务器流量的入口,挑选最合适的一台Web服务器,将客户端的请求转发给它处理,实现客户端到真实服务端的透明转发。最近几年很火的「云计算」以及分布式架构,本质上也是将后端服务器作为计算资源、存储资源,由某台管理服务器封装成一个服务对外提供,客户端不需要关心真正提供服务的是哪台机器,在它看来,就好像它面对的是一台拥有近乎无限能力的服务器,而本质上,真正提供服务的是后端的集群。
软件负载解决的两个核心问题是:选谁、转发,其中最著名的是LVS(Linux Virtual Server)
一个典型的互联网应用的拓扑结构是这样的:
负载均衡分类
现在我们知道,负载均衡就是一种计算机网络技术,用来在多个计算机(计算机集群)、网络连接、CPU、磁碟驱动器或其它资源中分配负载,以达到最佳化资源使用、最大化吞吐率、最小化响应时间、同时避免过载的目的。那么,这种计算机技术的实现方式有多种。大致可以分为以下几种,其中最常用的是四层和七层负载均衡:
二层负载均衡
三层负载均衡
四层负载均衡
七层负载均衡
七层负载均衡工作在OSI模型的应用层,应用层协议较多,常用http、radius、DNS等。七层负载就可以基于这些协议来负载。这些应用层协议中会包含很多有意义的内容。比如同一个Web服务器的负载均衡,除了根据IP加端口进行负载外,还可根据七层的URL、浏览器类别、语言来决定是否要进行负载均衡。
图:四层和七层负载均衡
对于一般的应用来说,有了Nginx就够了。Nginx可以用于七层负载均衡。但是对于一些大的网站,一般会采用DNS+四层负载+七层负载的方式进行多层次负载均衡。
常用负载均衡工具
硬件负载均衡性能优越,功能全面,但价格昂贵,一般适合初期或者土豪级公司长期使用。因此软件负载均衡在互联网领域大量使用。常用的软件负载均衡软件有Nginx、LVS、HaProxy等。
Nginx/LVS/HAProxy是目前使用最广泛的三种负载均衡软件。
1、 LVS
LVS(Linux Virtual Server),也就是Linux虚拟服务器,是一个由章文嵩博士发起的自由软件项目。使用LVS技术要达到的目标是:通过LVS提供的负载均衡技术和Linux操作系统实现一个高性能、高可用的服务器群集,它具有良好可靠性、可扩展性和可操作性。从而以低廉的成本实现最优的服务性能。
LVS主要用来做四层负载均衡。
LVS架构
LVS架设的服务器集群系统由三个部分组成:最前端的负载均衡层(Loader Balancer),中间的服务器群组层,用Server Array表示,最底层的数据共享存储层,用Shared Storage表示。在用户看来所有的应用都是透明的,用户只是在使用一个虚拟服务器提供的高性能服务。
LVS的各个层次的详细介绍:
Load Balancer层:位于整个集群系统的最前端,有一台或者多台负载调度器(Director Server)组成,LVS模块就安装在Director Server上,而Director的主要作用类似于一个路由器,它含有完成LVS功能所设定的路由表,通过这些路由表把用户的请求分发给Server Array层的应用服务器(Real Server)上。同时,在Director Server上还要安装对Real Server服务的监控模块Ldirectord,此模块用于监测各个Real Server服务的健康状况。在Real Server不可用时把它从LVS路由表中剔除,恢复时重新加入。
Server Array层:由一组实际运行应用服务的机器组成,Real Server可以是Web服务器、Mail服务器、FTP服务器、DNS服务器、视频服务器中的一个或者多个,每个Real Server之间通过高速的LAN或分布在各地的WAN相连接。在实际的应用中,Director Server也可以同时兼任Real Server的角色。
Shared Storage层:是为所有Real Server提供共享存储空间和内容一致性的存储区域,在物理上一般由磁盘阵列设备组成,为了提供内容的一致性,一般可以通过NFS网络文件系统共享数 据,但NFS在繁忙的业务系统中,性能并不是很好,此时可以采用集群文件系统,例如Red hat的GFS文件系统、Oracle提供的OCFS2文件系统等。
从整个LVS结构可以看出,Director Server是整个LVS的核心,目前用于Director Server的操作系统只能是Linux和FreeBSD,Linux2.6内核不用任何设置就可以支持LVS功能,而FreeBSD作为 Director Server的应用还不是很多,性能也不是很好。对于Real Server,几乎可以是所有的系统平台,Linux、windows、Solaris、AIX、BSD系列都能很好地支持。
2、Nginx
Nginx(发音同engine x)是一个网页服务器,它能反向代理HTTP、HTTPS,、SMTP、POP3、IMAP的协议链接,以及一个负载均衡器和一个HTTP缓存。
Nginx主要用来做七层负载均衡。
并发性能:官方支持每秒5万并发,实际国内一般到每秒2万并发,有优化到每秒10万并发的。具体性能看应用场景。
特点:
模块化设计:良好的扩展性,可以通过模块方式进行功能扩展。
高可靠性:主控进程和worker是同步实现的,一个worker出现问题,会立刻启动另一个worker。
内存消耗低:一万个长连接(keep-alive),仅消耗2.5MB内存。
支持热部署:不用停止服务器,实现更新配置文件,更换日志文件、更新服务器程序版本。
并发能力强:官方数据每秒支持5万并发;
功能丰富:优秀的反向代理功能和灵活的负载均衡策略
Nginx的基本工作模式
一个master进程,生成一个或者多个worker进程。但这里master是使用root身份启动的,因为nginx要工作在80端口。而只有管理员才有权限启动小于低于1023的端口。master主要是负责的作用只是启动worker,加载配置文件,负责系统的平滑升级。其它的工作是交给worker。那当worker被启动之后,也只是负责一些web最简单的工作,而其它的工作都是由worker中调用的模块来实现的。
模块之间是以流水线的方式实现功能的。流水线,指的是一个用户请求,由多个模块组合各自的功能依次实现完成的。比如:第一个模块只负责分析请求首部,第二个模块只负责查找数据,第三个模块只负责压缩数据,依次完成各自工作。来实现整个工作的完成。
它们是如何实现热部署的呢?是这样的,我们前面说master不负责具体的工作,而是调用worker工作,它只是负责读取配置文件,因此当一个模块修改或者配置文件发生变化,是由master进行读取,因此此时不会影响到worker工作。在master进行读取配置文件之后,不会立即把修改的配置文件告知worker。而是让被修改的worker继续使用老的配置文件工作,当worker工作完毕之后,直接当掉这个子进程,更换新的子进程,使用新的规则。
3、HAProxy
HAProxy也是使用较多的一款负载均衡软件。HAProxy提供高可用性、负载均衡以及基于TCP和HTTP应用的代理,支持虚拟主机,是免费、快速并且可靠的一种解决方案。特别适用于那些负载特大的web站点。运行模式使得它可以很简单安全的整合到当前的架构中,同时可以保护你的web服务器不被暴露到网络上。
HAProxy是一个使用C语言编写的自由及开放源代码软件,其提供高可用性、负载均衡,以及基于TCP和HTTP的应用程序代理。
Haproxy主要用来做七层负载均衡。
常见负载均衡算法
上面介绍负载均衡技术的时候提到过,负载均衡服务器在决定将请求转发到具体哪台真实服务器时,是通过负载均衡算法来实现的。负载均衡算法可以分为两类:静态负载均衡算法和动态负载均衡算法。
静态负载均衡算法包括:轮询、比率、优先权。
动态负载均衡算法包括:最少连接数、最快响应速度、观察方法、预测法、动态性能分配、动态服务器补充、服务质量、服务类型、规则模式。
轮询(Round Robin):顺序循环将请求一次顺序循环地连接每个服务器。当其中某个服务器发生第二到第7 层的故障,BIG-IP 就把其从顺序循环队列中拿出,不参加下一次的轮询,直到其恢复正常。
以轮询的方式依次请求调度不同的服务器;实现时,一般为服务器带上权重;这样有两个好处:
针对服务器的性能差异可分配不同的负载;
当需要将某个结点剔除时,只需要将其权重设置为0即可;
优点:实现简单、高效;易水平扩展
缺点:请求到目的结点的不确定,造成其无法适用于有写的场景(缓存,数据库写)
应用场景:数据库或应用服务层中只有读的场景
随机方式:请求随机分布到各个结点;在数据足够大的场景能达到一个均衡分布;
优点:实现简单、易水平扩展
缺点:同Round Robin,无法用于有写的场景
应用场景:数据库负载均衡,也是只有读的场景
哈希方式:根据key来计算需要落在的结点上,可以保证一个同一个键一定落在相同的服务器上;
优点:相同key一定落在同一个结点上,这样就可用于有写有读的缓存场景
缺点:在某个结点故障后,会导致哈希键重新分布,造成命中率大幅度下降
解决:一致性哈希 or 使用keepalived保证任何一个结点的高可用性,故障后会有其它结点顶上来
应用场景:缓存,有读有写
一致性哈希:在服务器一个结点出现故障时,受影响的只有这个结点上的key,最大程度的保证命中率;如twemproxy中的ketama方案;生产实现中还可以规划指定子key哈希,从而保证局部相似特征的键能分布在同一个服务器上;
优点:结点故障后命中率下降有限
应用场景:缓存
根据键的范围来负载:根据键的范围来负载,前1亿个键都存放到第一个服务器,1~2亿在第二个结点。
优点:水平扩展容易,存储不够用时,加服务器存放后续新增数据
缺点:负载不均;数据库的分布不均衡;
(数据有冷热区分,一般最近注册的用户更加活跃,这样造成后续的服务器非常繁忙,而前期的结点空闲很多)
适用场景:数据库分片负载均衡
根据键对服务器结点数取模来负载:根据键对服务器结点数取模来负载;比如有4台服务器,key取模为0的落在第一个结点,1落在第二个结点上。
优点:数据冷热分布均衡,数据库结点负载均衡分布;
缺点:水平扩展较难;
适用场景:数据库分片负载均衡
纯动态结点负载均衡:根据CPU、IO、网络的处理能力来决策接下来的请求如何调度。
优点:充分利用服务器的资源,保证个结点上负载处理均衡
缺点:实现起来复杂,真实使用较少
不用主动负载均衡:使用消息队列转为异步模型,将负载均衡的问题消灭;负载均衡是一种推模型,一直向你发数据,那么将所有的用户请求发到消息队列中,所有的下游结点谁空闲,谁上来取数据处理;转为拉模型之后,消除了对下行结点负载的问题。
优点:通过消息队列的缓冲,保护后端系统,请求剧增时不会冲垮后端服务器;水平扩展容易,加入新结点后,直接取queue即可;
缺点:不具有实时性;
应用场景:不需要实时返回的场景;
比如,12036下订单后,立刻返回提示信息:您的订单进去排队了...等处理完毕后,再异步通知;
比率(Ratio):给每个服务器分配一个加权值为比例,根椐这个比例,把用户的请求分配到每个服务器。当其中某个服务器发生第2到第7 层的故障,BIG-IP 就把其从服务器队列中拿出,不参加下一次的用户请求的分配,直到其恢复正常。
优先权(Priority):给所有服务器分组,给每个组定义优先权,BIG-IP 用户的请求,分配给优先级最高的服务器组(在同一组内,采用轮询或比率算法,分配用户的请求);当最高优先级中所有服务器出现故障,BIG-IP 才将请求送给次优先级的服务器组。这种方式,实际为用户提供一种热备份的方式。
最少的连接方式(Least Connection):传递新的连接给那些进行最少连接处理的服务器。当其中某个服务器发生第2到第7 层的故障,BIG-IP 就把其从服务器队列中拿出,不参加下一次的用户请求的分配,直到其恢复正常。
最快模式(Fastest):传递连接给那些响应最快的服务器。当其中某个服务器发生第二到第7 层的故障,BIG-IP 就把其从服务器队列中拿出,不参加下一次的用户请求的分配,直到其恢复正常。
观察模式(Observed):连接数目和响应时间以这两项的最佳平衡为依据为新的请求选择服务器。当其中某个服务器发生第二到第7 层的故障,BIG-IP就把其从服务器队列中拿出,不参加下一次的用户请求的分配,直到其恢复正常。
预测模式(Predictive):BIG-IP利用收集到的服务器当前的性能指标,进行预测分析,选择一台服务器在下一个时间片内,其性能将达到最佳的服务器相应用户的请求。(被BIG-IP 进行检测)
动态性能分配(Dynamic Ratio-APM):BIG-IP 收集到的应用程序和应用服务器的各项性能参数,动态调整流量分配。
动态服务器补充(Dynamic Server Act.):当主服务器群中因故障导致数量减少时,动态地将备份服务器补充至主服务器群。
服务质量(QoS):按不同的优先级对数据流进行分配。
服务类型(ToS): 按不同的服务类型(在Type of Field中标识)负载均衡对数据流进行分配。
规则模式:针对不同的数据流设置导向规则,用户可自行。
负载均衡的几种算法Java实现代码
轮询
加权随机负载均衡算法
随机负载均衡算法
负载均衡 ip_hash算法.
负载均衡器的诞生
在很长一段时间内小章公司的 DAU(日活)不超过 10,所以他只部署了一台机器,毕竟多一台机器要加钱,而且就算挂了也影响不了几个用户
但无意间小章的业务踩中了风口,业务量暴涨,dau 达到了好几万,眼看就要突破十万,小章慌了,赶紧全面升级了这台机器的内存,CPU 等配置,暂时扛过去了,但小章明白,单机性能无论怎么升都会遇到瓶颈,所以小章想了个办法,多部署几台机器,将流量平均分配到这几台机器上
怎么分配呢,最简单的方式,当然是用 DNS 负载均衡,在域名解析服务器上设置负载均衡策略,让流量随机打到其中某台机器上
但这个方案有以下两个明显的问题:
占用过多公网 IP,要知道现在租一个公网 IP 可是要好几千
DNS 缓存可能会引起致命故障
第一个问题加钱就能解决,但第二个问题可不是加钱就能解决的了,因为众所周知 DNS 解析是迭代或递归查询,需要经过 根 DNS 服务器
->顶级DNS服务器
->权威DNS服务器
这三步查找才能解析到域名对应的 ip,可想可知这个解析是有多么耗时,所以一般会有 DNS 缓存,DNS 缓存主要有「浏览器缓存」,「操作系统缓存」,「路由器缓存」,「ISP 缓存」四种
每次发起一个域名解析请求,都会依次在以上四个缓存里查找,如果命中缓存,则直接返回此域名对应的 IP,其中像 Chrome 缓存 1 分钟, ISP 缓存可能高达 1~2 个小时,于是问题就来了,如果某台机器宕机,但由于以上四个缓存中依然可能会有此域名的 IP 缓存,对请求方而言,是感知不到的,那么只要缓存未过期请求方就会持续地将将流量打到这台挂掉的机器,引起线上故障,这当然是不能容忍的。
那该怎么办呢,小章突然想起了计算机界的一个经典名言:「没有什么是加一层解决不了的问题,如果有,那就再多加一层」,何不在 DNS 与 server 间多加一层,负载均衡的工作让这个中间层来做,小章想了下脑海中浮现出了以下架构图
可以看到这个负载均衡器(以下简称 LB)有以下特点
对外用公网 ip(以下我们简称 VIP) 承接所有流量,对内则与真实的服务器(即 Real Server,以下简称 RS)通信,与 RS 在同一个内网里
LB 只负载转发请求的工作,实际的处理逻辑交由其背后的 RS,RS 处理完后将响应包发给 LB,然后 LB 再返回给 client
于是网络拓扑图改进如下
NAT
接下来的重点就是 LB 是如何工作的了,首先要明白,当我们说收到一个请求时,实际上收到的是一个数据包,那么这个数据包长啥样呢
当 RS 处理好后,由于这个数据包还要经过 LB 再转发给客户端,所以服务器的网关要设置为 LB 的内网 IP(即 192.168.0.1)再将数据包出去,LB 就能收到所有的响应数据包了。
此时的数据包如下
为什么 RS 的响应包要经过 LB 呢,因为为了保证四元组不变,LB 收到数据包后要将源 IP 改为 VIP,客户端才会识别到这是对之前请求的正确响应
画外音:客户端请求与响应包的四元组不能变
所以总结一下 LB 的主要工作机制:主要是修改了进出数据包的 IP,首先修改目的 IP 为其 RS 的 IP,将包传给 RS 处理,RS 处理完后再将包发给网关(LB),LB 再修改源 IP 为其出口的 VIP,只要四元组不变,那么客户端就能正常地收到其请求的响应,为了让大家更直观地感受负载均衡的对 IP 的修改,我做了一张动图,相信大家看了理解会更深刻
看到这问题似乎已经完美解决了,但是我们忽略了一个问题:每个网络数据包都是有大小限制的。如下图示,在每个数据包中,每个 payload(一般为应用层数据)大小一般不能超过 1460 byte
也就是说如果在客户端的请求数据(比如 HTTP 请求过大)超过了 1460 个字节,就要分包传,服务端收到所有分包后再组装成完整的应用层数据,那么显然,LVS 应该把同一个请求(即四元组相同)的分包转发给同一个 RS,不然把分包传给不同的 RS,数据就不完整了。所以 LVS 要根据四元组来记录包应该转发给哪一个 RS,四元组一样的数据包都转发给同一个 RS。
四元组的 IP 是在 IP Header 中,而端口号在 TCP Header 中,这意味着 LVS 需要卸下 TCP Header 拿到端口号,然后根据四元组是否相同再决定是否转发到同一台 RS 上,四元组对应一个 TCP 连接,也就是说 LVS 具有记录连接的功能,而连接是传输层的概念。至此相信你明白开头的一个问题:「LVS 起到了转发包的功能,为什么说它是四层负载均衡」
DR
经过这样的设计,由于 LVS 负载均衡的作用,轻松解决了单机瓶颈,小章的公司顺利度过了 C10K(并发连接 1 万),C20K,。。。。的问题,度过了瓶颈期,但随着并发数越来越高,小章发现了一个大问题,LVS 逐渐扛不住了,因为所有数据包的进出都要经过它,这让它成为了很大的瓶颈,随着 RS 水平扩展数量越来越多, LVS 迟早要挂掉。能否让 LVS 只负责转发请求包,但响应的数据包直接经由 RS 返回给客户端呢,类似下面这样
画外音:红色虚线为数据包的流转流程,可以看到响应数据包不经过 LVS
这样的话响应包就不用经过 LVS 了,LVS 的负载压力自然释放了,我们把这种模式称为 DR(Direct Router,直接路由)模式
方案有了,那么怎么实现呢?这个设计方案有两个注意点
首先 LVS 还是要承载所有的请求流量(接收所有数据包),然后再根据负载均衡算法转发给 RS
RS 处理完后是不经过 LVS,直接将数据包转发给路由器再发给客户端的,意味着 RS 必须要有与 LVS 同样的 VIP(四元组不能变),另外由以上拓扑图可知,它们也必须在同一个子网里(严格地说,应该是同一个 vlan,因为是通过交换机通信的),这就意味着 LVS 和 RS 都必须要有两个 IP,一个 VIP,一个子网 IP
那么一台主机如何才能有两个 IP 呢?
我们知道计算机要上网,首先要把网线插入网卡,一个网卡其实就对应着一个 IP,所以一台主机配两个网卡就有两个 IP ,但多数人不知道的是一个网卡是可以配置多个 IP 的,另外网卡一般分两种,一种是物理网卡,一种是虚拟网卡
物理网卡
:可以插网线的网卡,如果有多个网卡,我们一般将其命名为 eth0,eth1。。。,如果一个网卡对应多个 IP,以 eth0 为例,一般将其命名为 eth0,eth0:0,eth0:1。。。eth0:x,比如一台机器只有一个网卡,但其对应两个 IP 192.168.1.2, 192.168.1.3,那么其绑定的网卡名称分别为 eth0,eth0:0
画外音:一般服务器包括 LVS 是以双网卡的形式存在的,一来每个网卡带宽都是有限的,双网卡相当于提升了一倍的带宽,二来两个网卡也起到了热备的作用,如果一个网卡坏了,另外一个可以顶上。
理解了以上知识点,我们可以将拓扑图完善如下
你可能注意到了 RS 的 VIP 是绑定在 lo:0 虚拟网卡上而不是物理网卡上,这是为什么呢,主要是为了保证请求都打到 LVS 上。
1. arp_ignore=1
综上所述, RS 不能响应目的 IP 为虚拟网卡绑定的 VIP 的 arp 请求,但能响应目的 IP 为物理网卡绑定的 IP 的 arp 请求,这就是为什么 RS 需要把 VIP 绑定在虚拟网卡上,而把内网 IP 绑定在物理网卡上的真实原因,就是为了 arp 响应的需要
当然一般服务器默认都会响应所有 IP 的 arp 响应,所以需要对 RS 做额外配置,即
net.ipv4.conf.all.arp_ignore=1
net.ipv4.conf.lo.arp_ignore=1
设置的 arp_ignore=1 表示的含义如下
1 - reply only if the target IP address is local address
configured on the incoming interface
即我们上述所说的,只响应目的 IP 为接收网卡(即物理网卡)上的 IP 的 arp 请求(会忽略目的 IP 为虚拟网卡 上 VIP 的 arp 请求)
route add -host 115.205.4.214 dev lo:0
# 添加一条路由,目标 IP 为 VIP 的数据包使用 lo 接口发送,这样响应报文的源 IP 就会为 VIP
然后再通过 eth0 发出去,这样可保证四元组不会发生变化。
2. arp_announce=2
接下来还有一个问题,RS2 怎么将数据包传给它的网关(即路由器)呢,由于它们还是在同一个子网,所以也是通过 arp 的方式先获取到网关的 mac,然后在以太网包头上装上网关的 mac 传给网关的。
但这里有一个点需要注意,通过 arp 获取网关的 mac 时,网卡会发送一个包含「源IP」,「目标 IP」,「源 mac」的 arp 广播包
通常情况下源 IP 可以选择为数据包的源 IP,也可以选择为物理网卡上的 IP,但在 DR 模式下这里的源 IP 只能选择为物理网卡上 IP,这是为什么呢
net.ipv4.conf.all.arp_announce=2
net.ipv4.conf.lo.arp_announce=2
上面这段有点绕,大家可以多读几遍好好体会一下,其实主要目的就是为了避免路由器的 ARP 缓存表误更新 VIP 的 mac 为 RS 的 mac
从上面的介绍可以看出 DR 模式是比较复杂的,需要在 RS 上做额外的配置,所以线上一般使用 NAT 模式
FullNAT
但问题又来了,该怎么解决 NAT 模式下 LVS 的单点问题呢,毕竟所有进出流量都出入同一台 LVS(因为 RS 的网关只有有一个),在 RS 不断扩容下,单点 LVS 很可能成为巨大的隐患,而且 LVS 要作为所有 RS 的网关,意味着他们要在同一个网段下。
如果在阿里云这些公有云平台上部署肯定不现实,因为在公有云上,很可能 RS 是分布在各地的,这就意味着要跨 vlan 来通信,而 NAT 显然不符合要求,于是在 NAT 的基础上又衍生出了 FullNAT,FullNAT 其实就是为了公有云而生的
如图示,部署了两台 LVS,它们内网与 RS 的不在同一个网段,照样能通信,部分读者可能会注意到一个问题:LVS 转发给 RS 的数据包源 IP(即客户端 IP,client_ip)被替换成了内网 IP,这就意味着 RS 收到的数据包是不含有 client_ip 的,有时候 client_ip 对我们分析数据有很重要的作用(比如分析下单在不同地域分布情况就需要 client_ip),针对这种情况,LVS 会在收到请求包后在数据包的 TCP Header 中插入 client_ip
上图就是是 TCP Header,client_ip 就是放在 tcp option 字段中的,然后 RS 上只要安装了 TOA 模块就能从中读取 client_ip,TCP 的这个 option 的字段也提醒我们在做技术方案设计的时候适当的增加一些冗余字段能让你的程序可扩展性更好。
总结
至此,相信大家已经明白了 LVS 的 NAT,DR ,FullNAT 的工作机制了,实际上 LVS 还有个 TUNNEL 隧道模式,只是生产上不怎么用,所以不做介绍,另外每个 LVS 一般会做双机热备,如下,备机通过定时发送心跳包能感受到 LVS 主机的存活,另外注意虚线部分,备机还可以感知到服务器的存活,如果服务器挂了, LVS 会将其剔除,保证 LVS 转发的流量不会打到宕掉的机器上。
文中的小章就是章文嵩博士,1998 年他主导了 LVS 项目的开发,一开始只有 NAT,DR,TUNNEL 三种模式,但后来随着阿里云云上服务的崛起,这三种模式都无法满足实际的部署需要,所以他又指导其手下基于 NAT 来做改造诞生了 FullNAT,值得一提的是 LVS 是少数几个国人开发并得到 Linux 官方认可的开源软件,已集成进 Linux 内核,可见这一项目的巨大价值与贡献