【从单体架构到分布式架构】(二)请求增多,单点变集群(1):负载均衡

上一个章节,我们搭建了一个最简单的单体服务项目,单体架构就是把所有的功能都放在一个工程项目中。
但是当访问量不断增加,我们只部署一套环境就有些吃不消了,这时候有什么解决方案么?

如果我们去一个超市购物,当客户数量不多的时候,超市只开通一个结账通道就可以满足需要,但是当客户数量增加,只有一个结账通道的话,会造成客户等待时间过长,最简单的解决方法就是多开几个结账通道。

在软件架构中也会有相似的问题:

如果项目的用户量少、访问量不大、数据量也不多的时候,一台服务器足以支撑,那么直接项目部署一套,直接访问使用就可以了,但是当用户和数据量不断增多,访问量(并发量)不断增加,一台服务器不在能够支撑业务的时候,就需要使用多台机器,设计高性能的集群来应对。

那么当我部署了多台服务器(这里假如是两台),那么调用方是如何访问的呢?服务方如何均衡访问的流量呢?这时候就需要引出负载均衡了。

负载均衡就是通过一定的策略,把用户的访问量均匀地转发给后端的服务器;负载均衡可以提高系统的服务能力和高可用性。

1. 负载均衡分类

1.1 按照类型分类

1. DNS 负载均衡

大概的原理是,当用户访问域名的时候,需要先通过 DNS 解析域名,找到对应的 IP 地址,在这个过程中,可以让 DNS 服务器,根据用户的地理位置,返回不同的 IP,这样就可以实现负载均衡,同时也可以提升用户的访问速度。

DNS 负载均衡

2. 软件负载均衡

用软件来实现流量的分发,有基于传输层实现的负载均衡,比如 LVS,也有基于应用层来实现的,比如 Nginx;软件负载均衡实现起来很简单,只需要在服务器上部署并进行配置就可以实现;

3. 硬件负载均衡

用硬件来实现负载均衡,比如F5(F5 Network Big-IP),这是一台网络设备,性能很高,同时价格非常的贵。

软件/硬件负载均衡

1.2 按照谁来负载进行分类

1. 服务端负载均衡

调用方只访问负载均衡的IP,不需要管后面有多少台服务器。

服务端负载均衡有点儿像我们打客服电话,很多人可以同时拨打同一个客服电话号码,我们不关心实际上有多少个客服,也不关心是哪个客服人员接听电话。

服务端负载均衡

2. 客户端负载均衡

服务端部署多台服务器,客户端知道每台服务器的地址,并通过一定的路由规则,均衡地访问,比如 Spring Cloud Ribbon,当然客户端的负载均衡,通常是需要服务注册发现的配合。

客户端负载均衡更像是去超市购物结账,我们可以看到有几个结账柜台,我们可以自己选择在哪个柜台结账。

我们会在后面的章节中,详细介绍 Spring Cloud 中的客户端负载均衡组件 Ribbon 。

客户端负载均衡

1.3 按照网络模型分类

最常用的网络模型 OSI 模型共有 7 层结构:

OSI 模型

1. 二层负载均衡

基于数据链路层的负载均衡;让负载均衡服务器和应用服务器绑定同一个虚拟 IP,客户端通过这个虚拟 IP 进行请求,负载均衡服务器接受到请求后,再根据 MAC 地址进行分配转发。

2. 三层负载均衡

基于网络层的负载均衡;也是采用虚拟 IP 的方式,不过负载均衡服务器在接收到到请求后,按照实际 IP 进行分配转发。

3. 四层负载均衡

基于 IP + port 的负载均衡;用 IP + port 接受请求,再转发到后台的应用服务器上。

比如 TCP 应用实例,负载均衡服务器在接受到第一个 SNY 请求时(建立连接请求),会通过负载均衡算法找到服务器 A,然后将报文中的目标 IP 修改成服务器 A 的 IP,然后转发给服务器 A;

这就好像我们去银行办理业务,先领一个号之后(建立连接请求),银行的叫号系统会通知你:“请 101 号到 3 号窗口办理业务”(转发你的请求给 3 号服务器),真正办理业务的是 3 号窗口的小姐姐。

在这个过程中,负载均衡服务器相当于一个路由器。

四层负载均衡

4. 七层负载均衡

基于虚拟 URL 或主机 IP 的负载均衡;七层就是应用层,支持多种应用协议,比如 HTTP、FTP 等等,七层负载均衡服务器可以根据请求报文中的真正有意义的内容,加上负载均衡算法,来选择转发到哪个应用服务器;因此七层负载均衡服务器也被称为“内容交换机”;

