照片應(yīng)用程序是 Facebook 最流行的功能。直至目前為止,,F(xiàn)acebook 的用戶已經(jīng)上傳了超過 150 萬幅照片,這使得 Facebook 成為最大的照片共享網(wǎng)站,。對于每一個上傳的照片, Facebook 生成并保存成 4 種不同大小的圖像,,即總共有 60 億的圖片占 1.5PB 的存儲容量,。目前的增長速度是每星期 220 萬個新照片,即每周消耗 25TB 的額外存儲空間,。在高峰期,,平均每秒會上傳 550,000 幅圖像,。這些數(shù)字給 Facebook 的照片存儲基礎(chǔ)架構(gòu)帶來了嚴重的挑戰(zhàn)。 NFS 照片基礎(chǔ)架構(gòu) 舊的照片基礎(chǔ)架構(gòu)包含幾個層次: ◆上傳層接收用戶上傳的照片,,測量原始圖像的大小并將其保存到 NFS 存儲層,。 ◆照片服務(wù)層接收 HTTP 照片請求,并向用戶提供保存于 NFS 存儲層的照片,。 ◆NFS 存儲層建立于商業(yè)存儲設(shè)備之上,。 由于每個圖像存儲在自己的文件內(nèi),所以根據(jù)命名空間目錄和文件 inode(內(nèi)節(jié)點),,在存儲層產(chǎn)生了大量的元數(shù)據(jù)。這些元數(shù)據(jù)量遠遠超過了 NFS 存儲層的緩存能力,,導(dǎo)致了上傳和讀取每張照片時成倍的 I/O 操作,。整個照片服務(wù)的基礎(chǔ)架構(gòu)由于 NFS 存儲層的大量元數(shù)據(jù)負荷而成為了一個瓶頸,這就是 Facebook 嚴重依賴 CDNs 來提供照片服務(wù)的原因之一,。以下兩個附加的優(yōu)化部署,,用來在一定程度上減輕這個問題: Cachr :一個緩存服務(wù)層,用來緩存 Facebook 中較小的“個人資料”圖像,。 NFS 文件句柄緩存——部署在照片服務(wù)層,,消除了一些 NFS 存儲級元數(shù)據(jù)負荷 Haystack 照片基礎(chǔ)架構(gòu) 新的照片基礎(chǔ)架構(gòu)將照片服務(wù)層和存儲層合并為一個物理層。它實現(xiàn)了一個基于 HTTP 的照片服務(wù)器,,把照片存儲在名為 Haystack 的通用對象中,。對于新層次的主要要求是消除任何照片讀取操作的不必要的元數(shù)據(jù)開銷,使每個讀取 I/O 操作只是讀取實際照片數(shù)據(jù)(而不是文件系統(tǒng)元數(shù)據(jù)),。Haystack 可劃分為以下一些功能層 - ◆HTTP 服務(wù)器 ◆照片存儲 ◆Haystack 對象存儲 ◆文件系統(tǒng) ◆存儲設(shè)備 以下各節(jié)中,,我們會自底向上密切關(guān)注每一個功能層。 存儲設(shè)備 Haystack 部署于日常存儲片之上,。一個 2U 存儲片的典型硬件配置的是 - ◆2 x 4 核 CPUs ◆16GB – 32GB 內(nèi)存 ◆具有 256MB – 512MB NVRAM 緩存的硬件 RAID 控制器 ◆12+ 1TB SATA 驅(qū)動器 每個存儲片提供大約 10TB 的可用空間,,配置為一個 RAID-6 分區(qū),由硬件 RAID 控制器進行管理,。RAID 6 提供了足夠的冗余性和出色的讀取性能,,可以降低存儲成本。RAID 控制器 NVRAM 回寫高速緩存可以部分緩解低劣的寫性能,。由于讀取大多是隨機的,,所以 NVRAM 緩存完全保留給寫操作。磁盤高速緩存被禁用,,以保證在系統(tǒng)崩潰或電源斷電時數(shù)據(jù)的一致性,。 文件系統(tǒng) Haystack 對象存儲實現(xiàn)于一個文件之上,該文件存儲在一個單一文件系統(tǒng)上,,該文件系統(tǒng)建立于 10TB volume(卷)大小的空間之上,。 照片讀取請求導(dǎo)致 read() 系統(tǒng)調(diào)用請求讀取文件中不同偏移量的信息,,但為了執(zhí)行讀取操作,文件系統(tǒng)必須首先在實際物理卷上找到數(shù)據(jù),。在文件系統(tǒng)中,,每個文件的是由一個名為 inode 的結(jié)構(gòu)所描述,該結(jié)構(gòu)包含一個塊映射,,可以把邏輯文件偏移量映射到物理卷中的物理塊偏離量,。對于大文件,根據(jù)所使用的文件系統(tǒng)類型的不同,,塊映射可能會相當(dāng)龐大,。 基于塊的文件系統(tǒng)為每個邏輯塊維護其映射信息,對于大文件,,這些映射信息將不會像通常那樣存入緩存的 inode,,而是儲存在間接地址塊,讀取文件數(shù)據(jù)時需要進行轉(zhuǎn)換,。間接轉(zhuǎn)化可能存在好幾個層次,,因此,根據(jù)間接地址塊是否被緩存,,單一的讀取可能會導(dǎo)致若干個 I/O 操作,。 基于范圍的文件系統(tǒng)只為連續(xù)的塊(區(qū)域)維護映射信息。對于一個連續(xù)大文件的塊映射只由一個區(qū)域組成,,此區(qū)域的大小正好可以裝入 inode 之中,。但是,如果該文件是嚴重地分散和不連續(xù)的,,其區(qū)塊在卷中不連續(xù),,那么其塊映射可以隨之增長。有了基于范圍的文件系統(tǒng),,就可以通過積極分配一大塊空間來減少碎片,。 目前,所選擇的文件系統(tǒng)是的 XFS,,基于范圍的文件系統(tǒng)提供有效文件預(yù)分配,。 Haystack 對象存儲 Haystack 是一個簡單日志結(jié)構(gòu)(只追加)的對象存儲,包含描述存儲對象的指針,。一個 Haystack 包括兩個文件——實際的包含指針的 Haystack 存儲文件,,以及一個索引文件。下圖顯示了 Haystack 存儲文件的結(jié)構(gòu)布局: 第一個 8KB 的 Haystack 存儲由超級塊所占用,。緊接著超級塊的是指針,,每個指針由頁眉、數(shù)據(jù),、和頁腳組成,。 一個指針是由其﹤Offset(偏移量), Key, Alternate Key(替換鍵),Cookie﹥元組唯一確定,,其中偏移量是指在 Haystack 存儲中的指針偏移量。Haystack 對于關(guān)鍵字的值沒有任何限制,,有的指針可以有多個關(guān)鍵字,。下圖顯示的是索引文件的結(jié)構(gòu)布局— 在 Haystack 存儲文件中,每個指針有一個相應(yīng)的索引紀(jì)錄,,而且指針?biāo)饕o(jì)錄的順序必須與 Haystack 存儲文件中相關(guān)的指針順序相匹配,。索引文件提供查找 Haystack 存儲文件中某一特定指針?biāo)璧淖钚≡獢?shù)據(jù)。為了快速查找,,把索引記錄載入并組織到一個數(shù)據(jù)結(jié)構(gòu)中,,這是 Haystack 應(yīng)用程序(在我們的情況下是照片存儲)的職責(zé)。索引文件不是至關(guān)重要的,,因為它可以根據(jù)所需從 Haystack 存儲文件中重建,。索引的主要目的是可以快速加載指針元數(shù)據(jù)到內(nèi)存中,而無須遍歷龐大的 Haystack 存儲文件,,這是因為索引的大小通常還不到存儲文件的 1%。 Haystack 寫操作 Haystack 寫操作同步添加新的指針到 Haystack 存儲文件中,。當(dāng)指針成功添加到龐大的 Haystack 存儲文件中之后,,相應(yīng)的索引記錄也被寫入索引文件。由于索引文件不是至關(guān)重要的,,為了達到更快的性能,,該索引記錄是異步寫。 索引文件還會定期被刷新到下面的存儲設(shè)備,,以便限制由硬件故障所引起的恢復(fù)操作的程度,。在系統(tǒng)崩潰或突然斷電的情況下,Haystack 恢復(fù)程序丟棄所有存儲中的不完整的指針,,同時截斷 Haystack 存儲文件直到最后一個有效的指針,,然后,在 Haystack 存儲文件最后為所有跟蹤的孤立指針寫入丟失的索引記錄,。 Haystack 不允許覆蓋已存在的指針偏移量,,因此,如果某個指針的數(shù)據(jù)需要修改,,其修改后的新版本必須使用相同的﹤Key, Alternate Key, Cookie﹥元組,。然后應(yīng)用程序就可以認為,在那些有著多個關(guān)鍵字的指針中,,具有最大偏移量的指針就是最新添加的指針,。 Haystack 讀操作 傳遞給 Haystack 讀操作的參數(shù)包括指針偏移量、關(guān)鍵字,、替換鍵,、Cookie 和數(shù)據(jù)大小,。然后 Haystack 添加頁眉和頁腳的大小到數(shù)據(jù)大小中,并從文件中讀取整個指針,。只有當(dāng)關(guān)鍵字,、替換鍵和 Cookie 符合參數(shù)類型,所傳遞的數(shù)據(jù)通過校驗,,并且指針沒有被之前的操作刪除時,,讀操作才能成功(見下文)。 Haystack 刪除操作 刪除操作很簡單——通過設(shè)置指針的標(biāo)記域中的一個“deleted(已刪除)”標(biāo)記位,,標(biāo)記 Haystack 存儲中的指針為已刪除,。然而,相關(guān)的索引記錄并不進行任何方式的修改,,因此一個應(yīng)用程序可能會結(jié)束于引用某個已刪除的指針,。對于這樣的指針的讀操作會注意到“deleted”標(biāo)記,然后終止操作,,提示操作錯誤,,給出錯誤信息。已刪除的指針的空間不會以任何方式回收,?;厥找褎h除指針的空間的唯一方法是壓縮 c(見下文) 。 照片存儲服務(wù)器 照片存儲服務(wù)器負責(zé)接收 HTTP 請求,,并轉(zhuǎn)化成相應(yīng)的 Haystack 存儲操作,。為了盡量減少讀取照片所需的 I/ O 操作次數(shù),服務(wù)器在內(nèi)存中保存一個 Haystack 存儲文件中所有照片偏移量的索引,。啟動時,,服務(wù)器讀取 Haystack 索引文件并生成一個內(nèi)存中的索引。由于每個節(jié)點數(shù)以億計的照片(并且該數(shù)字只會隨著更大容量的驅(qū)動器而增加),,我們必須確保該索引能夠裝入可用的內(nèi)存中,。這是通過在內(nèi)存中保留最少數(shù)量的元數(shù)據(jù)來實現(xiàn),只保留查找照片所需的信息,。 當(dāng)用戶上傳一個照片,,該照片就被分配一個唯一的 64 位編號。然后將照片轉(zhuǎn)化為 4 個不同大小的圖片,。每個圖片具有相同的隨機 Cookie 和 64 位關(guān)鍵字,,合理的圖像大小(大,,中,,小,縮略圖)是儲存在替換鍵中。然后上傳服務(wù)器調(diào)用照片存儲服務(wù)器,,把所有 4 個圖像存儲在 Haystack 中,。 內(nèi)存中的索引為每張照片保存以下信息: Haystack 使用開源 Google 稀疏散列數(shù)據(jù)結(jié)構(gòu)來減小內(nèi)存中的索引,因為使用它,,每條記錄只占 2 位,。 照片存儲寫 / 修改操作 寫操作寫入照片到 Haystack,并更新內(nèi)存索引,。如果該索引中已經(jīng)包含了具有相同關(guān)鍵字的記錄,,那么這就是一個修改現(xiàn)有照片的操作,那么只修改索引記錄偏移量,,以反映新圖像在 Haystack 存儲文件中的位置,。照片存儲總是假設(shè)存在重復(fù)的照片(具有相同關(guān)鍵字的照片),只有存儲在最大偏移量位置的照片是有效的,。 照片存儲讀操作 傳遞到讀操作的參數(shù)包括 Haystack id 和照片關(guān)鍵字,、大小和 COOKIE 。服務(wù)器根據(jù)照片關(guān)鍵字,,執(zhí)行一個在內(nèi)存索引上的查找操作,,然后得到含有所需照片的指針偏移量。如果發(fā)現(xiàn)調(diào)用的是 Haystack 讀操作來讀取照片,,那么如上所述,,Haystack 刪除操作并不更新 Haystack 索引文件記錄。因此,,一個新的內(nèi)存索引可能會包含之前刪除的照片的舊記錄。讀取之前刪除的照片將會導(dǎo)致操作失敗,,并且內(nèi)存中的索引會自動更新,,設(shè)置已經(jīng)刪除圖像的偏移量為 0。 照片存儲刪除操作 在調(diào)用 Haystack 刪除操作之后,,內(nèi)存中的索引被更新,,設(shè)置特定圖像的偏移量為 0 來表示該圖像已經(jīng)被刪除。 壓縮 壓縮是一個聯(lián)機操作,,可以回收已被刪除的指針和重復(fù)指針(具有相同關(guān)鍵字的指針)所占用的空間,。它通過復(fù)制指針創(chuàng)建一個新的 Haystack,跳過所有重復(fù)和已刪除的指針,。每次這樣做,,就會交換文件和內(nèi)存中文件的結(jié)構(gòu)。 HTTP 服務(wù)器 我們使用的 HTTP 框架是由開源 lib event 圖書館所提供的簡單的 evhttp 服務(wù)器,。我們使用多線程,,同一時間內(nèi),每個線程能夠處理一個 HTTP 請求。因為我們的工作量最主要是由 I/O 操作產(chǎn)生,,因此 HTTP 服務(wù)器的性能并不是至關(guān)重要的,。 |
|
來自: 萬皇之皇 > 《IT互聯(lián)》