使用ConcurrencySchedulingPolicy实现可控并发下的请求优先级调度
本文介绍如何使用流量调度套件提供的ConcurrencySchedulingPolicy来实现可控并发下的请求优先级调度。
背景信息
ConcurrencySchedulingPolicy通过指定的并发数限制来判断流量是否过载,当请求并发数超过指定上限后,后续请求将被排队并根据请求优先级进行调度。大致工作流程如下:
记录请求并发数:该策略会使用并发数限制器记录同时正在处理过程中的请求并发数量,判断请求并发数是否已经达到上限。
请求调度:当请求并发数达到上限时,后续请求将会被排队,等待先前请求处理完成后再发送给服务,以保证请求并发数始终保持在给定数值。同时,高优先级的请求有更大的机会被从队列中取出发送给服务。
当请求并发数超过系统承载上限时,使用此策略可以对请求进行排队,和并发数限制不同,此时请求不会被直接拒绝,而是进入一个优先级队列,在保证请求并发数始终在限制内的同时对请求进行优先级调度。
前提条件
已添加Kubernetes托管版集群到ASM实例,且ASM实例为v1.21.6.97及以上。具体操作,请参见添加集群到ASM实例。
已为Kubernetes集群中的default命名空间开启自动注入。具体操作,请参见管理全局命名空间。
已通过kubectl连接至ACK集群。 具体操作,请参见获取集群KubeConfig并通过kubectl工具连接集群。
已开启ASM流量调度套件。具体操作,请参见开启ASM流量调度套件。
已经部署httpbin应用,并且可以通过网关访问,具体操作,请参见部署httpbin应用
步骤一:创建ConcurrencySchedulingPolicy限流规则
使用kubectl连接到ASM实例,具体操作,请参见通过控制面kubectl访问Istio资源。
使用以下内容,创建concurrencyschedulingpoilcy.yaml文件。
apiVersion: istio.alibabacloud.com/v1 kind: ConcurrencySchedulingPolicy metadata: name: concurrencyscheduling namespace: istio-system spec: concurrency_scheduler: max_concurrency: 10 concurrency_limiter: max_inflight_duration: 60s scheduler: workloads: - label_matcher: match_labels: http.request.header.user_type: guest parameters: priority: 50.0 name: guest - label_matcher: match_labels: http.request.header.user_type: subscriber parameters: priority: 200.0 name: subscriber selectors: - service: httpbin.default.svc.cluster.local
部分配置项说明如下。关于配置项的更多说明,请参见ConcurrencySchedulingPolicy CRD说明。
配置项
说明
max_concurrency
最大请求并发数。示例中指定为1,即只允许服务同时处理1个请求。
max_inflight_duration
请求处理超时时间。由于集群中可能发生Pod重启等突发情况,导致ASM流量调度套件可能无法记录到请求结束事件,为防止此类请求影响并发数限制算法的判断,需要指定请求处理超时时间,超过此时间还未响应的请求将视作处理结束。可以通过评估请求的期望最大响应时间来设定此值,示例中设定为60s。
workloads
根据请求header中的user_type定义了两类请求,分别是guest和subscriber。guest类型的请求优先级是50,subscriber类型的请求优先级是200。
selectors
指定应用限流策略的多个服务。示例中使用service: httpbin.default.svc.cluster.local 表示对httpbin.default.svc.cluster.local 服务进行并发数限制。
执行以下指令,创建并发数调度策略。
kubectl apply -f concurrencyschedulingpoilcy.yaml
步骤二:验证控制并发数场景下的请求优先级调度效果
本步骤使用压测工具fortio进行测试,安装方式请参见安装fortio。
同时打开两个终端,并分别运行下面两个压测命令(尽可能同时开始这两个测试),整个测试期间,请确保不要关闭对应的终端。两个测试都使用10并发、10000预期qps的设定对服务发起调用,远远超过了服务的预期并发数限制。
fortio load -c 10 -qps 10000 -H "user_type:guest" -t 30s -timeout 60s -a http://${ASM网关IP}/status/201
fortio load -c 10 -qps 10000 -H "user_type:subscriber" -t 30s -timeout 60s -a http://${ASM网关IP}/status/202
说明请将上述指令中的
${ASM网关IP}
替换为ASM网关的IP地址。有关获取ASM网关IP地址的具体操作,请参见使用Istio资源实现版本流量路由。测试1的预期输出:
... # target 50% 4.35294 # target 75% 5.39689 # target 90% 5.89697 # target 99% 6.19701 # target 99.9% 6.22702 Sockets used: 10 (for perfect keepalive, would be 10) Uniform: false, Jitter: false Code 201 : 84 (100.0 %) Response Header Sizes : count 84 avg 249.88095 +/- 0.3587 min 248 max 250 sum 20990 Response Body/Total Sizes : count 84 avg 249.88095 +/- 0.3587 min 248 max 250 sum 20990 All done 84 calls (plus 10 warmup) 3802.559 ms avg, 2.6 qps Successfully wrote 5186 bytes of Json data to xxxxxx.json
记录下测试1输出的json文件名,例如xxxxxx.json。
测试2的预期输出:
... # target 50% 1.18121 # target 75% 1.63423 # target 90% 1.90604 # target 99% 2.22941 # target 99.9% 2.28353 Sockets used: 10 (for perfect keepalive, would be 10) Uniform: false, Jitter: false Code 202 : 270 (100.0 %) Response Header Sizes : count 270 avg 250.52963 +/- 0.5418 min 249 max 251 sum 67643 Response Body/Total Sizes : count 270 avg 250.52963 +/- 0.5418 min 249 max 251 sum 67643 All done 270 calls (plus 10 warmup) 1117.614 ms avg, 8.8 qps Successfully wrote 5305 bytes of Json data to yyyyyy.json
记录下测试2输出的json文件名,例如yyyyyy.json。
由测试1和测试2的预期输出可以看到,测试2的平均请求延迟约为测试1的四分之一、qps约为测试1的四倍。这是由于先前定义的策略中,subscriber类型的请求优先级是guest类型的请求的四倍。
(可选)可视化查看结果。
在上一步执行两个测试命令的目录中执行以下指令,打开fortio本地服务器。
fortio server
使用浏览器访问
http://localhost:8080/fortio/browse
,根据上一步记录的两个测试输出的json文件名,点击文件查看测试的可视化结果。测试1的可视化结果示例:
测试2的可视化结果示例:
从可视化结果可以看到,除少数未被限制的请求外、guest类型的请求大多延迟在4000-6000ms内,而subscriber类型的请求大多延迟落在1000-2000ms内。在服务请求负载超限的情况下、subscriber类型的请求优先得到了响应,同时服务接受到的请求并发数始终被限制在给定数值。