比如七层负载均衡服务器,将图片类的请求转发到图片服务器,将文字内容类的请求转发到应用服务器;

这就好像我们去银行办理业务,在领号的时候,大厅经理看看你的银行卡,普通卡给一个 B101,金卡给一个 A101,如果是理财业务,那么就领你去理财窗口,这就相当于根据你的具体业务或银行卡类型(报文),讲请求转发到不同的服务器。

在这个过程中,负载均衡服务器相当于一个代理服务器。

七层负载均衡

2. 常用负载均衡工具

2.1. LVS

四层负载均衡;LVS 是使用Linux内核集群实现一个高性能、高可用的负载均衡服务器;性能比较强,有完整的双机热备方案,如 LVS + Keepalived;因为四层负载均衡只分发请求,所以 LVS 的 IO 性能不会受到流量影响。

2.2 Nginx

七层负载均衡;因为是七层,所以可以针对 HTTP 做一些分流策略,Nginx 的正则规则更加强大和灵活;Nginx 的安装、配置和测试都比较简单;可以承担高负载压力,不过会比 LVS 稍差;Nginx 还可以检测后端应用服务器的运行情况,可以根据处理请求的状态码或超时,把错误的请求提交到另外的服务节点;

Nginx 支持 HTTP, HTTPS, SMTP, POP3, IMAP 等协议,在较高的版本中开始支持 TCP 协议。

2.3 HAProxy

七层负载均衡;单纯从性能上看,HAProxy 比 Nginx 有更出色的速度,在并发处理上也是优于 Nginx 的;HAProxy 支持 TCP 协议,比如可以对 MySQL 的读操作进行负载均衡。

3. 常见的负载均衡调度算法

3.1 轮询法

轮询法就是按照顺序把请求轮流分配到每台服务器上;

轮训法简单高效,易于水平扩展,不过因为只求平均,不关心每台服务实际的负载;所以如果某一台服务器性能不好,极有可能产生木桶效应。

轮询法

3.2 随机法

随机分配请求到每台服务器上,如果请求数量足够多,从概率学角度看,实际效果会接近平均分配。

3.3 随机轮询法

随机法和轮询法相结合,随机找到一个服务器作为起点,然后开始轮询发送请求。(随机只体现在寻找第一个服务器的时候,剩余的工作和轮训法一样)

3.4 源地址哈希法

对客户端的 IP 地址进行哈希运算得到一个值 X,服务器数量为 N,通过 X % N 的结果,决定访问哪台服务器。

地址哈希法可以让相同的 IP 每次都落在同一台服务器上,这样不需要考虑 Session 共享的问题,但是可能会导致流量的分布不均匀,并且当某一台服务器出现故障,会导致这个服务器上的客户端无法使用,无法保证集群的高可用。

源地址哈希法

3.5 加权轮询法

加权轮询法是对轮询法的一个改进,因为每台服务器的配置不一样,所以它们的抗压能力也不一样,配置高的机器可以分配更高的权重,这样就可以处理更多的请求;

加权轮询法将机器的性能也纳入考量范围,集群性能可以发挥到最大。

加权轮询法

3.6 加权随机法

和加权轮询法类似;这里就不再赘述了。

3.7 最小连接数法

根据每个服务器节点的连接数,动态地选择当前连接数最少的服务器转发请求;

最小连接数法根据实时状态变化进行调整,最大限度地利用每一台机器的资源,提高集群整体的可用性;不过复杂度也高,需要计算每台服务器的连接数量。

3.8 最快响应速度法

根据每个服务器节点的响应时间(请求的往返延迟),动态地选择当前响应速度最快的服务器转发请求;

和最小连接数法类似,最快响应速度法也是动态调整的,控制粒度更细,能者多劳;同时复杂度也高,需要计算每台服务器的响应速度。

4. 总结

但是当访问量不断增加,只部署一台环境有些吃不消的时候,我们可以采用部署多台环境,通过负载均衡的方式将请求分配到不同的服务器上,以达到横向扩展的目的。

这个在架构中就叫做【集群部署】。

在这节课,我们了解到了:

负载均衡
【从单体架构到分布式架构】本系列文章希望用浅显直白的语言介绍架构发展过程中遇到的各种问题,以及对应的解决方案和优缺点。

适合人群:
想从事 JavaWeb 开发的学生,建议要有一定的 Java 语言基础;
新手程序员,想要了解现在 JavaWeb 开发比较流行的中间件和框架;
技术栈长期为 SSH、SSM ,但是想寻求改变的程序员。