服务网格 ASM 负载均衡算法全面解析

本文涉及的产品
网络型负载均衡 NLB,每月750个小时 15LCU
传统型负载均衡 CLB,每月750个小时 15LCU
全局流量管理 GTM,标准版 1个月
简介: 在本文中,笔者将解析服务网格的多种负载均衡算法的实现原理和使用场景,为服务网格负载均衡算法的选择提供参考。

【阅读原文】戳:服务网格 ASM 负载均衡算法全面解析


引言:当今,分布式微服务是毫无争议地主流架构模式,微服务将复杂大型系统拆分成多个松耦合的微型系统,以此使得大型系统的迭代更为灵活,容错率也变得更高。对于其中的单一微服务,支持横向扩容,以根据业务情况灵活地调整系统中每个服务所使用的资源。要正确地调用多副本服务,有两个基础的问题需要解决:服务发现和负载均衡。K8s作为当前业界广泛采用的部署平台,通过服务(Service)非入侵式地解决了服务发现和负载均衡的问题,但是,面对日益复杂的业务场景,K8s服务仍然存在一些不尽人意之处,例如,其负载均衡算法仅支持随机,而对于一些特定场景,随机算法的表现较差,且没有调优余地。因此,越来越多地微服务运维团队选择了服务网格作为网络基础设施,其在K8s服务的基础上,提供了比K8s更强大的负载均衡能力。在本文中,笔者将解析服务网格的多种负载均衡算法的实现原理和使用场景,为服务网格负载均衡算法的选择提供参考。

 

 

服务网格负载均衡的优势

 

K8s Service通过iptables规则,实现了连接级别的负载均衡,这种负载均衡不需要入侵应用,而是直接从网络层面将流量做DNAT,实现了负载均衡。但K8s的负载均衡存在一些显著的缺陷,首先,由于其使用iptables规则实现负载均衡,这使得K8s的负载均衡算法的时间复杂度是O(n),因此在集群规模逐渐膨胀时,负载均衡的性能可能受到显著影响。其次,其只支持随机负载均衡算法,这种算法并不能严格地将请求均匀地分布到后端实例上。由于其基于iptables规则实现的缘故,因为其工作在3层(IP层),因此只能做到4层,即TCP连接级别的负载均衡,而当今大多数主流应用使用HTTP/GRPC协议进行通信,基于iptables规则实现的K8s服务负载均衡注定无法实现请求级别的路由。而服务网格控制平面从K8s集群ApiServer获得工作负载和服务信息,并将这些信息下发至SIdecar,借助其7层能力,支持对HTTP/GRPC请求实现请求级负载均衡,同时支持了适用于多种场景的负载均衡算法,用户可以根据业务特性,为特定服务选择适用的负载均衡算法,以更高效地利用系统资源。


 


 

 

负载均衡算法

 

服务网格ASM提供了多种负载均衡算法,其中包括与社区Istio兼容的RANDOM、ROUND_ROBIN,LEAST_REQUEST以及ASM特有的PEAK_EWMA。在本文接下来的内容中,笔者将逐一分析每种负载均衡算法的特点及其适用场景。

 

 

RANDOM和ROUND_ROBIN

 

服务网格ASM提供了经典的随机(RANDOM)和轮询(ROUND_ROBIN)算法,对于随机负载均衡,与K8s服务不同的是,由于ASM Sidecar工作在7层,因此对于HTTP、GRPC协议的通信可以提供请求级别的随机负载均衡。随机负载均衡由于随机计算本身的不稳定性,不能保证请求完全均匀地分布到后端。此时若工作负载的性能和请求产生的计算量都比较平均,则可以考虑使用轮询算法进行负载均衡,轮询算法可以完全平均地将请求分布到后端工作负载。这两种算法被广泛使用在各种分布式系统的负载均衡中,它们足够简单直观,且被几乎所有负载均衡软硬件支持,但是,在实践中却存在一些场景,使得这两种算法的表现不尽人意。

 

 

RANDOM和ROUND_ROBIN的不足之处

 

由于RANDOM和ROUND_ROBIN两种负载均衡算法均是完全不考虑后端服务状态,仅使用本地状态计算得出负载均衡结果的算法,因此,后端服务状态变化完全不会影响到负载均衡计算的结果,从而导致做出不够理想的负载均衡决策,例如以下这些场景:

 

1.后端处理能力不均衡

 

在后端处理能力不均衡时,完全均衡地分布请求反而会影响服务质量,由于后端负载能力不平均,处理能力弱的后端会更早过载,而负载均衡算法仍然以平均分配的方式将请求分配至后端,这些被分配至已过载的后端的请求会加剧已过载后端的压力,进一步恶化服务的延迟,影响服务的整体表现,例如下图例子中,Server-1的处理能力更强,还能够接受新的请求,而Server-2已经满载,但随机或者轮询负载均衡算法仍然将新请求打到Server-2,而不是尚有余力的Server-1,这将导致这个请求的返回实践因Server-2的满载而显著延长。


 


 

