KONG为请求多个后端服务提供了多种负载均衡方案:一种是简单的基于DNS,另一种是更加动态的环形均衡器,他在不需要DNS服务器的情况下也允许服务注册。
基于DNS的负载均衡
当使用基于DNS的负载平衡时,后端服务的注册是在Kong之外完成,而Kong只接收来自DNS服务器的更新。如果请求的API被解析为多个IP地址,则已使用包含主机名(而不是IP地址)的upstream_url定义的每个API将自动使用基于DNS的负载平衡,前提是主机名未被解析为upstream名称或你的localhosts文件中的名称。DNS记录ttl设置(生存时间)确定刷新信息的频率。当设置ttl为0时,每个请求将使用自己的dns查询进行解析。显然这会带来性能损失,但更新/更改的延迟将非常低。
A记录
A记录包含一个或多个IP地址。因此,当主机名解析为A记录时,每个后端服务都必须有自己的IP地址。因为没有 weight 信息,所有条目在负载平衡器中将被视为同样的权重,平衡器将进行直线循环。来自DNS记录的IP地址的初始选择是随机的。这是为了确保即使当ttl为0时,负载也正确分配。
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请求添加/删除节点,并可立即启动/停止接收请求流量。
可以通过配置 upstream 和 target 属性来配置环形均衡器。
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_header
或hash_fallback_header
字段中)作为散列的输入。
哈希算法是基于“一致性哈希”,它确保当平衡器通过改变目标(添加、移除、失败或改变权重)来修改时,只有最小的散列损失发生。这将最大优化上游缓存的命中。
一堆原理实在不好理解,下面来几个案例研究下:
Blue-Green Deployments
这是一个安全部署应用的方法,它通过提供两个版本的应用同时运行。为了部署一个新版本的应用,你需要将当前版本切换到新版本,然后关闭老版本。Blue-green deployment不会使应用停止服务,在必要的情况下允许你快速回滚应用到blue版本。
设置“蓝色”环境,运行版本1的地址服务:
# 创建一个upstream
$ curl -X POST http://kong:8001/upstreams \
--data "name=address.v1.service"
# 给upstream添加两个target
$ curl -X POST http://kong:8001/upstreams/address.v1.service/targets \
--data "target=192.168.34.15:80" \
--data "weight=100"
$ curl -X POST http://kong:8001/upstreams/address.v1.service/targets \
--data "target=192.168.34.16:80" \
--data "weight=50"
# 创建一个把Blue上游作为目标的Service
$ curl -X POST http://kong:8001/services/ \
--data "name=address-service" \
--data "host=address.v1.service" \
--data "path=/address"
# 最后,为Service添加Route
$ curl -X POST http://kong:8001/services/address-service/routes/ \
--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的地址服务:
# 为地址服务v2,创建一个新的Green upstream
$ curl -X POST http://kong:8001/upstreams \
--data "name=address.v2.service"
# 给upstream添加两个目标
$ curl -X POST http://kong:8001/upstreams/address.v2.service/targets \
--data "target=192.168.34.17:80"
--data "weight=100"
$ curl -X POST http://kong:8001/upstreams/address.v2.service/targets \
--data "target=192.168.34.18:80" \
--data "weight=100"
# 将服务从Blue环境转换为Green环境, v1 -> v2
$ curl -X PATCH http://kong:8001/services/address-service \
--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个目标示例:
# 第一个目标权重 1000
$ curl -X POST http://kong:8001/upstreams/address.v2.service/targets \
--data "target=192.168.34.17:80" \
--data "weight=1000"
# 第二个目标权重 0
$ curl -X POST http://kong:8001/upstreams/address.v2.service/targets \
--data "target=192.168.34.18:80" \
--data "weight=0"
通过重复请求,但是每次改变权重,流量将慢慢地路由到另一个目标。例如,将其设置为10%:
# 第一个目标权重 900
$ curl -X POST http://kong:8001/upstreams/address.v2.service/targets \
--data "target=192.168.34.17:80" \
--data "weight=900"
# 第二个目标权重 100
$ curl -X POST http://kong:8001/upstreams/address.v2.service/targets \
--data "target=192.168.34.18:80" \
--data "weight=100"
同样,通过Kong管理API的更改是动态的,并将立即生效。不需要重新加载或重启,在进度请求中不需要删除。