Kong工作原理 - 负载均衡 - 负载均衡算法

时间:2024-01-25 07:47:14

负载均衡器支持以下负载均衡算法:

1. 轮询(Round-robin)
2. 一致性哈希(Consistent Hashing)
3. 最少连接(Least Connections)
4. 延迟(Latency)

这些算法仅在使用upstream实体时可用,详见高级负载均衡。

注意:对于所有这些算法,重要的是要了解如何设置每个后端的权重和端口。

 轮询

轮询算法将以加权方式进行。它在结果上与基于DNS的负载均衡相同,但由于它是一个upstream实体,因此在这种情况下还提供了健康检查和断路器的附加功能。

选择此算法时,请考虑以下因素:

  • 请求的良好分布。
  • 相对静态,只有DNS更新或目标更新可以影响流量的分布。
  • 不改善缓存命中率。
 一致性哈希

使用一致性哈希算法时,将使用可配置的客户端输入来计算哈希值。然后,该哈希值将与特定的后端服务器相关联。

一个常见的例子是使用消费者作为哈希输入。由于该ID对于来自该用户的每个请求都是相同的,因此它将确保相同的用户始终由同一个后端服务器处理。这将允许在后端进行缓存优化,因为每个服务器仅为用户的一个固定子集提供服务,并且因此可以改善其与用户相关数据的缓存命中率。

这个算法实现了ketama原则,以最大化哈希的稳定性,并在已知后端列表发生变化时最小化一致性丢失。

在使用一致性哈希算法时,哈希的输入可以是none、consumer、ip、header或cookie。当设置为none时,将使用轮询方案,并禁用哈希。一致性哈希算法支持主要和备用哈希属性;如果主要哈希失败(例如,如果主要哈希设置为consumer,但未进行消费者身份验证),则使用备用属性。这最大化了upstream 缓存命中。

可支持的哈希属性如下:

  • none:不使用一致性哈希算法,而是使用轮询(默认)。
  • consumer:将消费者ID作为哈希输入。如果没有可用的消费者ID,它将回退到凭证ID(例如,在使用LDAP等外部身份验证机制时)。
  • ip:将原始IP地址作为哈希输入。在使用此功能时,请查看配置设置以确定真实IP。
  • header:将指定的头部作为哈希输入。头部名称分别在hash_on_header或hash_fallback_header中指定,具体取决于头部是否是主要或备选属性。
  • cookie:将指定路径上的特定cookie作为哈希输入。cookie名称在hash_on_cookie字段中指定,路径在hash_on_cookie_path字段中指定。如果请求中未找到指定的cookie,响应将设置该cookie。因此,如果cookie是主要哈希机制,hash_fallback设置无效。生成的cookie将具有随机UUID值。因此,第一次分配将是随机的,但后续请求将保持相同,因为它保存在cookie中。

一致性哈希负载均衡器旨在同时适用于单个节点和集群。在使用基于哈希的算法时,重要的是所有节点都构建相同的负载均衡器布局,以确保它们的工作完全相同。为了实现这一点,负载均衡器必须以确定性的方式构建。

在选择这个算法时,考虑以下几点:

  • 提高后端缓存命中率。
  • 需要足够的哈希输入基数以实现均匀分布(例如,在仅具有2个可能值的头部进行哈希处理是没有意义的)。
  • 基于Cookie的方法对于基于浏览器的请求非常有效,但对于往往省略Cookie的机器对机器客户端则效果较差。
  • 尽量避免在负载均衡器中使用主机名,因为负载均衡器可能会逐渐偏离,原因是DNS ttl只有秒级精度,并且续约是由名字实际请求时确定的。此外,一些域名服务器不返回所有条目的问题会加剧这个问题。因此,在Kong集群中使用哈希方法时,最好通过IP地址添加目标实体来避免这个问题。可以通过负载均衡器的重建和更高的ttl设置来缓解这个问题。
 最少连接

 该算法会跟踪每个后端正在处理的请求数量。权重用于计算每个后端的“连接容量”。请求将被路由到剩余容量最高的后端。换句话说,该算法会根据后端的连接容量来选择路由请求。

在选择这个算法时,考虑以下几点:

  • 流量的良好分布。
  • 不会提高缓存命中率。
  • 更具动态性,因为速度较慢的后端将有更多的连接打开,因此新的请求将自动路由到其他后端。
 延迟

延迟算法基于峰值EWMA(指数加权移动平均),确保负载均衡器根据最低的延迟(upstream_response_time)选择后端。所使用的延迟指标是完整的请求周期,从TCP连接到响应体的时间。由于它是一个移动平均值,这些指标会随着时间的推移而“衰减”。换句话说,旧的延迟数据在计算中会逐渐减少。

权重将不会被考虑在内。

在选择这个算法时,考虑以下几点:

  • 提供良好的流量分布,前提是有足够的基础负载来保持指标持续更新,因为它们会 “衰减”。
  • 不适合长期连接,如Websockets或服务器推送事件(SSE)。
  • 非常动态,因为它会不断进行优化。
  • 最理想的情况是,当延迟变化较小时工作效果最佳。这意味着后端的流量和工作负载大致相似。例如,一个用于GraphQL后端的应用,既需要处理快速的小查询,也需要处理慢速的大查询,那么延迟指标就会有很大的变化,导致指标失真。
  • 正确设置后端容量,并确保网络延迟正常,以防止资源饥饿。例如,使用两个服务器:一个容量小、距离近(网络延迟低),另一个容量大、距离远(延迟高)。大部分流量将被路由到较小的服务器,直到其延迟开始增加。然而,延迟的增加意味着较小的服务器很可能正在经历资源饥饿。因此,在这种情况下,算法将使较小的服务器处于持续的资源饥饿状态,这很可能是低效的。