热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

容器调度•Docker网络•持续交付•动态运行应用程序部署的多元化

《英雄联盟》在线服务运维之道 - InfoQ https://www.infoq.cn/article/running-online-services-riot/

 

第一章 简 介

 

我是Jonathan McCaffrey,来自Riot公司的基础设施团队。在讲述我们 如何进行后端应用的部署和运维之前,首先要先了解一下我们是如何看待 我们的应用开发的。游戏玩家的价值对于Riot来说是至高无上的,我们的 开发团队经常与玩家社区互动,为了给玩家们提供最佳的游戏体验,我们 必须具备根据玩家反馈快速做出变更的能力。基础设施团队的使命就是为 开发人员提供支持,我们提供支持的力度越大,玩家们就能越快体验到最 新的功能。

当然,说起来容易做起来难!因为部署的多元化,我们面临着很多 挑战。我们有公有云服务器,也有本地数据中心,还要与腾讯和Garena 合作。这些环境的复杂性给开发团队增加了不少负担,于是就有了基 础设施团队。我们使用基于容器的内部云来简化部署,这个云叫作 “rCluster”。在这篇文章里,我将介绍Riot从手动部署到使用rCluster进 行部署的演变过程。为了更好地描述rCluster,我将以海克斯工匠系统 (Hextech Crafting System)作为例子。

 

历史背景简述

我在七年前加入Riot,当时我们并没有那么多部署流程和服务器管理 流程,我们还只是一个怀揣大梦想的初创公司。我们的预算很有限,做什 么事情都要求快。我们为《英雄联盟》构建了一套基础设施,努力满足游 戏不断增长的需求,为开发团队提供支持,同时还要支持区域团队拓展新 的疆域。我们通过手动配置服务器和应用程序,没有太多指南和战略规划 之类的东西。

后来,我们使用Chef来完成常见的部署和基础设施任务,使用公有云 进行大数据计算和提供Web服务。在这一过程中,我们多次重新设计了我 们的网络,也更换过供应商,甚至重组了整个团队结构。

我们的数据中心有数千台服务器,每新增一个应用程序就要添加新的 服务器。新服务器被接入手动创建的虚拟局域网,并手动配置路由和防火 墙规则来提升安全性。虽然这样可以提升安全性,但费时又费力。因为这 个痛点的存在,当时的新功能都被设计成小型的Web服务,导致《英雄联 盟》生态系统的服务数量大肆膨胀。

 

除此之外,我们的开发团队对应用程序的测试环节缺乏信心,在进行 部署时经常出现一些配置或网络连接问题。因为应用程序与物理基础设施 的耦合太过紧密,以致于生产环境与测试环境、Staging环境和公测环境 难以保持一致。

 

我们的应用程序数量一直在增长,我们也在经历着手动配置服务器 和网络的艰难过程。与此同时,Docker开始在我们的开发团队中流行起 来,用于解决配置和开发环境一致性问题。我们开始意识到,我们可以用 Docker做更多的事情,它可以在基础设施方面扮演一个更重要的角色。

 

2016 全明星赛及其他

基础设施团队的目标是为游戏玩家、开发团队和2016全明星赛提供支 持。在2015年底,我们从手动部署转向了自动部署,比如海克斯工匠系统 8 InfoQ 中文站 就使用了自动部署。我们开发了rCluster——一个全新的系统,它使用了 Docker和微服务风格的SDN(Software Defined Networking)。rCluster解 决了不一致性问题和部署流程问题,让产品团队可以集中在他们的产品研 发上。

 

接下来我们将深入探讨rCluster是如何支持海克斯工匠系统的。

海克斯工匠系统在我们内部被称为“战利品(Loot)”,由三个核心 组件组成。

• 战利品服务——一个Java应用程序,通过基于HTTP/JSON的REST API处理战利品请求。

• 战利品缓存——基于Memcached的缓存集群,并使用了一个Go语 言开发的小型边车(sidecar)来监控、配置、启动和关闭缓存集 群。

• 战利品数据库——一个MySQL集群,包含了一个主数据库和多个 从数据库。

在进入工匠系统时,会发生以下一系列事件

容器调度 • Docker网络 • 持续交付 • 动态运行应用程序   部署的多元化

 

 

1. 玩家在客户端打开工匠系统的屏幕。

2. 客户端向前端应用程序发起 RPC 调用,前端应用(也就是 “feapp”)就是玩家和后端服务之间的代理。

3. feapp向战利品服务器发起调用请求。 • feapp从“服务发现”(Service Discovery)中找到战利品服务 器的IP地址和端口。 • feapp向战利品服务器发起HTTP GET请求。 • 战利品服务器检查战利品缓存里是否保存着玩家的物品。 • 玩家物品不在缓存里,于是战利品服务向数据库发起请求,并 将返回的结果放进缓存。 • 战利品服务将结果返回给feapp。

