爲什麼我要選擇使用 Yarn 來做 Docker 的調度引擎


原文鏈接


作者: 祝威廉

編者按

Mesos 和 Yarn 都是非常優秀的資源調度框架,社區也有很多的人分析二者的區別以及使用場景。之前 InfoQ 也有發問聊過二者的關係。目前業界用的較多的是 Mesos,這篇文章就是爲了解釋爲什麼作者選擇使用 Yarn 而不是 Mesos,並介紹瞭如何基於 Yarn 開發分佈式程序。本文首發於祝威廉的博客,經授權由 InfoQ 轉載發佈。

前言

Mesos 其實我不是非常熟悉,所以有些內容可能會有失偏頗,帶有個人喜好。大家也還是需要有自己的鑑別能力。

Mesos 和 Yarn 都非常棒,都是可編程的框架。一個硬件,不能編程,就是死的,一旦可以編程就活了,就可以各種折騰,有各種奇思妙想可以實現,同樣的,一個軟件,只要是可編程的,基本也就活了,容易形成生態。

Yarn VS Mesos

我先說說在做容器調度引擎的時候,爲什麼選擇 Yarn 而不是 Mesos。

可部署性

先說明下,這裏探討的是 Yarn 或者 Mesos 集羣的部署,不涉其上的應用。Yarn 除了依賴 JDK,對操作系統沒有任何依賴,基本上放上去就能跑。Mesos 因爲是 C/C++ 開發的,安裝部署可能會有庫依賴。 這點我不知道大家是否看的重,反正我是看的相當重的。軟件就應該是下下來就可以 Run。所以 12 年的時候我就自己開發了一套 Java 服務框架,開發完之後運行個 main 方法就行。讓應用包含容器,而不是要把應用丟到 Tomcat 這些容器,太複雜,不符合直覺。

二次開發

Yarn 對 Java/Scala 工程師而言,只是個 Jar 包,類似索引開發包 Lucene,你可以把它引入項目,做任何你想要的包裝。 這是其一。

其二,Yarn 提供了非常多的擴展接口,很多實現都是可插拔。可替換的,在 XML 配置下,可以很方便的用你的實現替換掉原來的實現,沒有太大的侵入性,所以就算是未來 Yarn 升級,也不會有太大問題。

相比較而言,Mesos 更像是一個已經做好的產品,部署了可以直接用,但是對二次開發並不友好。

生態優勢

Yarn 誕生於 Hadoop 這個大數據的“始作俑者”項目,所以在大數據領域具有先天優勢。

  1. 底層天然就是分佈式存儲系統 HDFS,穩定高效。

  2. 其上支撐了 Spark、MR 等大數據領域的扛頂之座,久經考驗。

  3. 社區強大,最近發佈版本也明顯加快,對於長任務的支持也越來越優秀。

長任務支持

談及長任務(long running services)的支持,有人認爲早先 Yarn 是爲了支持離線短時任務的,所以可能對長任務的支持有限。其實大可不必擔心,譬如現在基於其上的 Spark Streaming 就是 7x24 小時運行的,跑起來也沒啥問題。一般而言,要支持長任務,需要考慮如下幾個點:

  1. Fault tolerance,主要是 AM 的容錯。

  2. Yarn Security,如果開啓了安全機制,令牌等的失效時間也是需要注意的。

  3. 日誌收集到集羣。

  4. 還有就是資源隔離和優先級。如果資源隔離做的太差,會對長時任務產生影響。

大家感興趣可以先參考Jira。我看這個 Jira 13 年就開始了,說明這事很早就被重視起來了。下面我們隊提到的幾個點做下解釋。

Fault tolerance

  1. Yarn 自身高可用。目前 Yarn 的 Master 已經實現了 HA。

  2. AM 容錯,我看從 2.4 版本(看的源碼,也可能更早的版本就已經支持)就已經支持 keep containers across attempt 的選項了。什麼意思呢?就是如果 AM 掛掉了,在 Yarn 重新啓動 AM 的過程中,所有由 AM 管理的容器都會被保持而不會被殺掉。除非 Yarn 多次嘗試都沒辦法把 AM 再啓動起來(默認兩次)。 這說明從底層調度上來看,已經做的很好了。

