Serverless 技术正在获得越来越多的认可。CNCF 2019年报告显示,41% 的受访者表示已经在使用 Serverless,另外 20% 的受访者表示计划在未来 12-18 个月内采用 Serverless 技术。
Serverless 技术关注者对其价值点讨论⼤多是基于公有云场景的云函数等产品,其关注点在资源支付方式更加细粒度,和公有云Baas的粘合上,和私有云环境中业务团队关注的价值不太契合;在我们对业界落地场景调研以及同业务团队⼀起实践后,我们发现私有云环境中业务团队关心的Serverless价值可概括为三点:
其中“提效”和“降本”为核心价值,解耦为重要考虑点。
我们认为Serverless出现不是为了替代现有的Serverful(传统云)框架,两者是互补的关系,Serverless有其业务场景优势(后续⽂章再展开),合适最重要。笔者目前工作是聚焦轻舟Serverless(“轻舟”系网易研发的云原生基础设施平台代号)和业务团队⼀起实现业务开发的提效、降本和解耦。当前开源Serverless方案很多,而选型强大活跃开源社区方案让我们能够持续改进自己的Serverless平台。基于此诉求,我们很早便选型了Knative,因为从一开始其社区非常活跃,有Google,IBM,RedHat等大公司参与,其次是标准先行。而事实也在慢慢印证了我们的选择。
如图所示, Knative 占据了 34% 的份额,遥遥领先于第⼆名 OpenFaaS,Knative 是搭建 Serverless 平台的首选。( 数 据 来 源 于 CNCF 2019 年 社 区 调 查 报 告 )
目前,网易轻舟云原生团队已经和网易云音乐前端团队合作共建云音乐Serverless部署平台ALPACA,将Serverless用于前端场景。该平台架构如下图。
其中轻舟负责底层能力,Knative是其中的核心能力,我们基于其业务场景,对Knative进行了压测分析,也做了性能调优POC,本文主要从性能角度,基于Serverless前端使用场景对Knative进行分析,尝试揭开Knative核心数据路径性能真相并给出调优思考。
本文暂不讨论流量如何导⼊到ALPACA平台,先聚焦到ALPACA平台Knative系统内部本身。
Knative系统内部数据路径是, Knative网关->Activator->Queue Proxy->业务App;社区推荐使用的方式是不注入Sidecar以获取更佳的性能,因此我们讨论场景是“不注入Sidecar,管控面使用Pilot,Knative网关使用轻舟的API网关产品”。
Knative系统内部默认的数据路径如上图,用户业务流量经过一层Knative网关,经过Activator 到达Queue Proxy 代理组件,最后到达应用程序。
从上图可知,默认情况下流量经过三层代理(Knative网关、Activator、Queue Proxy)后才到达应用APP,每⼀层代理均可能是性能的拦路虎。
我们的分析思路如下:
首先Activator作用是:
其次Queue Proxy作用是:
Queue Proxy以Sidecar⽅式和应⽤容器部署到同⼀个Pod,Queue Proxy是为了配合完成扩缩容事宜以及满足App可观测性要求,以Sidecar方式部署主要考虑到对App应用无侵入,功能描述如下:
谈到Activator必要性,需要先了解当前Serverless 难题“冷启动”,所谓冷启动是Serverless缩容到0 后,重新从0扩容到1的过程,该过程目前是非常慢的,也是业界难题,根据社区对Knative冷启动分析得知,冷启动时间大概6s ,很显然6s的冷启动任何业务都⽆法容忍;当前可以尽量优化冷启动时间,但是想达到ms级别,做到业务⽆感知,挑战非常大,目前有两种解决思路:
方向1: 温启动,通过冗余方式建立预热池来解决,当需要0-1时候,从预热池取,然后将用户程序注入,省去建立容器的过程
方向2: 通过默认预留实例来规避
目前该问题我们先通过方向2来解决,至于方向1也在考虑,但是涉及到的开发工作量大,且需要对K8s框架改动,需要根据需求触发。所以目前在我们使用场景中不需要Activator帮助从0-1扩容。
对于突发流量保护功能,在使⽤场景中可降低扩容触发的并发要求,预留出一定的Pod计算能力来抵御突发流量;因此在目前业务场景中,Activator存在必要性⼀般,可以考虑将其从核心数据路径中彻底去除。
Queue Proxy核心作用是收集App的指标(并发、RPS等)来决定扩容,当前以Sidecar⽅式部署是非常有必要的:
所以Queue Proxy Sidecar是非常有必要的,但是相比裸业务容器而言,会增加⼀层代理(该场景就像服务网格Server Sidecar⼀样),导致业务容器性能降低,这是选择这种架构所要付出的资源成本,我们要做的就是将该成本降到最小。
如上图,总结下分析结论,从性能⾓度出发,我们需要关注:
将Activator从数据路径中去除 重点关注Queue Proxy 和App路径 关注Knative网关和Queue Proxy路径
从上文的分析结论可知,我们得到了具体的性能关注点,于是对这些关注点进行实际的性能测试。
在Knative框架下,性能可以通过CPU和实例个数横向扩展性能,所以后续测试均固定在单个业务容器,通过对比测试来发现性能瓶颈,业务容器选型社区简单的go语言实现的helloworld服务程序(镜像为hub.c.163.com/qingzhou/knative/demo/helloworld-go:v0.1),采用测试工具Hey(https://github.com/rakyll/hey )使⽤HTTP长连接进行测试。
root@pubt1-k8s59:/home/liuqinlong# cat performance.yaml
apiVersion: serving.knative.dev/v1alpha1
kind: Service
metadata:
name: helloworld-go
namespace: default
spec:
template:
metadata:
labels:
app: helloworld-go
annotations:
autoscaling.knative.dev/maxScale: "1"
autoscaling.knative.dev/minScale: "1"
spec:
containers:
- image: hub.c.163.com/qingzhou/knative/demo/helloworld-go:v0.1
env:
- name: SIMPLE_MSG
value: "helloworld-go"
hey -z 60s -c 70 --host "helloworld-go.default.example.com" "<http://10.178.67.100/>"
如下结果显示,虽然Activator采用HPA进行性能扩展,但是其扩容非常慢,如果性能测试时候没有来得及扩容Activator,对整个延迟影响效果巨⼤只有920Qps。即使Activator扩容成了8个发现p90延时也在7ms以上,Qps约7千。
避坑说明:在测试过程中,需要确认Activator HPA扩容是否生效,笔者测试过程中默认环境中没有安装metrics-server导致Activator无法HPA扩容。整个核⼼路径中Activator 默认限制单个CPU,其使用率达到100%,导致QPS非常低(才920),P90延迟要111ms,p99延迟要195.2ms
经过前文的分析Queue Proxy以Sidecar⽅式存在是Knative 架构要求,当前测试case情况下,加⼊Queue Proxy Sidecar后,相⽐原⽣容器,QPS从3.9w->3.1w,P90 延迟翻倍(2.5->4.2)。
相对来说,在相同并发压力情况下,因为新增⼀层代理延迟肯定提升,QPS会跟着降低。但是我们发现CPU损失代价有些大,CPU使⽤率达到了1497% (Server CPU才482.4%),理论测试的App为hello world程序业务逻辑⾮常简单,业务处理延迟不长,Queue Proxy 和当前测试App CPU使用率比值最好是1:1,所以Queue Proxy存在CPU异常消耗的问题,需要进行调优解决。
注意:v0.14 Queue Proxy 性能要比v0.9版本Queue Proxy性能要好,后⽂Queue Proxy测试版本均采⽤的是v0.14版本,下面给出性能对比:
QPS提升 (31891.7207-20505.6853)/20505.6853 = 55%(计算过程后文不再赘述)。
经过对Knative性能测试,进⼀步确认了下面性能调优点:
1.数据路径上去除Activator 2.Queue Proxy 和App路径优化 3.优化Knative Gateway性能
分析对比去除Activator路径带来的性能收益,如下表,将Activator移出核心数据路径后,QPS能力提升三倍(7776.1257 -> 25569.5698),且P99延迟大幅降低
1.组件优化
经过对Queue Proxy-> App路径分析,有两种优化方法,阐述如下:
优化方向一: 优化Queue Proxy
优化Queue Proxy HTTP代理解析过程,延迟大幅度降低(4.2->2.4 ms),且CPU使用率大幅度降低(代理CPU使用率接近Server CPU使用率),QPS小幅度提升。
优化方向二:将Queue Proxy替换成Envoy
优化后QPS相对社区Queue Proxy版本提升23%,延迟也大幅度降低,代理CPU使用率接近ServerCPU使用率。
2.框架优化
框架上协议栈穿透,通过sockmap以及sock redirect特性加速Queue Proxy和业务容器App之间通信。原理如下图:
基于轻舟的基于EBPF的高性能网络加速组件–SOPS,开启该功能,测试结果如下:
注:单位百分百CPU支撑的Qps= Qps/(Gateway(cpu%)+ QueueProxy(cpu%) + server(cpu%))
Knative社区也在讨论Envoy代替Queue Proxy,但是具体何时未知,考虑到工作量较大,我们打算follow社区进度;从性能角度和使用场景考虑,当前优化Queue Proxy也不差,所以先优化Queue Proxy来满足业务需求。
网关性能优化方面轻舟网关团队已经做了较多工作,性能也较为可观,在Knative当前使用场景,我们计划将Gateway底层网络更换成轻舟高性能网络,继续降低延迟,提升Gateway性能天花板,降低CPU使用率,使得单位百分比CPU支撑更多的业务QPS。
Knative框架内,默认情况下引入了三层代理路径,固定压力(70连接)下测试发现,默认情况下Knative性能表现非常不佳;经过调优(去除Activator 这⼀层代理+ 使用Queue Proxy v0.14并优化+ 使用Sops加速Queue Proxy和App路径)Knative框架性能表现还是非常优异的。
和裸业务容器相比:
1、单位百分比CPU支撑的QPS 5:1
2、链路的变长,当前测试场景和测试方法下,链路延迟p90提升 2.5->4.7 约2.2ms
从性能角度看Knative业务容器和裸业务容器,直接使用容器性能是最好的,使用Knative业务容器牺牲还是可以接受的。
下面进一步探讨,Knative 和 K8s到底是什么关系?
从功能角度看,Knative框架是K8s补充,工作在业务层次,解决业务的 “什么时候该扩容”,“怎么扩容”,“什么时候触发业务运行”等问题,是专业搞定业务自动扩缩容和事件触发的功能组件。
Knative框架支持功能并不什么新鲜事情,其功能特性,完全可以通过,K8s容器 + 智能网关+ 自定义扩容数据收集机制和并发控制+自己编码事件机制来代替+上层业务封装逻辑来替代,但是需较多的研发投入,而且对接API 为私有API接口,对用户有绑定。
从自动扩容角度看,业务的扩缩容也可以通过HPA来完成,但是这种方案速度较慢,一般3-5分钟,无法适应业务快速扩容需求。
我们基于K8s角度对Knative框架下一个定义:Knaitve=K8s++,是⼀种对K8s补充,是一种通过牺牲CPU和局部的延迟,换取业务流量管理能力(红绿发布、回滚、流量管理)和业务扩展能⼒(自动扩容能力、事件机制等)的开源软件框架。
前文性能分析均是基于单个业务Pod,Knative本身性能可从单个业务Pod横向扩展出多个业务Pod来进行性能扩容而且其非常擅长这一点,这里不赘述。下面介绍业务流量如何从外部导入Knative系统,因为 Knative系统内部扩展性没什么问题,我们需要使得接入Knative系统部分具备更强的横向扩展能⼒,以满足业务扩容的性能需求。
在选型之初,我们打算按照如下架构图,流量接入到Knative系统。流量经过Nginx Https代理 -> 轻舟网关-> 轻舟Knative网关 -> Queue Proxy -> 业务App,其中:
Nginx:主要作用是HTTPS加密
轻舟网关:主要做URL路径和域名路径的转换、业务降级
轻舟Knative网关:主要实现红绿发布、流量管理等功能
上图中业务路径比较长,特别是经过了三次7层网关(Nginx、轻舟网关、轻舟Knative网关),且Nginx和轻舟网关存在能力集重复问题,所以我们打算做如下调整:
使用轻舟网关接管Nginx的HTTPS的能⼒,缩短七层代理的路径,采用轻舟网关自动降级功能,业务降低避免了人为操作,为了方案的可扩展(性能横向扩展、未来IPv6需要等)和部署的灵活性,引入低延时的轻舟的四层LB。架构如下图,做到各个层可横向扩展。
因为方案降级需求,轻舟网关需要连云外的降级资源,但Knative网关无法管理该云外资源,所以目前无法将Knative网关和轻舟网关融合成一个网关。未来Serverless平台不再需要云外的降级资源,再将轻舟网关和轻舟Knative网关合并,达到如下流量框架,进一步缩短流量路径,达到最佳性能。
实现轻舟网关和轻舟Knative网关的融合需要修改Knative,原因是:Knative默认通过域名来区分应用,非常适合公有云,但是往往私有云业务场景,域名是固定且受限的,甚至有时候固定嵌入到客户端代码中,所以通过域名进行应用区分非常不适合,对于HTTP协议来说,我们需要使用请求路径来区分应用。
基于云原生化的泛前端部署平台依赖的底层Knative场景,通过分析,我们发现Knative社区默认情况下性能非常差,配置调优(不注入Sidecar + 将Activator从数据路径中去除后+使用Queue Proxy v0.14版本)后,除Queue Proxy CPU偏高外,性能还可以,特别是经过调优Queue Proxy、框架上协议栈穿透优化以及业务流量导入路径缩短后,性能可满足绝大部分业务需求,目前社区对于性能也在继续优化中(v0.14相比v0.9 QPS性能约有55%提升),我们相信社区Knative数据路径的性能会越来越好。
作者简介:
刘勤龙,网易杭州研究院资深云计算开发工程师,7年服务端开发和优化经验,负责网易轻舟四层负载均衡数据面设计,参与轻舟服务网格性能优化,目前专注于轻舟云原生Serverless平台底层的开发和优化工作。主要关注Kubernetes、Istio、Knative、Cilium等技术领域。
领取专属 10元无门槛券
私享最新 技术干货