可横向扩展的高并发的七层负载均衡器方案
在我们搭建 openstack 或者 kubernetes 或者其他集群时,我们通常会被要求集群支持高可用,一个通用的解决方案就是:keepalived + haproxy/nginx。这个模式在大多数场景都够用了,但是有时我们会遇到一些要求高并发高负载的场景,如果只是简单的 keepalived + haproxy/nginx 方式就不够用了。这篇文档主要时回顾一下我在过往工作经历中为搭建高负载
在我们搭建 openstack 或者 kubernetes 或者其他集群时,我们通常会被要求集群支持高可用,一个通用的解决方案就是:keepalived + haproxy/nginx。这个模式在大多数场景都够用了,但是有时我们会遇到一些要求高并发高负载的场景,如果只是简单的 keepalived + haproxy/nginx 方式就不够用了。这篇文档主要时回顾一下我在过往工作经历中为搭建高负载的 openstack 或者 k8s 集群,整理一些负载均衡器的方案供大家参考,接下来我从简单到复杂一一为大家介绍这些方案,最后的方案可以做到百万并发并支持动态扩展。当然这些方案都是软件负载均衡器方案,你过你所在公司不差钱直接购买硬件负载均衡器设备,那么恭喜你,你的头发一定比我茂密许多(不需要在想方设法的压榨服务器,提高系统并发,有问题找硬件厂商即可)。
注意: 这里 haproxy/nginx 也可以是别的软件,只要是有七层负载均衡能力的软件就行,以为笔者之前接触的最多的就是 haproxy,所以文档以 haproxy 为例。
概念解释
在正式开讲之前我想和大家同步一些概念,方便我们后面行文,以及大家的理解。
什么是七层负载均衡器?
OSI 参考模型把网络分为了七层:物理层、链路层、网络层、传输层、会话层、表示层、应用层。根据负载均衡器所能处理的数据包所在层级,负载均衡器可以分为:二层负载均衡器,三层负载均衡器,四层负载均衡器,七层负载均衡器。
- 二层负载均衡器
二层负载均衡器我知道的可以分为两个方向:1、主要涉及到网络硬件,如交换机堆叠,网卡 bond 等,但是这些不是本文关注的方向后面文档中不会涉及;2、LVS 的 DR 模式主要是根据 MAC 来分发流量,可以视为二次负载均衡器。
- 三层负载均衡器
三层负载均衡器通常是通过 ECMP 协议实现的,可以把支持 ECMP 协议的设备视为三层负载均衡器;
- 四层负载均衡器
四层负载均衡器可以处理传输层数据,也是分为两种:TCP 和 UDP。TCP 负载均衡器的实现方案有 haproxy, nginx 等;能处理 UDP 报文的我所知道的就 LVS 一种。四层负载均衡器在进行流量分发时通常会进行地址转换,也就是要修改数据包的目的IP,目的端口,源IP,源端口。
- 七层负载均衡器
七层指的是应用层,但是在大多数情况下七层特指 http 或者 https 协议的应用。那么七层负载均衡器就是要求能处理http 报文(https 需要负载均衡器支持 TLS 终结的功能,去除安全套接字层)。
另外需要强调一个规律:层数越高,负载均衡器需要处理的数据越复杂,就越消耗负载均衡器实例的 CPU 和内存。同样配置的实例,三层,四层,七层负载均衡器的性能能达到指数级的差异。
高并发负载均衡器,这里并发指的是什么?
并发指的是同一时刻系统保持的连接数,那么什么是连接呢?连接的区分主要是通过五元组(协议,目的IP,目的端口,源IP,源端口)只要他们中有任何一个不同则可以视为一个连接,那么要达到百万级并发都需要什么条件呢?在有负载均衡器的系统中一个完整请求可以被分为两部分:客户端到负载均衡器;负载均衡器到后端真实服务。先来分析客户端到负载均衡器,这部分负载均衡器的协议,IP,端口都是确定的,也就是说五元中已经确定了三元,可变的就是客户端,也就是源 IP 和源端口,而一个客户端 IP 是固定的,可用端口只有 6 万个,所有要想客户端到负载均衡器达到百万级别,测试客户端就需要有很多个。我们在来分析从负载均衡器到后端真实服务,这个阶段情况就要复杂一些,这部分唯一保持不变的就是协议,在支持横向扩展的情况下一个负载均衡器可以有多个实例,同时后端真实服务也会有多个,这样源 IP,源端口,目的 IP,目的端口都是变化的,这样就需要根据情况,负载均衡器先达到性能瓶颈就需要扩展负载均衡器实例,后端真实服务先达到性能瓶颈就需要扩展后端真实服务。
传统的 keepalived + haproxy 模式
上图就是我们常见的方式,haproxy 分发请求到后端服务,keepalived 保持 haproxy 的高可用性。这种方案的缺点也很明显,一次只用一个 haproxy 实例在工作,其他的 haproxy 实例只是作为备件(只有当中间的 haproxy 实例出现问故障,VIP 切换,其他 haprox 实例才起作用)。这种方案单个 haproxy 实例的瓶颈就是整个系统的瓶颈。
多 VIP 的 keepalived + haproxy 模式
这种架构负载均衡器系统有多个入口(多个 VIP),不同的客户端可以访问不同的 VIP,这种方式,系统中的每个 haproxy 实例都能发挥作用,而且还能互相作为备件(当某个实例出现了问题,剩下的两个实例中有一个会同时有两个 VIP),这种架构很好的避免了一核干活多核围观的现象,但是缺点也很明显:入口不统一,需要在客户端指定入口。我在搭建 openstack 高可用环境时会经常用到这种方案,我们可以为不同的 openstack 组件配置不同的入口,如:neutron,keystone 使用 VIP1;nova,glance 使用 vip2;其他使用 vip3。在客户端只需要配置 keystone 的 VIP,其他组件的 VIP 可通过 keystone 查询,正是因为 opentack 的这个特性,所以这个方案很适合 openstack。
keepalived + LVS + haproxy
从上图可以看出这种方案多了一个 LVS 层(LVS 采用 DR 模式),系统的入口在 LVS 实例,LVS 在把流量分发到不同的 haproxy 实例(每个 haproxy 都能处理请求),而且这种方式 haproxy 实例的数量还可以动态的调整。但是这种方案的缺点和第一种一样,同一时间只有一个 LVS 实例在干活,单个 LVS 实例的瓶颈就是整个系统的瓶颈,那么为什么这种方案比第一种要好呢?这是因为 LVS 的 DR 模式可以视为二次负载均衡器,其性能要远远强于haproxy(七层),也就是说一个 LVS 实例可以带动 haproxy 实例(多个 haproxy 实例是同时工作的),这样可以做到入口同一(只有一个 VIP),haproxy 实例数量可以动态调整
缺点:由于 DR 模式的限制,回复流量不在经过 LVS 实例,这也就意味着请求流量的路径和回复流量的路径是不一致的,这种流量很容易被系统防火墙认为是非法的。
注意:上图中 haproxy 的 VIP 我画在了 haproxy 实例的内部(表示它们不会响应外部请求),这也是LVS DR 模式的配置要求,每个 haproxy 实例的 VIP 都是相同的,这个 VIP 可以配置在实例的 lo 网卡或者为其创建一个 dummy 网卡。
BGP + ECMP + haproxy
从前面介绍的方案我们可以看出整个负载均衡器系统的性能受限于最前端设备,前面几个方案最前端是 haproxy 和 lvs,都是软件方案。接下来我们介绍的方案前端设备是一个硬件,而且是数据中心必须用到的硬件:路由器(核心交换机),但是要求这个路由器支持 BGP 和 ECMP 功能(我相信现在市场上 99.9% 的数据中心路由器都支持这两个功能),我们先来看架构图,结合架构图详细讲解:
如上图所示:HAProxy
和 BGP Speaker
组成一个小的负载均衡器单元,整个系统中这种单元可以有多个。而且根据性能需求还可以随时添加。这种单元在 openstack 中可以是一个虚机,在 k8s 中可以是一个 pod。BGP Speaker
功能可以由 exabgp 提供。这套系统在配置监控,如果监控检测到负载均衡器单元 CPU 或内存将要耗尽时可以通过 openstack 或 k8s 在创建一个或多个负载均衡器单元,每个负载均衡器单元在启动时都会通过 BGP Speaker
向外部物理路由器通告,物理路由器会在 ECMP 路由条目中增加一个下一跳(下一跳的地址为负载均衡器单元的真实 IP,目的地址为 VIP),VIP在负载均衡器单元中都要设置且要保持相同,而且不对外响应 arp,这个 VIP 可以设置在 dummy
网卡上。
这套系统的并发上限由外面的物理路由器决定,而通常这是数据中心的核心路由器,它的性能上限就是数据中心的上限。因此这套方案就可以作为我们软件负载均衡性能追求的终极方案。
更多推荐
所有评论(0)