日誌收集到集羣

日誌收集在 2.6 版本已經是邊運行邊收集了。

資源隔離

資源隔離的話,Yarn 做的不好,目前有效的是內存,對其他方面一直想做支持,但一直有限。這估計也是很多人最後選擇 Mesos 的緣由。但是現在這點優勢 Mesos 其實已經蕩然無存,因爲 Docker 容器在資源隔離上已經做的足夠好。Yarn 和 Docker 一整合,就互補了。

小結

Mesos 和 Yarn 都是非常優秀的調度框架,各有其優缺點,彈性調度,統一的資源管理是未來平臺的一個趨勢,類似的這種資源管理調度框架必定會大行其道。

一些常見的誤解

脫胎於 Hadoop,繼承了他的光環和生態,然而這也會給其帶來一定的困惑,首先就是光環一直被 Hadoop 給蓋住了,而且由於固有的慣性,大家會理所當然的認爲 Yarn 只是 Hadoop 裏的一個組件,有人會想過把 Yarn 拿出來單獨用麼?

然而,就像我在之前的一篇課程裏,反覆強調,Hadoop 是一個軟件集合,包含分佈式存儲,資源管理調度,計算框架三個部分。他們之間沒有必然的關係,是可以獨立開來的。而 Yarn 就是一個資源管理調度引擎,其一開始的設計目標就是爲了通用,不僅僅是跑 MR。現在基於 Yarn 之上的服務已經非常多,典型的比如 Spark。

這裏還有另外一個誤區,MR 目前基本算是離線批量的代名詞,這回讓人誤以爲 Yarn 也只是適合批量離線任務的調度。其實不然,我在上面已經給出了分析,Yarn 是完全可以保證長任務的穩定可靠的運行的。

如何基於 Yarn 開發分佈式程序

本文不會具體教你如何使用 Yarn 的 API,不過如果你想知道 Yarn 的 API,但是又覺得官方文檔太過簡略,我這裏倒是可以給出兩個建議:

  1. 代碼使用範例可以參看 Spark Yarn 相關的代碼。算的上是一個非常精簡的 Yarn 的 adaptor。

  2. 買本 Yarn 相關的書,瞭解其體系結構也有助於你瞭解其 API 的設計。

接下來的內容會探討以下兩個主題:

  1. 基於 Yarn 開發分佈式程序需要做的一些準備工作

  2. 基於 Yarn 開發容器調度系統的一些基本思路

基於 Yarn 開發分佈式程序需要做的一些準備工作

肯定不能擼起袖子就開始幹。開始動手前,我們需要知道哪些事情呢?

Yarn 原生的 API 太底層,太複雜了

如果你想愉快的開發 Yarn 的應用,那麼對 Yarn 的 API 進行一次封裝,是很有必要的。 Yarn 爲了靈活,或者爲了能夠滿足開發者大部分的需求,底層交互的 API 就顯得比較原始了。自然造成開發難度很大。這個也不是我一個人覺得,現在 Apache 的 Twill,以及 Hulu 他們開發的時候 Adaptor 那一層,其實都是爲了解決這個問題。那爲什麼我沒有用 Twill 呢,第一是文檔實在太少,第二是有點複雜,我不需要這麼複雜的東西。我覺得,Twill 與其開發這麼多功能,真的不如好好寫寫文檔。

最好是能開發一個解決一類問題的 Framework

Yarn 只是一個底層的資源管理和調度引擎。一般你需要基於之上開發一套解決特定問題的 Framework。以 Spark 爲例,他是解決分佈式計算相關的一些問題。而以我開發的容器調度程序,其實是爲了解決動態部署 Web 應用的。在他們之上,纔是你的應用。比如你要統計日誌,你只要在 Spark 上開發一個 Application 。 比如你想要提供一個推薦系統,那麼你只要用容器包裝下,就能被容器調度程序調度部署。

所以通常而言,基於 Yarn 的分佈式應用應該符合這麼一個層次:

Yarn -> Adapter -> Framework -> Application

