爱奇艺基于 Docker 的 App Engine 实践

1,683 阅读21分钟
原文链接: mp.weixin.qq.com

本文由谢恒忠根据 2016 年 1 月 24 日@Container容器技术大会·北京站上杨成伟的演讲《爱奇艺基于 Docker 的 App Engine 实践》整理而成。

大家下午好,我是来自爱奇艺的杨成伟,现在在爱奇艺公司负责弹性计算云方面的建设。

内容提要

今天我主要给大家介绍一下爱奇艺 App Engine(iQIYI App Engine,简称 QAE)的设计与实现。

爱奇艺从 2013 年年底开始接触 Mesos,在将业务接入到 Mesos 系统时,我们发现 Mesos 原生的隔离方案并不能很好的解决文件系统级别的隔离,业务非常受制于底层计算节点的环境,后来发现 Docker 在容器解决方案中初露锋芒,并且 Mesos 也开始加入对 Docker 的支持;所以我们顺势基于 Mesos 和 Docker 生态来搭建自己的应用引擎服务。

随着业务的接入,用户的反馈,QAE 的也逐步实现了很多功能,这里将详细的剖析 QAE 平台的架构,各个功能模块的设计与实现。由于经验有限,我们在实现 QAE 平台时,也趟过一些坑,填过一些坑,积累了一些设计和选型上的经验。

最后会分享一下 QAE 在爱奇艺的现状:包括业务的现状以及开发状态;以及一点前景展望。

背景、出发点、目标

背景——业务上

查看图片

爱奇艺在 IaaS(Infrastructure as a Service)方面起步比较早,公司大部分的业务都已经实现了从物理机到虚机的迁移;并且,在基础服务方面:像 DB、MQ 等重要服务几乎都已经实现了服务化,有专门的团队来提供高效,稳定的支持。

以此为背景,为什么要从虚机迁移到 Docker?

虽然我们已经实现了 IaaS 在公司内部的几乎全覆盖,但是,由于 IaaS 属于层级较低的服务,业务开发者对于虚机,特别是 Linux 操作系统并不是很熟悉,在部署,管理大量业务虚机的时候也会显得力不从心,从而也会加重 IaaS 平台运维的负担;除了运维方面,虚机和容器相比,在业务扩展性,灵活性方面也存在明显差距。

在爱奇艺内部,大部分业务都已经从物理机迁移到虚机(IaaS 平台),我们将这些业务按照服务类型笼统地概括为:

  • 后台服务,特指比较轻量的 HTTP/RPC 服务,一部分是基于 Java + Tomcat

  • Worker,长时间运行,获取任务并处理,返回结果

  • 其它,中间件、DB、搜索、推荐;开发、测试环境等

前两种类型的业务比较适合从虚机直接迁移到容器平台上来,介于虚机在公司内部的基数非常大,所以单单实现这些业务的 Docker 化也是非常艰巨的任务。

背景——技术上


我们在 2013 年年底的时候开始调研 Mesos,然后 2014 年上半年我们把公司大约 30% 左右的转码(图片、音频、视频)任务都已经跑在了 Mesos + Chronos 上,并且是基于 Docker 作为运行环境,随着几个重要 Chronos bug 的解决,业务运行日趋稳定,已经能够达到 99.99% 的可用性。

随着转码业务的全面接入,Marathon 框架的出现,我们也开始基于 Marathon 来支持 Long-Running 类型(轻量后台服务和 Worker)业务,后来逐渐演变成今天的 QAE 服务。

背景——出发点


当初实现 QAE 的出发点其实很简单,考虑到我们的 Mesos 背景,而 Mesos 的设计目标就是要把静态分配的一些数据中心资源整合,组成资源池,动态共享,达到提高资源综合利用率的目的。例如:有一些业务可能是 CPU binding 的,而另一些业务可能是内存 binding 的;如果都为他们单独搭建集群的话,维护成本高,而且资源的综合利用率也不高,因为有一些资源可能是闲置的。

所以,我们从 Mesos 设计理念出发,开始做 App Engine 的时候,主要的出发点是为了提高业务对资源的利用率,目标是节省资源,成本。所以,一个具有 Auto Scaling(自动扩展)的 Docker 应用平台就出现了。

说到节省资源这个目标,到底能到什么程度是不太清晰的,因为业务时时刻刻都在变化,但是我们相信基于Docker这种轻便灵活的 Auto Scaling 平台,按需申请使用资源,肯定能节约计算资源。Docker 和虚机相比有一个非常大的好处,它的横向扩容能力非常强:因为基于虚机模式,业务在上线业务之前需要预估整个业务需要的资源量,而且还需要预留一定的冗余量,所以往往会成倍申请资源,以免因为资源估计不足导致的故障。