2.请求计算量不平均

 

即使后端的处理能力类似,同类请求对后端造成的压力也可能存在显著的差异,一个典型的例子是LLM应用,同样是几个单词的prompt,“write me a novel”和“what is the time”两个prompt在后端计算量上的差异可谓天壤之别,因此返回时间可能也存在显著差异,例如下图的例子中,Server-1和Server-2正在处理的请求虽然都是2个,但是,Server-2处理了一个大计算量的请求,导致其已经满载,然而随机或者轮询负载均衡算法仍然将新请求打到Server-2,而不是尚有余力的Server-1,这将导致这个请求的返回实践因Server-2的满载而显著延长。

 

即使是在请求计算量大致均等的场景下,错误的请求也可能导致类似的问题,例如客户端发送了错误的请求,服务端可能在校验失败后不做任何处理就立即返回,就会间接导致请求计算量不平均的问题。

 


 


 

如何避免RANDOM和ROUND_ROBIN的不足

 

RANDOM和ROUND_ROBIN存在的缺陷本质上还是因为负载均衡无法感知后端的状态所致,理论上来说,最优的负载均衡决策应该结合后端实时状态和请求的潜在计算量做出,然而,这两者在真正的负载均衡实现中都存在很大的挑战,那么是否存在对后端状态间接感知的方式呢?笔者将在下面的篇幅中介绍ASM支持的另外两种负载均衡算法。

 

 

LEAST_REQUEST

 

LEAST_REQUEST算法在用户未显式指定时被作为ASM默认提供的负载均衡算法,该负载均衡器会记录当前每个后端上未完成的请求数量,处理能力更强的后端往往会因请求更快完成而更快地消耗这个计数,负载均衡器借助这个现象来间接感知后端的压力状态,并总是将请求路由到未完成请求数最少的后端。

 

下面,我们来通过例子直观地感受一下LEAST_REQUEST的优势,首先以前面提到过的后端处理能力不均衡场景为例,在T1时刻,负载均衡向Server-1和Server-2分别分配了3个请求,由于Server-1的并发处理能力更大,到T2时刻时,Server-1已经完成了对全部3个请求的处理,而Server-2仍然有一个请求未完成处理,由于LEAST_REQUEST总是会向进行中请求最少的后端分配请求,因此,新到达的请求被分配至负载更低的Server-1。


 


 

我们再来看看请求计算量不均的场景,这个场景下同样的请求对后端的计算复杂度差异显著,下图例子中,在T1时刻,Server-1有2个进行中的请求,Server-2只有一个,但Server-2处理的是一个大计算量请求(例如一个复杂的Prompt)。到T2时刻,Server-1的2个请求都已经返回,而Server-2尚未完成一个复杂请求的计算和返回。此时,如果负载均衡器收到了新的请求,由于Server-1的进行中请求数量少于Server-2,新请求会被分配至Server-1。


 

 


结合上述两个例子,我们可以直观地看到LEAST_REQUEST负载均衡算法在应对更加复杂场景时相对于RANDOM和ROUND_ROBIN算法表现出了更强的自适应能力,通过进行中请求数的变化实时地感知后端地状态以做出更优的负载均衡决策,降低请求平均延迟,提升整个系统的利用率。这样的特性非常适合对于同类请求计算量差异的AI场景。

 

LEAST_REQUEST能在绝大多数情况下提供较好的负载均衡表现,但是LESAT_REQUEST是任何情况下的最优解吗?我们不妨思考这样一种情况,当后端因为异常出现报错时,由于错误请求没有被实际处理,往往会立即返回,LEAST_REQUEST负载均衡器中记录的报错节点的进行中的请求数量会快速降低,该后端在该评价体系下被误认为是“高性能”的,因此更多的请求被分配到发生错误的后端,进而造成系统的整体错误率提升。显然,这个缺陷是由于LEAST_REQUEST评估体系无法感知错误率的存在导致的,那么是否有更好的选择呢,接下来,笔者将介绍ASM提供的PEAK_EWMA负载均衡器。

 

 

PEAK_EWMA

 

 

ASM在1.21版本提供了PEAK_EWMA负载均衡器,该负载均衡器会ASM结合端点在过去一段时间内的响应时间、错误率,静态权重等因子计算出端点的负载均衡权重计算节点的分值,在一段时间内响应时间越短、错误率越低,静态权重越高,则该节点的分值越高,更容易被负载均衡选中。相比于LEAST_REQUEST,PEAK_EWMA的感知范围更全面,延迟升高、错误率上升都会造成该后端的权重降低,更少的请求被路由到这个后端,从而尽可能地提升服务整体地延迟和成功率表现。

 

