如何利用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/

相關文章
相關標籤/搜索