在 Istio 中使用硬件卸载加速连接负载均衡
在 Istio 网关中使用 DLB 加速连接负载均衡。
什么是连接负载均衡?
负载均衡是一种核心网络解决方案,用于在服务器群中分配流量到多台服务器上。 负载均衡器提高了应用程序的可用性和响应性,并防止服务器超载。 每个负载均衡器位于客户设备和后端服务器之间,接收并将传入的请求分发给任何可满足这些请求的可用服务器。
对于一个常见的 Web 服务器,通常会有多个工作进程(处理器或线程)。 如果许多客户端连接到单个工作进程,该工作进程将变得繁忙,并带来长尾延迟, 而其他空闲状态的工作进程则无法运行,影响了 Web 服务器的性能。 连接负载均衡是解决这种情况的方法,也被称为连接均衡。
Istio 为连接负载均衡做了什么?
Istio 使用 Envoy 作为数据平面。
Envoy 提供了一个名为 Exact 连接均衡的连接负载均衡实现。 顾名思义,它在均衡期间会持有一个锁,以使连接计数在工作进程之间几乎完全均衡。 在某种程度上,这个均衡是“几乎”精确的,因为连接可能会并行关闭,从而使计数不正确, 但这应该在下一次接收时得到纠正。这种负载均衡器在接受吞吐量上牺牲了一些精度, 应该在服务网格 gRPC Egress 这类连接数较少且很少循环的情况下使用。
显然,它不适用于入口网关,因为入口网关在短时间内接受数千个连接,锁带来的资源成本会导致吞吐量大幅下降。
现在,Envoy 已经集成了 Intel® Dynamic Load Balancing (Intel®DLB) 连接负载均衡, 以加速在入口网关等高连接数场景中的负载均衡。
Intel® Dynamic Load Balancing 如何加速 Envoy 中的连接负载均衡
Intel DLB 是一个硬件管理的队列和仲裁器系统,连接生产者和消费者。 它是一个 PCI 设备,预期安装在服务器 CPU 的 Uncore 中, 并且可以与运行在核心上的软件交互,也可以与其他设备交互。
Intel DLB 实现了以下负载均衡功能:
- 从软件中卸载队列管理 —— 在存在重要的基于排队成本的情况下有用。
- 特别适用于多生产者/多消费者场景和将任务批量排队到多个目的地的情况。
- 在软件中访问共享队列需要使用锁。Intel DLB 实现了无锁访问共享队列。
- 动态的、流感知的负载均衡和重新排序。
- 确保任务均匀分配并更好地利用 CPU 核心。可以在需要的情况下提供基于流的原子性。
- 在不丢失报文顺序的情况下,将高带宽流量分布到多个核心中。
- 更好的确定性,避免过多的排队延迟。
- 使用更少的 IO 内存占用和节省 DDR 带宽。
- 优先级排队(最多 8 个级别)—— 允许 QOS。
- 对于延迟敏感的流量,可以实现较低的延迟。
- 报文中可选的延迟测量。
- 可扩展性
- 允许动态调整应用程序的大小,无缝缩放。
- 功耗感知;应用程序可以在负载较轻的情况下将工作进程降低到较低功耗状态。
负载均衡队列有三种类型:
- 无序:适用于多个生产者和消费者。任务的顺序不重要, 每个任务都分配给负载最小的处理器核心。
- 有序:适用于多个生产者和消费者,任务的顺序很重要。 当多个任务由多个处理器核心处理时,它们必须按照原始顺序重新排列。
- 原子:适用于多个生产者和消费者,任务按照一定的规则分组。 这些任务使用相同的资源集进行处理,并且组内任务的顺序很重要。
入口网关被期望尽快地处理尽可能多的数据,因此 Intel DLB 连接负载均衡使用无序队列。
如何在 Istio 中使用 Intel DLB 连接负载均衡
在 1.17 版本发布中,Istio 正式支持 Intel DLB 连接负载均衡。
以下步骤展示了如何在 Istio 入口网关中使用 Intel DLB 连接负载均衡,在一个 Kubernetes 集群正常运行的 SPR(Sapphire Rapids)机器上。
第 1 步:准备 DLB 环境
按照 Intel DLB 驱动程序官网的指示说明安装 Intel DLB 驱动程序。
使用以下命令安装 Intel DLB 设备插件:
$ kubectl apply -k https://github.com/intel/intel-device-plugins-for-kubernetes/deployments/dlb_plugin?ref=v0.26.0
有关 Intel DLB 设备插件的更多细节,请参阅 Intel DLB 设备插件主页。
您可以查看 Intel DLB 设备资源:
$ kubectl describe nodes | grep dlb.intel.com/pf
dlb.intel.com/pf: 2
dlb.intel.com/pf: 2
...
第 2 步:下载 Istio
在这篇博文中,我们使用 Istio 1.17.2。先下载安装包:
$ curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.17.2 TARGET_ARCH=x86_64 sh -
$ cd istio-1.17.2
$ export PATH=$PWD/bin:$PATH
您可以看到版本是 1.17.2:
$ istioctl version
no running Istio pods in "istio-system"
1.17.2
第 3 步:安装 Istio
为 Istio 创建一个安装配置,注意我们为入口网关分配了 4 个 CPU 和 1 个 DLB 设备, 并将并发数设置为与 CPU 数量相等的 4。
$ cat > config.yaml << EOF
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
profile: default
components:
ingressGateways:
- enabled: true
name: istio-ingressgateway
k8s:
overlays:
- kind: Deployment
name: istio-ingressgateway
podAnnotations:
proxy.istio.io/config: |
concurrency: 4
resources:
requests:
cpu: 4000m
memory: 4096Mi
dlb.intel.com/pf: '1'
limits:
cpu: 4000m
memory: 4096Mi
dlb.intel.com/pf: '1'
hpaSpec:
maxReplicas: 1
minReplicas: 1
values:
telemetry:
enabled: false
EOF
使用 istioctl
安装:
$ istioctl install -f config.yaml --set values.gateways.istio-ingressgateway.runAsRoot=true -y
✔ Istio core installed
✔ Istiod installed
✔ Ingress gateways installed
✔ Installation complete Making this installation the default for injection and validation.
Thank you for installing Istio 1.17. Please take a few minutes to tell us about your install/upgrade experience! https://forms.gle/hMHGiwZHPU7UQRWe9
第 4 步:设置后端服务
因为我们想在 Istio 入口网关中使用 DLB 连接负载均衡,所以需要先创建一个后端服务。
我们将使用 Istio 附带的样例 httpbin 进行测试。
$ kubectl apply -f samples/httpbin/httpbin.yaml
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: httpbin-gateway
spec:
# 选择器与入口网关 Pod 标签进行匹配。
# 如果您参照标准文档已使用 Helm 安装了 Istio,此项将为 "istio=ingress"
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "httpbin.example.com"
EOF
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- "httpbin.example.com"
gateways:
- httpbin-gateway
http:
- match:
- uri:
prefix: /status
- uri:
prefix: /delay
route:
- destination:
port:
number: 8000
host: httpbin
EOF
您现在已经为 httpbin 服务创建了一个包含两个路由规则的虚拟服务配置, 这些路由规则允许针对路径 /status 和 /delay 的流量通过。
gateways 列表指定只有通过 httpbin-gateway 的请求才被允许。 所有其他外部请求将会被拒绝,并返回 404 响应。
第 5 步:启用 DLB 连接负载均衡
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: dlb
namespace: istio-system
spec:
workloadSelector:
labels:
istio: ingressgateway
configPatches:
- applyTo: LISTENER
match:
context: GATEWAY
patch:
operation: MERGE
value:
connection_balance_config:
extend_balance:
name: envoy.network.connection_balance.dlb
typed_config:
"@type": type.googleapis.com/envoy.extensions.network.connection_balance.dlb.v3alpha.Dlb
EOF
如果您检查入口网关 Pod istio-ingressgateway-xxxx
的日志,您将看到类似以下的日志条目:
$ export POD="$(kubectl get pods -n istio-system | grep gateway | awk '{print $1}')"
$ kubectl logs -n istio-system ${POD} | grep dlb
2023-05-05T06:16:36.921299Z warning envoy config external/envoy/contrib/network/connection_balance/dlb/source/connection_balancer_impl.cc:46 dlb device 0 is not found, use dlb device 3 instead thread=35
Envoy 将自动检测并选择 DLB 设备。
第 6 步:测试
$ export HOST="<YOUR-HOST-IP>"
$ export PORT="$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')"
$ curl -s -I -HHost:httpbin.example.com "http://${HOST}:${PORT}/status/200"
HTTP/1.1 200 OK
server: istio-envoy
...
请注意,您可以使用 -H
标志将 Host HTTP 头设置为 httpbin.example.com
,
因为现在您还没有为该主机绑定 DNS,所以只是将请求发送到入口 IP。
您也可以在 /etc/hosts
中添加 DNS 绑定并移除 -H
标志:
$ echo "$HOST httpbin.example.com" >> /etc/hosts
$ curl -s -I "http://httpbin.example.com:${PORT}/status/200"
HTTP/1.1 200 OK
server: istio-envoy
...
访问还未显式暴露的任何其他 URL,您应看到一个 HTTP 404 错误:
$ curl -s -I -HHost:httpbin.example.com "http://${HOST}:${PORT}/headers"
HTTP/1.1 404 Not Found
...
您可以打开调试日志级别以查看更多 DLB 相关的日志:
$ istioctl pc log ${POD}.istio-system --level debug
istio-ingressgateway-665fdfbf95-2j8px.istio-system:
active loggers:
admin: debug
alternate_protocols_cache: debug
aws: debug
assert: debug
backtrace: debug
...
运行 curl
发送一个请求,您将看到类似以下的信息:
$ kubectl logs -n istio-system ${POD} | grep dlb
2023-05-05T06:16:36.921299Z warning envoy config external/envoy/contrib/network/connection_balance/dlb/source/connection_balancer_impl.cc:46 dlb device 0 is not found, use dlb device 3 instead thread=35
2023-05-05T06:37:45.974241Z debug envoy connection external/envoy/contrib/network/connection_balance/dlb/source/connection_balancer_impl.cc:269 worker_3 dlb send fd 45 thread=47
2023-05-05T06:37:45.974427Z debug envoy connection external/envoy/contrib/network/connection_balance/dlb/source/connection_balancer_impl.cc:286 worker_0 get dlb event 1 thread=46
2023-05-05T06:37:45.974453Z debug envoy connection external/envoy/contrib/network/connection_balance/dlb/source/connection_balancer_impl.cc:303 worker_0 dlb recv 45 thread=46
2023-05-05T06:37:45.975215Z debug envoy connection external/envoy/contrib/network/connection_balance/dlb/source/connection_balancer_impl.cc:283 worker_0 dlb receive none, skip thread=46
有关 Istio 入口网关的更多细节,请访问 Istio 入口网关官方文档。