这里我们提供了一个PEAK_EWMA负载均衡器的端到端实例,该示例使用simple-server应用作为服务端,该应用可通过启动参数指定,模拟不同状态码返回、随机延迟范围等多种服务端响应行为。在本例中,我们将部署两个Deployment,其中名为simple-server-503的deployment使用--mode=503启动参数设置为固定返回503,模拟一个收到请求立即返回503状态码的后端;名为simple-server-normal的deployment则使用--mode=normal--delayMin=50--delayMax=200模拟一个正常返回200的后端,其处理延迟在50-200之间波动。


 

 

 


前提条件

 

已创建ASM 1.21或以上版本的实例

已创建K8s 1.21或以上版本的集群,并已将K8s集群添加至ASM实例

 

 

部署示例

 

在K8s集群中通过以下yaml部署simple-server应用和服务,以及用于发起测试流量的sleep应用:


apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: simple-server
  name: simple-server-normal
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: simple-server
  template:
    metadata:
      labels:
        app: simple-server
    spec:
      containers:
      - args:
        - --mode
        - normal
        image: registry-cn-hangzhou.ack.aliyuncs.com/test-public/simple-server:v1.0.0.2-gae1f6f9-aliyun
        imagePullPolicy: IfNotPresent
        name: simple-server
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.name
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: simple-server
  name: simple-server-503
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: simple-server
  template:
    metadata:
      labels:
        app: simple-server
    spec:
      containers:
      - args:
        - --mode
        - "503"
        image: registry-cn-hangzhou.ack.aliyuncs.com/test-public/simple-server:v1.0.0.2-gae1f6f9-aliyun
        imagePullPolicy: IfNotPresent
        name: simple-server
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.name
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: simple-server
  name: simple-server
  namespace: default
spec:
  ports:
  - name: http
    port: 8080
    protocol: TCP
    targetPort: 8080
  selector:
    app: simple-server
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: sleep
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sleep
spec:
  replicas: 1
  selector:
    matchLabels:
      app: sleep
  template:
    metadata:
      labels:
        app: sleep
    spec:
      terminationGracePeriodSeconds: 0
      serviceAccountName: sleep
      containers:
      - name: sleep
        image: registry-cn-hongkong.ack.aliyuncs.com/test/curl:asm-sleep
        command: ["/bin/sleep", "infinity"]
        imagePullPolicy: IfNotPresent

 


为了避免ASM默认存在的重试机制(默认重试2次)对验证结果造成影响,我们通过为simple-server应用VirtualService来显式地关闭重试。使用ASM实例的kubeconfig,应用以下VirtualService:

 

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: simple-server
  namespace: default
spec:
  hosts:
    - simple-server.default.svc.cluster.local
  http:
    - name: default
      retries:
        attempts: 0 # 关闭重试
      route:
        - destination:
            host: simple-server.default.svc.cluster.local

 


使用K8s集群kubeconfig,执行以下命令来发起测试:

 

$ kubectl exec -it deploy/sleep -c sleep -- sh -c 'for i in $(seq 1 10); do curl -s -o /dev/null -w "%{http_code}\n" simple-server:8080/hello; done'
200
200
200
503
503
503
503
503
200
503

 


可以看到,由于simple-server服务下有一个后端是固定返回503的,默认的LEAST_REQUEST并不能很好地在负载均衡阶段避开返回错误的节点。接下来我们来看看ASM的PEAK_EWMA负载均衡器的表现,在ASM实例中应用以下DestinationRule,为simple-server服务启用PEAK_EWMA负载均衡器:

 

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: simple-server
  namespace: default
spec:
  host: simple-server.default.svc.cluster.local
  trafficPolicy:
    loadBalancer:
      simple: PEAK_EWMA
---

 


使用同样的命令再次执行测试:

 

$ kubectl exec -it deploy/sleep -c sleep -- sh -c 'for i in $(seq 1 10); do curl -s -o /dev/null -w "%{http_code}\n" simple-server:8080/hello; done'
200
503
200
200
200
200
200
200
200
200

 


可以看到,在返回了一个503后,后续全部都是200,这是因为PEAK_EWMA负载均衡器在后端返回503后,导致错误率上升,从而降低了该断点的分值,因此在之后的一段时间内,该后端将在分值比较时低于正常的后端,因此不会被选择到。但是,过一段时间后,这种影响因为移动平均的缘故又被消除,从而使得负载均衡器可以重新选择到该后端。我们在前文提到过,PEAK_EWMA算法不仅可以感知后端的错误率,同时还可以感知后端延迟变化,尽可能将请求路由给延迟更低的端点,关于这一点ASM官方文档提供了一个例子,欢迎各位读者前往体验。

 

 

