如何利用Mesos持久化存储方案部署ArangoDB 集群

调度分配无状态应用的 Docker 容器很方便,可是该如何处理那些须要保持状态的应用呢?html

咱们没法轻易的中止一个挂载了本地文件系统的 Docker 容器并在另外一台机器上重启它。然而,出于性能的考量,分布式数据库和其余有状态的服务一般又须要使用本地存储,甚至是 SSD 盘。因此数据中心操做系统须要考虑为应用提供保留并访问本地存储的方式;确保某些任务重启后被从新调度到同一个节点,进而从新使用它的本地存储。git

Mesos 0.23 的 persistence primitives 特性解决了上述这些挑战。本文中,咱们首先解释下 Mesos 的 persistence primitives 特性是如何工做的,其次会给出一个具体的例子,一个 Mesosphere 认证的使用 persistence primitives 特性的框架: ArangoDB —— 分布式 NoSQL 数据库。github

Find ArangoDB on Github数据库

概述

为了确保任务失败后仍然可以访问本地持久化的数据,Mesos须要解决下面两个问题:apache

  1. 为了在同一个台节点上重启任务,框架须要可以再次收到该节点的资源offer。编程

  2. 在默认的状况下,任务中止后,Mesos会清除掉该任务沙盒里面的数据,可是对于须要持久化的数据,该如何避免任务失败或重启后数据被清除掉呢?缓存

经过配合使用不一样的 persistence primitives,咱们就能够解决以上问题。服务器

动态保留

由于 Mesos 的动态保留特性容许框架保留曾提供给它的资源,而且被保留的资源不会提供给其它 role,从而框架能够借助该特性来将任务再次部署到同一个节点上,该节点上已经存储了任务须要的数据。关于 Mesos 动态保留技术的细节,请参考连接:https://github.com/apache/mesos/blob/master/docs/reservation.md网络

持久卷

框架利用 Mesos 的特性能够在磁盘资源上建立持久化卷。持久化卷是任务沙盒以外的资源,不会因任务异常退出或完成而被清除。任务退出时,任务的资源(包括持久化卷)会被从新提供给该任务所属的 role,从而该 role 下面的框架能够在相同的节点上启动原来的任务,或者启动修复任务,或者启动新的任务来消费前一个任务的输出(这些输出已经被存储到了持久化卷中)。另外值得注意的是,咱们只能从动态保留的磁盘资源上建立持久化卷。框架

关于如何建立和销毁持久化卷的技术细节,请参考连接:https://github.com/apache/mesos/blob/master/docs/persistent-volume.md 另外,Mesos也给出了操做持久化卷的例子:https://github.com/apache/mesos/blob/master/src/examples/persistentvolumeframework.cpp

使用 persistence primitives 的最佳实践

下面是 persistence primitives 的一些入门技巧:

  • 在一个 acceptOffers 调用里面同时建立动态保留和持久化卷
  • 因为网络异常,或者 master 拒绝操做等,框架在尝试动态保留资源或建立持久化卷时可能会失败,这时框架须要检查这些失败并处理失败的状况(譬如 重试机制)。
  • 经过mesos调度的API很难监听失败的动态保留状况,由于保留的资源没有惟一的ID,并且,对于一个动态保留请求成功与否,Mesos master没有提供明确的反馈。在下面的ArangoDB的例子中,给出了处理这种状况的技巧。另外,Mesos 将来会支持为资源保留打标签的功能,https://docs.google.com/document/d/1HdS4TxmfMkMR_2mvOHZR-LLmyLNdyqRrPBdiGCp6-w8/edit 这会简化上述流程。
  • 由于有许多须要处理的“状态”,咱们最好为持久化框架的应用逻辑维护一个状态机,处理应用从初始状态(没有保留资源和持久化卷),到某个结束状态(须要的资源获得了保留,而且持久化卷建立成功)的过渡。下面 ArangoDB 的例子给出了更多细节。
  • 因为持久化卷与 role 有关,一个卷可能会被提供给该 role 下的任何一个框架。譬如,一个持久化卷多是由框架 A 建立的,而后被 offer 给了同一个 role 下的框架 B。利用这一点,能够很容易的在框架之间分享该卷下的数据。然而,从另外一方面看,这也可能致使框架 A 的敏感数据被框架 B 获取到。

关于在 持久化卷特性上编程的更多细节,请参考连接:https://github.com/apache/mesos/blob/master/docs/persistent-volume.md#programming-with-persistent-volumes

ArangoDB 是什么?以及它为何须要持久化?

ArangoDB 是一个分布式的多模型数据库,它是一个包含文档存储、key-value 存储和图存储的数据库,全部的操做都基于同一个引擎,使用统一的 query 语法。

做为一个分布式应用,因为 Apache Mesos 或者数据中心操做系统(DCOS)负责分发和调度应用,管理集群资源和失败检查,ArangoDB 运行在其上会有不少好处。Mesos 也能够利用 Docker 容器部署应用,从而为开发者解决了不少分布式系统下使人头疼的问题。

