从 0 到 1,CDN 边缘节点容器调度发展之路

百家 作者:又拍云 2018-06-14 13:35:27

5月27日,OSC 源创会第75期在上海成功举办。又拍云系统开发高级工程师黄励博在活动上进行了精彩的主题演讲——《CDN 边缘节点容器调度的实践》。黄励博在又拍云主要负责私有容器平台、云存储、云处理相关的架构设计和开发工作,熟悉 Python/Lua/Go 等语言,在 Docker 容器方面拥有丰富的实践经验,在 ngx_lua 和 OpenResty 方面有着丰富的模块开发和维护经验。平时热衷于参与开源社区,分享开源经验。

在分享中,黄励博主要介绍又拍云自主开发的边缘节点容器调度方案,从 0 到 1 实现零停机、负载均衡,以及基于容器的子网组建、管理等底层功能。本文根据黄励博的演讲内容整理而成。

观看分享视频,请点击“阅读原文”移步 IT 大咖说。

黄励博在 2017 年 8 月 15 日“Gopher 杭州 meetup”上分享过“基于Mesos的容器调度框架”的主题演讲,分享视频可点此(http://www.itdks.com/dakalive/detail/4019)观看。


以下为讲师分享内容:

又拍云容器云是基于 Docker 的分布式计算资源网,节点分散在全国各地及海外,提供电信、联通、移动和多线网络,融合微服务、DevOps 理念,满足精益开发、运维一体化,大幅降低分布式计算资源构建复杂度,大幅降低使用成本。

上文是对容器云的简介,又拍云容器云是一个基于 Docker 的边缘容器网络。

过去,又拍云数据中心用的是基于 Mesos 的容器调度平台。它把数据中心的 CPU、内存、磁盘等抽象成一个资源池,Mesos 官方称之为分布式系统内核,。


Mesos架构

下图是 Mesos 容器调度平台的架构图。

△ Mesos 架构

Mesos 调度平台相当于数据中心的 Master,同时在每个节点上都有一个 Agent。当每个Agent 启动后会向 Mesos 注册,Agent 携带的资源信息,让 Mesos 决定每个框架的资源数量。当框架收到资源后,再根据需求调度资源。

Mesos Master 调度机制后面是 framework,通过 framework 可以满足数据中心的容器调度。


边缘容器调度方案概述

下面我们简要介绍下又拍云的边缘容器调度方案。又拍云边缘节点容器调度方案需要有一个部署在数据中心的 Master,负责集中调度统一管理。而 Agent 则部署在全国各个边缘节点上,每个节点的每台机器上都会有一个 Agent,负责采集数据,管理 Docker。在边缘运行长期服务,支持故障恢复。同一个节点的一批机器会组成一个集群。另外,因为又拍云有不同需求的客户,所以边缘节点需要部署多种功能,功能部署时要完成容器网络的隔离,还会有一些负载均衡和定制化的需求。


版本 1 实现了调度策略最基本的功能

△ 版本1

上图是最基础的版本1 Master—Agent 架构。最上面是 Hancock (又拍云内部项目名称),它本身就是 Master,App 的拥有者可以通过 API 接口接入,部署任务、创建 Docker 项目到边缘节点。

这两个虚线的框分别表示两个不同的节点,每个节点上数量不等的机器会组成一个小集群,每个机器上会部署一个 Agent, Agent 会负责创建各个 Docker 的 Task,容器服务的用户(App user ) 直接会去边缘节点访问容器服务。

Agent 启动后会上报消息到 Master, 而 Master 会根据用户的请求和上报的消息下发指定给 Agent 。由于边缘节点和数据中心的网络可能处于不稳定的状态,在处理数据的时候会出现超时、延迟等问题,同步操作可能会导致用户的请求一直得不到响应,最终导致信息丢失等问题,因此 Master 与 Agent 的数据交互、消息处理都是异步进行的。这种情况下,用户只要把请求提交到 Hancock Master 上,这个任务就会分发到所有的边缘节点。

下面是 Master-Agent 消息介绍:

● 上报消息 Agent -> Master

● 下发指令 Master -> Agent

Resource  消息

当 Agent 启动时会携带 Resource 消息 ,当携带资源信息发生变更时,会更新一次 Resource 消息 。如图所示,Agent 通过节点名和主机名来唯一表示一台边缘设备,设备的资源信包括,网络信息(包括运营商信息、宽带信息),CPU, 内存, 磁盘,可用端口信息等,其中端口段的分配是因为有个摄像头的用户一个服务需要用到几千个端口,这种情况就不再适合逐个端口进行随机或者指定分配,这样维护成本会变得很高。

Offer 消息

Agent 会定时上报 Offer 消息上报给 Master,会发送机器的 load 和当前网络状况的使用情况、CPU、Memory、Disk等使用情况信息,以此维持 Master 与 Agent  之间的联系。

一般来说,Master 可以计算出 CPU、Memory、Disk 的使用情况。但是 load 和网络状况,Master 是无法知晓的,所以每隔一段时间就要上报,以供 Master 合理的调度 Docker 机器,比如不应该再安排服务部署到 load 较高的机器上。上述就是 offer 的作用。

Update 消息

负责提供实例的状态变更,Docker 实例运行成功失败等信息, 由 Agent 实时上报给 Master, 包含任务的状态信息和相关描述。方便 Master 进行故障恢复等操作。

Containers 消息

负责提供机器容器列表, 防止有僵尸任务和任务遗漏, 由 Agent 定时上报给 Master,  Master  负责检查。

Master 到 Agent 的指令下发过程中,主要包括两个类下发指令:

1.实例创建,如增删改查,把客户增删改查请求转变为对容器的操作;

2.镜像操作,如镜像拉取,镜像查询。比如 Docker 镜像很大的时候,在边缘节点拉取镜像可能会超时。所以我们设置了一个单独的镜像操作,保证在创建容器前,可以预先异步提交拉取命令。

△ 处理流程

上图是消息处理流程,当 Agent 启动时上报 Resource、Offer、Container 等定时消息。其中 offer 消息频率最高, 一旦一段时间没有受到 Offer 消息, Master 会尝试迁移这个 Agent 对应机器上的所有容器实例。

上述版本 1 的架构实现了调度策略最基本的功能。当 Master 收到各个集群中 Agent 上报的资源时,通过自定义策略来完成任务调度。一般来说是寻找满足条件的(Node Cpu Mem Disk Port 等)机器。再选择根据带宽、load 等指标,进行权重估算,在估算出权重的前提下进行随机调度。在权重类似的情况下,每次调度尽可能让同一服务的各个实例分布到节点的不同机器,保证在某台机器崩溃的情况下,其他实例正常运行保证高可用。


版本 2 增加 calico,负责网络控制和访问限制

在版本 1 中,Master 和 Agent 已经完成了两者之间的消息交互。App 拥有者可以创建服务,并且在边缘机器上创建 Task。

但我们不希望客户的服务混杂在一起,希望可以隔离不同所有者的容器网络, 可以完成一些访问控制的功能。又拍云使用了 calico 的方案,它是基于 BGP 的路由协议的三层通信模型,不需要额外报文封装。

△ 容器网络(图片来自网络)

如图所示,其中 calico BGP client 负责每个节点和集群其他节点建立 BGP Peer 连接,增长趋势是  O(n^2),它并不适合大规模的集群网络, 解决方法是 Route Reflector,选择一部分节点作为 Global BGP Peer,由它们互联来交换路由信息。而又拍云每个边缘集群都是小规模集群网络,O(n^2) 的增长是可以接受的,并不需要 Route Reflector 的机制。

其中 Felix 负责节点网络相关配置。由它负责配置路由表、iptables 表项等。以便完成访问控制和隔离的功能。

另外,集群中还会有一个分布式的 kv 数据库—— etcd,负责保存网络元数据。

calico 的优点: 三层互联,不需要报文封装。访问控制, 满足隔离网络, 隔离容器。

calico 的缺点: 网络规模限制, iptables 和路由表项限制

△ 版本2

在我们的场景下,它很好的满足了需求。加上 calico 方案,版本 2 的架构如上图所示。


版本 3 支持动态负载均衡

版本 2 完成了对 App 所有者的隔离和限制,我们来看下服务的访问者,现在他们都是直接访问节点的机器,这样并不适合完成一些服务的调度, 比如负载均衡和服务更新等。

由于之前提供端口映射方案可以是随机的,在这种情况下,App 的访问者甚至不知道服务具体跑在哪些机器, 监听在哪些端口上,因此需要有一个统一的入口。

△ Slardar

上图是又拍云开源的基于 ngx_lua 的动态负载均衡方案——Slardar。它可以做到在不 load Nginx 的情况下,动态更新 upstream 列表和动态更新 lua 代码。方便动态的维护容器服务的地址。

那么 Slardar 是如何完成服务动态选择的?

如图所示,  首先对于 http 服务我们可以通过 host 来区分不同服务,动态地找到指定的服务,类似的, 对于 tcp 服务,我们通过接入的端口来区分不同的服务

其中, checkups 是一个动态选择上游的组件,他提供了一个注册机制,我们可以注册用户自定义的负载均衡策略, 默认支持轮询和 hash 算法,同时也支持注册主动的健康检查策略, 默认支持 tcp http mysql等协议,这样为每个服务选择一个正常工作的地址。

上图是健康检查页面,在 slardar 中我们会启用一个定时器来定时检查所有上游的状态。其中 checkup_timer_alive 字段代表这个定时器是否还存活着,last_check_time 字段代表上一次定时器的检查时间。后面是上游的健康状态, 包括 IP、端口号、服务名称, status 状态等。

△ 版本3

版本 3 的架构如上图所示,我们可以在节点上部署 slardar 作为容器服务的统一入口完成服务的负载均衡和健康检查。服务的用户访问时,都会接入到 Slardar 这个统一入口。由 Slardar 代理到具体的 Task。


版本 4 支持零停机更新

有了统一的入口,我们可以保证在任务更新时,服务不会出现不可用的状态。可以通过运行两个不同版本的服务同时运行来实现蓝绿更新。

当 Master 收到服务更新请求的时候,Master 会让  Agent 负责启动服务新版本的容器 Tasks,同时把新版本容器地址写入 etcd 把旧版本的地址删除, 之前我们介绍过 calico 会用到这个分布式的 key value 服务器,这边管理 upstream 列表, 我们也同样使用了 etcd 这个 kv 数据库。

旧版本是图中三个蓝色的 Tasks,更新任务开始,会部署三个绿色的新版本 Tasks。当三个新版本任务起来后,Agent 会把 Tasks 中的地址更新到 etcd 中。图中看到有个 confd 的服务会监听 etcd 中 upstream 列表的变更, 把 upstream 列表主动同步给 slardar 完成 upstream 的切换, 而 slardar 启动的时候也支持从 etcd 加载 upstream 列表, 这样就完成了服务的更新, 等旧版本的服务流量没有的时候 Agent 会主动删除旧版本完成更新操作。

△ 零停机更新

结合上文讲的访问控制、统一入口以及动态更新,我们就拥有了这样一个架构。

版本4

版本 4 架构中,Slardar 是 HTTP/TCP 代理,它是一个无状态的代理服务,所以可以任意部署,不存在单点问题,直接部署多台就可以保障可用性。而 Hancock Master 作为服务拥有者的入口,拥有着所有服务的状态,可以看到到现在为止,还是单点的,不是一个高可用的服务。为了解决这个问题,我们需要有一个高可用的方案。


版本 5 实现高可用

与版本 4 项目,版本 5 中使用 Raft 分布式一致性协议实现高可用。

Raft 主要特点有三个:

1.领导选举: 心跳机制来触发选举, term 充当逻辑时钟的作用;

2.日志复制: 领导者把一条指令(能被复制状态机执行)附加到日志中,发起附加条目 RPC 请求给其他角色;

3.强领导者:日志条目只从 leader 发送给其他的服务器。

如图所示,服务起来时默认为跟随者, 如果发现当前集群中有一个领导者, 那就接受它。如果超时时间内一直没有收到领导者的消息, 它就会把角色切换成获选人, 同时把自己的 term 任期号加1,  开始一轮选举, 如果获得了集群中半数以上的节点的投票, 它就会变成领导者。如果在此过程中, 发现了集群领导者, 而且它的任期号不小于自身的任期号, 那么就把角色退化成跟随者, 如果在随机的一段超时时间到来后, 没有发现领导者也没有多数人的投票, 那么就再进行一轮新的选举。

领导者会把指令附加到日志中, 然后发起 RPC 请求给集群中的其他服务器, 让他们复制日志, 这条指令会最终在集群的每台机器上在 Raft 的状态机中执行,  日志条目只能从 leader 发送给其他服务器。

△ 版本5

在增加了 Raft 之后,版本 5 已经是一个高可用的方案,leader 平时是会与所有的 Agent 交互,并且它是有状态的,可以把状态同步到两个跟随者中。当 leader 挂掉时,follower 拥有 leader 完整的状态,只要重新选举出来一个成为新的 leader,服务就可以继续运行下去。


版本 6 监控与告警

由于系统中的消息都是异步交互, App 服务可以通过注册回调通知地址,来实时获取各个事件。除了用户需要及时获取一些事件(实例状态变更,服务状态变更等)之外, 我们也需要一个监控和告警方案来及时了解我们边缘服务的情况。

监控:

Agent 会收集 Metrics 到 InfluxDB, 由 Grafana 展示, 如图所示几个节点的流量监控

告警:

告警信息分两类, 一类是任务相关: Hancock 会发送消息到 slack , 截图是 Hancock 的一个告警信息

还有一类是监控相关, 比如设定的指标异常时, 发送实时消息到 slack, 截图是 slardar 上 500-504 响应的告警信息 , 可以看到在 21点左右 502 的状态出现了一个峰值,有三百多次 502。

最后有了我们现在的边缘容器调度架构。

这些就是我们边缘节点容器调度架构涉及到的一些主要组件, 一些更具体的细节就不再这边一一展开了, 欢迎感兴趣的公司或个人使用我们的这个服务。


---------------小广告分割线---------------

扫码报名 

又拍云 Open Talk No.42 | 2018 音视频技术沙龙·上海站

6月24日,上海

网易云音乐、谷人云、战旗等公司的音视频技术专家,邀你一起交流音视频领域的技术

关注公众号:拾黑(shiheibook)了解更多

[广告]赞助链接:

四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

公众号 关注网络尖刀微信公众号
随时掌握互联网精彩
赞助链接