7.3.2 自动扩缩容效率
FaaS函数运行时实现的扩缩容策略为按步长增加和减少函数副本数。该策略下,函数负载情况、函数配置伸缩的最大副本数、最少副本数、伸缩的因子、伸缩的触发条件,以及组成边缘集群的设备数量、设备硬件配置等因素都会影响自动扩缩容效率。
给基准函数每秒10次请求的负载,配置函数伸缩的最大副本数50,最少副本数1,伸缩因子4,扩容的触发条件是函数最近10秒的函数服务请求率大于5触发AlertManager告警标记状态为firing,缩容的触发条件是Alertmanager持续10秒未接收到告警后标记告警状态为resolved。本文在1台Raspberry Pi 4上,使用Golang Vegeta HTTP库执行时长3分钟的负载,监控某次基准函数的自动伸缩指标,如图7.4所示。
基准函数一开始处于闲置状态,函数副本数缩容到零,随着开始加上负载,函数预热到最少副本数1。之后检测到函数调用率超过阈值,触发扩容,基于最大副本数50和伸缩因子4计算出步长2,扩容2个函数副本数,Desired是声明的副本数,Nomad具体执行函数容器启停,达到预期的副本数,当负载撤走后,触发缩容,按步长逐渐缩容函数到最少副本数。注意到的是,Nomad每次作业更改重新评估调度,对函数副本重新逐个健康检查。
图7.4 函数副本数随时间变化
在以上环境和配置下,以从声明的副本数变更到所有函数实例准备就绪并通过健康检查的时间间隔为时间窗口计算,基准函数的平均扩容效率约为0.19个/s,平均缩容效率约为0.34个/s。
此外,本文发现在函数伸缩时的稳定性也影响着服务质量。使用与上文相同的配置,将文件描述符和进程的限制都设置为大数字后,使用Vegeta库执行一定压力的负载,实验中的成功率、吞吐率来自Vegeta生成的报告,测试结果见表7.9。实验中,在每次更改负载开始前先等待函数冷却,默认设置是30秒缩容到零,故开始时实例数均为0。Vegeta负载时长1min,超时设置为30s。边缘集群采用ansible-playbook自动化部署。
表7.9 FaaS函数运行时负载下扩容的服务质量
边缘某区域设备数 | 每秒请求数 | 成功率 | 结束时实例数 | 吞吐率 |
---|---|---|---|---|
1 | 1 | 100% | 1 | 1.02 |
1 | 2 | 100% | 1 | 2.01 |
1 | 3 | 100% | 1 | 3.01 |
1 | 5 | 100% | 1 | 5.01 |
1 | 10 | 100% | 3 | 10.00 |
1 | 20 | 18.42% | 3 | 3.25 |
3 | 5 | 100% | 1 | 5.01 |
3 | 10 | 100% | 3 | 10.00 |
3 | 20 | 33.58% | 3 | 6.71 |
3 | 30 | 21.61% | 3 | 5.74 |
8 | 5 | 100% | 1 | 5.01 |
8 | 10 | 100% | 3 | 10.00 |
8 | 20 | 88.08% | 3 | 17.60 |
8 | 30 | 58.11% | 3 | 17.36 |
8 | 50 | 2.50% | 3 | 1.10 |
当负载增大,服务质量明显下降。反复寻找原因,一方面是扩缩容时的稳定性,Nomad在Consul中服务注册的函数实例只有健康检查通过的才能提高服务,而Nomad在每次伸缩时都会重新将Healthy降为0,也就是有短暂的没有函数实例处理流量的空窗期;另一方面由于本文的FaaS API网关实现上只做了简单的路由转发和基本认证等功能,没有在网关层面做限流等,也导致在没有触发扩容逻辑时,少数容器处理大量请求,服务端处理不过来,0类响应码也明显增多,有时后端函数容器重启,进一步促使扩缩容时的稳定性下降。扩容策略采用的固定步长,对短时间内的增加的大量负载效果不大,当然用户可以调整设置更大的伸缩因子,但需要进一步完善根据负载情况的动态伸缩因子,提升一定流量负载下的稳定性。
同样与AWS Lambda云FaaS产品对比,通过持续监视AWS CloudWatch Metrics获得基准函数的实例数,成功率、吞吐率由Vegeta报告生成。多次测试Lambda函数在一定负载下的自动伸缩情况和调用成功率,结果见表7.10。Vegeta负载时长1min,超时设置为30s,Lambda函数开始时实例数均为1。测试过程中由于CloudWatch的指标观测粒度,没能准确的统计基准函数的平均伸缩效率,但从观测过程大致评估,云FaaS的基准函数副本数总是立即准备就绪,平均伸缩效率不低于50个/s,云FaaS能够毫秒级弹性伸缩。
表7.10 AWS Lambda负载下扩容的服务质量
预留并发配置 | 每秒请求数 | 成功率 | 结束时实例数 | 吞吐率 |
---|---|---|---|---|
1 | 5 | 16.67% | 1 | 0.83 |
5 | 1 | 100% | 2 | 1.00 |
5 | 3 | 100% | 5 | 2.96 |
5 | 5 | 83.33% | 5 | 4.10 |
10 | 3 | 100% | 5 | 2.96 |
10 | 5 | 100% | 8 | 4.93 |
10 | 10 | 84.67% | 10 | 8.32 |
16 | 10 | 100% | 14 | 9.82 |
16 | 20 | 70.08% | 16 | 13.77 |
16 | 50 | 28.67% | 16 | 14.06 |
32 | 10 | 100% | 15 | 9.82 |
32 | 20 | 100% | 28 | 19.64 |
32 | 50 | 56.77% | 32 | 27.85 |
50 | 10 | 100% | 15 | 9.82 |
50 | 20 | 100% | 27 | 19.64 |
50 | 50 | 87.8% | 43.09 | 43.09 |
根据CloudWatch监控指标,虽然部分请求当负载超过预留并发实例数的处理上限后被限流,但凡是服务端处理的每个请求的成功率都是100%,AWS Lambda的自动扩缩容时性能十分稳定,得益于此,Lambda能够应对更高的流量负载。
相比之下,本文实现的FaaS函数运行时与AWS Lambda最大的不同是Lambda每个函数实例同一时刻只处理一个请求,而本文FaaS函数运行时的函数实例处理更多的请求。此外,本文FaaS函数运行时在一定负载下扩缩容时的服务稳定性、动态扩缩容策略、伸缩效率等方面还很粗糙,有待进一步研究和完善。
本章对本文设计和实现的Libvirt虚拟机运行时和FaaS函数运行时进行了功能和性能测试。并将本文基于Nomad的边缘计算平台上FaaS函数运行时,在冷启动时间和自动扩缩容效率上,与业界标杆AWS Lambda云FaaS产品进行了对比,分析目前的不足之处。