Haystack 太强了!存 2600 亿图片
作者 | 奇伢
來源 |?奇伢云存儲
小文件存儲
小文件存儲,老生常談的問題。先聊聊小文件存儲重點關注的是什么?
以前我們提過,對于磁盤來說,小 io 吃 iops,大塊 io 吃吞吐。
劃重點:小文件的重點是 io 次數。
為什么每次提到海量小文件的時候,總說傳統的文件系統不合適呢?
因為它的元數據操作太惹人眼球了。假設有 1K 的數據,元數據如果搞個 1K ,這個開銷就太大了,空間大一倍,性能下降一倍。所以,只要是針對小文件的存儲優化,基本上都會在元數據上下點功夫。
Haystack 的背景
Haystack 是 Facebook 為了解決他們圖片存儲而專門設計的一套存儲架構,2012 年發表論文《 Finding a needle in Haystack: Facebook’s photo storage 》。
文中提到當時( 2012 年 )他們已經有 2600 億張圖片,超過 20 PB 的數據,用戶每周上傳 10 億張,大約 60 TB 的數據。
從這個數據量來看,確實談得上海量的文件。算出來的圖片平均大小 64K 左右吧,不大,就是以前普通圖片的大小。
64K 不知道怎么算的?
用 60 TB 除一個 10 億就知道了。
Haystack 的特點
接下來聊聊 Haystack 的設計到底有什么神奇特點呢?可以歸納下面四點:
Write Once
Read Often
Nerver Modify
Rarely Deleted
大白話就是,只寫一次,從不更新,不定期會讀,極少刪除。這個 Haystack 特點是適配 Facebook 的圖片場景的。
注意,是先有 facebook 的業務場景特點,然后才把 Haystack 設計成這樣的。因果關系不要搞反了哦。
海量的文件的挑戰在哪里?
每一次文件存儲會涉及到元數據和數據兩部分的操作。當數量是海量的時候,無論是對存儲容量和元數據的量都會帶來巨大的影響。
存儲容量這個自不用提,這是用戶的數據,它是你必須要存儲的,通常這里考慮的是存儲效率,考慮用更少的介質、更高的可靠性,來存儲更多的數據,通常這里的選型是副本和糾刪碼。
元數據就有意思了,因為這個是內部的設計導致的冗余數據(為了索引用戶數據而產生的數據),元數據的設計則會影響到用戶的體驗,特別是海量的場景。
童鞋思考個問題:海量、小文件 的前提下,為什么元數據會帶來挑戰?挑戰主要是哪些方面?
?1???存儲成本有挑戰
劃重點:任何的評估不能脫離場景。
舉個簡單的例子,假如每個文件 1K ,每個文件對應元數據也 1K ,這開銷大不大?
太大了嘛。一倍的浪費。在海量的背景下,用戶存儲 1P 的數據,就要存儲 1P 的元數據,浪費在元數據的成本無法容忍。
那元數據設計成 1K 的是錯誤的嗎?
不一定。
比如說,如果是每個文件 1G,對應每個元數據 1K 呢,這個開銷大不大?
不大,因為 1K/1G 才是 0.00009% ,也就是說,用戶存儲 1P 的數據,元數據消耗為 0.092 TB ,這成本幾乎可以忽略。
所以,前提很重要,設計好壞并不是絕對的,都是相對而言的,任何架構都要適配自己的場景。
?2???存儲性能有挑戰
接著上面的例子,每個文件 1K ,每個文件對應元數據也 1K ,這性能開銷大不大?
太大了嘛。性能是一倍的損耗。每個文件 1K ,本該一次磁盤 IO 就能解決,但是另外還要加一次元數據操作的磁盤 IO 。也就是說磁盤極限如果 1 萬的 iops ,用戶只能獲取到 5000 的 iops 性能。內部損耗一半。
那如果是每個文件 1G,對應每個元數據 1K 呢,這個開銷大不大?
不大嘛,假設每筆 io 是 4K 的定長大小。1G 的數據寫 262144 次。只是多加一次元數據 IO ,無關緊要。
?3???Hasystack 的突圍方向
劃重點:小文件的場景,元數據的成本消耗和性能消耗會顯得更突出。再加上海量的前提下,這個是必須要解決的挑戰。
那 Haystack 應該怎么做呢?兩個方面:
重新設計元數據結構,而不是使用文件系統的結構,要精簡元數據的大小;
削減元數據的 io 的次數,甚至從 io 路徑上徹底消除元數據它;
你如果理解了上面的栗子,對于這兩個優化方向的導出應該也是水到渠成的。
Haystack 的目標
高吞吐,低延遲
高可靠,具備故障容錯能力;
架構簡單,底成本
Haystack 的架構設計
?1???整體架構
Haystack 的架構非常簡單,截取論文中的圖片:
圖中表明了三個核心組件:
Haystack Directory
Haystack Cache
Haystack Store
Store 就是一個單機的存儲引擎,上層告訴它寫哪,它就寫哪。管理的單位是一個個大塊文件。Haystack 里面叫做 Physical Volume ,其實就是一個個大文件而已啦。
劃重點:Haystack 也是基于文件系統之上的。
Physical Volume 有一個閾值,比如寫滿 100 GB就不寫了??梢园阉斫獬梢粋€大日志文件,數據的寫入方式也是 log 日志的方式,append 寫入。
Directory 是最上層的一個抽象,上面提到 Store 管理的是 Physical Volume ,上報到 Directory 組件,Directory 把這些底層的 Physical Volume 按照副本關系組織起來形成 Logical Volume 。Logical Volume 就是提供給用戶寫入數據用的。
舉個簡單的例子,如果是三副本的 Haystack 系統,那么一個 Logical Volume 由 3 個 Physical Volume 組成副本鏡像。
Cache 這個就不用說了,就是一個單純的緩存組件。
?2???數據怎么組織
奇伢用幾個問題的形式來闡述數據的組織。
問題一:Physical Volume 是什么?
其實就是大文件,Haystack Store 是基于文件系統之上的。Physical Volume 就實現形式來講就是文件,可以是 ext4 的文件,也可以是 xfs 的文件。只不過這個文件有名字( Physical Volume ID ),也是一個閾值,比如 100 GB 。
問題二:Logical Volume 是什么?
抽象出來的結構。由多個 Physical Volume 組成。它的個數由副本數決定,比如一個 3 副本 Logical Volume 由 3 個 Physical Volume 組成。
問題三:Physical Volume 內部又是有什么構成呢?
一個叫做 Needle 的東西。
Needle 其實就是用戶數據加一些頭部,加一些尾部構成的一個整體結構。Physical Volume 就是由這一個個 Needle 組成的。
問題四:Needle 的頭尾有啥用?
主要幾個方面:
用來構建元數據索引用的,里面有 key,size 等關鍵數據;
用來校驗數據是否損壞,里面有 magic,crc 等;
用來標識數據是否刪除,里面有 Flags 標記位;
這些頭尾數據就是 Haystack 給每個用戶對象重新設計的元數據了,相比文件系統的元數據,這個太精簡了。
在內存中的內存表,甚至只需要一個 16 個字節就夠了,8 字節的 key ,4 字節的 offset,4 字節的 size 。這個比內核文件系統動輒幾百字節甚至幾 K 字節要好太多了。
問題四:元數據現在多大了?
元數據分為磁盤元數據(持久化了的)和內存元數據。
磁盤元數據可以看上面的 Needle 結構體,具體實現在 32 字節左右。內存元數據可以控制在 16 個字節。
?3???讀、寫、刪
數據寫入的流程:
Web 接入點先去 Haystack Directory 選一個 Logical Volume ;
把數據發往 Haystack Store ,寫到對應的三個 Physical Volume 即可(注意,append 寫入哦);
數據讀取的流程:
Web 接入點先去 Haystack Directory 拿到指定對象的元數據;
然后請求發給 Haystack Store ,讀取數據(這里就不提 Haystack Cache 或者 CDN 的邏輯了,過于簡單);
數據刪除的流程:
Web 接入點先去 Haystack Directory 拿到指定對象的元數據;
然后把刪除請求發給 Haystack Store ,就地更新 Needle 的標記位,標記成刪除;
劃重點:Haystack 的刪除是就地更新,而不是 append 寫入。這里跟純粹的 log 文件不大一樣。 但由于刪除是極少的,所以就算不是 append 寫入,也不影響大局。
?4???空間回收
Haystack 也和 LSM,Bitcask 等設計類似,刪除是刪除,回收是回收,這是兩個步驟。
空間回收就是 Compact ,太簡單了,論文甚至都沒稀的提它,寥寥數語說了兩句,原文描述如下:
A Store machine compacts a volume file by copying needles into a new file while skipping any duplicate or deleted entries.
實現很簡單,和以前提過的 Compact 并無二樣。邏輯就是遍歷 Volume 文件,把重復的和標記刪除了的 Needle 跳過,有效的 Needle 讀出來寫到新的地方,即可。
不一樣的思考
回想一下這個架構,思考一下它做到了它立的 flag 嗎?
?1???它的目標:高吞吐,低延遲,怎么實現的呢?
對于寫請求,全都化為 append 請求,極力的保持磁盤的順序性能。并且得益于 Needle 的設計,Haystack 把數據和元數據放在一起,一次性落盤,相當于省去了元數據的 IO 寫開銷。
當然,這種設計也必然有代價,由此帶來的代價就是加載時間變長。
對于讀請求,通過元數據的精簡,讓內存 hold 住所有的元數據,去除了元數據的 IO 開銷,這樣讀操作也就只剩用戶數據的 IO 。
注意:Haystack 刪除不是 append 哦,而是覆蓋寫,但之前已經說過了,Haystack 的適用場景就是“極少刪除” 。
?2???高可靠,故障容錯怎么實現的呢?
這個很簡單,通過副本冗余來做的。Volume 的組織邏輯放在 Directory 組件中,一份數據存儲多份,并且分散在不同的位置。當其中一份故障,則只需要拷貝其他副本即可。
?3???畢竟 2012 年的論文,Haystack 的實踐過時了嗎?
論文中提到,Facebook 當時的實踐是用 2U 的刀片服務器,48G 內存,搭配 12 * 1TB 的 SATA 盤。
如果按照一個文件 64 KB 算,一個 needle 內存元數據 16 字節(這個很極限了),只需要 3 G 的內存,單機 48 GB 的物理內存應對這整機的元數據確實綽綽有余。
但現在很多服務器已經升級到 64 盤,單盤 16 TB,滿載的話需要 256 G 的內存裝元數據。這個內存配比就不大合適了,如果元數據再稍微大點,就更不行了。
但話說回來,并不是每個人都用 64 盤 16 T 的高密服務器,所以并不能一概而論,還是要看自己的需求場景。
就算過去 10 年,我覺得它還能秀。
總結
Haystack 最核心的優化是?重新設計元數據的結構,使得內存元數據只有十幾個字節,極大的減輕了負擔,且設計的 Needle 結構可以完整恢復內存元數據;
得益于元數據的精簡,Haystack 就能把單機全量元數據放在內存;
讀的時候,元數據在內存,只有用戶數據的 IO 消耗,極大的提高了性能;
寫的時候,得益于 Needle 的設計,元數據更新操作不單獨刷,而是和用戶數據在一起刷,相當于省掉了元數據 IO 的開銷;
和 Bitcask 類似,為了提高內存加載速度,也有索引(Index 文件)的實現;
Haystack 并不過時,可以結合自己的場景,煥發生機;
往期推薦
為什么還有這么多的網絡故障?
k8s集群居然可以圖形化安裝了?
用了HTTPS,沒想到還是被監控了
將 k8s 制作成 3D 射擊游戲,好玩到停不下來
點分享
點收藏
點點贊
點在看
總結
以上是生活随笔為你收集整理的Haystack 太强了!存 2600 亿图片的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Node18 即将支持 import H
- 下一篇: 华为汪涛:走向智能世界2030,无线网络