KONG为请求多个后端服务提供了多种负载均衡方案:一种是简单的基于DNS,另一种是更加动态的环形均衡器,他在不需要DNS服务器的情况下也允许服务注册。

基于DNS的负载均衡

当使用基于DNS的负载平衡时,后端服务的注册是在Kong之外完成,而Kong只接收来自DNS服务器的更新。如果请求的API被解析为多个IP地址,则已使用包含主机名(而不是IP地址)的upstream_url定义的每个API将自动使用基于DNS的负载平衡,前提是主机名未被解析为upstream名称或你的localhosts文件中的名称。DNS记录ttl设置(生存时间)确定刷新信息的频率。当设置ttl0时,每个请求将使用自己的dns查询进行解析。显然这会带来性能损失,但更新/更改的延迟将非常低。

A记录

A记录包含一个或多个IP地址。因此,当主机名解析为A记录时,每个后端服务都必须有自己的IP地址。因为没有 weight 信息,所有条目在负载平衡器中将被视为同样的权重,平衡器将进行直线循环。来自DNS记录的IP地址的初始选择是随机的。这是为了确保即使当ttl0时,负载也正确分配。

SRV记录

SRV记录包含所有IP地址的权重和端口信息。可以通过唯一的IP端口号的组合来标识后端服务。因此,单个IP地址可以托管不同端口上相同服务的多个实例。因为权重信息可用,每个条目将在负载平衡器中获得自己的权重,并且它将执行加权循环。

类似地,任何给定的端口信息将被来自DNS服务器的端口信息覆盖。如果一个API的 upstream_url=http://myhost.com:1234/path 并且 myhost.com 被解析为 SRV 记录中的 127.0.0.1:5678,此时的API将会被代理到 http://127.0.0.1:5678/path,之前的 1234 端口会被重写为 5678 端口。IP地址+端口组合在初始时是随机选择的,这是为了确保服务能被正确分配,即使ttl设置为0。

tip:每当刷新DNS记录时,都会生成列表以正确处理加权。建议将权重保持为彼此的倍数以保证系统的性能。

DNS的优先级

DNS解析器按顺序开始解析以下记录类型:
1. 最后一个成功的类型优先解析;
2. SRV记录
3. A记录
4. CNAME记录

所以,如果你使用的主机名称中同时含有SRV记录和A记录时,将仅解析SRV实例。如果你想使用A记录,那么你必须得把SRV记录从DNS中删除。如果你只有A记录,则SRV记录查询失败,然后自动指向到A记录,并查询A记录是否存在,依次类推。

环形均衡器

使用环形平衡器时,后台服务的添加和删除将由Kong处理,不需要进行DNS更新。KONG将扮演服务注册的角色。可以通过单个HTTP请求添加/删除节点,并可立即启动/停止接收请求流量。

可以通过配置 upstreamtarget 属性来配置环形均衡器。

  • upstream: 在API中把一个虚拟主机名称配置到upstream属性里。例如:一个weather.service的主机可以接收所有类似于http://weather.service/path/xxx/…的请求。
  • target: 后台服务所在的IP和端口号的组合。例如:192.168.11.48:8080。每一个target都附加有一个weight属性来指示获得的相对负载。

负载均衡算法

默认情况下,一个环平衡器将使用一个加权循环的方案。另一种方法是使用基于散列的算法。散列的输入可以是none, consumer,ip, 或者 header。当设置为none时,将使用加权循环方案,并且将禁用哈希。

有两种选择,一种主要的和一种备用方案,以防主服务器出现故障(例如,如果主服务器被设置为consumer,但是没有经过身份验证)

不同的散列选项:

  • none:不要使用哈希,而是使用加权轮询(默认)。
  • consumer:使用消费者id作为散列输入。如果没有可用的消费者id(如ldap等外部认证),此选项将在凭据id上后退。
  • ip:远程(原始)IP地址将用作输入。在使用此方法时,请检查配置设置,以确定真正的IP。
  • header:使用指定的头(在hash_on_headerhash_fallback_header字段中)作为散列的输入。