总结

 

负载均衡是一个现代分布式应用绕不开的一个重要话题,每一种负载均衡都有其适用的场景,根据业务场景正确地选择负载均衡算法能为应用带来更好的表现。阿里云服务网格ASM团队在结合了大量客户实际场景后,于1.21版本推出了PEAK_EWMA负载均衡算法,该负载均衡算法在传统的负载均衡算法上更进一步,提供了综合后端延迟、错误率、静态权重的负载均衡选择能力,让负载均衡能够动态适应应用状态的变化,做出更优的负载均衡决策,从而提升应用的全局表现。



我们是阿里巴巴云计算和大数据技术幕后的核心技术输出者。

欢迎关注 “阿里云基础设施”同名微博知乎

获取关于我们的更多信息~

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
1月前
|
存储 负载均衡 算法
负载均衡算法
负载均衡算法
32 1
|
29天前
|
缓存 负载均衡 算法
slb支持多种负载均衡算法
slb支持多种负载均衡算法
54 6
|
11天前
|
机器学习/深度学习 人工智能 算法
深入解析图神经网络:Graph Transformer的算法基础与工程实践
Graph Transformer是一种结合了Transformer自注意力机制与图神经网络(GNNs)特点的神经网络模型,专为处理图结构数据而设计。它通过改进的数据表示方法、自注意力机制、拉普拉斯位置编码、消息传递与聚合机制等核心技术,实现了对图中节点间关系信息的高效处理及长程依赖关系的捕捉,显著提升了图相关任务的性能。本文详细解析了Graph Transformer的技术原理、实现细节及应用场景,并通过图书推荐系统的实例,展示了其在实际问题解决中的强大能力。
89 30
|
15天前
|
存储 算法
深入解析PID控制算法:从理论到实践的完整指南
前言 大家好,今天我们介绍一下经典控制理论中的PID控制算法,并着重讲解该算法的编码实现,为实现后续的倒立摆样例内容做准备。 众所周知,掌握了 PID ,就相当于进入了控制工程的大门,也能为更高阶的控制理论学习打下基础。 在很多的自动化控制领域。都会遇到PID控制算法,这种算法具有很好的控制模式,可以让系统具有很好的鲁棒性。 基本介绍 PID 深入理解 (1)闭环控制系统:讲解 PID 之前,我们先解释什么是闭环控制系统。简单说就是一个有输入有输出的系统,输入能影响输出。一般情况下,人们也称输出为反馈,因此也叫闭环反馈控制系统。比如恒温水池,输入就是加热功率,输出就是水温度;比如冷库,
107 15
|
19天前
|
缓存 负载均衡 监控
slb基于DNS的负载均衡
slb基于DNS的负载均衡
57 8
|
16天前
|
负载均衡 网络协议 算法
Docker容器环境中服务发现与负载均衡的技术与方法,涵盖环境变量、DNS、集中式服务发现系统等方式
本文探讨了Docker容器环境中服务发现与负载均衡的技术与方法,涵盖环境变量、DNS、集中式服务发现系统等方式,以及软件负载均衡器、云服务负载均衡、容器编排工具等实现手段,强调两者结合的重要性及面临挑战的应对措施。
44 3
|
1月前
|
算法 Linux 定位技术
Linux内核中的进程调度算法解析####
【10月更文挑战第29天】 本文深入剖析了Linux操作系统的心脏——内核中至关重要的组成部分之一,即进程调度机制。不同于传统的摘要概述,我们将通过一段引人入胜的故事线来揭开进程调度算法的神秘面纱,展现其背后的精妙设计与复杂逻辑,让读者仿佛跟随一位虚拟的“进程侦探”,一步步探索Linux如何高效、公平地管理众多进程,确保系统资源的最优分配与利用。 ####
70 4
|
1月前
|
缓存 负载均衡 算法
Linux内核中的进程调度算法解析####
本文深入探讨了Linux操作系统核心组件之一——进程调度器,着重分析了其采用的CFS(完全公平调度器)算法。不同于传统摘要对研究背景、方法、结果和结论的概述,本文摘要将直接揭示CFS算法的核心优势及其在现代多核处理器环境下如何实现高效、公平的资源分配,同时简要提及该算法如何优化系统响应时间和吞吐量,为读者快速构建对Linux进程调度机制的认知框架。 ####
|
19天前
|
负载均衡 Java 持续交付
深入解析微服务架构中的服务发现与负载均衡
深入解析微服务架构中的服务发现与负载均衡
46 0
|
7月前
|
Oracle 关系型数据库
oracle asm 磁盘显示offline
oracle asm 磁盘显示offline
349 2

推荐镜像

更多