4. feapp将RPC响应消息返回给客户端。 通过与战利品团队的合作,我们将服务器和缓存放进了Docker容器, 并使用JSON文件来定义它们的部署配置。 战利品服务器的JSON配置示例:

{
"name": "euw1.loot.lootserver",
"service": {
"appname": "loot.lootserver",
"location": "lolriot.ams1.euw1_loot"
},
"containers": [
{
"image": "compet/lootserver",
"version": "0.1.10-20160511-1746",
"ports": []
}
],
"env": [
"LOOT_SERVER_OPTIOnS=-Dloot.regiOns=EUW1",
"LOG_FORWARDING=true"
],
"count": 12,
"cpu": 4,
"memory": 6144
}

战利品缓存的JSON配置示例:

{
"name": "euw1.loot.memcached",
"service": {
"appname": "loot.memcached",
"location": "lolriot.ams1.euw1_loot"
},
"containers": [
{
"name": "loot.memcached_sidecar",
"image": "rcluster/memcached-sidecar",
"version": "0.0.65",
"ports": [],
"env": [
"LOG_FORWARDING=true",
"RC_GROUP=loot",
"RC_APP=memcached"
]
},
{
"name": "loot.memcached",
"image": "rcluster/memcached",
"version": "0.0.65",
"ports": [],
"env": [
"LOG_FORWARDING=true"
]
}
],
"count": 12,
"cpu": 1,
"memory": 2048
}

 不过要真正部署好它们,我们还需要创建一些集群,它们需要支持南 美、北美、欧洲和亚洲的Docker。我们因此需要解决一大堆问题:

 

• 容器调度

• Docker网络

• 持续交付

• 动态运行应用程序

后续的章节将会详细介绍这些组件,所以在这里先简要提及。

 

 

容器调度

我们自己编写了一款叫作Admiral的软件,并把它用在rCluster系统 里,进行容器调度。Admiral与一组物理机上的Docker后台进程进行通 信,以便了解它们的健康状态。运维人员通过HTTPS发送上述的JSON 请求,Admiral则用它们了解相关容器的状态。Admiral会持续地更新集 群的状态,并在必要的时候采取相应的行动。Admiral会根据实际情况向 Docker后台进程发起请求来启动或停止容器,从而达到预期的状态。 如果容器发生崩溃,Admiral会在另一台主机上启动一个新的容器。 这种灵活的机制让服务器的管理变得十分容易,我们可以无缝地“灭掉” 它们,做一些维护工作,然后再重启它们。 Admiral与开源工具Marathon有点像,我们目前也正打算使用Mesos、 Marathon和DC/OS的替代方案。如果这样可行,我们将会在后续的文章中 分享我们的经验。

 

Docker 网络

在容器可以运行了之后,我们还要为战利品应用程序和系统的其他 部分提供网络连接。我们使用OpenContrail为每个应用设置私有网络,然 后让开发团队使用托管在GitHub上的JSON文件来配置他们自己的网络策 略。 战利品服务器网络配置示例:

{
"inbound": [
{
"source": "loot.loadbalancer:lolriot.ams1.euw1_loot",
"ports": [
"main"
]
},
{
"source": "riot.offices:globalriot.earth.alloffices",
"ports": [
"main",
"jmx",
"jmx_rmi",
"bproxy"
]
},
{
"source": "hmp.metricsd:globalriot.ams1.ams1",
"ports": [
"main",
"logasaurous"
]
},
{
"source": "platform.gsm:lolriot.ams1.euw1",
"ports": [
"main"
]
},
{
"source": "platform.feapp:lolriot.ams1.euw1",
"ports": [
"main"
]
},
{
"source": "platform.beapp:lolriot.ams1.euw1",
"ports": [
"main"
]
},
{
"source": "store.purchase:lolriot.ams1.euw1",
"ports": [
"main"
]
},
{
"source": "pss.psstool:lolriot.ams1.euw1",
"ports": [
"main"
]
},
{
"source": "championmastery.server:lolriot.ams1.euw1",
"ports": [
"main"
]
},
{
"source": "rama.server:lolriot.ams1.euw1",
"ports": [
"main"
]
}
],
"ports": {
"bproxy": [
"1301"
],
"jmx": [
"23050"
],
"jmx_rmi": [
"23051"
],
"logasaurous": [
"1065"
],
"main": [
"22050"
]
}
}

 

战利品缓存网络配置示例:

{
"inbound": [
{
"source": "loot.lootserver:lolriot.ams1.euw1_loot",
"ports": [
"memcached"
]
},
{
"source": "riot.offices:globalriot.earth.alloffices",
"ports": [
"sidecar",
"memcached",
"bproxy"
]
},
{
"source": "hmp.metricsd:globalriot.ams1.ams1",
"ports": [
"sidecar"
]
},
{
"source": "riot.las1build:globalriot.las1.buildfarm",
"ports": [
"sidecar"
]
}
],
"ports": {
"sidecar": 8080,
"memcached": 11211,
"bproxy": 1301
}
}