所以,经过简单的估算,单纯从虚机迁移到 Docker 几乎就能节省一半以上的资源,其实也就是节约了业务组预留的冗余资源,因为业务组一旦能够接受 Docker 平台扩容快这个事实,那么冗余资源也就不再必需了。


揣着节省资源的目标,我们上线了第一版 Auto Scaling 平台,效果非常好,和虚机相比,节约了超过 75% 的计算资源,主要在以下几个方面:

  • 减少资源冗余甚至取消冗余

  • 降低单个容器配置,提高单个容器负载

  • Auto Scaling 能在闲时自动减少容器数量

但是随着更多业务的接入,用户也反馈学习成本太高,用户对于节省资源并不感兴趣;另一方面,从公司的实际情况出发,我们发现,通过 Auto Scaling 节省资源收效并不如预期的大,主要原因是作为一家本土公司,一家服务于人的公司,几乎所有的业务都和人的活动相关,所有几乎所有业务都具有相近的波峰波谷时段,并不能很好的错峰甚至互补。

所以,综合用户的反馈以及实际情况,我们的目标也从最初的单纯节省资源,提高资源利用率转变为更多的为用户考虑:

  • 让用户感受到受益

  • 降低学习成本

  • 提高易用性

而节省资源,提高利用率则成了次要目标。

下面简单介绍一下迁移到 QAE 平台的用户受益。

用户受益

用户受益主要是这几方面:

  • 资源到位快

    和虚机相比,即使资源充足,从提交申请到资源到位可用也需要几天时间,但现实情况是资源往往不是很充足,因为各个业务部门并不会很准确的提前提供扩容计划,以便能够提前采购,所以对于一家快速发展的公司来说,采购的服务器总是不够用。而对于 QAE 平台来说,应用扩容非常快,如果应用还有剩余配额,那么立即可以扩容,即使配额不足,那么申请配额即可,在相同的情况下,分配配额也比分配虚机来的更快。

  • 部署容易(上线、升级)

    从业务上线、升级这两个方面来看,基于虚机的方式,开发者需要自行开发一套自动化脚本来管理所有虚机,以便能够保证虚机的软件一致性,以及快速部署业务,执行升级等。但是,对于普通的应用开发者来说,对于 Linux 虚机并不是很熟悉,所以使用起来并不是很得心应手,所以常常会有业务开发者报障。而通过将业务 Docker 化之后,在 QAE 平台上线和升级都是一件非常简单的事,用户可以通过 WEB 界面或者 API 来完成,不再需要维护一批虚机,而是只需要维护业务的 Docker 镜像即可。

  • 扩容快

    业务在 QAE 平台上线之后,如果需要扩容,只需要自助完成 App 的横向扩展即可,能够在几分钟甚至几秒钟内完成扩容。

  • 自动故障转移

    Mesos 实现了对底层计算节点的监控,能够发现计算节点失效,并且能够将任务转移到其它健康的节点上;而 Marathon 实现了对任务的健康检查,所以能够进一步检测任务的状态,保证任务在故障的时候能够启动新的任务来继续服务。这对于应用开发者来说,是一个非常大的进步,有了这套自动检测,恢复的机制后,应用的维护及故障处理都将极大的简化。

  • 完善的监控预警

    QAE 平台能够保证底层 Mesos 集群,Marathon 服务,QAE 平台自身的稳定,以及和用户相关的容器的监控以及应用的监控;例如:容器的资源利用情况,这样,应用开发者不需要再开发配置相关监控。而在预警方面,我们采用了发布/订阅模式,每个应用可以由具有权限的用户配置报警条件,而这些报警则会发送给订阅了报警的人员,当然,要订阅报警,前提是需要具有相应的权限。

iQIYI App Engine 设计与实现

QAE 的总体架构如下图所示:


QAE 的最底层是由 Mesos 和 Marathon 组成的弹性资源池,这个资源池本质上具有多个集群,多个 DC,每个 DC 一般来说有多个集群,分别针对不同的服务级别,例如:生产集群,测试集群等。

对于每一个集群,上面可能会跑多套 Marathon 框架,如果业务有需求的话可能会进行一些物理节点方面的隔离,因为从实践来看,各个业务之间还没法做到完全隔离特别是 CPU 响应时间、网络速率等。

在所有 Marathon 集群之上是 QAE,所以 QAE 从设计上支持应用的跨 DC 部署;QAE 在功能模块上主要包含:

  • 自动扩展(Auto Scaling)

  • 任务管理(CRUD)

  • CI/CD

  • 事件总线

  • 监控

  • 服务发现

  • 预警系统

  • 日志

