容器與持久化存儲:容器的開源分布式存儲方案選型
容器正逐漸成為雲上應用的標準部署單元,容器該如何解決持久化存儲的需求?
容器編排系統已成當紅炸子雞,在無狀態的容器中,存儲系統面臨哪些新的挑戰?
容器與持久化存儲系統是融合架構還是分離架構?
張朝潞
有容雲平台存儲架構師
張朝潞,有容雲平台存儲架構師。曾工作於UIT、華三、騰訊、專註分布式存儲的研究和開發,對雲計算存儲解決方案方面有很深的技術造詣和行業理解。
一.容器對存儲插件的定義
以 Docker 為例, Docker 對存儲卷定義了一組簡單的介面,外部存儲只要實現簡單的介面便可以和外部存儲對接。
Docker daemon 和 plugin daemon 基於 UNIX 域套接字,使用 RESTful API 進行通信,下面是詳細的 API:
Plugin.Activate : 握手。
VolumeDriver.Create : 創建卷。
VolumeDriver.Mount : 掛載卷。
VolumeDriver.Path : 獲取卷的路徑。
VolumeDriver.Unmount : 卸載卷。
VolumeDriver.Remove : 刪除卷。
VolumeDriver.List : 獲取 volume 列表。
VolumeDriver.Get : 獲取 volume 信息。
VolumeDriver.Capabilities : 獲取 volume 屬性
從上面這組介面可以看出, Docker 容器是通過 mount 的方式將外部存儲掛載到本地目錄,盡量使內部應用程序對存儲是無感知的,應用程序就像使用本地目錄一樣使用外部存儲卷,而將外部存儲的管理交給存儲 Plugin 負責(如 Flocker、Rancher Convoy,REX-Ray 等)。
容器正逐漸成為雲計算平台應用程序的標準部署單元,容器能輕易的將各式各樣的應用程序及其 runtime 打包成統一的對象,於是編排調度系統能把各種應用程序當成統一的容器進行處理,大大簡化編排調度系統的複雜度。結合 Docker 對存儲插件的定義,不難看出 Docker 希望容器的運行環境獨立而純粹,不希望引入有狀態和複雜的存儲系統。
二、存儲插件
Convoy 作為一個 Docker volume plugin,支持不同的後端存儲,為 Docker 提供 MountPoint,也就是一個的目錄,可能是掛載了後端存儲、本地塊設備或者就是本地目錄。
Convoy 的代碼從結構、風格和使用的庫,都與 Docker 十分相似,並且比 Docker 簡單很多。
(小編:下面展開介紹一下 convoy 源代碼的部分模塊,不需要了解細節的讀者可以直接跳到第三部分:容器、應用程序、持久化存儲。)
Convoy 在源碼級別上值得留意的點,我認為有兩點:①插件式結構與 interface 的運用。② 作者對事物的抽象能力與方法。
1、convoy daemon (convoy / daemon)
圖 1 中黑色部分
daemon 是主要的功能模塊,可以接收來自 convoy client 和 Docker 的命令,對 backend 存儲進行了抽象,以便統一管理。下面先從 daemon 的啟動開始。
1.1、daemon 進程啟動
1)執行命令:
convoy daemon --drivers glusterfs --driver-opts glusterfs.servers=192.168.0.3 --driver-opts glusterfs.defaultvolumepool=vol2
2) convoy 程序解析參數,獲得 daemon 子命令,調用到 daemon.Start 函數(convoy/daemon/daemon.go), Start 函數中主要圍繞 daemon struct 建立所需要環境和配置。
3) Driver 初始化,優先從配置文件讀取信息忽略命令行輸入的參數,如果配置文件不存在則根據命令行參數初始化。
圖 2. convoy 配置文件內容
遍歷 DriverList,找到配置文件或命令行指定的 Driver,執行初始化函數 Init,並添加到 daemon.ConvoyDrivers 中。
4)根據 convoy 的工作目錄的內容,更新管理元數據,圖 1 中也有相應的模塊。
NameUUIDIndex: volume name : volume UUID
SnapshotVolumeIndex : snapshot UUID : volume UUID
圖 3.convoy 工作目錄和 volume 配置文件
5) Router 註冊: Router 提供兩部分的路由,並將 daemon 的 Router 指向該 Router。
(1) 處理 convoy client 的命令 Client Request Router,處理客戶端發送的 HTTP request。
(2) 處理來自 Docker 的請求 Docker Volume Plugin Router, convoy 本身就是 Docker 的 volume plugin,提供了如下的介面。
6) HTTP server 啟動,根據 sockFile = /var/run/convoy/convoy.sock 和 上一步驟的 Router,啟動 HTTP server。
2.2、daemon 的請求處理邏輯
Daemon 啟動後便可以處理請求( convoy client 或 Docker),主要處理邏輯 Router 收到 HTTP 請求,將請求分發給各個模塊: Docker、 volume、 snapshot、 backup。這個 4 個邏輯模塊根據 driver name( 指定的或者默認的 ) 從 daemon.ConvoyDrivers 中獲取對應的 Driver。 ConvoyDrivers 中的 Driver 是實現了 ConvoyDriver interface 的結構。
圖 4.convoy daemon 請求處理邏輯
從圖 4 中可以看出 ConvoyDriver 介面規定了 3 組介面對應 volume, snapshot, backup 的操作,用於操作 backend storage。邏輯處理最終調用這些介面訪問 Backend Storage。
2.3、ConvoyDriver implement
截止到 0.4.3 版本, convoy 支持 4 種後端存儲(實現了 ConvoyDriver 介面),如下表。
下面來說說,convoy 是如何對後端存儲進行抽象和管理,它使用了 4 種結構 Driver, Volume, Snapshot, Device。
Driver:主要實現了 ConvoyDriver 介面,提供對 Volume, Snapshot, Backup 等功能。
Volume:管理提供到 Docker 或者 convoy client 的 Volume。
Snapshot:用於管理 Volume 的快照。
Device:管理後端存儲提供的存儲空間,如: devicemapper 的 device ; glusterfs 的 volume ; vfs 的目錄等。
圖 5.ConvoyDriver 的實現
圖 5 Device 結構內容,記錄了該 Driver 的後端存儲的信息。
2.4、objectstore 提供實現備份的框架
Objectstore 模塊是實現 BackupOperations 介面所需要的基本功能,目前實現了兩種備份後端: S3 和 VFS。
它提供了兩種備份方案: DeltaBlockBackup(增量塊)和 BackupFile(備份文件)。
devicemapper 使用 DeltaBlockBackup 方式備份,實現了 DeltaBlockBackupOperations 介面。
vfs 使用 BackFile 方式備份。
Volume, Snapshot, Backup 用於管理備份存儲的數據。
ObjectStoreDriver 後端備份存儲需要實現的介面。
S3ObjectStoreDriver, VfsObjectStoreDriver 實現 ObjectStoreDriver。
Ebs 在實現 BackupOperations 介面時,使用 ebs 自身的 client 來實現 Backup。 ebs 本身就是一個分布式存儲系統,不再需要額外的 objectstore 對其進行備份。
圖 6. objectstore 框架
通過 vfs 備份的目錄結構:
volume.cfg 的內容,保存圖 6 中的 Volume 結構
backup_[ID].cfg,保存圖 6 中的 Backup 結構
blocks 目錄保存了 snapshot 存儲的真實數據,以 block 的形式存儲在不同目錄。
三、容器、應用程序、持久化存儲
容器與持久化存儲,在我看來本不該拿來一起討論,二者關聯性是比較弱的。
容器是一種打包方式,基於這種打包方式帶來了一系列的好處,如部署、程序運行環境統一,編排,調度等,誠然這些貌似與外部持久化存儲真心沒太大關係。
對持久化存儲真正有需求的是容器裡面的應用程序,應用程序對存儲的需求是多種多樣的。
基於容器化應用程序帶來的好處,運維工程師都是期望能將更多的應用程序容器化,以減輕運維負擔。
對於無狀態應用程序,容器化幾乎帶來的只有好處。
對於一些有狀態的應用程序,如資料庫,需要進行容器化時,便面臨持久化存儲的問題。下面是一個外部持久化存儲解決 MySQL 容器化問題的例子。
三台運行 MySQL 資料庫的主機將持久化存儲系統的虛擬磁碟映射上, MySQL 將數據寫入這些虛擬磁碟中。
當其中一個 MySQL 資料庫發生故障時,在新的主機上將故障主機的虛擬磁碟映射上,供 MySQL 使用,可以快速恢復資料庫故障。
此時,將 MySQL 資料庫容器化將變得十分簡單,編排調度系統,能夠快速發現 MySQL 集群異常,並快速調度其他主機上,減少故障時間。
由上述討論,其實無論容器在或不在,存儲還是存儲。當然為了適應容器的快速遷移(相對於虛擬機),多種多樣的應用程序對存儲也提出了細粒度控制、應用感知、快速創刪等新的需求,但存儲作為以穩定性為重的基礎設施,依然萬變不離其宗。
四、持久化存儲系統的選擇
持久化存儲系統可分為開源存儲系統和商業存儲系統。通常商業存儲系統會由廠商解決所有問題,這裡就不談商業化存儲了。
開源分布式存儲方案如下:
塊存儲: ceph rbd, sheepdog
文件存儲: glusterfs, cephfs, HDFS
對象存儲: OpenStack swift, ceph rgw
塊存儲、文件存儲、對象存儲三種存儲訪問方式不同的存儲系統,最合適容器的,我想應該是對象存儲系統,對象存儲系統是通過 URL 訪問的,應用程序只需要知道對象存儲系統的 URL 就可以直接訪問存儲系統,這種方式更貼近容器的無狀態、臨時性和快速調度。
為什麼選擇分布式存儲系統?
1、雲計算時代,傳統存儲不能滿足虛擬化、容器對存儲的需求
傳統存儲缺少靈活性,虛擬機、容器的部署及其負載是快速變化的,並且容器還是快速遷移的。
傳統存儲缺少自動化
傳統存儲缺少細粒度控制
傳統存儲的配置是非常嚴格的
2、構建存儲的 TCO( 總擁有成本 ) 十分高昂
數據量成指數級增長,但存儲的預算卻沒有相應的增長,傳統存儲的價格是無法承受之痛。
數據規模快速增長,企業往往需要過度預算,過度採購,因為傳統存儲的擴展,升級和替換是十分昂貴的。
3、高昂的存儲系統運營成本 (OPEX)
需要專業的存儲管理團隊,不僅需要學習專業的存儲知識,還要學習存儲廠商指定的技巧。
處理存儲系統問題是相當花費時間。
當然開源分布式存儲系統,只解決了第 1, 2 點,第 3 點並沒有得到有效的解決,反而有點加深的趨勢。
Q&A
提問:請問有沒有對 Flocker、 Rancher Convoy, REX-Ray 進行對比,性能,可用性及易用性?
張朝潞: Docker volume plugin 只做管理,數據流並不經過這三種插件,我們對比過 Flocker 和 convoy, flocker 成熟一些,但是兩者都沒達到我們項目的要求,因為這些插件開發起來比較簡單,我們就自己做了一套,主要是解決高可用的問題。
提問:請問實際環境中分布式存儲和容器應用運行需要注意哪些問題,資料庫程序在容器中運行結合分布式存儲做持久化有實際的生產環境案例嗎?
張朝潞:分布式存儲作為基礎設施必須要穩定,目前看來容器並沒有對存儲提出革命性的變革。但藉助外部存儲可以使系統更大程度的容器化,從而得到一系列容器帶來的好處。容器結合 Ceph 的案例我們確實遇到過,但是是非關鍵數據小範圍上生產環境,難點還是在存儲上。
提問:貴司是 K 黨還是 M 黨?技術選型是怎麼考慮的?
張朝潞:我們深入研究過 Kuberntes 和 Rancher,最終選用 k8s,技術選型要根據公司內部研發人員的技術長處和興趣點,無論是 K 或是 M 都能解決問題。
提問: gluster 與 Ceph 的區別是啥?應用場景有哪些不同?
張朝潞: gluster 支持文件介面, Ceph 支持塊,文件,對象介面;簡單的 gluster 比較簡單,社區版本就已經足夠穩定,但是海量小文件問題比較突出。 Ceph 隨著 OpenStack 已經十分火了,社區很活躍,也有不少存儲廠商基於 Ceph 做分布式存儲產品。
提問: convoy 不支持 Ceph?並沒有說明 Docker 怎麼與 Ceph 結合使用 ?
張朝潞: convoy 不支持 Ceph,並且已經不再更新, Docker 跟 Ceph 結合非常簡單,或者說 Docker 跟所有外部存儲結合都非常簡單,就像分享內容提到的滿足幾個介面就行了。
提問:對象存儲,和塊存儲是不是有不同的技術選型?
張朝潞:當然兩者應用場景不一樣,塊存儲主要是在虛擬化環境、資料庫場景。對象存儲優勢在於大規模海量數據和 HTTP 介面上。 針對不同的應用場景選型,如果需要非常大規模的,跨區域的場景建議使用 OpenStack swift,簡單好用。如果應用場景既需要塊存儲,對象存儲只需要中小規模的情況,一個 Ceph 搞定所有,也是不小的誘惑。如果公司內部沒有專業的研發和運維團隊,謹慎使用開源存儲上生產。
提問:開源化存儲 Ceph 和 sheepdog 的 IOPS 能達到多少?這兩種存儲的使用場景。
張朝潞:具體的 IOPS 跟物理的存儲介質和如何設置 Cache 的關係太大了, Ceph 用的最多的地方就是塊存儲, sheepdog 是塊存儲。個人感覺, Ceph 的設計比較學院派,大而全,數據拆分很細,元數據很多,維護難度較大,但是社區活躍,找人比較容易一些。 Sheepdog 體量小,架構複雜度較低,但出問題估計找人難度大。兩者都可以塊存儲,應用場景類似。
提問: Docker 已經提供了 volume 功能, convoy 做為 Docker 的插件,在那方面有做改進或者優化?而且我們在實際部署 Docker 應用的時候,一般都沒有考慮過存儲的問題,都是通過存儲工程師分配好的文件(包含共享存儲),為何要引入 convoy?
張朝潞: Docker 的 volume 是使用本地存儲系統,通過 volume plugin 機制訪問外部存儲,如 convoy 就是 Docker volume plugin 的一種實現。
提問:貴司用 Docker 做塊存儲?為何不用 Ceph 呢?
張朝潞: Ceph 複雜程度太大,自用都需要專門的運維與研發團隊。想要產品化還是自研靠譜。
提問:能說下 Ceph 的瓶頸在哪方面嗎?
張朝潞:磁碟和網路,計算機體系結構中最慢的兩個部件。 Ceph 的代碼級沒有什麼可以優化的空間。當然 Ceph 的強一致性,造成 IO 路徑加長會影響性能。
提問:我對最後那個 MySQL 的例子比較感興趣,我的理解是三個 MySQL 實例同時連接到存儲,然後一個掛了後,另起一個實例,我的問題是,這之前的三個存儲是共享數據的 cluster 集群環境嘛?如果是怎麼保證數據的一致性和寫入衝突問題?
張朝潞:多個 MySQL 最好不要掛同一個存儲空間,數據的性能瓶頸在於存儲端,多個掛一個存儲卷並不會提升性能。通常都是有上層業務來實現分表分庫,負載均衡,從而避免一致性問題。例子中是每個 MySQL 實例掛載一個單獨卷。
※模塊化還是微服務-為什麼說大部分團隊微服務化都走入了陷阱
※Protobuf有沒有比JSON快5倍?用代碼來擊破pb性能神話
TAG:高可用架構 |
※最早儲存電的容器
※你家儲存廚房調料用對容器了嗎?
※壓力容器的分類方法匯總
※電容器主要特性參數-無源元件之——電容器基礎知識!
※塑料容器裝冷飲也有風險
※基奧普斯金字塔的設計原理,居然跟電容器一樣可以儲存能量
※乾冰是不能儲存於密封性容器內,實驗告訴你有多危險
※可食用能源,完全由食物構成的可食用超級電容器
※空調電容器的作用是什麼 如何購買空調電容器 0
※放射性材料運輸容器:絕不變形的金剛!
※活在玻璃容器里的人
※cos正片——我想要容器 空白的容器
※塑膠容器能否裝冷飲?
※開源和商業的結合,或許是容器生態更光明的未來
※微軟與紅帽擴大圍繞容器支持的合作關係
※如何給無孔容器多肉植物澆水
※貓,液體流質動物,色彩斑斕形狀隨著容器的變化而變化……
※融化的巧克力倒入瓶中,一刀切開做成趣味好玩的容器
※超越作為容器的身體 吳凡個展「容身」開幕