酷家乐服务网格与Serverless落地情况
云原生技术生态近几年狂飙猛进,已经成为服务端技术栈中不可忽视的一股潮流。但由于业内各种各样的原因,服务网格,Serverless等技术概念虽然广泛传播,但鲜有真实场景中业务落地的案例。本文介绍的正是酷家乐技术团队在业务发展的过程中,将服务网格框架Istio和Serverless框架Knative在生产环境中落地的情况。
总体情况介绍
酷家乐业务范围介绍,业务特性
酷家乐是一个聚焦于”在线设计软件”领域的互联网公司,个人用户或企业用户可以在酷家乐平台上完成室内设计、模型设计、建筑设计、景观设计等领域的设计工作(如图);在部分领域,我们已经直接打通了对接工厂生产或者电商平台下单等关键环节。这样的业务场景,带来几个特性:
属于大部分用户的生产力工具,流量特性为上午下午双高峰,夜间,周末低谷。
用户一般都具有行业属性,所以一般不会出现电商活动、社交网站那样的超级高峰。
3D设计建模和渲染,需要大量的图形图像相关的算法,所以酷家乐平台有很多CPU密集的API,也有非常多离线计算场景。
酷家乐技术栈现状,Kubernetes以及云原生技术应用现状
酷家乐这个网站建立自2013年,整体技术栈带有时代的烙印。目前,酷家乐的服务主要是以Spring Boot为核心,使用自研的服务治理体系(RPC,监控,调用链,服务注册发现等)。目前,酷家乐的容器化工作已经开展了两年多,完成了全部线下环境上Kubernetes,线上环境部分业务已经上Kubernetes。在云原生领域,酷家乐也有一些实践,主要集中在运维团队,中间件团队,前端基础架构团队和我所在的国际站业务团队。其中,我们在国际站业务上落地了Istio服务网格,另外跟前端基础架构团队合作实验性落地了Knative作为酷家乐Serverless的基础设施。
团队实践服务网格和Serverless的主要诉求和契机
我们2018年开始应用Istio作为服务网格的主要诉求在于:
当时整个酷家乐容器化工作刚刚开始,整个服务治理体系还没有做面向Kubernetes体系的改造
由于国际业务的天然诉求,我们希望海外集群的服务部署工作和服务治理系统尽量精简
2019年底实验性落地Knative作为酷家乐函数计算基础设施,主要的契机是Knative发布了RC版本(v0.8),且酷家乐开始了业务线小团队作战的尝试,我们希望用更轻量的方式赋能业务线团队对业务进行快速迭代。
Istio现状与Knative现状
最近,Istio发生了两件大事:第一是Istio发布了1.5版本,将原来分离开的各个组件重新规整,合为一个巨石型应用;第二是Google云的负责人宣布未来会将Istio捐赠给某个基金会。这代表了Istio在面对当下难题上的一些应对手段,这些难题包括了在企业中落地较难,生态建设和竞争,以及社区积极性等问题。关于企业落地相关问题在后续篇幅中会论述。
Knative是一个相对新鲜的东西,是Google主推的一个Serverless计算框架,它比现在市面上的其他可用serverless框架更厂商中立,更面向云原生。目前为止,Knative更新到了0.14版本,仍然没有发布production-ready版本,但是这并不妨碍国内各个大厂开始研究并使用它。据我的了解,阿里云,华为云,腾讯云,以及网易都已经有专门的团队在应用和落地Knative,最核心的场景还是主要是把Knative做成云服务,以及用Knative来实现BFF(Backend for frontend)。
服务网格落地现状(Istio)
落地服务网格同时兼容酷家乐已有技术基础设施
如上所述,在我们2018年尝试使用Istio的时刻,酷家乐内部已经有一套自研的服务治理体系,那么在部分业务使用服务网格的时候,我们选择的策略是逐步兼容,并尽量复用原有的基础设施。例如,在Istio中的服务注册与发现实际上使用的是Virtual Service和Kubernetes内部的DNS服务,我们兼容的时候使用的是用类似Gateway的方式沟通两个体系之间的调用和服务(如下图):
这样,通过加入内部Gateway这一层,我们基本上实现了对原有服务体系的兼容。
又比如在调用链收集系统上,我们使用了开源的Jaeger在Istio上开箱即用的组件,但是在调用链的收集/存储上,我们直接复用了原有的基础设施,最后达到的效果就是在原有的系统中可以无缝查询使用Jaeger查到的调用链:
使用Istio实现灰度发布
基于Istio提供的流量控制能力,我们实现了简易的灰度发布机制:核心逻辑是给服务不同的版本打上不同的标签,然后通过Istio的route配置,将正确的流量导向正确的版本:
实践问题:性能
我们在生产环境跑Istio已经两年了,单纯从稳定性上来说,在我们的业务场景中是没有问题的。但是实践过程中还是暴露了一些性能上的问题,这个跟其他厂的服务网格用户交流过之后基本是一致的:由于Istio的Mixer机制,所有服务间的调用请求都会在Mixer这里“过一道”,如果遥测,安全,高级路由等功能同时加上去,那么每个跳转的性能和时间开销就不可忽视了,这也会使得Mixer成为资源开销大户。
所以不少团队在实践中对这块有改造或者取舍,比如我们就没有使用Mixer相关的安全功能。
实践问题:组件管理
我们知道Istio这一层切入到服务治理体系之后,可以把它当作一个平台,在这个平台上可以安装各种各样开箱即用的服务治理相关组件和工具。但是由于Istio/Kubernetes/其他组件都在不断演进当中,我们在这个体系的维护上遇到了一些问题,例如我们希望应用新版本的Istio但是发现不兼容现在版本的Kubernetes,导致我们需要从头升级Kubernetes,某个组件兼容当前版本的Kubernetes,但是却又不兼容当前版本的Istio,等等。特别是Istio本身也在快速迭代(包括1.5版本进行了大规模升级),经常会发现一些版本声明中没有提到的兼容性问题。
另外,Istio中包含了多个组件,实际运作上,任何一个组件在出问题,Istio都有可能不再正常工作,多个组件会增大排查的心智负担和解决问题的难度,这是另一个层面的组件管理问题。
变局:Istio 1.5的思路与解决方案
(上图来自王延飞的博客文章)通过将组件一模块的形式集中到Istiod里面,降低了维护成本和心智负担;通过移除Pilot,默认关闭Mixer等手段,大大降低性能风险。这次大的升级使得1.5之后和1.5之前相当于是不同的两个系统,可以感受到Istio开发社区对敏捷开发的实践和勇气。
在1.5之后,Istio对中小团队到底意味着什么?
在1.5之后,Istio成为一个复杂度没有那么高的,扩展性强的,开箱即用的一整套服务治理解决方案,建议有云原生经验的团队采用;但是根据目前的情况,我们不建议已经有一套另外的成熟服务治理套件的团队应用Istio。我们已经在自己的线下环境部署了Istio1.5版本,不日将应用到生产环境,希望到时候可以再来社区进行分享。
Serverless落地现状(Knative)
在酷家乐,我们已经向内部提供了以Knative为核心的函数计算基础设施。我们的的主要思路是:针对JS技术栈(主要是Node.js),我们提供了从函数开发,部署,注册和管理等整个链路的脚手架,可以实现“JS工程师只需要写业务逻辑,就可以完成一个API的编写,发布,上线全流程”;针对其他语言,由于团队资源有限,我们只提供了通过API进行镜像发布和配置设置的功能。在应用场景上,我们主要有两块: 提供在线的,以API为管理维度的聚合类API;提供离线的,以响应式和弹性为特点的离线计算业务。
已经落地在30+在线场景,但主要集中在边缘业务
由于Knative是全新的技术架构且目前尚在快速迭代,我们初步推广的种子用户是酷家乐体系内用量较少的线上业务。这些业务相对独立,调用量较小,恰好匹配我们按照单个API进行管理,弹性伸缩的核心特性。举例: 用户申请试用企业账号,账号被升级之后的后处理,例如邮件发送提醒,数据更新等等逻辑,我们就放在Knative服务离进行。
使用Knative搭建酷家乐FaaS/BFF基础设施
前述围绕JS技术栈的这套流程我们一般称之为FaaS(函数即服务)。目前,它的最常见的作用如下图:
在这里,函数既可以用于业务领域内的API,又可以做聚合API。但是如果只看图片的上半部分,本质上我们可以把它当作是一个基本的BFF(backend for frontend)架构,它的制作在于聚合后端领域服务提供的数据,计算结果,按照页面视图上的需求组织数据结构,并且返回给浏览器做页面呈现。
沿着这个思路,酷家乐在接下来的一年时间里将会推进服务架构往BFF方向演进,在这个演进过程中,Knative将承担BFF核心基础服务的角色。
使用Knative承接离线计算业务
由于Knative按需启停服务,带有消息事件机制等技术特性,我们认为Knative也非常适合进行离线计算,特别是流式/多阶段的离线计算任务。
这次分享开头已经提到过,酷家乐的业务特性导致我们内部有比较多的离线计算,离线处理业务,例如三维模型处理,大批量图片压缩等,特别适合进行分阶段的,事件驱动的离线计算。所以我们在这个场景也投入了一些资源做落地探索。
目前,我们已经在三个不同业务领域分别落地了离线计算,但是目前尚未落地基于event的事件驱动型离线计算。
实践问题:冷启动时间
Knative是一种Serverless的计算框架,而Serverless意味着应用或服务可以缩容到0个实例。能够缩容到0个实例,就代表着在某些情况下,用户的请求调用过来的时候,对应的API实际上是没有实例提供服务的。这个时候就出现了”冷启动时间”这一概念。根据我们的测试,目前最简单helloworld服务,在我们的集群上平均的冷启动时间为3s出头。这个数据已经比半年前的Knative版本优化了不少,但是仍然还未到达用户无感知的程度。有这座大山挡在前面,部分业务就不会允许缩容到0的情况。好在这些都是可以配置的,对于这些业务场景,我们就配置它最小缩容到1。
实践问题:版本管理
Knative引入了一个新的概念——Revision(如下图)。
这里Revision相当于是版本,也就是说同一个时间一个服务可以存活多个版本,如有需要可以进行快速的软切换(也体现了Istio的流量管理能力),这就要求应用Knative的团队需要根据自己的业务场景决定自己的版本管理策略,是长期只维护一个版本呢,还是维护两个或多个不同版本,切换策略是什么,这个都需要自己做,Knative本身没有提供这样的管理框架。
如何看待与评价Knative
事件驱动的计算,可以缩容到0的弹性计算,以更小的粒度进行服务管理,这是最近几年逐渐兴起的一种方法论。在某些业务场景,应用这个方法论带来的价值可能比服务网格带来的价值还要大。因此强烈建议有云原生经验的团队进行Serverless的实践和布局;如果是个人开发者或者小型团队,也完全可以尝试一下云服务上直接提供的函数服务,或尝试完全使用函数的框架搭建一个业务。2020年应该是Knative走向成熟并开始有落地案例的一年,期待下次给社区同学带来我们在BFF和离线计算领域落地Knative的经验。
总结
云原生生态快速成熟,影响力已经建立起来。我们会看到越来越多传统商业软件和系统被开源、面向云基础设施的技术体系替代。
改革进入深水区,部分企业开始尝试规模化落地,目前大部分体系落地需要容器化经验与改造成本。在酷家乐,我们从2018年到现在进行了容器化、服务网格、函数计算等方面的落地实践,也遇到了很多技术上,组织上的问题,要时刻提醒自己新技术的应用不是一蹴而就的,需要我们见招拆招,巧妙推进,善于妥协和取舍。
不要为了新技术而落地,应该着眼于在业务中释放云原生带来的技术红利,没有业务价值的技术改造,最终是不会得到更大范围的支持的。
Q&A
Q:如何解决Knative Queue Proxy性能问题?和容器相比Knative引入Queue Proxy导致QPS性能有很大的降低,这方面有调优?能否介绍下?
A:这个问题要辩证来看,就像Istio也引入了istio-proxy这个边车,也同样带来性能下降是一致的。就是说你从引入这个新框架,给业务和团队带来的收益,能否覆盖引入这个新框架带来的损失?你是否接受这样的损失,这个损失是否可能会被你们团队或者社区优化?这些问题考虑清楚的话,才可以下决策或者判断。在我们落地的实践中,我们尚未对Queue Proxy本身进行调优,这块我们的计划是等社区成熟到一定版本之后,再考虑自己的优化,不要Hit a running target。举个反例,我们之前曾对Kubernetes,Istio做过一些改造,但是由于版本更新很快,最后带来的兼容性问题,升级升不了等问题也很多。所以我的方法论是稳定之前不要提前优化,不要过度优化。
Q:Istio框架中对于网络请求的来源IP是如何通过应用层获取到的呢?一般来说IP地址会被换成Sidecar的地址或者是被Kubernetes的LB换成Node的主机地址。当然有一种办法是在请求进入Kubernetes前面加Reverse Proxy,写入HTTP header。除此之外,还有什么比较好的办法吗?
A:这块似乎不是一个服务网格或者Kubernetes的问题吧,HTTP请求里面有多个header跟IP相关,例如x-forwarded-for,real-ip等等,你只要保证网关层没有丢掉这些header,其他中间层透传了这些header,应该不会遇到拿不到客户端IP的情况啊。我遇见过的类似情况都是因为某些业务需求魔改了Nginx导致的。不魔改应该不会出这么基础的问题。
Q:Custom Gateway在Istio框架中是怎么实现的呢?Custom Gatway 如何与Istio的Gatway共存?例如 WAN -> Istio Gatway(all-to-my-own-gatway) -> my gatway -> back to istio gateway(routing) -> Microservice 是一个好的设计么?
A:你说的两种Gateway共存我没遇见过,不好说。我们内部的网关都是自己的写的,可以当作一个Service来使用,严格来说不跟Istio Gateway并列。你说的这个链路我直观感觉是太长了,可能不是个最优设计。
Q:当前Knative成熟度怎么样?是否生产上使用,能否介绍下踩了哪些坑?
A:比较成熟,可以在生产上小规模使用(大规模使用建议等他发布1.0)。大坑在分享中已经提到过了,小坑不少,可以举几个例子,由于我们自己改了Kubernetes的源码导致Knative的activator不能正常扩缩容;新的Revision卡住起不来;Webhook组件偶尔不正常工作,这些小坑最后也都解决了,不是什么重大影响。
Q:Microservice统一配置管理,有什么比较好地解决方式么?尤其是对生产数据库**的下放。
A:这个问题应该是放在配置中心或者数据库中间间里?这应该是一个服务治理的基础问题吧,很多公司和团队解决过了,可以搜一下Nacos,TDDL,etcd等。
Q:你认为当前Knative存在哪些框架上的问题和缺陷?这些问题社区进展怎么样?
A:冷启动时间太长,这个社区有专项跟踪,应该会不断优化;Proxy臃肿,这个社区里似乎还不急,现在只能作为一个前提来接受了;还有一些杂七麻八的管理问题,这些肯定会被社区逐步完善,或者会出现专门管理Kantive的三方系统。个人觉得Knative社区进取心还是可以的,缺点是人比较少,劳动力不足。
Q:Knative的冷启动情况是怎么样的?有没有什么监测数据可以共享一下。官方说会有10s以上的冷启动时间且至今无解。相比AWS Lambda的冷启动时间会短很多。https://github.com/knative/serving/blob/master/docs/roadmap/scaling-2019.md
A:AWS的冷启动做的已经非常好了,他们里面有很多优化。我们自己内部一直在关注。我们的Benchmark是找最简单的Go语言的helloword服务,关闭istio-proxy,做好镜像在host机器上的缓存,然后测冷启动平均值,这个值已经从0.8版本的4秒下降到现在的3秒左右了。社区还是在不断优化的。
Q:你们灰度发布也是放在CI流程里面的,还是Ops team手动发布的?
A:放在CI流程里,可以选择手动触发或者通过API触发(CI主要是使用的GitLab-CI)。
Q:兼容原有服务体系这块可以再详细介绍下吗?比如Dubbo的Provider是否可以一部分在原有服务体系,一部分在Istio里?
A:兼容原有服务体系本质上就是能让两边服务互相调用。这个严重取决于你原来的服务治理体系的情况,因为我们的服务体系是魔改+自建的,所以可能对你直接参考意义不大,Dubbo这个问题我不是专家。
Q:Knative部署的服务初始资源多少(CPU,内存)?什么条件去扩容和缩容?
A:如果Queue Proxy和Istio Proxy都在,那么起步要80M内存 + 你的业务服务内存。扩容缩容看你用的是什么组建了,Kubernetes的HPA用的是CPU或者自定义指标,Knative的KPA用的是并发量。
基于Kubernetes的DevOps实战培训
基于Kubernetes的DevOps实战培训将于2020年6月19日在上海开课,3天时间带你系统掌握Kubernetes,学习效果不好可以继续学习。本次培训包括:容器特性、镜像、网络;Kubernetes架构、核心组件、基本功能;Kubernetes设计理念、架构设计、基本功能、常用对象、设计原则;Kubernetes的数据库、运行时、网络、插件已经落地经验;微服务架构、组件、监控方案等,点击下方图片或者阅读原文链接查看详情。