一旦GitHub上的配置文件发生变更,就会启动一个传输作业,调用 Contrail的API来创建和更新应用程序的私有网络策略。 Contrail使用了一种叫作叠加网络(Overlay Network)的技术来实现私 有网络。在我们的系统里,Contrail在计算机主机之间启用了GRE通道, 并使用网关路由器来管理流经通道的流量。OpenContrail系统的灵感来自

容器调度 • Docker网络 • 持续交付 • 动态运行应用程序   部署的多元化

 

 于标准MPLS L3***,所以在概念上与之非常相似。

在实现这个系统时,我们必须解决一些关键性挑战:

• 集成Contrail和Docker;

• 允许rCluster之外的网络无缝地访问叠加网络;

• 允许不同集群之间的应用发生交互;

• 在AWS上运行叠加网络;

• 在叠加网络上构建高可用的面向边缘的应用。

 

持续集成

战利品应用程序的CI流程类似下面这样:

容器调度 • Docker网络 • 持续交付 • 动态运行应用程序   部署的多元化

 

 我们的主要目标是这样的:一旦主仓库发生变化,就会创建一个新的 应用容器,并将其部署到QA环境中。有了这个流程,我们的团队就可以 快速迭代他们的代码,并看到代码实际的运行情况。紧凑的反馈闭环加快 了改进用户体验的速度,这也正是Riot的关键目标——以玩家为中心,为 玩家提供最佳体验。

 

动态地运行应用程序

到目前为止,我们谈论了我们是如何构建和部署应用程序的,但如果 你曾经在这样的容器环境里工作过的话,你就会知道,我们要面临的挑战 远不止之前提到的那些。

在rCluster里,容器有动态的IP地址,而且一直在启动和关闭。这与之

前提到的静态服务器的部署方式是完全不一样的,所以我们需要新的工具 和流程。

一些关键问题:

• 如何监控容量和端点一直在变化的应用?

• 如果端点一直在变化,那么应用程序如何才能知道其他应用程序 的端点是什么?

• 如果不能通过ssh连接到容器上,而且容器日志在重启之后就会消 失,那么该如何进行问题诊断?

• 如果我们是在构建阶段预热(bake)容器,那么如何配置数据库 密码,或者如何为其他地区的容器配置不同的参数? 为了解决这些问题,我们开发了一个微服务平台,用于解决服务发 现、配置管理和监控问题,我们将在其他详述该平台的细节,以及它为我 们解决了哪些问题。

 


推荐阅读
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • PHP设置MySQL字符集的方法及使用mysqli_set_charset函数
    本文介绍了PHP设置MySQL字符集的方法,详细介绍了使用mysqli_set_charset函数来规定与数据库服务器进行数据传送时要使用的字符集。通过示例代码演示了如何设置默认客户端字符集。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • Oracle分析函数first_value()和last_value()的用法及原理
    本文介绍了Oracle分析函数first_value()和last_value()的用法和原理,以及在查询销售记录日期和部门中的应用。通过示例和解释,详细说明了first_value()和last_value()的功能和不同之处。同时,对于last_value()的结果出现不一样的情况进行了解释,并提供了理解last_value()默认统计范围的方法。该文对于使用Oracle分析函数的开发人员和数据库管理员具有参考价值。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了在Oracle数据库中创建序列时如何选择cache或nocache参数。cache参数可以提高序列的存取速度,但可能会导致序列丢失;nocache参数可以避免序列丢失,但在高并发访问时可能导致性能问题。文章详细解释了两者的区别和使用场景。 ... [详细]
  • 开发笔记:计网局域网:NAT 是如何工作的?
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了计网-局域网:NAT是如何工作的?相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 本文介绍了如何使用JSONObiect和Gson相关方法实现json数据与kotlin对象的相互转换。首先解释了JSON的概念和数据格式,然后详细介绍了相关API,包括JSONObject和Gson的使用方法。接着讲解了如何将json格式的字符串转换为kotlin对象或List,以及如何将kotlin对象转换为json字符串。最后提到了使用Map封装json对象的特殊情况。文章还对JSON和XML进行了比较,指出了JSON的优势和缺点。 ... [详细]
  • 本文介绍了如何使用jQuery和AJAX来实现动态更新两个div的方法。通过调用PHP文件并返回JSON字符串,可以将不同的文本分别插入到两个div中,从而实现页面的动态更新。 ... [详细]
  • 本文介绍了OkHttp3的基本使用和特性,包括支持HTTP/2、连接池、GZIP压缩、缓存等功能。同时还提到了OkHttp3的适用平台和源码阅读计划。文章还介绍了OkHttp3的请求/响应API的设计和使用方式,包括阻塞式的同步请求和带回调的异步请求。 ... [详细]
author-avatar
四川盛地地产顾问有限公司_255
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有