在大规模服务场景下,成千上万个服务运行在不同的地域,这些服务需要相互调用来完成完整的功能。为了确保获得最佳性能,应当将流量路由到最近的服务,使得流量尽可能在同一个区域内,而不是只依赖于Kubernetes默认提供的轮询方式进行负载均衡。基于Istio的阿里云服务网格ASM产品提供了基于位置的路由能力,可以将流量路由到最靠近的容器。这样可以确保服务调用的低延迟,并尽量保持服务调用在同一区域内,降低流量费用。本文介绍如何在ASM内实现基于位置的路由请求,以提高性能并节省成本。
前提条件
已创建ASM实例。
创建一个多可用区的托管版ACK集群,集群使用的节点分别位于同一地域下的不同可用区(本文示例中分别为北京地域下的可用区G和H),详情请参见创建Kubernetes托管版集群。
部署后端示例服务
在ACK集群中分别部署Nginx的两个版本(V1和V2),并通过Nodelabel将版本V1部署到可用区G,将版本V2部署到可用区H,操作步骤如下所示。
在ACK集群中部署Nginx版本V1,对应的YAML如下。
apiVersion: v1 kind: ConfigMap metadata: name: mynginx-configmap-v1 namespace: backend data: default.conf: |- server { listen 80; server_name localhost; #charset koi8-r; #access_log /var/log/nginx/host.access.log main; location / { return 200 'v1\n'; } }
通过Nodelabel将版本V1部署到可用区G,对应的YAML如下。
在ACK集群中部署Nginx版本V2,对应的YAML如下。
apiVersion: v1 kind: ConfigMap metadata: name: mynginx-configmap-v2 namespace: backend data: default.conf: |- server { listen 80; server_name localhost; #charset koi8-r; #access_log /var/log/nginx/host.access.log main; location / { return 200 'v2\n'; } }
通过Nodelabel将版本V2部署到可用区H,对应的YAML如下。
部署后端示例应用服务,对应的YAML如下。
apiVersion: v1 kind: Service metadata: name: nginx namespace: backend labels: app: nginx spec: ports: - name: http port: 8000 targetPort: 80 selector: app: nginx
部署客户端示例服务
在ACK集群中分别部署2个客户端示例服务,并通过Nodelabel将版本V1部署到可用区G,将版本V2部署到可用区H,对应的操作步骤如下。
在ACK集群中部署客户端示例服务,通过Nodelabel将版本V1部署到可用区G,对应的YAML如下所示。
apiVersion: apps/v1 kind: Deployment metadata: name: sleep-cn-beijing-g namespace: backend spec: replicas: 1 selector: matchLabels: app: sleep version: v1 template: metadata: labels: app: sleep version: v1 spec: containers: - name: sleep image: tutum/curl command: ["/bin/sleep","infinity"] imagePullPolicy: IfNotPresent nodeSelector: failure-domain.beta.kubernetes.io/zone: "cn-beijing-g"
在ACK集群中部署客户端示例服务,通过Nodelabel将版本V2部署到可用区H,对应的YAML如下所示。
apiVersion: apps/v1 kind: Deployment metadata: name: sleep-cn-beijing-h namespace: backend spec: replicas: 1 selector: matchLabels: app: sleep version: v2 template: metadata: labels: app: sleep version: v2 spec: containers: - name: sleep image: tutum/curl command: ["/bin/sleep","infinity"] imagePullPolicy: IfNotPresent nodeSelector: failure-domain.beta.kubernetes.io/zone: "cn-beijing-h"
部署客户端示例服务,对应的YAML如下。
apiVersion: v1 kind: Service metadata: name: sleep namespace: backend labels: app: sleep spec: ports: - name: http port: 80 selector: app: sleep
执行如下脚本,在2个Sleep Pod中访问后端示例服务。
echo "entering into the 1st container" export SLEEP_ZONE_1=$(kubectl get pods -lapp=sleep,version=v1 -n backend -o 'jsonpath={.items[0].metadata.name}') for i in {1..20} do kubectl exec -it $SLEEP_ZONE_1 -c sleep -n backend -- sh -c 'curl http://nginx.backend:8000' done echo "entering into the 2nd container" export SLEEP_ZONE_2=$(kubectl get pods -lapp=sleep,version=v2 -n backend -o 'jsonpath={.items[0].metadata.name}') for i in {1..20} do kubectl exec -it $SLEEP_ZONE_2 -c sleep -n backend -- sh -c 'curl http://nginx.backend:8000' done
预期输出:
可以看到后端示例服务以循环方式进行负载均衡。
本地优先负载均衡
本地优先的负载均衡算法会优先访问同一可用区的Pod,并在本可用区Pod不可用时,调用其他可用区的Pod。
为了实现本地优先的负载均衡,您需要具有虚拟服务和带有异常策略的目标规则。离群策略检查Pod是否健康,并作出路由决策。
登录ASM控制台。
在左侧导航栏,选择 。
在网格管理页面,找到待配置的实例,单击实例的名称或在操作列中单击管理。
在网格详情页面左侧导航栏,选择 ,然后在右侧页面,单击使用YAML创建。
按照以下步骤定义虚拟服务,然后单击创建。
选择相应的命名空间。本文以选择backend命名空间为例。
在文本框中,定义Istio虚拟服务,YAML定义如下所示。
apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: nginx namespace: backend spec: hosts: - nginx http: - route: - destination: host: nginx
在网格详情页面左侧导航栏,选择 ,然后在右侧页面,单击使用YAML创建。
按照以下步骤定义目标规则,然后单击创建。
选择相应的命名空间。本文以选择backend命名空间为例。
在文本框中,定义Istio目标规则,YAML定义如下所示。
apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: nginx namespace: backend spec: host: nginx trafficPolicy: outlierDetection: consecutiveErrors: 7 interval: 30s baseEjectionTime: 30s
执行如下脚本,在2个Sleep Pod中再次访问后端示例服务。
echo "entering into the 1st container" export SLEEP_ZONE_1=$(kubectl get pods -lapp=sleep,version=v1 -n backend -o 'jsonpath={.items[0].metadata.name}') for i in {1..20} do kubectl exec -it $SLEEP_ZONE_1 -c sleep -n backend -- sh -c 'curl http://nginx.backend:8000' done echo "entering into the 2nd container" export SLEEP_ZONE_2=$(kubectl get pods -lapp=sleep,version=v2 -n backend -o 'jsonpath={.items[0].metadata.name}') for i in {1..20} do kubectl exec -it $SLEEP_ZONE_2 -c sleep -n backend -- sh -c 'curl http://nginx.backend:8000' done
预期输出:
可以看到以本地优先方式进行负载均衡。
局部加权的负载均衡
大多数情况下使用本地优先的负载均衡可以满足平衡的要求,但是有时候您可能需要将流量分成多个区域,如果所有请求都来自单个区域,则容易使一个区域超载。此时可以使用局部加权的负载均衡。
譬如设置如下的加权规则:
将从cn-beijing/cn-beijing-g的80%流量路由到cn-beijing/cn-beijing-g,20%的流量路由到cn-beijing/cn-beijing-h。
将从cn-beijing/cn-beijing-h的20%流量路由到cn-beijing/cn-beijing-g,80%的流量路由到cn-beijing/cn-beijing-h。
登录ASM控制台。
在左侧导航栏,选择 。
在网格管理页面,找到待配置的实例,单击实例的名称或在操作列中单击管理。
在网格详情页面左侧导航栏,选择 ,然后在右侧页面,单击使用YAML创建。
按照以下步骤定义虚拟服务,然后单击创建。
选择相应的命名空间。本文以选择backend命名空间为例。
在文本框中,定义Istio虚拟服务,YAML定义如下所示。
apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: nginx namespace: backend spec: hosts: - nginx http: - route: - destination: host: nginx
在网格详情页面左侧导航栏,选择 ,然后在右侧页面,单击使用YAML创建。
按照以下步骤定义目标规则,然后单击创建。
选择相应的命名空间。本文以选择backend命名空间为例。
在文本框中,定义Istio目标规则,YAML定义如下所示。
apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: nginx namespace: backend spec: host: nginx trafficPolicy: outlierDetection: consecutiveErrors: 7 interval: 30s baseEjectionTime: 30s loadBalancer: localityLbSetting: enabled: true distribute: - from: cn-beijing/cn-beijing-g/* to: "cn-beijing/cn-beijing-g/*": 80 "cn-beijing/cn-beijing-h/*": 20 - from: cn-beijing/cn-beijing-h/* to: "cn-beijing/cn-beijing-g/*": 20 "cn-beijing/cn-beijing-h/*": 80
执行如下脚本,在2个Sleep Pod中再次访问后端示例服务。
echo "entering into the 1st container" export SLEEP_ZONE_1=$(kubectl get pods -lapp=sleep,version=v1 -n backend -o 'jsonpath={.items[0].metadata.name}') for i in {1..20} do kubectl exec -it $SLEEP_ZONE_1 -c sleep -n backend -- sh -c 'curl http://nginx.backend:8000' done echo "entering into the 2nd container" export SLEEP_ZONE_2=$(kubectl get pods -lapp=sleep,version=v2 -n backend -o 'jsonpath={.items[0].metadata.name}') for i in {1..20} do kubectl exec -it $SLEEP_ZONE_2 -c sleep -n backend -- sh -c 'curl http://nginx.backend:8000' done
预期输出:
可以看到以局部加权比例进行负载均衡。
相关文档
如果您希望确保流量仅在特定地域内流通,可以在不同地域中分别创建ACK集群,并使用集群内流量保持功能将流量严格限制在各自的集群中。具体操作,请参见在ASM中使用集群内流量保持功能。