《英雄联盟》在线服务运维之道 - 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集群,包含了一个主数据库和多个 从数据库。

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

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系统的灵感来自

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

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

• 集成Contrail和Docker;

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

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

• 在AWS上运行叠加网络;

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

持续集成

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

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

动态地运行应用程序

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

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

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

一些关键问题:

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

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

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

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

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

  1. 利用jenkins和docker实现持续交付

    利用jenkins和docker实现持续交付 一.什么是持续交付 让软件产品的产出过程在一个短周期内完成,以保证软件可以稳定.持续的保持在随时可以发布的状况.它的目标在于让软件的构建.测试与发布变得更 ...

  2. Docker学习总结(14)——从代码到上线, 云端Docker化持续交付实践

    2016云栖大会·北京峰会于8月9号在国家会议中心拉开帷幕,在云栖社区开发者技术专场中,来自阿里云技术专家罗晶(瑶靖)为在场的听众带来<从代码到上线,云端Docker化持续交付实践>精彩分 ...

  3. Docker学习总结(8)——利用Docker开启持续交付之路

    持续交付即Continuous Delivery,简称CD,随着DevOps的流行正越来越被传统企业所重视.持续交付讲求以短周期.小细粒度,自动化的方式频繁的交付软件,在这个过 程中要求开发.测试.用 ...

  4. BumbleBee: 如丝般顺滑构建、交付和运行 eBPF 程序

    本文地址:https://www.ebpf.top/post/bumblebee 1. 前言 不久前,Solo.io 公司在官网博客宣布了开源了一个名称为 BumbleBee 的新项目.该项目专注于简 ...

  5. Docker网络讲解 及实验redis集群部署

    理解docker0 准备工作:清空所有的容器,清空所有的镜像 docker rm -f $(docker ps -a -q) # 删除所有容器 docker rmi -f $(docker image ...

  6. Docker第一弹:下载运行hello-world程序

    1.需要安装好docker程序 没有安装的请看在centos 6.8下安装docker 2.从docker镜像仓库中拉去hello-world镜像 docker pull hello-world 3. ...

  7. 初识容器和Docker

    什么是Docker? Docker 是一个用于开发,交付和运行应用程序的开放平台.能够就应用程序和基础架构分开,从而可以快速的交付软件. 借助Docker可以和管理应用程序的方式来管理基础架构. 使用 ...

  8. Jenkins自动化部署-----持续交付【转】

    感谢之前带领过我的leader,让我能够知道什么是好的开发方法. 在很早之前就接触过敏捷开发.什么是敏捷开发,简单来说就是让软件可靠地,快速地发布出来的一种开发方法和技巧. 而敏捷开发中有许多的实践, ...

  9. Jenkins自动化部署——持续交付

    感谢之前带领过我的leader,让我能够知道什么是好的开发方法. 在很早之前就接触过敏捷开发.什么是敏捷开发,简单来说就是让软件可靠地,快速地发布出来的一种开发方法和技巧. 而敏捷开发中有许多的实践, ...

随机推荐

  1. Loki 初体验

    Loki 是什么 Loki 是 Grafana Lab开发的一套日志系统,使用Go语言实现.根据官方的介绍, Loki,高可用性,多租户的日志聚合系统,受到Prometheus的启发.它的设计非常经济 ...

  2. IDEA使用SVN上传项目

    文章最后附上svn服务器和客户端下载地址 一.IDEA集成SVN 二.查看SVN仓库 调出svn视图: 连接svn服务器: 连接后效果如下: 忽略上传文件 忽略文件如下:可以选择按规则匹配 .idea ...

  3. ArrayList哪种遍历效率最好,你真的弄明白了吗?

    ArrayList简介 声明:以下内容都是基于jdk1.8的 ArrayList 是一个数组队列,相当于 动态数组.与Java中的数组相比,它的容量能动态增长.它继承于AbstractList,实现了 ...

  4. Java虚拟机详解04----GC算法和种类

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...

  5. 学习Promise异步编程

    JavaScript引擎建立在单线程事件循环的概念上.单线程( Single-threaded )意味着同一时刻只能执行一段代码.所以引擎无须留意那些"可能"运行的代码.代码会被放 ...

  6. ProceedingJoinPoint 某些方法记录一下

    转载与百度知道,记录一下.遇到在去看API 官方文档//拦截的实体类 Object target = point.getTarget(); //拦截的方法名称 String methodName = ...

  7. 【分布式锁的演化】“超卖场景”,MySQL分布式锁篇

    前言 之前的文章中通过电商场景中秒杀的例子和大家分享了单体架构中锁的使用方式,但是现在很多应用系统都是相当庞大的,很多应用系统都是微服务的架构体系,那么在这种跨jvm的场景下,我们又该如何去解决并发. ...

  8. java中byte,byte[]和int之间的转换

    1>byte类型转换为,直接隐式转换,适用于要求保持数值不变,例如要求进行数值计算 如 byte b=0x01; int i=b; 2>另一种是要求保持最低字节中各个位不变,3个高字节全部 ...

  9. VoltDB成功入选CNCF Landscape云原生数据库全景图

    近日,VoltDB正式入选 CNCF Landscape(可能是目前其中唯一的关系型分布式内存数据库).此次VoltDB 进入 CNCF Landscape,意味着 VoltDB 正式成为了 CNCF ...

  10. linux操作系统可以ping通ssh连接长时间无响应

    一.问题描述 某集群数据节点服务器频繁无法连接,服务器间出现可ping通但ssh无法连接的情况,使用带外地址登录后远程控制也无法显示正常界面,重启后会短暂恢复. 二.排查问题 重启服务器后检查服务器S ...