另外,对数据库来讲,一个很是大的需求是维护不停变化的状态,同时因为数据库须要数据持久化,ArangoDB 须要访问持久化的数据。理想状况下,甚至须要使用本地的 SSD 数据盘(如今,这种 SSD 盘可以提供很是好的IO性能,数据持久化保障以及智能预测的数据缓存能力。)

与利用分布式文件系统托管上面承载的分布式应用的方法不一样,针对于ArangoDB,咱们决定使用下面的方法来进一步提升数据持久化性能,即,全部的 ArangDB 集群的任务都访问本地存储,并在重启(譬如版本升级致使的重启)后可以仍然访问他们的数据。这就是咱们选择利用 Apache Mesos 的 persistence primitives 特性的缘由。

概要及不一样的任务类型

有四种不一样的 ArangoDB 任务:

  • Agency 任务:Agency 是一个中心化,低数据量,低IO的数据存储,主要存储了 ArangoDB 集群的配置以及数据库/集合的摘要信息。 Agency 也使用了 Raft 一致性协议来维护集群层面的日志同步操做和锁操做。Agency 的数据变化不频繁,可是对整个集群的运转特别重要。这也意味着 Agency 的数据须要使用持久化卷,可是 IO 性能并不重要。
  • Coordinator 任务:Coordinator 任务就是面向客户端的 ArangoDB 实例。它们本质上是无状态的:它们接受外部的 HTTP 请求,经过 Agency 了解集群的配置,并将 query 操做分发到集群中。Coordinator 知道集群切片的细节,从而可以制定分布式的query执行策略,并管理它们的运行情况。
  • 主数据服务任务:主数据服务器保存了真正的数据。这些任务状态频繁变化,有很重的数据IO操做。从而,这些任务须要持久化卷和很好的磁盘IO性能。
  • 备数据服务任务: 备数据服务器是主数据服务器的异步分片。它们有规律的轮训主数据服务器的变化并将这些变化应用到它们的数据备份上,因此它们也须要持久化卷。另外,若是主数据服务器崩溃了,它的备数据服务器可以马上接管。

ArangoDB 调度器的职责

ArangoDB集群按下面的顺序加载:

  1. 加载 Agency 任务。
  2. 主数据服务器启动。
  3. 备数据服务器在主数据服务器以后启动,确保其不与主数据服务器运行在同一个节点上。
  4. Coordinator 任务启动。
  5. 在全部的任务启动并运行正常后,ArangoDB 集群执行初始化。

在下面的状况下,ArangoDB 调度器也须要采起行动并维护相似的依赖需求:

  • 集群须要在数据服务器层面伸缩来改变它的数据存储能力。
  • 集群须要在 Coordinator 层面伸缩来改变它的 query 能力。
  • 集群须要不停服升级。
  • 集群须要重启。

ArangoDB 调度器也须要进行失败处理。接到 Mesos master 的任务被杀或者 Mesos 节点失联的通知后,调度器须要自动的进行失败处理。为了进行失败处理,调度器会监听集群中任务的状态,维护时间戳,并进行超时处理。

ArangoDB 经过一个事件轮训的主程序来完成上述功能。这个主程序周期性从其余线程获取资源 offer,接受 Mesos 的更新信息,维护超时处理和事件响应。咱们会在下面详细讨论这里的技术细节。

ArangoDB 服务器的状态图

下面是使用了持久化卷的ArangoDB集群的一个任务状态图。(以一个数据服务任务为例)

“NEW” 状态

任务从 “NEW” 状态开始:此时任务尚未动态保留资源和持久化卷。调度器收到了知足条件的资源offer后会返回一个 类型为 “RESERVE” 的 “mesos::Offer:Operation” 信息来尝试为 role —— arangodb 保留足够的资源。接着,任务状态变为 “TRY TO RESERVE” 。

“TRY TO RESERVE” 状态

Mesos master 一般会从同一个节点向上述任务再发送一次资源 offer,此次的 offer 中将包含为 role —— arangodb 动态保留资源的标示。此后,调度器会返回一个类型为 “CREATE” 的 “mesos::Offer::Operation” 信息来尝试建立持久化卷。接着任务状态变为 “TRY TO PERSIST”。持久化卷拥有一个全局惟一的 ID 标识。

“TRY TO PERSIST” 状态

Mesos master 从同一个节点再发送一次资源 offer 来响应上述的建立请求,此次的 offer 中将包含动态保留资源的标示和持久化卷。最终,Docker 容器启动并挂载持久化卷到容器上。任务状态变为 “TRY TO START"。

“TRY TO START” 状态

任务初始化完成后,Mesos Master 通知调度器任务启动成功。调度器将状态置为 “RUNNING”。

在前面的任务变为 “TRY TO START” 状态后,调度器开始启动依赖于这些任务的其它任务。若集群中全部的任务启动成功,调度器开始进行集群的全局初始化流程。

若在某些节点上有为role —— arangodb 静态保留的资源,调度器可以直接从状态 NEW 变为状态 “TRY TO PERSIST”。在这种状况下,调度器可以马上获取到知足需求的资源 offer 并建立持久化卷。

