云中负载均衡器
负载均衡在分布式系统架构中被广泛应用,是分布式系统必不可少的组件之一。目前负载均衡器不断发展完善,已经从最初经典的负载均衡器,发展到了现在的区分四层、七层的负载均衡器,然后又在此基础上推出了网关负载均衡器。随着负载均衡功能越来越完善,种类也越来越多,怎么在众多的负载均衡器中选择适合自己的一个呢?这就需要我们在了解的基础上进行合理地选择与配置。
负载均衡器的类型
云端的负载均衡,本质上是对现有成熟的热门开源技术做了定制化开发及封装云化。比如阿里云的云端负载均衡,就是基于 LVS 和 Tengine 进行开发优化的。
云中的负载均衡器分为三大类:四层负载均衡器、七层负载均衡器及网关负载均衡器。由于四层和七层负载均衡用得最多,所以今天我们着重讲解四层、七层负载均衡器。之所以称之为四层和七层负载均衡器,是因为两种负载均衡器是根据 OSI 模型中的不同层级划分的,四层负载均衡器在 OSI 模型中的第四层——传输层工作,七层负载均衡器在第七层——应用层工作。
不同云厂商对四层和七层负载均衡器有不同的叫法,比如 AWS 把四层负载均衡器叫做网络负载均衡器,把七层负载均衡器叫做应用负载均衡器。而阿里则称之为传统负载均衡器、应用负载均衡。
四层负载均衡器
我们先来看四层负载均衡器,它又被称为网络负载均衡器、传统负载均衡器等,是使用频率最多的负载均衡器,也是最传统的一种负载均衡器。在云中,云厂商延续了四层负载均衡器后端高可用黑盒机制,实现了其产品的无感知、高可用。无论是四层还是七层,云中的负载均衡的模型组件分别是:负载均衡实例主体 Load Balancer、监听器 Listener、目标组 Target Group。
PaaS 级别的负载均衡器的使用及运行机制很简单。首先你需要在负载均衡器的监听组件中,配置不同的监听规则,如监听某个端口。当你的请求符合你所监听的规则时,负载均衡器就会将流量导向不同的后端目标组中。后端的目标组相当于“文件夹”,你需要在文件夹中增加文件,即服务器。你还需要为不同的服务器设置权重,按照你的期望来运行。
云端的负载均衡可以自动检测我们后端服务端口的健康状态。如图 3 中右边目标组所示,目标组中的健康检查器会对后端进行健康检测。当后端的服务器由于一些原因宕机,服务不可达的时候,负载均衡器会将不健康的后端(图中红色部分)踢出流量路由,流量将不会路由至不健康的实例,以保障业务正常运行。等后端的服务器恢复正常之后,负载均衡器会再次将正常流量拉回目标群组中,继续为业务服务。
七层负载均衡器
七层负载均衡,又被称为应用负载均衡器,相比于四层负载均衡更具有实战性、云原生性。应用负载均衡是专门面向云端应用场景的,支持 HTTP/HTTPS/QUIC 等应用层协议,也支持谷歌的 gRPC 框架。
应用负载均衡器可以基于(URL)路径的路由,什么意思呢?比如,我们有个 geektime.com 的学习网站,geektime 既有文字课程,又有音频课程,还有视频课程。而这三种载体所要求的服务器性能是不一样的。显然,存储文字的服务器性能要求低且存储量也小,而视频服务器要求高且数据量大,音频则居中。如果我们将三者都存储到一台服务器上,就会存在挤占资源的情况,导致资源分配不均匀。无论是从收纳的角度来说还是从业务的角度来说,都不应该将这三者存放到一台服务器上,尤其是大型企业。
我们应当将其独立出来进行导流,如存储文字、音频的服务器只需要配置 1 核 2G 内存 1T 存储,存储视频的服务器配置可能需要 4 核 8G 内存 5T 存储。所以,我们可以基于不同的 URL 进行不同的转发。
https://geektime.com/txt/ →负载到文字服务器
https://geektime.com/sound/ →负载到音频服务器
https://geektime.com/vedio/ →负载到视频服务器
这样就能从性能、业务和费用等方面进行针对性配置,不至于让单个服务器过于混乱。这样做的好处是可以节省成本,并且后端可以形成“组”的概念,利于不同业务的组装与卸载。当然,应用负载均衡器的作用远不止于此。
除了基于 ULR 路由之外,应用负载均衡器还支持 HTTP Header、HTTP Request、Cookie 等多种条件进行路由,细化到点。ALB 还针对云原生做了一系列的优化,比如除了和普通的 ECS 使用之外,ALB 可以直接与云上 Kubernetes、FC 等对接,或者直接在云上挂载 SSL 证书,实现高度集成化的方案。
负载均衡算法
那么负载均衡是如何运作的呢?接下来,我们看一下负载均衡的算法。负载均衡的算法比较多,一般主流的有轮询、加权轮询、最小连接数以及一致性哈希算法。
- 轮询,即按照流量进行顺序分配,在一轮分配完成后,返回进行新一轮匹配,循环往复,周而复始。
- 加权轮询是轮询的升级补充,为后端的不同服务器赋予不同的权重,按照所属权重占权重总比例来进行分配,权重越高,目标机器被分配的次数也越高。
- 最小访问是基于连接数产生的,负载均衡会判断后端服务器的连接个数,将请求分配至连接数较小的后端服务器上,这样最大限度地保证了服务器的连接数平衡。
- 还有一种是哈希算法,由于一些请求是有状态的,需要在同一台服务器上进行完全处理。如果将相同的访问导流到不同的后端服务器上,可能会出现文件不一致的问题,导致用户要重复登录或操作,所以哈希算法会基于 IP 通信四元组(源 IP、目的 IP、源端口和目的端口)进行哈希运算,保证将同一个地址的请求分配到同一台机器上。这样对于有状态的服务,就可以直接命中。
通过负载均衡实现更高可用
负载均衡可以承担起系统的高可用,就是维护系统的高可用,在云端架构中,通过简单的概论(即云服务提供商和云服务使用者直接的承诺协定),可以得出科学的高可用服务等级协议(SLA)。
我们把不同的服务器挂载在不同的可用区中,来达到满足其高可用的目的。标准云厂商但地域单可用区的虚拟机可靠性是 99.95%,那么如果再增加一个可用区,可用率就达到 99.99% 了,基本能满足大部分的 Web 应用服务 SLA 要求。当然你可以再增加不同可用区,让 SLA 呈现指数上升,进一步提高 SLA。
通过负载均衡实现蓝绿发布
负载均衡器的另一个作用是能实现一键蓝绿发布,我们可以利用云端负载均衡器来一键进行切换。蓝绿部署是一种零宕机的应用更新策略,进行蓝绿发布时,新版本服务器与旧版本服务器共存。同一个应用不同版本的服务器之间共享路由,通过调节权重的方式进行流量切换。
很明显,我们可以在目标组中配置不同的应用服务,一组是 active(绿)服务器,权重为 100%,另一组是 inactive(蓝)服务器,权重为 0。当一切准备就绪后,只需要修改权重,将原先绿权重改为 0,原先蓝权重改为 100%,这样就实现了蓝绿发布。如果发布后出现问题,只需要调回权重即可切回原环境,这样我们就能通过云端负载均衡实现蓝绿部署。由此引申,如果我们有多台服务器,就可以按比例控制权重,实现金丝雀发布、AB 测试等一系列的功能。
通过负载均衡实现升级配置
既然负载均衡能够通过修改权重的方式控制服务器服务的“启停”,那么我们就可以在这个启停的过渡期间,完成服务器的垂直升级。当我们要升级服务器的 CPU 和内存时,由于一些老旧服务器需要重启才可以让升级生效,我们同样就可以将流量通过修改权重的方式将服务器“优雅”下线,等待服务器重启升级成功后,再进行正常的操作,直至所有服务器都升级完毕,完成一轮换血。这种情形,通常在企业淘汰老旧服务器,迁移业务到新一代服务器上使用。
有状态和无状态
在先前的例子中,我们提到一个词叫做“有状态”。当服务端保存用户信息时,如 session、token,我们可以通过负载均衡器中的哈希算法来保证请求都能达到同一后端实例中,也可以通过开启“会话保持”来将同一客户端的会话请求转发到指定的服务器。
但当我们要进行蓝绿切换、升级换血的时候,有状态的缺点就显现出来了——带有用户信息的服务器不能直接停机,无法通过标准化的方式进行操作。
有状态的缺点也就显而易见了:
- 服务器保存大量客户端数据,增加服务器压力;
- 服务器保存用户状态,无法进行横向扩展;
- 服务器依赖负载均衡器的算法,消耗负载均衡器性能。
而在云原生架构中,架构被要求设置成“无状态”。无状态相对于有状态来说,没有 session,不记录信息,不关心响应方是谁,也不担心被删除,因此使用无状态能够减轻服务器和负载均衡压力,并且很容易就能实现横向扩展。如果服务器被设置成有状态,当我们要进行负载均衡器后端的权重归零时,可能会造成数据的丢失。
弹性伸缩
引入无状态的概念,既可以减少业务上对共享资源使用的冲突,又可以降低系统的耦合。
和负载均衡经常一起使用的另一个云产品是弹性伸缩,弹性伸缩能够使后端的服务器性能算力维持在指定水平,满足业务需求。弹性伸缩基于对后端服务器的监控,通过指定的配置模板来启动服务,并通过负载均衡的服务注册与服务发现,自动地加入目的服务组中。弹性伸缩的工作原理如下:云中的云监控会监控服务器的参数,比如 CPU、内存、IO 等参数,当服务器的指标达到设定阈值时,弹性伸缩组根据给定的“黄金镜像”模板启动服务器,并自动加入到负载均衡中,实现服务的自动弹性伸缩。
负载均衡器配合弹性伸缩组,是云中架构实践的黄金搭档,而此“黄金搭档”能默契配合的点就是因为服务“无状态”。从本质上讲,弹性伸缩的扩容与缩容期间,其实就是服务器点的增加或者删除。如果是有状态应用的服务器,在缩容期间,系统删除服务器可能会导致用户多次访问的状态不一致,或者数据丢失,这是我们不愿意见到的,无状态的服务在此时就显得特别重要。无状态的模式使得所有业务可以“批量化”“标准化”生产,这种完全对称性使请求分发到任意一台服务器上,最终都能得到完全一样的处理结果。