Mesos持久化存儲初探
【編者按】 持久化是Mesos下一個版本的一項重點工作,也是提高Mesos分布式環境資源利用率必須解決的問題。本文系作者根據自己在Mesos Meetup第二期的演講內容整理,講解Mesos 解決持久化存儲問題的思路,介紹了即將發布的Mesos 0.23的兩個相關特性:Persistent Volumes 和 Dynamic Reservations。
如何將 MySQL、Mongodb 等存儲型服務或stateful service融到 Mesos 中是使用 Mesos 時需要思考的一個問題。我們認為只有讓 MySQL 集群、MongoDB 集群、RabbitMQ 集群等等所有這些都使用 Mesos的資源池,Mesos才能成為一個真正的分布式操作系統,才能提高整個分布式環境的資源利用率。然而,在當前的 Mesos 0.22,社區并沒有給出一個generic的解決方案,有的只是某些團隊針對個例開源的項目,譬如,推ter 開源的 Mysos ,是一個運行 MySQL 實例的Mesos framework。拋開 Mysos 等的可用性不談,我認為 Mesos 需要的是一個統一的、公用的解決方案。
最近 Mesos 社區在其郵件列表里公布了 Mesos 0.23 發布計劃概要 (Proposal) , 其提到了3個重要的feature:SSL、Persistent Volumes 和 Dynamic Reservations, 后兩者都是跟存儲相關的功能。 這些功能是 Mesos 社區解決持久化問題的雛形,這里我會分享下 Mesos 解決此問題的大致思路。另外, 由于本篇文章寫作時,Mesos 0.23 還沒有 release,所以可能跟最終版本有些出入。而且,從 Mesos 的原始 Paper 可以看到,Mesos 是為 short-term 或者stateless的計算型任務而生的,所以說使用 Mesos 來管理 long-term 的服務,其穩定性和可行性,還有待實踐驗證。
當前我們可以怎么解決持久化問題
- 將stateful service放到 Mesos 集群之外
顯然這有違我們使用 Mesos 的初衷,我們無法利用 Mesos 來提高集群外節點的資源利用率。但是在很多應用場景下,譬如stateful service的資源使用在大部分時間內趨于常量,利用現有的成熟方案快速搭建穩定的Redis,RabbitMQ集群等,仍然是effort最小的解決方案。
- 使用 Mesos 節點上的本地文件系統
Mesos 通過限制 role 可以將task發布到指定的slave上,這樣我們就可以讓 stateful service 的task持久化數據到該slave的數據盤上,同時不要將該數據盤作為集群的resource,這樣才能避免持久化的數據被Mesos回收掉,新的 task才能recover以前的數據。以MySQL數據庫為例,通過marathon將 MySQL( Dockerized) 發布到 role=MySQL 的唯一一臺slave上,同時map slave上的數據卷 /data 到 docker container 的目錄 /var/lib/mysql, 這樣MySQL的task就會把數據持久化到slave上的/data目錄,而且將來被分發到這個slave上的MySQL task仍然可以restore /data 里的數據。
這個方案會存在許多問題:第一,為了保證 MySQL task 運行時所需的CPU,Memory等,我們需要static reserve 該 slave 上的資源。這樣無論MySQL task有沒有在使用這些資源,集群中的其它 task 都不能使用它。這個問題可以通過下面我們提到的分布式文件系統部分解決;第二,目錄 /data 里的資源無法被集群釋放掉,盡管 /data 里的數據是持久化的,我們仍然可能會在未來的某個時刻刪除過時的數據以回收資源,在當前的架構下,只能通過集群之外的手段去完成;第三, 可能會出現 data conflict,多個MySQL task使用同一個 host 目錄 /data,不僅數據沖突難以避免,而且data size也無法限制。在當前的情況下,可以通過限制一個 slave 只運行一個 MySQL task 來臨時解決;第四,對 MySQL 集群無能為力,這樣也就無法保證服務高可用。
- 為 Mesos 集群配置分布式文件系統
為了保證 stateful service 能在任何 slave 上訪問持久化的數據,我們可以為集群配置 DFS,這就解決了 static reserve 資源的問題。 但隨之而來的是數據傳輸的網絡延遲,像MySQL或PG數據庫對網絡延遲的容忍有待驗證。同時,在這個架構下,Mesos無法管理DFS節點間的網絡傳輸,這又相應增加了集群的復雜度。一個顯而易見的解決辦法是,犧牲網絡的資源利用率,在Mesos集群之外再為DFS配置一套高性能的網絡環境,避免 DFS占用集群的網絡資源。
- 本地文件系統+stateful service build-in 數據分片功能
許多 stateful service 先天支持數據分片功能,譬如Cassandra,MariaDB Galera,MongoDB等,這些是當前最適合接入 Mesos 集群的 stateful service。其中Mesosphere已經實現了[cassandra-on-mesos]( https://github.com/mesosphere/cassandra-mesos )-一個 Cassandra的mesos framework, 另外,我還在網絡上發現了關于 [MariaDB Galera on mesos]( http://sttts.github.io/galera/mesos/2015/03/04/galera-on-mesos.html )的博客-利用 Marathon發布MariaDB Galera。
以 Cassandra為例,限制 Cassandra Framework 使用指定的多個 slave 節點資源,Cassandra 可以在這些節點上的本地文件系統進行數據分片的持久化。顯然, 這種情況下沒有網絡延遲問題,同時,由于 Cassandra 的 task 受 Mesos 集群管理,所以網絡傳輸也是集群可控的,不會增加集群的復雜度。
綜上所述,在當前版本下,為了進行數據持久化, 除了集群資源的 static partition,我們還需要在 Mesos 集群之外提供磁盤,甚至網絡資源。顯然,這大大降低了集群的資源利用率。
disk isolation and monitoring(磁盤隔離和監測)
在探討 persistent volumes 與 dynamic reservations 之前,我們有必要了解下 Mesos 的磁盤隔離和監測機制。盡管磁盤是廉價的,但為了保證 Mesos slave 上其它 task 的正常運行,Mesos 仍然需要限定 slave 上 task 的磁盤配額。
首先,這里所提到的 task 磁盤是一個generic的概念,它有可能是一個通過物理磁盤或LVM卷創建的獨享的文件系統,在這種情況下,task如果嘗試寫超出它所申請的數據量到磁盤中,它會收到信號ENOSPC,即No Space left on Device,(由于筆者沒有研究具體的實現細節,mesos 也有可能是通過kernel事件回調來處理data size超出的情況),顯然task將會被中斷,這種設置比較適合生產環境,又稱為 hard enforcement;另外一種是對應的 soft enforcement,task 的磁盤是與其它運行在該 slave 上的 task 共享的文件系統下的一個目錄,在這種情況下,Mesos 是通過周期性的運行 du 命令來監測 task 磁盤的使用狀況的,所以 task 寫入到磁盤的數據量可能會超出它所申請的磁盤大小。
其次,對于上述共享的文件系統, Mesos 實現了 shared filesystem 隔離,當然這個只支持Mesos build-in 容器的隔離,它通過命令 mount -n --bind 來將容器的path映射到slave的path,并且task完成后,kernel會自動執行mount的cleanup工作;對于docker容器的隔離,Mesos使用Docker自身的volumn映射機制。
再次,為了避免重度磁盤 IO的task阻塞另一個task的磁盤IO操作,Mesos 社區正在討論利用Cgroups blkio controller 進行磁盤IO隔離。
最后,在 task 寫入到磁盤的數據量超出它所申請的磁盤大小時, Mesos 是否應該中斷task呢? 對于上面提到的第一種 task 磁盤來說,task 顯然會因異常而被終止,進而數據被 Mesos 垃圾回收掉;對于第二種 task 磁盤來說,由于當前 Mesos 不支持持久化磁盤,被中斷的 task 將無法 recover 先前的數據,所以 Mesos 默認是不會中斷 task 的,Mesos 將這種情況交給 Framework 處理。
更多詳細信息, 請參考 issue [enforce disk quota in MesosContainerizer]( https://issues.apache.org/jira/browse/MESOS-1588 ) 。
Persistent Volumes(持久化卷)
在即將 release 的 Mesos-0.23 中,Mesos 可以為 task 提供持久化卷,在 task 運行結束后, 持久化卷里的數據不會被 Mesos 回收。同時,新的 task 可以通過該持久化卷讀取前一個已完成task存儲的數據。與前面提到的在 Mesos 集群外提供磁盤資源不同,這里的持久化卷是Mesos集群內的資源,受Mesos的管理。另外,即使 slave 被重啟,或 slave info/id 改變,持久化卷里的數據依然不會丟失。
基于持久化卷, Mesos 會向 Framework offer 兩種資源:regular resource 和 persistent resource。其中 regular resource 就是 0.22 版本中的 resource,regular resource 適合 stateless service,task完成后,CPU,RAM和磁盤資源都會被 Mesos 回收;persistent resource 是0.23版本中的一個新概念,它 除了包括持久化卷標,還包含了CPU和RAM等資源,這可能與我們的直觀感覺不一樣。原因很簡單,集群需要避免這種狀況,即 slave 可以為 task 提供持久化卷但是 CPU/RAM 已經被占用,所以 Mesos 需要將部分或全部CPU/RAM和持久化卷打包在一起offer給framework。對于提供 stateful service 的Framework來說,它會在 persistent resource 上執行 task,并且 task 完成后,持久化卷里的數據會被保留,這與 google Borg 的工作方式類似。下面是帶有persistent resources 的 offer 例子:
{“id” : { “value” : “offerid-123456789”}, “framework_id” : “MYID”, “slave_id” : “slaveid-123456789”, “hostname” : “hostname1.prod.twttr.net” “resources” : [ // Regular resources. { “name” : “cpu”, “type” : SCALAR, “scalar” : 10 } { “name” : “mem”, “type” : SCALAR, “scalar” : 12GB } { “name” : “disk”, “type” : SCALAR, “scalar” : 90GB } // Persistent resources. { “name” : “cpu”, “type” : SCALAR, “scalar” : 2, “persistence” : { “framework_id” : “MYID”, “handle” : “uuid-123456789” } } { “name” : “mem”, “type” : SCALAR, “scalar” : 2GB, “persistence” : { “framework_id” : “MYID”, “handle” : “uuid-123456789” } } { “name” : “disk”, “type” : SCALAR, “scalar” : 10GB, “persistence” : { “framework_id” : “MYID”, “handle” : “uuid-123456789” } } ] ... }
這里社區給出了一個 Framework 使用持久化卷的例子[an example framework for testing persistent volumes]( https://reviews.apache.org/r/32984/diff/2/ )
另外,由于 task 之間可能需要共享相同的持久化數據,Mesos 未來還會支持資源共享。譬如,MySQL 的 framework 可能會運行一個 mysqld server 的 task 和另一個周期備份數據庫的 task,并且,這兩個 task 都需要訪問同一個持久化數據文件。
更多詳細信息,請參考 issue [persistent resources support for storage-like services( https://issues.apache.org/jira/browse/MESOS-1554 )
Dynamic Reservations(動態保留)
前面已經提過,對于 stateful service framework 來說,framework 需要在特定的一個或幾個 slave 上運行新的 task 以能夠讀取已完成 task 存儲在持久化卷里的數據。在 0.22 版本,為了保證任何時刻在這些特定的 slave 上都能執行上述操作,slave 在啟動時會靜態的為相應的role保留資源,即每一個slave需要為每一個支持 stateful service 的role進行配置,資源無法被其它 framework 使用,靈活性特別差。這種狀況在0.23實現了 Dynamic Reservations 之后得到了改善,相對于static role,集群引入了新的 reserved role。
- 當啟動一個 task時, framework 可以設置 “reserved_role” 去聲明動態保留resource(無論是regular resource 還是 persistent resource),其中這里的 “reserved_role” 是framework注冊到Mesos的role;
- 當 task完成后,設置了“reserved_role” 的 resource 會重新 offer 給相應的 framework;
- 當一個 framework收到了帶有 “reserved_role” 的resource,它會知道這個資源是動態保留的,如果framework不再需要這些動態保留的資源了,它可以通過新的 API “release" 來釋放掉這些資源。但是,framework無法釋放靜態分配的資源給其它framework使用。
更多詳細信息,請參考 issue[Dynamic Reservation] ( https://issues.apache.org/jira/browse/MESOS-2018 )
展望
基于 Mesos 0.23,我們可以怎樣讓 stateful service 更好更快的使用 Mesos 集群資源呢?從有狀態服務與 Mesos 集成的工作量大小角度來看,有狀態服務可以分為兩大類:
- 無中心節點的 stateful service 。譬如Cassandra,由于各節點的功能平等,我們可以利用docker包裝Cassandra程序成excutor,并通過已有schedule 如 Marathon 發布到特定的已進行了持久化配置的 slave 節點上來提供服務。
- master-slave 或者 leader-follower 模式的 stateful service 。例如HDFS,MongoDB,MySQL等,這種類型服務的節點功能是不一樣的,有name node, config node,data node 等等。我們需要為各個服務的各種節點dockerize excutor, 并開發schedule,同時解決容錯,備份等問題以達到production ready。
綜上, Mesos 0.23 的 release 將極大的改進stateful service使用Mesos集群的方式,這也讓企業的整個環境集成到 Mesos 成為可能。
作者簡介: 周偉濤,數人科技(www.dataman-inc.com) 云平臺負責人。曾在 Red Hat工作。Pythoner,對NLP、CI、Mesos和Docker有一定的實踐經驗。
Reference
- https://docs.google.com/presentation/d/1ku7YnAzUai0A0i79tYycqlg5EhewhXoTomYeRPLTBw/edit#slide=id.g39b2d4eb6_00
- https://docs.google.com/document/d/1Az4pYN9LEOsCqTgL0MXn7YyId6IU2HZKa0_hIaxu0uE/edit
- https://docs.google.com/document/d/1GwI0gk6oZHL3tJbdZRFstnUftR0C4udRY6al9XRhgI/edit#heading=h.fm07s55ubih4
- http://cloudarchitectmusings.com/2015/03/31/dealing-with-persistent-storage-and-fault-tolerance-in-apache-mesos/
- https://docs.google.com/document/d/1Az4pYN9LEOsCqTgL0MXn7YyId6IU2HZKa0_hIaxu0uE/edit