哈希算法是基于“一致性哈希”,它确保当平衡器通过改变目标(添加、移除、失败或改变权重)来修改时,只有最小的散列损失发生。这将最大优化上游缓存的命中。

一堆原理实在不好理解,下面来几个案例研究下:

Blue-Green Deployments

这是一个安全部署应用的方法,它通过提供两个版本的应用同时运行。为了部署一个新版本的应用,你需要将当前版本切换到新版本,然后关闭老版本。Blue-green deployment不会使应用停止服务,在必要的情况下允许你快速回滚应用到blue版本。

设置“蓝色”环境,运行版本1的地址服务:

  1. # 创建一个upstream
  2. $ curl -X POST http://kong:8001/upstreams \
  3. --data "name=address.v1.service"
  4. # 给upstream添加两个target
  5. $ curl -X POST http://kong:8001/upstreams/address.v1.service/targets \
  6. --data "target=192.168.34.15:80" \
  7. --data "weight=100"
  8. $ curl -X POST http://kong:8001/upstreams/address.v1.service/targets \
  9. --data "target=192.168.34.16:80" \
  10. --data "weight=50"
  11. # 创建一个把Blue上游作为目标的Service
  12. $ curl -X POST http://kong:8001/services/ \
  13. --data "name=address-service" \
  14. --data "host=address.v1.service" \
  15. --data "path=/address"
  16. # 最后,为Service添加Route
  17. $ curl -X POST http://kong:8001/services/address-service/routes/ \
  18. --data "hosts[]=address.mydomain.com"

将主机头设置为address.mydomain.com,就可以让那Kong代理这个请求转发到定义的两个目标;三分之二的请求将发送到http://192.168.34.15:80/address(权重=100),1/3将转到http://192.168.34.16:80/address(权重=50)。

设置“绿色”环境,运行版本2的地址服务:

  1. # 为地址服务v2,创建一个新的Green upstream
  2. $ curl -X POST http://kong:8001/upstreams \
  3. --data "name=address.v2.service"
  4. # 给upstream添加两个目标
  5. $ curl -X POST http://kong:8001/upstreams/address.v2.service/targets \
  6. --data "target=192.168.34.17:80"
  7. --data "weight=100"
  8. $ curl -X POST http://kong:8001/upstreams/address.v2.service/targets \
  9. --data "target=192.168.34.18:80" \
  10. --data "weight=100"
  11. # 将服务从Blue环境转换为Green环境, v1 -> v2
  12. $ curl -X PATCH http://kong:8001/services/address-service \
  13. --data "host=address.v2.service"

将主机头设置为address.mydomain.com,现在已经给Kong设置了一个新的目标;一半的请求将被发送到http://192.168.34.17:80/address(权重=100),另外1/2将转到http://192.168.34.18:80/address(权重=100)。

通常,通过Kong管理API的更改是动态的,并将立即生效。不需要重新加载或重启,在进度请求中不需要删除。

金丝雀版本

使用环型平衡器,目标权重可以精确地调整,允许一个平滑的、可控的金丝雀环境。
使用一个非常简单的2个目标示例:

  1. $ curl -X POST http://kong:8001/upstreams/address.v2.service/targets \
  2. --data "target=192.168.34.17:80" \
  3. --data "weight=1000"
  4. $ curl -X POST http://kong:8001/upstreams/address.v2.service/targets \
  5. --data "target=192.168.34.18:80" \
  6. --data "weight=0"

通过重复请求,但是每次改变权重,流量将慢慢地路由到另一个目标。例如,将其设置为10%:

  1. $ curl -X POST http://kong:8001/upstreams/address.v2.service/targets \
  2. --data "target=192.168.34.17:80" \
  3. --data "weight=900"
  4. $ curl -X POST http://kong:8001/upstreams/address.v2.service/targets \
  5. --data "target=192.168.34.18:80" \
  6. --data "weight=100"

同样,通过Kong管理API的更改是动态的,并将立即生效。不需要重新加载或重启,在进度请求中不需要删除。