Adapter 就是我第一條說的,你自個封裝了 Yarn 的 API。 Framework 就是解決一類問題的編程框架,Application 纔是你真正要解決業務的系統。通過這種解耦,各個層次只要關注自己的核心功能點即可。

保證你上層的 Framework/Application 可以移植

Spark 是個典型,他可以跑在 Mesos 上,也可以跑在 Yarn 上,還可以跑在自己上面(Standalone),實時上,泡在 Yarn 上的,以及跑 Standalone 模式的,都挺多的。這得益於 Spark 本身不依賴於底層的資源管理調度引擎。

這其實也是我上面說的兩條帶來的好處,因爲有了 Adaptor,上層的 Framework 可以不用綁死在某個資源調度引擎上。而 Framework 則可以讓 Applicaiton 無需關注底層調度的事情,只要關注業務即可。

另外,你費盡心機開發的 Framework 上,你自然是希望它能跑在更多的平臺上,已滿足更多的人的需求,對吧。

基於 Yarn 開發容器調度系統的一些基本思路

首先我們需要了解兩個概念:

  • 啞應用。所謂啞應用指的是無法和分佈式系統直接進行交互,分佈式系統也僅僅透過容器能進行生命週期的控制,比如關閉或者開啓的應用。典型的比如 MySQL、Nginx 等這些基礎應用。他們一般有自己特有的交互方式,譬如命令行或者 socket 協議或者 HTTP 協議。

  • 伴生組件。因爲有了啞應用的存在,分佈式系統爲了能夠和這些應用交互,需要有一個代理。而這個代理和被代理的啞應用,具有相同的生命週期。典型的比如,某個服務被關停後,該事件會被分佈式系統獲知,分佈式系統會將該事件發送給 Nginx 的伴生組件,伴生組件轉化爲 Nginx 能夠識別的指令,將停止的服務從 Nginx 的 ProxyBackend 列表中剔除。

在容器調度系統中,如果 Yarn 的 NodeManager 直接去管理 Docker 則需要 Yarn 本身去做支持,我覺得這是不妥的。Yarn 的職責就是做好資源管理,分配,調度即可,並不需要和特定的某個技術耦合,畢竟 Yarn 是一個通用型的資源調度管理框架。

那基於上面的理論,我們基於 Yarn,開發一套框架,這個框架會是典型的 master-slave 結構(這是 Yarn 決定的)。這個框架的 slaves 其實都是 Docker 的伴生對象。master 可以通過這些 Slave 對容器實現間接的管理。

 我們簡單描述下他們的流程:

  1. 用戶提交 Application,申請資源;

  2. Yarn 啓動 Framework 的 master;

  3. Yarn 啓動 Framework 的 slave;

  4. slave 連接上 master,並且發送心跳,從而 master 知道 slave 的狀況 slave 啓動 Docker,slave 與被啓動的這個 docker container 一一對應;

  5. slave 定時監控 Container;

  6. slave 發現 container crash,slave 自動退出,Yarn 獲得通知,收回資源;

  7. master 發現有節點失敗,發出新的節點要求,重新在另外一臺服務器上啓動 slave,重複從 2 開始的步驟。

這裏還有一個問題,如果 slave 被正常殺掉,可以通過 JVM ShudownHook 順帶把 Container 也關掉。 但是如果 slave 被 kill -9 或者異常 crash 掉了,那麼就可能導致資源泄露了。目前是這個信息是由 master 上報給集羣管理平臺,該平臺會定時清理。你也可以存儲該信息,譬如放到 Redis 或者 MySQL 中,然後啓動後臺清理任務即可。

瞭解了這個思路後,具體實施就變得簡單了,就是開發一個基於 Yarn 的 master-slave 程序即可,然後 slave 去管理對應的 Docker 容器,包括接受新的指令。master 提供管理界面展示容器信息,運行狀態即可。

當然,你還可以再開發一套 Framework B 專門和 Nginx 交互,這樣比如上面的系統做了節點變更,通知 B 的 master,然後 B 的 master 通過自己的伴生組件 Slave 完成 Nginx 的更新,從而實現後端服務的自動變更和通知。

現在看來,是不是這種概念完美的覆蓋了應用之間的交互呢?


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章