這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
秋收圖
也許生活在這鋼筋混泥土之中,早已淡了季節輪迴的感觸,忽視了做為大自然的有機體,新陳代謝,生生不息的一面。秋天短暫,卻是收穫喜悅的季節,幸福四溢,風乍起,那麥浪的金黃。
與分布式fs擦肩而過
2013年開始籌劃資料庫的拆分,2C的分類資訊網站時間序特徵很明顯。每天都有對曆史資料進行歸檔,不斷的瘦身,典型按時間 "horizontal sharding"。隨著業務增長和變化,熱資料已有幾百GB,特別是開放免費連接埠後,短時間資料暴增,例如二手房源表,單表100G,按主鍵的查詢也非常慢,系統極不穩定。
由於系統設計問題,MySQL 直接儲存詳情頁描述部分的 HTML 程式碼。經過分析,描述 TEXT欄位平均 6KB 左右,100G的單表,貼子屬性資料只有20G,其它均為描述 TEXT 欄位,決定拆欄位,也就是所謂的 "vertical sharding"。拆出的 TEXT 欄位儲存有兩個選擇,MySQL 或是Distributed File System。對市面上一些系統做調研後,沒有營運經驗,出於穩定性和非侵入考慮,選擇扔然儲存在 MySQL 中。後來做 Automan SQL 自動上線,支援批量檔案上傳,儲存在本機檔案系統中,一直沒有改成儲存Distributed File System中,很可惜,擦肩而過。
上周看毛劍在寫基於 haystack 的檔案系統,正好重溫一遍。
臉書老的圖片架構
圖片訪問流程
是標準的圖片訪問流程,使用者上傳圖片,Web Server 直接儲存到後端儲存中,並將圖片 Url 儲存到資料庫中,例如 MySQL等。Url 類似如下格式:
http://<Machine ID>/FILE/PATH
當請求發出後,Web Server 從 MySQL 中取出圖片 Url 資訊,包裹一層 CDN 資訊,扔到使用者的瀏覽器頁面。由使用者瀏覽器按照包裹後的 Url 渲染頁面,包裹的格式可能如下:
http://<CDN>/<TAG>/<Machine ID>/FILE/PATH
CDN 處理請求,如果圖片不存在,那麼根據協議剝離出真實圖片 Url,去來源站點請求沖 Cache,這就是人們常說的 CDN 回源,監控回源率來不斷最佳化業務。
NFS-Based Design
自然地,臉書老架構也是將圖片儲存到類 POSIX 檔案系統中,商業共用儲存 + NFS 掛載模式。這個模式支援臉書的飛速發展,比較像05年阿里的IOE。後來這個架構遇到了瓶頸:
1. 臉書圖片四個尺寸,隨著量越來越大,長尾理論突顯,CDN 緩衝這些長尾成本太高。
2. 類 POSIX 儲存方式,為擷取檔案,訪問 metadata 產生很多 IO 。比如說許可權這些屬性資訊就是不必要的,如果 metadata 全部緩衝在記憶體中,成本太高。
臉書haystack架構
Haystack 是臉書在2012年發布的論文《Finding a needle in Haystack: Facebook’s photo storage》,詳細描述了他們的圖片儲存架構更迭。那麼 haystack 就是要解決這些問題,有四個設計目標:
1. High throughtput and low latency. 和資料庫 OLTP 業務類似,要求高吞吐和低延遲,一方面熱門圖片緩衝到 CDN 中,另外一方面減少儲存磁碟 IO 次數,將 metadata 存放到記憶體中,擷取圖片只發生一次 IO 操作。
2. Fault-tolerant. 高可用性是不可避免的話題,haystack 設計時考慮了地區 IDC 容災和機櫃容災。服務端上傳圖片時指定冗餘策略。
3. Cost-effective. 基於商業共用儲存的都比較貴,普通 PC 伺服器掛載大硬碟便宜很多,但是故障率也比較高,這一點比較考驗 Fault-tolerant 高可用。
4. Simple. 架構簡單,部署和營運更方便。最近在研究的 vitess 架構和部署非常複雜,這也是他流行不起來的一個原因。
基於這個思想,haystack 設計者繞過了 POSIX 檔案系統這塊,把 haystack 變成了一個 KV FS,即 NOFS。每個圖片對應一個 FID,不再單獨存放檔案系統中,而是同一個物理卷 Volume 圖片全部寫入一個檔案中,由 Volume Server 記憶體維護 FID : <Volume Machine, Offset, Size> 映射關係,Volume Server 記憶體中維護開啟的檔案控制代碼,讀取圖片時只需一次 IO 順序讀操作。
haystack架構圖
架構比較簡單,分為三部份:Haystack Directory, Haystack Cache, Haystack Store
Directory: 即所謂的 Meta Server
1. 產生 FID,維護 logical volume 與 physical volume 映射關係,解決上傳時的負載平衡問題。
2. 新加入的 Store Server 要在這裡註冊。
3. 維護 logical volume 的 read-only 屬性,唯讀 logical volume 不再接受 upload 請求。
4. 決定請求走 CDN 還是內部 Haystack Cache Server.
Cache: 所謂的內部 CDN
1. 對圖片 FID 採用一致性 hash 演算法儲存。
2. 只緩衝使用者請求,而不是來自 CDN 的請求。
3. 只緩衝 write-enabled store 圖片,由於上傳的時間序,相當於只緩衝最新產生的圖片。比如說使用者剛上傳的圖片,可能就會存到 Cache 中預熱。
Store: 最終落地儲存服務
1. 圖片順序追加到一個大檔案中,記憶體中維護圖片在檔案中的 Offset 和 Size 的索引資訊。
2. 為瞭解決重啟快速載入問題,索引資訊會單獨儲存到一個 Index File 中。
Store 儲存格式
涉及兩類檔案, Store File 和 Index File。
Store File Layout
Store File 是一個大檔案,檔案頭為 Superblock 儲存全域的版本號碼等資訊。每個圖片為一個 Needle 結構,順序追加到檔案尾。每個 Needle 儲存圖片的 Cookie, Key, Flags, Size, Data, CheckSum等資訊,由於臉書上傳圖片一式四份,四個尺寸共用同一個 Key, 那麼就由 Alternate Key 做區分。
Index File Layout
當機器重啟後,需要利用 Index File 快速重建記憶體中圖片索引資訊。如果沒有索引檔案,那麼順序掃描 Store File 也可以重建,但耗時。 假設 Needle Index 佔用24byte,那麼128G記憶體機器可以儲存68億圖片的中繼資料資訊。論文中表示,Index File 非同步寫,重啟後可能會有 Ophen Photo 需要從 Store File 中重建。
圖片上傳,更新與刪除
圖片時間序特徵很明顯,所有的上傳,更新與刪除均為 Append 追加操作。 Web Server 請求 Directory Server, 擷取 Volume Id, Key, Alternate Key, Cookie。Web Server 將這些與圖片資料上傳到指定 Store 機器上,資料的冗餘由 Store 同步完成,強一致。
更新操作與上傳一致,更新記憶體索引資訊,資料追加到 Store File 即可。刪除操作將記憶體和 Index File 中的 Flags 標記為刪除即可。對於大量刪除操作,會產生檔案空洞,需要根據一定策略回收。
圖片讀取
在 Url 中可以解出圖片的 Volume Id, Key, Alternate Key, Cookie 資訊,Web Server 訪問 Directory Server 得到該 Volume Id 所在的 Store Server。再由 Store Server 查詢記憶體中索引資訊,根據 Flags 標記判斷是否已刪除。如果未刪除,根據 Offset Size 去 Store File 擷取詳細資料,解出儲存的資料和 Cookie,判斷與請求的 Cookie 是否一致,不一致則報錯。
Weadfs
Weadfs 是開源版本的GO實現,代碼比較簡單易懂。仔細閱讀源碼,可以加深對 haystack 的理解和認識。看知乎上說好多公司在使用,比較穩定。
1. 臉書的 Paper 裡還是有好多細節沒有披露,比如 Directory Server 的高可用,如果多個那麼資料一致性的保證。從源碼上看 Weadfs 通過 Raft 來達到多個 Master Server 的高可用。
2. Weedfs 的 Padding 為8,Size使用4位元組,那麼單 Volume 檔案最大32GB.
3. 相比 haystack, 多了很多實用功能:Gzip壓縮,索引資訊可以儲存在 LevelDB 中,多 Master 高可用,filer server 等等。
BeansDB&FastDFS&HDFS
趕集使用 FastDFS 做圖片儲存,Tracker Server 對應 haystack 的 Directory Server. 但是 FastDFS是使用 POSIX 檔案系統的,IO 壓力有些大。
BeansDB 是 nice 在使用的儲存,Memcache協議,基於 Bitcask 模型,由 R+W>N 來保證一致性。豆瓣一直在用,儲存 mp3 文本 圖片資訊。
這兩個開源產品也是針對小檔案儲存體做的最佳化,有時間還得好好讀讀源碼加深理解。另外一個 HDFS 用來儲存大檔案,按塊打散儲存,適合批量作業,輸送量大,但時延比較高。
結語
本來要寫 Redis Proxy Step By Step 系列的,先耽擱一周,下周繼續好了。推薦一首李榮浩的歌 《自拍》。