在云原生技术全面爆发之前,我们开发的应用可以被称为非云原生应用,非云原生应用并没有考虑到应用的弹性和规模性,甚至很多都不具备扩展性,当业务规模扩大时,特别依赖硬件的升级,进而带来了很多问题。云原生的出现带来了新的开发方式,然而这一技术处于快速的发展过程中,导致很难定义清楚各类概念和理解各种技术名词,本文采访了京东云中间件团队负责人李道兵,了解京东云在云原生领域的理念和相关探索,以期对开发者有所帮助。
如今,企业很难在聊云原生这个话题时避开容器,但是往回倒四年,容器在国内的应用并不普遍,大多集中在技术实力较强的互联网大厂,但也并非后来大火的 Docker,当时的不少文章还将这群早期实践者称作“敢于吃螃蟹的人”。显然,在云原生领域,容器的发展是推动其落地的重要条件,但最大的需求并不是为了使用容器,这个逻辑本身就很奇怪,为了出现而出现的技术往往不会有好的结局,容器所解决的问题才是组织或开发者最大的需求。那么,组织现阶段对云原生实践最大的需求是什么呢?
过去几个月,InfoQ 先后就云原生这一话题采访了阿里巴巴、腾讯、青云、居然之家、华为等众多厂商,对值得关注的开源技术及相关落地实践进行了初步探索。本文,InfoQ 对京东云中间件产品研发部高级总监李道兵进行了独家专访,了解京东云在云原生领域的理念和相关探索。
云原生理念
关于云原生,其实每篇相关文章都会特意留出一部分讲解企业的理念,也多次提到了 Pivotal 公司的 Matt Stine 写的一本叫做迁移到云原生应用架构的小册子以及 CNCF 在今年 KubeCon 上海站提出的定义(V1.0):
云原生技术有利于各组织在公有云、私有云和混合云等新型动态环境中,构建和运行可弹性扩展的应用。云原生的代表技术包括容器、服务网格、微服务、不可变基础设施和声明式 API。
但是,正如李道兵在接受采访时所言:“与其说云原生涉及了众多理念,不如说现在社区还没有找到最佳实践应该是什么样子。”正因如此,每篇文章都会花费一些篇幅介绍本文所讨论的云原生理念的范围。
相比于“云原生”这个名字的诞生,李道兵认为这一概念的出现可以追溯到更早之前。
2008 年,通过将 cgroups 的资源管理能力和 Linux Namespace 的视图隔离能力组合在一起,LXC(Linux Container)这样的完整的容器技术出现在了 Linux 内核当中。当然,在这之前的虚拟机的概念此处就不赘述了,李道兵介绍道,LXC 比虚拟机轻量很多,但可以达到大部分虚拟机的效果,隔离性和安全性却不够好。
在这之后,Docker 项目的正式发布是对云原生领域产生深远影响的重要事件。李道兵补充道,Docker 真正的成功在于 Docker Hub,也就是官方维护的公共仓库,其内存储了大量镜像。其次就是构建镜像的方法,Docker 构造镜像的方法比其他的简单很多,也能更轻松地利用其他人的已有成果。总之,Docker 的出现大幅降低了微服务的运维负担,让微服务能真正成为一个可以大面积推广的技术。在服务拆分之后,组织就会出现服务治理的需求,包括服务发现、服务伸缩、日志收集、问题定位等,随即就出现了很多类似 Mesos、Kubernetes 的技术,做服务的方式由原来的用 Java 写完后跑在 Tomcat 上演变成将服务部署在容器之上,再利用 Kubernetes 进行管理,开发者已经不需要操心服务器的事情,这一系列由此产生的新理念可以称之为“Cloud Native(云原生)”。
不难看出,容器是云原生得以落地的重要条件,但这背后的真正诉求则是开发者对服务治理和去运维化的需求,可以认为在云原生时代,系统运维这个角色可能完全消失掉,因为不需要操心服务器,自然就无运维,容器镜像可以直接将一个应用运行所需的完整环境,即:整个操作系统的文件系统全部打包进去,这才是容器得以大面积普及的原因。换句话说,这样的服务交付方式才是开发者的真正诉求。
云原生最佳实践
正如开篇所言,现在谈到云原生实践很难避开容器这个话题,同样也很难避开 Kubernetes(k8s),这就好像曾经的 Hadoop 是大数据领域的事实标准一样,但 Kuberntes 的复杂性也是有目共睹的,李道兵表示:“我承认 Kubernetes 底层体系的重要性,但它的接口真的不够简单。相比较而言,早些年谷歌推出的 Google App Engine 反而是对未来很好的示范,但很可惜,由于种种原因(当时云的概念还没有起来、在 AppEngine 写一个有状态服务非常困难、对 AppEngine 的性能分析和优化困难等),Google App Engine 并没有获得很好的反响。但就这个层面来讲,未来,我们应该可以得到比 Kubernetes 友好得多的界面。”
既然如此,为什么 Kubernetes 顶着“复杂性”的帽子还可以发展得如此迅速呢?李道兵认为,首先,底层的复杂性是不可避免的,开发者只能在上层通过合适的抽象来简化使用界面;其次,过去几年采用 K8s 大都是技术好的团队,他们能驾驭这种复杂性,同时还能从底层的灵活性中获益。但最近几年随着 K8s 的更广泛采用,这个问题就愈发严重了,也有很多项目在尝试解决这个问题。
那么,K8s 是否会被新的框架取代呢?李道兵认为这个问题可以类比为编程语言来看待,比如“Java 就足够好到把所有编程语言都比下去吗?”这也未必,当年,Java 确实好到足以淘汰 COBOL(现在依旧有一些企业在使用),但一旦 Java 被大面积采用,你淘汰 Java 就需要比 Java 好一个数量级的语言出现。所以,尽管出现了一些针对 Java 作出改进的语言,比如 Groovy、Scala 等,但仍然无法撬动 Java 在企业市场的占有率,毕竟对于整个 IT 业界,做出决定更换编程语言是要耗费很多成本的。同理,Kubernetes 还是有非常多优点的,并且已被广泛采纳,所以要被取代其实很难。
如今,在 Kubernetes 上进行探索的大部分企业以技术见长的互联网大厂为主,这些企业有动力也有能力选择 Kubernetes,因为搞得定。但是,为了面向更加广泛的用户,Kubernetes 社区一直没有停止在这个领域的持续探索,并已经取得一些关键性突破。因此,云原生领域的核心技术其实是处在不断的发展和变化之中,现在很难对最佳实践给出定论。
京东云的云原生实践
京东云虽然是一个云服务的提供者,但其内部也需要进行云原生改造,比如京东云提供的对象存储服务,其下的数十个组件同样有服务治理的需求。因此,京东云在这个过程中有很多 Service Mesh 相关实践,主要是通过 Service Mesh 的 sidecar 将原本需要写在代码中的逻辑替换掉,而微服务改造和容器化可以认为在此之前已经陆续完成(如果对这部分感兴趣,可以阅读《专访京东云:愿云原生不再只有 Kubernetes》,本文不作为重点介绍)。
在 Service Mesh 方面,目前比较有代表性的开源工具就是 Istio。
如上图,Istio 的核心组件主要包括 Proxy 代理、Mixer 混合器、Pilot 引导、Citadel 堡垒和 Galley。其中,Proxy 代理的代理组件主要是 Envoy,用来拦截所有想拦截的流量;Mixer 混合器混合了各种策略以及后端数据采集或遥测系统的适配器,实现了前端 Proxy 与后端系统的隔离与汇合;Pilot 引导提供了一系列 rules api,允许运维人员指定一系列高级的流量管理规则;Citadel 堡垒管理着集群的密钥和证书,是集群的安全部门;Galley 主要是用来验证用户编写的 Istio api 配置。
目前来看,Istio 并没有太大的问题,但李道兵表示,Envoy 可能成为 Istio 发展的阻碍,Envoy 本身是用 C++编写的,主要由核心团队维护,社区参与度一般。Envoy 支持了多种调用机制,但仍然不能满足部分工业界的需求(比如 Backup Request),而 Envoy 的复杂性又限制了使用者自行扩展,不排除未来 Envoy 会被更灵活的 Sidecar 组件替代掉。
除此之外,过去一段时间,京东云在 Serverless 层面进行了大量实践,这也是京东云整体改造中非常重要的一个环节。
Serverless 实践
2019 年,Serverless 被 Gartner 称为最有潜力的云计算技术发展方向,并被赋予是必然性的发展趋势。Serverless 从底层开始变革计算资源的形态,为软件架构设计与应用服务部署带来了新的设计思路。在行业内,对 Serverless 的解读并没有公认的准确定义,京东云认为 Serverless 技术目前有三种实现:
真正的无服务器,就是所谓的函数计算 FaaS;
类似京东云的原生容器,容器直接呈现给用户,并且背后不需要有虚拟机来支持;
应用比较广泛的无服务器,背后虚拟机由云厂商来提供,但是对用户不可见,仍然是以虚拟机的方式来提供容器。
目前,京东云在 Serverless 还在开发中,完整的 Serverless 实践需要包括如下几个模块:
负责提供计算能力的 FaaS
负责提供通信能力的 Queue Service 和 Notification Service
负责提供持久化能力的 Serverless KV 和 Object Storage
负责提供入口的 API Gateway
负责提供编排能力的 Step Function
京东云已经提供了 FaaS, Queue Service, Object Storage 和 API Gateway, 其他模块也会在近期陆续发布。
FaaS
在 FaaS 层面,京东云和 AWS 的 Lambda 以及 Azure 的 Function 类似,都是需要用户提供一段代码,这段代码以 HTTP 的入口形式可以访问。代码可以用 Java 等多种语言写出,处理完用户请求后给出一定反馈,整体代码的生存周期就是请求的处理过程。代码是由函数计算来提供包括 CPU、内存、语言平台等运行环境,用户完全不用关心代码运行在什么地方。
当并发请求非常多时,平台就会运行这段代码容器的多个副本,这样就能做到:用户无需预留计算资源,仅根据调用的时长、次数来付费。这种情况是目前为止计算资源能做到的最小化分配粒度。粒度越小时,越有可能填满服务器的计算能力,粒度越大,后期就可能有越多的计算能力被闲置。
李道兵表示,FaaS 的优势和劣势都很明显,主要优势包括:彻底的无运维、近乎无限的伸缩能力和零启动成本。劣势则包括:冷启动比较慢,相对常规服务延时较高、压力稳定时没有成本优势。不过这些劣势并不是 FaaS 的本质造成的,而是可以解决掉的问题,在解决掉这些问题之后,FaaS 就能获得更大的适用范围和更远大的前景。
现阶段,FaaS 比较适合的应用场景主要有两类:一是事件驱动型应用,比如 IoT、网页游戏等类型;二是实验性项目,这类项目租用虚拟机的成本比较高,而 FaaS 几乎是零成本,不调用的情况下不会产生开销。目前还有一个趋势是逐步用 FaaS 取代 AppEngine。京东云目前将 FaaS 应用在多媒体内容分析处理和 Serverless 后端服务两个场景:
通过对象存储上传事件可以触发多个函数,完成实时图片或文件筛选、转存、创建缩略图、转换视频编码等处理分析。通过事件触发机制,您能够快速部署复杂的应用与服务,构建一个弹性、可靠的后端系统。
通过函数服务和 API 网关构建后端,以验证和处理 API 请求。采用函数服务构建可灵活拓展架构,轻松创造丰富、个性化的应用程序体验。
如上,京东云目前的 FaaS 主要支持 Python 2&3 和 Nodejs 6&8,这两者是目前 FaaS 适用场景中使用较多的语言,而接下来也会陆续支持 Java 和 PHP 等编程语言,毕竟几行代码就可以处理的事件通常开发者更愿意用 Python 而不是 Java。笼统地说,可以通过 K8s 和 Docker 来实现的服务,也可以选择用 FaaS 实现,但要认清楚 FaaS 的优劣。李道兵表示,FaaS 的冷启动是业界目前在共同努力解决的问题,这个概念很好理解,就是指函数第一次调用时平台部署函数实例的过程。
在本地调用函数时,响应基本是实时的,而云上的 FaaS 需要部署计算环境,这个过程的时间从数百毫秒到数秒不等,难于应对时延敏感型应用;此外,FaaS 的优势是极度弹性伸缩,这让其在调用量下降时会进行资源回收清理,下次调用时则又需要冷启动,这个过程一直反复存在于服务的整个生命周期中。
李道兵表示,京东云在这方面进行了不少尝试,主要可以分为两部分:一是加快原生容器(下文将介绍这一概念)和云硬盘的启动速度,甚至说在云硬盘加载之前先按需加载数据;二是预留部分实例,需要的时候再启动,不过这未必适合所有场景,当 FaaS 运行在客户的 VPC 中时,使用的是 VPC 中的资源,第二种方案暂时并不适用。
目前,业界也有一些方案,比如 Kata、Firecracker 对 qemu,虚拟机镜像做裁剪来加速虚拟机的创建和启动,但是效果并没有那么好。李道兵表示,虚拟机启动慢的问题并不是第一天出现,因此没有那么好解决,而容器的问题则是安全性不够高,如果容器足够安全,也不需要造虚拟机了,直接物理机上运行可以节省不少时间,而原生容器算是平衡各种利弊后的一个不错的尝试。
队列服务
根据了解,京东云的队列服务(Queue Service)是一项基于 Serverless 架构的全托管消息队列服务,它可以提供高可靠并且几乎无限扩展的托管消息队列。
如上图是队列服务的架构图,主要分为底层分布式存储、功能及解决方案、安全管理及用户接入四层,其特点是毫秒级自动伸缩和无规格限制。在消息类型上,标准队列理论上无限制的 TPS 上限,最大努力的消息排序以及至少一次消息传达;FIFO 队列保证消息的传达顺序与消息发送顺序一致以及精确的一次性处理。主要的应用场景是如下两种:
异步解耦,削峰填谷。上下游系统处理能力存在差距的时候,利用队列作为数据的缓冲器,增加系统架构的可用性和可靠性,平滑处理峰值流量,解耦系统架构,避免对业务主流程的影响。
性能扩展,容错处理。由于队列服务会解耦分离用户应用的处理进程,因此对于有扩展需求的应用,可以轻松提高从队列服务发送或接收速率来增加用户应用的处理能力,对于部分故障的模块可以从整个系统中摘除。
原生容器
原生容器与普通意义的容器还是有一些差别,通常容器会被认为是在 PaaS 层,由 PaaS 团队负责,而原生容器在京东云内部属于 IaaS 团队,这也可以看出原生容器与底层的关联比较密切。简单来说,可以将原生容器理解为普通容器和削薄后的虚拟机的结合体。
如上文所言,容器的安全性和隔离性是很大的问题,一旦容器被入侵,入侵者很容易通过穿透容器到达下面的物理机,从而影响整个云平台上的用户,虽然这也是老生常谈的问题,但要想既保证性能和启动时间不受影响,又达到更高的安全级别,这本身就是一件棘手的事情,常规的安全手法成本又太高,最好的方式是将虚拟机隔离起来,通过这个弥补容器安全性上的不足,当容器被入侵时,入侵者不至于影响整个云平台的用户。同时,原生容器对虚拟机做了大幅简化,资源损耗和启动时间均有所降低,这就是所谓的原生容器的概念。坦白地说,用户申请的每一个原生容器里面跑的就是一个 Docker 或者 Pod。
在原生容器方面,京东的产品推出时,Kubernetes 还没这么流行。所以为了实现节点容量的无限大,是通过一个叫 virtual kubelet 的插件让 Kubernetes 集群拥有一个虚拟节点。而如今,原生容器完全看用户需求。如果是一次性的任务处理批量计算工作,这种方式非常有效,因为虚拟节点可能会在某些方面不能实现 Kubernetes 所有的接口,某些特殊应用可能需要一定的适配工作,例如 daemonset。京东云正在考虑把原生容器运行的节点暴露出来,并提供和现在 Kubernetes 所有接口兼容的一个应用。而在 Docker 方面,京东云希望能向轻量化发展,可以随时创建、随时销毁,并且可以随时随地创建更多的副本。
此外,京东云也希望能将原生容器和 Kubernetes 通过比较紧密的方式结合在一起。比如在 Kubernetes 里的 Kata Container,其在 Kubernetes 里使用了更安全的容器;还有 Rancher Labs 基于 K8s 推出的轻量级的 Kubernetes 发行版 K3s,可以满足在边缘计算环境中运行在内存和处理能力受限的小型、易于管理的 Kubernetes 集群日益增长的需求。
结束语
面向未来,京东云的整体目标还是希望在云原生领域有更多投入。李道兵表示,具体来说,在 Service Mesh 方面达到更好的透视遥感能力,如果是较大调用量的分析需要很好地分析服务之间的关系以及出现瓶颈和延迟的原因,甚至在开发者不需要增加代码的情况下就可以享受这些功能。
在 Serverless 层面,需要进一步优化 FaaS 的冷启动能力,大幅缩短启动时间至毫秒级别,并尽可能降低延迟,因为现在需要过的层和转换的协议还比较多,这部分消耗的时间需要尽量减少,并增加更多语言支持,将界面简化到接近当年 Google App Engine 的样子。
作者简介:
京东云中间件产品研发部高级总监,先后在金山、盛大云、七牛云等公司工作,曾任盛大云资深研究员,七牛云 SVP 兼首席架构师等职位。作为开源项目的爱好者,李道兵曾担任 Debian Developer、维基百科中文管理员,维护 iso-codes 等开源方面的工作。 关注服务安全、架构健壮性(高可用、可测试、可追溯)等领域,主导了多个高压力项目,推崇高可用、可伸缩、低耦合的架构设计。目前,京东云函数服务正在公测,点击链接可以申请试用,想了解京东云更多云原生技术实践可以关注京东云开发者社区。
评论 2 条评论