除了这些核心的模块,QAE 向上提供了两种交互接口,一种是 WEB UI,对用户友好,一种是 API,对其它团队开发基于 QAE 的服务比较友好。

QAE——监控和预警

从用户的角度来看,将自己的业务迁移到一个完全陌生的环境、陌生的平台,必须要知道它的运行状态,所以应用和容器的监控和报警显得非常重要。QAE 的监控和预警模块如下图所示:


我们知道,Docker 的最佳实践不推荐在容器中运行多个进程,而是只希望做一个应用容器,只运行应用的进程。所以,我们也遵守这个最佳实践,将容器的监控实现在了容器外部,即计算节点上。

在这种设计中,每个计算节点上有一个容器的监控 agent 叫 dAdviser,它会负责监控所有 QAE 容器,并且采集包括 CPU、内存、磁盘、网络上/下行速率等基础数据,通过使用 Graphite 的聚合功能,将属于同一个应用的所有监控数据聚合成应用的数据;这样,用户可以从应用层面宏观的查看整个应用的状态。

除了容器层面的资源监控,应用的监控也非常重要,因为一个业务通常由多个容器组成,所以这里需要监控例如:每个容器的状态,是否健康,所有容器数量,不健康容器占总数的比例;整个业务的流量情况,QPS 是多少等等。

一旦有了容器和应用的监控数据后,就可以基于这些数据配置报警了,在报警方面,QAE 对接了一个内部报警平台,支持多个渠道报警。

QAE——日志


和 QAE 监控类似,QAE 日志也采用容器外采集方案,在每个 Mesos 计算节点上,会部署运行一个 log-agent 来负责采集日志,同时提供实时日志查看/下载和日志上云的功能。而 QAE 在启动容器的时候,会注入一个日志卷,注入到容器里的日志卷在计算节点上有一个唯一的目录;并且是用户可以配置的,非常灵活,所以用户几乎不用修改代码,只需要在创建应用的时候配置一个环境变量,即可接入 QAE 日志系统。

QAE 日志模块包含两个功能:

  • 实时日志,用户可以在 QAE Web 界面上查看、下载,几乎没有时延,方便排障

  • 备份日志,日志会被采集到云端,用户可以通过编写 ELK 查询,Spark,Storm 业务来分析日志,生成报表,呈图等,但是有一定时延

QAE——CI/CD

CI(Continuous Integration)实际上是一个非常老的概念,最早作为极限编程的关键要素之一出现,而 CD(Continuous Devlivery)的流行一定程度上得益于 Docker 的兴起。

在 QAE 平台中,我们设计了一个 CI/CD 功能模块,如下图所示:


对于 CI/CD,我们并没有选择老牌的 Jenkins,而是使用了 GitLab,GitLab 在定位上实际是 Gerrit + Jenkins,甚至更多,因为它还提供了 wiki,Issue 管理等,更类似于 GitHub + TravisCI。

这里为什么没有选择 Gerrit 和 Jenkins,一方面是因为他们丑,不易用,门槛高;更是因为有一些更重要的原因。

对于 Gerrit 来说,它的安装配置虽然不算复杂,但是项目的配置和维护却不可谓不繁琐,不能做到完全的自助服务,所有的用户,组,项目权限都需要管理员来控制,需要占用管理员的运维时间;另一方面,Gerrit 对于用户来说,入门门槛也非常高,特别是对于项目的所有者来说,配置个性化的分支,review 权限等非常复杂,项目越大,分支模型越复杂,学习成本越高;而 GitLab 在这方面其实就是 GitHub 的翻版,熟悉 GitHub 工作方式就可以快速上手,而且全自助。

Jenkins 虽然非常老牌,插件众多,几乎是只有想不到,没有做不到,但是 Jenkins 最核心的 CI 功能已经完全落后于 TravisCI, CircleCI 等这些现代化的 CI 了,Jenkins 通过 WEB 界面来配置 CI 任务存在太多缺点:

  • 有权限的用户随便改

  • 没有任何 review 机制

  • 没有修改历史,不能跟踪修改

而现代的 CI 有一个共同的特点:CI 任务代码化,非常优雅,而且在代码多分支情况下,更显得灵活强大。

另外,由于要在前人轮子上造车,所以 API 和二次开发的难度也很重要,Jenkins 的 XML 数据交互模式也不够友好,而且 API 至今还不够全面。