因为存在消息丢失的状况,从 “TRY TO RESERVE” 到 “TRY TO START” 全部的 “TRY” 状态都有超时处理。若是状态超时,调度器会把状态重置为 NEW 来从节点接收新的资源 offer。

“RUNNING” 状态和 “FAILURE” 状态

理论上来讲,“RUNNING” 状态的任务不须要跟调度器交互。可是,因为任务可能死掉,甚至会出现机器硬件失效致使 Mesos 节点整个失联,或者,计划内的停机维护,或者网络异常等,这些都会致使任务中断。

一个容错的分布式系统必须优雅的处理上述状况。持久化卷支持任务快速重启,并重连到集群中继续工做。调度器收到任务被杀(或者节点失联)的消息后,会把状态变为 KILLED 并等待资源 offer。

假设网络是正常的,任务所在节点的资源 offer 将如常到达调度器。这个 offer 包含了任务的保留资源和标记了全局惟一 ID 的持久化卷。调度器接收到 offer 后将马上尝试重启任务并把状态变为 “TRY TO RESTART”。除了超时处理不一样, “TRY TO RESTART” 状态本质上与 “TRY TO START” 状态等价。在 “TRY TO RESTART” 状态下,当响应超时时,任务状态变回 “KILLED”,而不是 “NEW”。 对于失败处理,调度器有另外一个更长的超时处理机制。

若是被杀掉的主数据服务没可以尽快重启,调度器会把主数据服务切换为备数据服务,同时原来的备数据服务马上变为主数据服务对外提供服务。原来的主数据服务状态变为 “FAILED OVER”。 原节点上存在的持久化数据可使得任务可以更快恢复,因此调度器仍然会尝试在原节点上重启任务。

最终,在更长的时间后,若任务仍然重启失败,调度器将放弃这个任务和它的持久化数据并把状态从 “FAILED OVER” 变回 “NEW”。 在这种状况下,调度器会认为任务死亡并建立新的任务。接着调度器会销毁死亡任务的持久化卷并释放动态保留的资源。

若任务死亡后,调度器没有清除数据, Mesos 集群会发生资源泄漏:这些资源将被咱们的框架永久占有而没法为其余框架所用。另外,因为该卷的惟一 ID 永久绑定在了特定的任务实例上,咱们的框架也没法再度使用这个持久化卷了。

为了解决上述问题,调度器收到带有持久化卷或者动态保留的资源 offer,而该 offer 又没有对应的等待任务时,它将回复 “mesos::Offer::Operation”去销毁持久化卷或者释放相应的动态保留资源。这也能够归还建立超时时的遗留资源。

目标,计划和当前

与其它分布式系统同样,调度器自己也须要容错。咱们经过下面两步来实现。首先,经过 Marathon 部署调度器实例。其次,利用 Apache Mesos 的状态模块来持久化调度器的内部状态,本质上是将数据存储到了 Zookeeper 上。这样在调度器新的实例启动成功后,它可以从 Mesos 获取原来实例的状态并正常运行。

为了保证无缝工做,咱们实现了调和协议:若调度器已经获取了原来的状态,它首先会尝试与 Mesos 提供的正在运行任务的状态进行调和。即,调度器会将相应的已知任务信息发送给Mesos master,Mesos master 将这些信息更新后返回给调度器。

调度器持久化状态分为三个部分:目标,计划和当前。 ArangoDB 集群用户能够设置集群的“目标”,譬如数据服务实例的数量,coordinator 的实例数量等。调度器会一直监控集群“目标”,并经过修改“计划”来响应其变化。

“计划”比“目标”更具体,譬如它包含了各个任务的状态,以及调度器想要每一个任务达到的状态等。因为“计划”是机器生成的信息,它将会一直保持在一个明智的状态下,从而会给出一个切实可达的情况。

调度器会根据Mesos发来的信息频繁更新 “当前”状态。“当前”状态反应了ArangoDB 集群的当前状况,譬如成功启动的任务,杀掉的任务等。调度器会经过操做相应的资源 offer 来持续尝试将“当前”状态变为“计划”状态。

“目标”,“计划”与“当前”三态是搭建一个容错,自愈的分布式系统经常使用的方法。但愿它在更多的相似系统中发挥做用。考虑到稳定与自愈的特性,咱们在 ArangoDB 集群中使用一样的方法获得了很是好的效果。

结论

Mesos 的 persistence primitives 是一个新的强大的工具,它使得更多的有状态应用能够运行在 Mesos 上。利用它,咱们把 ArangoDB 集群改形成了一个极易扩展到数百节点的分布式持久化框架。

咱们在这里分享了咱们开发该系统的经验。考虑到大量的不一样状态和超时状况,咱们建议把持久化卷的逻辑模型化为状态机。这种方法也可以帮助你在调度器中实现很重要的失败处理,从而构建一个稳定的有状态框架。

英文原文连接地址: https://mesosphere.com/blog/2016/02/18/arangodb-mesos-persistent-storage/

翻译首发:
http://blog.dataman-inc.com/20160225-arangodb-mesos-persistent-storage/

相关文章
相关标签/搜索