未来的Kubernetes将效仿Facebook的做法
【编者的话】如今,Kubernetes最大管理大约5000个节点,这不但与Borg或Tupperware的可扩展性相去甚远,而且做不到无感知地调度不同区域的节点。本文通过介绍Tupperware与Delos背后的一些思想以及完成的一些工作,最终Facebook能够随时随地使用其全球资源,而不再考虑数据中心和区域。
如果你想知道Kubernetes容器管理系统的未来会是什么样子,那么Facebook自2011年以来一直在使用和发展的封闭源代码、自主研发的Tupperware容器控制系统(Docker容器以及Kubernetes出现之前)可能是一个很好的灵感来源。
Kubernetes是5年前由谷歌开源的,并不是说谷歌内部Borg和Omega集群以及容器控制系统对Kubernetes没有很好的启发。实际上,谷歌并没有直接拉取Borg代码,将其关键信息清理干净,然后将其转储到GitHub上,而是用Go编程语言(谷歌也创建了这种语言)从零开始创建了Kubernetes,并在周围建立了一个社区,取得了巨大的成功。在这一点上,没有人会因为选择Kubernetes作为应用程序构建的下一代容器编排平台而被解雇。
但这并不意味着Facebook等其他超大规模公司没有遇到大规模的问题,也没有以Kubernetes没有努力解决或解决的方式来解决这些问题,即使谷歌在内部也面临着与Borg和Omega类似的问题。遗憾的是,Facebook不会创建一个开源版本的Tupperware容器集群和控制器,或新的Delos存储服务支撑当前迭代控制平面的Tupperware,这两者都是在上周晚些时候Facebook的系统规模活动上讨论的。
Tupperware系统的构建非常精确,能够运行Facebook的应用程序和数据服务,很难创建一个通用版本的控制器来整合和支持企业中运行的各种服务。谷歌的Borg和Omega也是如此,它花了相当大的努力重写了Borg和Omega的核心部分,使其成为一个通用的集群和容器控制器,老实说,Kubernetes平台尚未完成,即使五年来它已经取得了长足的进步。
简单地说,Chunqiang Tang是脸书负责Tupperware工作的工程经理,之前曾在IBM的TJ沃森研究中心负责云自动化研究,他向“next平台”讲述Facebook没有计划从Tupperware学习,然后应用它们,汇聚到Kubernetes,就像谷歌有一天可能做的那样。(已经有很多谷歌服务在谷歌云平台上运行在Kubernetes之上,而不是在Borg/Omega裸机上运行。)
虽然Facebook目前还没有计划开放与Tupperware一起使用的Delos低延迟、可插拔的应用编程接口数据存储,但密歇根大学计算机科学与工程教授杰森·弗林(Jason Flinn)曾与Facebook一起参与Delos项目,他暗示说,这个项目仅在一年前开始,在生产中仅使用了大约四个月,所以开放它还为时尚早,即使这样但从长远来看是有可能的。
关键是,在“系统规模”会议上披露的Tupperware和Delos的信息可以用来通知和激励其他集群和容器管理及存储子系统的工作,包括开源和闭源。毕竟,谷歌在2005年发布的MapReduce论文直接导致雅虎创建了Hadoop。
我们对Facebook在大规模运行基础设施方面提供的洞见感兴趣,正如对两组代码的技术细节感兴趣一样。这些见解适用于许多人,即使代码可能只适用于一个人。
就规模而言,Tang透露Kubernetes不能与Borg/Omega相提并论,当然也不能与Tupperware相提并论。当它首次推出时,Kubernetes艰难的在数百台服务器上运行,一年后它突破了1000个节点。根据Tang的说法,现在Kubernetes最大管理大约5000个节点。这与Borg或Tupperware的可扩展性相去甚远。谷歌和Facebook数据中心的物理集群跨越大约10万台机器,多个数据中心组成一个区域。在谷歌,这些物理集群被Borg分割成单元,在过去,这些单元平均有10000个节点,但有些被缩小到几千个节点,有些被扩大到高达50000个节点。
在Tupperware最初构思的时候,Facebook就像大多数数据中心一样,从机架、集群和数据中心的角度来组织Tupperware,而这些结构通常具有难以超越的物理配置。同样在2010年代早期,当时Docker容器甚至不存在(并且在很多年内不会投入到生产),所以Facebook起初使用chroot运行沙箱应用程序,这样它们就可以在一个物理的Linux服务器上同时运行,就像谷歌已经做了很长一段时间一样,随着命名空间的成熟,Facebook也采用这些来提供工作负载之间的隔离。
众所周知,由谷歌创建并捐赠给Linux社区的Cgroups和Namespaces是Docker和Linux容器的基础,而Facebook部署了Linux容器并在内部向一个方向扩展,Docker抓取了Linux容器并以稍微不同的方式对它们进行了进化(我们意识到,这过于简单化了)。我们的观点是,在容器化方面,Facebook比谷歌落后了几年,最终它也面临同样的问题,并以稍微不同的方式解决了这些问题。问题是,你不能通过集群级别的管理来提高效率,最终,你还是需要跨数据中心和区域。
如今,Tupperware不再考虑机架、集群和数据中心,而是提供了一个跨越一个区域的多个数据中心的抽象层,该区域可能有几十万台物理服务器,或者有时跨越全球多个区域。Tupperware已经从一个管理集群的操作工具发展成为一个有意识的工具,对于在Facebook上部署应用程序的程序员来说是件简单的事情,比如部署这个应用程序在普林维尔地区的不同数据中心运行,或者在普林维尔和卢拉数据中心部署这个应用程序,Tupperware根据可用性来计算。这不是无服务器计算——对我们来说这是一个愚蠢的术语——而是系统无管理计算,这是所有数据中心的最终目标,如果你想说实话的话(系统管理员不会这样做,除非他们计划成为公司雇佣的唯一剩余的现场可靠性工程师)。
对于Facebook来说,集群管理是一个很大的障碍,它使用了一个名为Resource Broker的工具来解决这个问题,该工具允许Facebook通过将工作从一个集群转移到另一个集群,并将集群松散耦合到调度程序,从而对集群进行维护。Resource Broker还监视Facebook所有服务器的容量和可用性。
一旦Tupperware调度程序和物理集群之间的链接断开,事情就开始变得轻松一些。现在,在每个区域或跨区域内,调度程序工作被切分,每个切分管理运行在Tupperware上的作业的子集,但关键是所有这些切分都被聚合起来,以显示所管理的所有服务器、容器和工作负载的单一视图。有趣的是,Tang说Tupperware调度程序中负责将容器分配到其管理下的服务器的分配器功能强大,足以在不分片的情况下处理整个Facebook区域(这并不意味着Facebook不会因为其他原因而将Tupperware碎片化)。在每台服务器上都有一个Tupperware守护进程,它将打开和删除容器,这些容器是使用BTRFS文件系统中的自定义格式创建的,并由systemd管理。
有趣的是,Facebook一直站在单套接字服务器的前沿,尤其是Yosemite微服务器,它们被广泛部署在Facebook上运行基础设施软件。这里是这样的效果,每个Facebook数据中心现在都有更多的物理服务器,如果没有更多的标准双套接字机器,可能会有更多的物理服务器,这会给Tupperware带来更多的负载,而摩尔定律(Moore’s Law)正在增加每个节点能够支持的核心,因此也就增加了容器的数量。因此,需要分割Tupperware的工作,但希望与Tupperware的界面保持透明。
但这里还有另外一个使命,最终,Facebook希望能够通过一个面板管理其整个机群,这将需要更多的Tupperware工作分片,以及与Facebook网络上的工作负载相关的类似存储分片。到目前为止,Facebook已经安装的服务器中只有20%包含在这个巨大的共享资源池中,但最终Facebook希望能够随时随地使用其全球资源,而不再考虑数据中心和区域。
这是另一个有趣的观察,Borg考虑工作负载的方式是,有在线工作和批处理工作,调度程序的主要工作是用批处理工作(如MapReduce数据分析工作)填充空闲的容量,直到在线工作(如填充搜索引擎请求)需要更多的容量。因此,这两种类型的工作在系统上交错进行,按需要按比例增加和减少它们的使用,以提高利用率。
Facebook采取了一种不同的方法,并在原始服务器级别进行思考。首先,使用微服务器时,每个服务器节点的原始计算量更小,因此与使用双套接字机器相比,可以分割的部分更少(这一点随着AMD Rome Epyc处理器的高内核数量而发生变化)。在Facebook,程序员被教导以这样一种方式编码,即使用他们在服务器上所能使用的所有容量。在每个区域的夜间,当新闻提要、Messenger、Web前端和应用程序的其他层没有被大量使用时,该区域的服务器节点将执行各种批处理工作,如MapReduce分析和统计机器学习(毕竟,并不是所有的东西都需要GPU才能进行深度学习)。因此,不必担心多少在线或批处理工作提供每个物理服务器上不同的容器与Resource Broker,Facebook将批处理或在线工作分配给每个服务器,确保它运行完整得到最有价值的消费。这是谷歌和Facebook之间一个有趣的区别,在Facebook中,容器实际上更像是一种部署机制,而不是工作负载隔离工具。
除了规模之外,还有一个领域是Facebook声称对Kubernetes有吹嘘的权利,那就是管理有状态的应用程序——比如Facebook网站、Instagram、Messenger和WhatsApp背后的数据库和数据存储,包括ZippyDB、ODS Gorilla和Skuba——而不是无状态的应用程序——比如构成Facebook应用程序前端的网络和PHP服务器。
Tupperware控制器上增加了一项名为TaskControl的服务,该服务查看应用程序对维护与其存储的有状态链接的依赖性,然后根据这些需求决定如何部署运行这些应用程序的容器,并根据需要更新和移动它们,而不会破坏该有状态链接,从而损坏或崩溃应用程序。TaskControl与一个名为ShardManager的数据服务协同工作,该服务决定数据在Facebook网络中的放置和复制。这一切都是自动完成的,程序员不必为此大惊小怪。
按比例控制按比例存储
正如你可能想象的那样,管理Tupperware和其他Facebook服务中的控制平面的数据是一项很大的工作,为此,Facebook正在谈论一种新的复制存储系统Delos,部署在Facebook堆栈的控制平面中,最终可能成为文件和对象存储的架构。
在Delos创建之前,Facebook软件的各种控制平面中使用的数据以各种不同的方式存储,有些使用MySQL,有些使用ZooKeeper,有些使用其他键值存储或数据库。与大多数公司一样,每个独特的应用程序似乎都需要一个独特的数据存储或数据库,具有自己的API、性能、容错和部署方法。控制平面的这些存储系统通常必须从头开始设计,并在每次向这些控制平面添加一组新特性时重写。这真是件麻烦事。
因此,Flinn告诉“Next平台”,Facebook放弃了使用Delos的单片存储系统设计。
Flinn解释说,Delos背后的想法是围绕可重构、虚拟、分布式共享块的新抽象构建一个存储系统,这允许我们满足控制平面的许多独特目标。所以你有了高可靠存储的标准:它必须是高可用的,它必须是强一致的。它还必须有一个相当丰富的API,其中包含一些类似于带有辅助索引的关系查询的内容,以及一些查询规划和复杂谓词。它还必须运行在各种各样的硬件上,我们最新的和最好的机器上,它们的存储空间肯定是最好的,但是它也应该运行在旧的机器上,这些机器可能与它提供元数据的服务位于同一位置。最后,在我看来,这方面最大的要求,也是Delos所提供的独特之处之一,就是它必须没有依赖关系,而且它的设计目标是在堆栈的底部。这简化了一些事情,比如打开一个新的数据中心、恢复工作等等。
Delos背后的关键思想是,所谓物化的数据状态与存储的顺序和持久性方面是分离的,并且可以从相对简单的日志构建具有不同级别容错或复制的更复杂的日志。像下图这样:
VirtualLog可以切换模式,以一种SimpleLog格式操作另一种SimpleLog格式,同时仍然在更高的具体化级别上维护状态,这就是关系、键值、文件系统和其他API对外公开的方式。这样做的好处是,可以在不破坏上层API层的情况下完全更改存储系统的底层,这意味着两件事:存储系统可以具有多个并发的特性,并且可以根据需要独立地更新不同的层。
Delos的第一个用例是创建一个名为DelosTable的关系系统,它位于Tupperware资源代理下面,取代了Facebook从Hadoop堆栈的开源ZooKeeper项目创建的定制ZKLog系统。起初,Facebook将DelosTable放在ZKLog之上运行,四个月后,它能够使用原生的SimpleLog格式替换掉ZKLog层,该格式基于LogDevice系统,Facebook在Tupperware生产软件环境中开放了一段时间。下面是运行Tupperware资源代理的每种不同日志格式的性能概要:
Flinn在Delos的帖子中解释说,我们根据延迟SLA在分解的日志设备排序层和聚合的本地日志排序层之间动态切换。当满足延迟SLA时,我们选择聚合实现(它使用更少的资源,并且没有关键路径依赖关系),当违反延迟SLA时,我们切换到分解实现。