所以综合上述原因,我们选择了 GitLab,另外一个原因也是因为 GitLab 的开发非常活跃,我们在去年年底调研的时候,GitLab CI 还不支持 Docker,而现在已经支持了,所以这一块工作我们会尽快启动。

所以整个 QAE 平台,它不仅会简化业务的上线及运维这条线,还会解决业务代码的开发这条线,这里只介绍了 QAE 的几个常见模块,更多内容:

  • Auto Scaling

  • 事件总线

  • 服务发现

等请参考大会分享的 PPT(http://pan.baidu.com/s/1geKTMO7)。

一些经验(坑)

QAE 当前的设计形态以及选型和最初的样子有挺大的区别,下面分享一下在设计与实现 QAE 过程中的一些经验。

容器监控——Zabbix

Zabbix 作为老牌的基础监控软件,应用非常广泛,爱奇艺也不例外,采用了 Zabbix 来构建基础监控服务。但是,对于容器的快速兴起,Zabbix 并没有准备好。

优势

  • 已有 Zabbix 基础服务

  • Auto Discovery 能发现容器启动/消失事件

劣势

  • 需要在容器内部安装 zabbix, footprint 太大,并且每个容器中都会安装;

  • 不是很稳定

  • 数据统计/聚合比较复杂

在容器监控方面,考虑到虚机监控以及物理机监控方面都是采用的 Zabbix,而且已经有比较成熟的 Zabbix 基础服务,所以沿用 Zabbix 对于我们的优势就是能够沿用已有的基础服务,结合 Zabbix 的 Auto Discovery 机制,它能够发现你在主机上如果有容器启动或者消失事件,并且根据配置自动挂载监控模板,所以当时看来几乎是能够直接采用的。

但是后来发现 Zabbix 的问题也是比较明显:

  • 在镜像安装 Zabbix 这个 footprint 比较大,因为在一个计算节点上往往需要运行多个容器,而 Zabbix 占用资源也不小,另外也不符合 Docker 最佳实践

  • Zabbix 的数据统计/聚合比较复杂,因为 Zabbix 是为单机设计的,也就是这里的单个容器,而对于容器化的业务来说,整个业务的监控指标实际比单个容器的指标更为重要

容器监控——cAdvisor

在排除了 Zabbix 后,我们开始调研一些专注于容器监控的方案,其中不乏一些 SaaS 服务,例如:Datadog;但是对于公司内部平台,SaaS 服务首先排除,然后发现了 Google 开源的 cAdvisor。

优势

  • 背靠 Google 且开源

  • 监控数据详尽

劣势

  • 集群化开发成本较高,Kubernetes heapster 实现

  • influxDB 而非 graphite(当时有基础服务)

Google 在 2014 年开源了 Kubernetes(简称 K8S)平台,其中的监控组件使用了 heapster + cAdvisor,后者只专注于容器的监控,而 heapster 则是集群化容器监控方案。所以 cAdvisor 的优势比较明显,我们在开始调研的时候一度以为 cAdvisor 就是适合我们的方案;很不幸,后来发现 cAdvisor 也并不太适合 QAE。主要原因有两点:

  • cAdvisor 是单机容器监控,集群化聚合数据需要自己开发

  • cAdvisor 的存储后端基于 influxDB,需要我们再维护一套 influxDB 服务,而当前我们已有的 TSDB 服务为 graphite

所以,我们开发了 dAdvisor,取意 Docker Advisor,灵感来自于 cAdvisor(Container Advisor);dAdvisor 最初有一些监控指标来自于 Docker API,后来完全废弃从 Docker API 读取数据,以为我们发现,Docker API 非常脆弱,包括 Docker Daemon,时常卡住。所以 dAdvisor 的监控数据也都直接来自于 cgroups 数据。

容器监控——dAdvisor

dAdvisor 主要有以下特点:

  • 采集:CPU、内存、磁盘、网络

  • 集成现有 Graphite 服务

  • 统计数据方便(Graphite 内置一些聚合操作符)

  • 呈现方便(Graphite Render URL API)

  • 开发量不大

事实证明 dAdvisor 完全能够满足目前对于容器和业务的监控需求,后续 dAdvisor 还会提供一些常见性能数据的监控,例如:容器内的进程数,链接数,打开的文件数等;以及一些常见服务器的监控;用户自定义数据的监控。

Time Series Database——Graphite

对于 TSDB 的选择,我们并没有花时间去调研其它的方案,例如:openTSDB,influxDB,Premeths 等,而是直接使用了现有的 Graphite 服务。

优势

  • 老牌(Since 1999),已有服务,经过验证

  • 简单、内置 aggregator,Render URL API

劣势

  • 项目及社区已经几乎停滞

  • 集群化配置复杂,需要详细规划

  • 缺乏多用户认证,授权机制,黑白名单太单薄

  • 数据删除缺少 API

在使用了一段时间的 Graphite 之后,在享受简单,便利的同时,我们也发现 Graphite 有一些不足,所以后续我们也在慢慢调研其它方案,总体对于目前的需求来说,还没有感觉特别挚肘的地方;对于用户认证,授权方面,由于是私有云项目,并不是显得特别迫切。

服务发现(Service Discovery)

负载均衡/反向代理方案:

  • HAProxy:Marathon 支持,但是公司内部用户少

  • Nginx:Marathon 不支持,公司内部大量用户

服务发现:

  • Flask 推送,SSH,不可靠,不安全

  • Ansible 推送,SSH,不可靠,不安全

  • event bus + guardro-template

在 7 层的负载均衡和反向代理方案中,HAProxy 和 Nginx 几乎是最流行的方案,而介于公司内部大量 Nginx/Tengine 用户,QAE 也选择优先支持 Nginx/Tengine 作为标准的 7 层负载均衡方案;在 4 层方面,则和内部的 4 层服务团队合作、集成。

服务发现方面,需有实时的更新负载均衡器并且重新加载,由于 Marathon 本身并没有对 Nginx 的支持,而我们选择了 Nginx,所以需要自行做一些开发,在最初的版本中,我们分别使用了 Flask 和 Ansible 模块来推送 Nginx 配置,后来发现 ssh 服务实际上非常脆弱,很可能由于服务器不稳定导致 SSH 卡死无响应。

目前 QAE 的服务发现采用了 Event Bus + guardro-template 的方式来实现,一定程度上借鉴了 Consul 的实现。

日志

ELK(Elasticsearch + Logstash + Kibana):

  • 延时较高(分钟级)

  • 只支持格式化后的日志(for machine)

用户诉求:

  • 低延时(秒级),准实时

  • 裸日志(for real person)

  • 备份日志(Apache Flume)

QAE 日志最早采用的是 ELK 套件,ELK 使用非常广泛,而且公司内部也有 ELK 服务,所以自然而然就在 QAE 上集成了 ELK 服务;但是后来的实践发现,用户对于 ELK 这种日志方式接纳程度非常低,用户的诉求很简单:

  • 实时,低时延

  • 裸日志

所以,ELK 完全没能命中用户的需求,而且改变用户的胃口也是一件非常费力不讨好的事;所以我们后来完全废弃了 ELK 方案,重新实现了日志系统,也就是现有的日志方案(参考本文前面)。

现状与展望

现状

  • 处于活跃开发状态

  • 接入了几十个业务

  • 主要业务类型:服务型、RPC、Worker

  • 服务型业务 QPS 大于 10 万

  • 4 个数据中心

QAE 目前处于活跃开发状态,有大概 2 个成员负责开发运维;目前接入了几十个业务,主要的业务类型为后台服务,包括 HTTP 服务和 RPC 服务,以及 Worker 业务。目前 QAE 总共有 4 个数据中心,提供生产和测试集群,生产环境的 QPS 已经超过 10 万。

展望

  • 支持短任务

  • Quota 和计费

  • Web Console

  • 内置典型服务(如:Tomcat)数据统计

  • Docker 持久化卷和跨主机通信

  • 支持更多类型服务:Cache、DB、MQ 等

QAE 到目前为止提供了基础的平台服务,但是对于以前适应了虚机的用户来说,容器服务平台,以及抽象的更高层次的服务并不能完全让用户放心,所以首当其冲,为了避免用户在容器中安装 ssh 服务,尽量靠近 Docker 最佳实践,Web Console 是必须提供的功能,这样,用户可以直接在 QAE 上登入指定容器。

另外,对于服务平台来说,资源 Quota 也非常重要,能够在不影响用户自助使用,减少管理员运维的同时,一定程度上限制用户无节制的使用资源;其它如典型服务的内置监控,数据持久化等也是 QAE 平台后续的工作重点。

在业务模型上,QAE 目前只支持 long-running 业务类型,未来也考虑接入 Chronos/Sysphus(爱奇艺 Chronos Fork)API,提供短任务支持。

查看图片
查看图片

查看图片

活动推荐

【CNUTCon全球容器技术大会】微服务、持续集成、容器云、大数据、电商、传统行业、创业公司等12个专题,Docker、Kubernetes、Netflix、Mesos、CoreOS、阿里巴巴、京东等公司的核心技术负责人现场独家揭秘,容器化和微服务化,从这里开始,8折报名中,详情请点击阅读原文链接。

查看图片