前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >揭秘LOL背后的IT基础设施丨关键角色“调度”

揭秘LOL背后的IT基础设施丨关键角色“调度”

原创
作者头像
Tungsten Fabric
修改2020-06-11 17:40:06
5720
修改2020-06-11 17:40:06
举报

欢迎来到Tungsten Fabric用户案例系列文章,一起发现TF的更多应用场景。“揭秘LOL”系列的主人公是Tungsten Fabric用户Riot Games游戏公司,作为LOL《英雄联盟》的开发和运营商,Riot Games面临全球范围复杂部署的挑战,让我们一起揭秘LOL背后的“英雄们”,看他们是如何运行在线服务的吧。 作者:Kyle Allan和Carl Quinn(文章来源:Riot Games) 译者:TF中文社区

我们是Kyle Allan和Carl Quinn,在Riot的基础架构团队工作。欢迎阅读这个系列的第二篇文章,详细介绍我们如何在全球范围内部署和操作后端功能。在本文中,我们将深入探讨部署生态系统的第一个核心组件:容器调度。

在Jonathan的第一篇系列文章中,讨论了Riot的部署历史和我们面临的挑战。特别是,他概述了当我们为《英雄联盟》不断添加基础架构设施时,尤其是面对“为每个应用程序手动配置服务器”这样的场景下,我们软件部署难度不断加剧。后来,出现了一个名为Docker的工具,改变了我们的服务器部署方法——进一步在我们内部就迭代出来Admiral,它是我们用于集群调度和管理的内部工具。

重要的是,应用程序部署的旅程还远远没有结束,它还在不断发展,我们正在为下一个阶段做准备(可能采用DC/OS,稍后讨论)。本文介绍了如何到达这一步,以及为什么做出这样的决定,希望其他人也可以从这个故事中有所收益。

什么是调度(Scheduling),为什么要调度

当Docker横空出世,并且Linux容器化成为一种更广为人知的技术时,我们意识到,可以通过容器化基础架构的实施而受益。Docker容器映像提供了一个不变的、可部署的“神器”,它可以一次构建并部署在开发、测试和生产中。此外,它还保证生产环境中运行的映像的依赖性,与测试期间的依赖性完全相同。

另一个好处尤其重要:Docker允许将部署单元(容器)与计算单元(主机)解耦,它通过利用调度程序将容器分配给主机(希望以一种智能的方式),从而消除了服务器与应用程序之间的耦合——给定的容器可以在任意数量的可能的服务器上运行。

通过将后端服务打包成Docker映像,并且可以随时将其部署并扩展到服务器集群,我们应该能够迅速适应变化。我们可以添加新的玩家功能,当流量增加时进行扩容,并快速推出更新和修复程序。在考虑将容器内的服务部署到生产环境时,需要解决三个主要问题:

1. 给定一个主机集群,如何选择一组特定的主机来接收一组容器?

2. 这些容器实际上是如何在远程主机上启动的?

3. 容器“死机(或者关机)”时会发生什么?

这三个问题的答案是,我们需要一个调度程序——一种在服务集群层面运行并执行我们的容器策略的服务。调度程序是维护集群、确保容器在正确的位置运行,以及在容器退出时重新启动它们的关键组件。

例如,我们可能要启动诸如Hextech Crafting之类的服务,该服务需要六个容器实例来处理其负载。调度程序负责查找具有足够内存和CPU资源以支持这些容器的主机,并执行使这些容器运行所需的任何操作。如果这些服务器之一发生故障,调度程序还负责为受影响的容器查找替换主机。

当我们决定使用调度程序时,就快速进行原型设计,以便了解容器化服务在生产中是否适合我们。此外,我们需要确保现有的开放源代码选项可以在目前的环境中运行,或者确保维护人员愿意接受我们的调整。

为什么要自己写

在开始编写Admiral调度程序之前,我们调查了现有集群管理器和调度程序的状况。都有谁在Docker主机集群之间调度容器,它们是如何做到的?它们的技术还能解决我们的问题吗?

在最初的研究中,我们调研了一些项目:

Mesos + Marathon

  • 这些技术已经相当成熟并且可以大规模使用,但是安装起来却复杂且棘手,这使得它们难以进行尝试和评估。
  • 当时,它们对容器的支持还非常有限,没有跟踪Docker的快速发展,并且在Docker生态系统中表现不佳。
  • 它们不支持容器组(pods)——我们认为需要将sidecar容器与许多服务捆绑在一起(附注:sidecar是容器日志的一种模式)。

LMCTFY => Kubernetes

  • Kubernetes刚刚从LMCTFY演变而来,尽管它看起来很有希望,但尚不清楚它的未来发展是否能满足我们的需求。
  • Kubernetes还没有一个约束系统可以像我们需要的那样进行容器放置。

Fleet

  • Fleet是后来开放源代码的,当时还不够成熟。
  • Fleet似乎更专注于系统服务的部署,而不是常规应用程序服务。

我们还原型化了一个小型命令行工具,该工具可通过REST与Docker API进行通信,并且成功演示了如何使用此工具来协调部署。然后,我们决定继续编写自己的调度程序。

我们借鉴了研究过的系统的一些最佳功能,包括Kubernetes的Pods和Marathon的约束系统背后的核心思想。我们的愿景是跟踪这些系统的体系结构和功能,在可能的情况下影响它们,并最终尝试在将来与其中之一融合。

Admiral概述

