調度分配無狀態應用的 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
爲了在同一個臺節點上重啓任務,框架須要可以再次收到該節點的資源offer。編程
在默認的狀況下,任務中止後,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 的一些入門技巧:
關於在 持久化卷特性上編程的更多細節,請參考連接:https://github.com/apache/mesos/blob/master/docs/persistent-volume.md#programming-with-persistent-volumes
ArangoDB 是一個分佈式的多模型數據庫,它是一個包含文檔存儲、key-value 存儲和圖存儲的數據庫,全部的操做都基於同一個引擎,使用統一的 query 語法。
做爲一個分佈式應用,因爲 Apache Mesos 或者數據中心操做系統(DCOS)負責分發和調度應用,管理集羣資源和失敗檢查,ArangoDB 運行在其上會有不少好處。Mesos 也能夠利用 Docker 容器部署應用,從而爲開發者解決了不少分佈式系統下使人頭疼的問題。
另外,對數據庫來講,一個很是大的需求是維護不停變化的狀態,同時因爲數據庫須要數據持久化,ArangoDB 須要訪問持久化的數據。理想狀況下,甚至須要使用本地的 SSD 數據盤(如今,這種 SSD 盤可以提供很是好的IO性能,數據持久化保障以及智能預測的數據緩存能力。)
與利用分佈式文件系統託管上面承載的分佈式應用的方法不一樣,針對於ArangoDB,咱們決定使用下面的方法來進一步提升數據持久化性能,即,全部的 ArangDB 集羣的任務都訪問本地存儲,並在重啓(譬如版本升級致使的重啓)後可以仍然訪問他們的數據。這就是咱們選擇利用 Apache Mesos 的 persistence primitives 特性的緣由。
有四種不一樣的 ArangoDB 任務:
ArangoDB集羣按下面的順序加載:
在下面的狀況下,ArangoDB 調度器也須要採起行動並維護相似的依賴需求:
ArangoDB 調度器也須要進行失敗處理。接到 Mesos master 的任務被殺或者 Mesos 節點失聯的通知後,調度器須要自動的進行失敗處理。爲了進行失敗處理,調度器會監聽集羣中任務的狀態,維護時間戳,並進行超時處理。
ArangoDB 經過一個事件輪訓的主程序來完成上述功能。這個主程序週期性從其餘線程獲取資源 offer,接受 Mesos 的更新信息,維護超時處理和事件響應。咱們會在下面詳細討論這裏的技術細節。
下面是使用了持久化卷的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/