在创建了一个基于JSON的基础部署元数据语言(我们称为CUDL,ClUster描述语言)之后,我们开始编写Admiral。CUDL成为Admiral在其REST API中使用的语言,两个主要组成部分如下:

  • 集群——一组Docker主机。
  • 打包(Packs)——启动一组一个或多个容器所需的元数据。类似于Kubernetes Pod加Replication控制器。

集群和打包具有两个不同的方面:spec和live。每个方面都代表对容器生命周期不同阶段的描述。

Spec,表示元素所需的状态

  • 从某些外部事实来源(如来源控制)发布到Admiral
  • 一经交付给Admiral便一成不变
  • Spec集群和主机描述了集群中可用的资源
  • Spec打包描述了运行服务所需的资源、约束和元数据

Live,表示元素已实现的状态

  • 镜像实际的运行对象
  • Live集群和主机镜像正在运行的Docker守护程序
  • Live打包镜像正在运行的Docker容器组
  • 通过与Docker守护进程通信,实现可恢复性

Admiral用Go编写,并且在生产数据中心中运行时,被编译并打包到Docker容器中。Admiral有几个内部子系统,其中大部分如下图所示。

从用户的角度来看,与Admiral的交互是通过其提供的admiralctl命令行工具进行的,该工具通过REST API与Admiral进行通信。借助admiralctl,用户可以通过标准指令访问Admiral的所有功能:POST新的Spec打包以进行调度,DELETE旧包(Packs),以及GET当前状态。

在生产过程中,Admiral将使用Hashicorp的Consul存储Spec状态,定期对其进行备份,以防发生灾难性故障。万一完全丢失数据,Admiral还能使用从各个Docker守护程序检索到的Live状态中的信息,来部分重建其Spec状态。

协调器(reconciler)属于Admiral的核心,是驱动调度工作流程的关键子系统。协调器会周期性地将实际的Live状态与所需的Spec状态进行比较,并且在出现差异时,调度所需的操作,以便将Live状态恢复正常。

Live状态及其驱动程序包通过缓存Live主机和容器状态,并通过其REST API提供与集群主机上所有Docker守护程序的通信,来支持协调器。

深度调度

Admiral的协调器可对Spec打包进行操作,有效地将其转换为Live打包。在将Spec打包提交给Admiral时,协调器将创建容器并使用Docker守护程序启动它们。正是通过这种机制,协调器实现了我们前面所述的最重要的两个高级调度目标。当协调器收到Spec打包时,它将:

1. 评估集群的资源和打包的约束,为容器找到合适的主机。

2. 知道如何使用Spec中的数据在远程主机上启动容器。

让我们看一下在Docker主机上启动容器的示例。在此示例中,我们将使用本地Docker守护程序作为Docker主机,并与Admiral服务器的本地实例进行交互。

首先,我们使用“admiral pack create <cluster name> <pack file>”命令启动一个打包。此命令针对特定集群,并将Spec打包的JSON 提交到Admiral服务器。

你能注意到,几乎在刚刚运行命令后,容器就已经在我的机器上启动。这个容器是使用我的打包文件中的参数启动的,如下所示:

接下来,在调用“admiral pack create”之后,我们可以使用“show”命令来查看Admiral创建的Live打包。这里的命令是“admiral pack show <cluster name> <pack name>”。

最后,通过点击容器中的服务,我们可以验证打包是否正常工作。使用来自“admiral pack show”命令的信息,我们可以通过一个简单的curl来拼出我们的服务:

在Admiral内部,协调器始终处于运行状态,以确保集群的Live状态始终与所需的Spec状态相匹配。这样,当容器由于崩溃而失败并退出,或者由于硬件故障而导致整个服务器不可用时,我们还可以进行恢复业务。协调器努力确保状态匹配,以便玩家永远不会遇到中断问题。此功能解决了我们前面提到的第三个,也是最后一个问题:当容器意外退出时,我们可以快速恢复,并且将影响控制到最小。

下面将展示通过“admiral pack create”命令启动的现有容器。然后,我将终止该容器,并停止其执行。在几秒钟内,协调器启动了一个新的容器(具有不同的ID),因为它意识到Live状态与Spec状态不匹配。

资源和约束

为了最好地分配容器,调度程序必须洞悉主机集群。解决此问题有两个关键组件:

资源——服务器可用资源的一种表示形式,包括内存、CPU、I/O,以及网络等其他资源。

约束——打包随附的一组条件,可为调度程序提供有关可放置打包的限制的详细信息。例如,我们可能要放置一个打包实例:

  • 在整个集群中的每个主机上
  • 在名为“myhost.riotgames.com”的特定主机上
  • 在集群里每个标记的区域中

通过在主机上定义资源,我们使调度程序可以灵活地决定将容器放置在何处。

通过在打包集(packs)上定义约束,我们可以限制调度程序的选择,以便将特定的模式强制应用到集群中。

结论

对于Riot而言,Admiral是我们部署技术不断发展的重要组成部分。通过利用Docker和调度系统的功能,我们能够比以前更快地向玩家交付后端功能。

在本文中,我们深入研究了Admiral的一些功能,并展示了如何在一组机器集群之间调度容器。就像Jonathan在他的第一篇文章中提到的那样,开源世界已经迅速转向非常相似的模型。展望未来,我们将转移Admiral的工作,并专注于部署DC/OS,它已成为调度容器工作负载的领先的开源应用程序之一。

如果你经历了类似的旅程,或者觉得自己有话要补充,非常欢迎与我们取得联系。


·END·

更多“揭秘LOL”系列文章

揭秘LOL背后的IT基础架构丨踏上部署多样性的征程


原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档