本文翻譯自How Twitter Handles 3,000 Images Per Second,作者是Todd Hoff,翻譯已獲得本人授權。
今天的Twitter每秒鐘能夠創建并保存3000張(200GB)圖片。甚至早在2015年,Twitter就通過改進媒體存儲策略節約了6百萬美元。
以前并不是這樣的。Twitter在2012年主要以提供文字信息為主,當時的用戶也很少發布各種炫酷的動態圖片。到現在2016年,Twitter開始提供富媒體功能。這樣的轉變是通過Twitter自行開發的全新媒體平臺(Media Platform)實現的,這個平臺可以支持照片預覽、多張照片發送、動態Gif圖片、Vine視頻,以及內嵌視頻等功能。
Twitter軟件開發工程師Henna Kermani在Mobile @Scale London活動中,通過一場名為每秒3000張圖片的有趣演講介紹了Twitter的媒體平臺。演講主要側重于圖像處理方面,但她講的大部分細節也同樣適用于其他形式的媒體。
演講中一些比較有趣的重點包括:
因陋就簡的處理方法注定將會失敗。在原本不支持的情況下,不假思索通過簡單的手段支持上傳帶圖片的推文,這樣的做法會造成某種形式的“套牢”。并且這種方式缺乏縮放能力,尤其是在網絡狀況不佳的時候,這使得Twitter很難增加新的功能。 去耦合。通過將推文與所包含的媒體去耦合,Twitter可以分別針對每個途徑進行優化,在運營方面獲得更大程度的靈活性。 移動句柄,而非存儲塊。不要在您的系統內部移動過大的數據塊。這種做法將消耗大量帶寬,會導致所有需要訪問這些數據的服務遭遇性能問題。更好的方法是單獨存儲數據,并通過句柄的方式進行引用。 使用分塊可續傳方式上傳可大幅降低媒體文件的上傳失敗率。 持續的實驗和研究。Twitter研究發現,對于圖片的不同變體(例如縮略圖、小圖、大圖等),20天的存活時間(Time to live, TTL)是最佳甜區,這個值可以在存儲和計算之間實現良好的平衡。圖片內容發布20天之后的訪問概率會大幅降低,因此可以刪除圖片的各種變體,這樣的做法每天可以幫助Twitter節約4TB數據存儲空間,并將需要的計算服務器數量減少幾乎一半,同時每年可節約數百萬美元。 按需。老圖片的不同變體可以放心刪除,并在需要時重建,而無須預先創建好。這種按需執行服務的做法可改善靈活性,讓您更清楚任務的執行方式,并對其進行集中的控制。 漸顯式JPEG(Progressive JPEG)作為一種標準圖片格式無疑是真正的贏家。這種格式在前端和后端都有良好的支持,在速度不快的網絡中也能提供不錯的表現。Twitter開發富媒體功能的過程中還發生了一些很棒的故事,一起來學學他們是如何做到的...
舊途 - 2012年的Twitter寫入路徑用戶在某個應用中撰寫了一條推文,并可能在推文中附加了一張圖片。
客戶端將該推文發送至一個單體端點(Monolithic endpoint)。圖片會作為附帶內容與推文的所有其他元數據一起上傳,并傳遞至這一過程涉及到的每個服務。 在原本的設計下,這個端點是造成很多問題的根源。問題1:浪費大量網絡帶寬
推文的創建和媒體的上傳緊密耦合為一個操作。
相關廠商內容
滴滴出行iOS客戶端架構演進之路! 微信客戶端如何應對弱網絡! 函數式編程中的Swift與Swift中的函數式編程! 你離成為一位合格的技術領導者還有多遠? 國際范 最前沿 不容錯過的容器技術盛會相關贊助商
GMTC全球移動技術大會2016年6月24日-25日,北京,點擊了解詳情!
上傳過程充滿不確定性,或者完全成功或者徹底失敗。失敗可能出于任何原因,例如網絡卡頓或傳輸錯誤等,如果失敗就只能從頭開始重新執行整個上傳過程,包括上傳圖片。例如,假設上傳操作在進行到95%后出錯,也需要將所有內容重新上傳一遍。
問題2:面對新出現更大體積的媒體無法很好地縮放
這種方式無法通過縮放支持視頻等更大體積的媒體文件。體積的增大會導致出錯概率增加,尤其是在諸如巴西、印度、印度尼西亞這樣網絡速度慢并且不可靠的新興市場,而Twitter非常迫切地希望提高這些地區用戶上傳推文的成功率。問題3:內部帶寬使用效率低下
端點需要連接至負責處理用戶身份驗證和路由的Twitter前端(TFE),隨后用戶會被路由至某個圖片服務(Image Service)。
圖片服務聯系變體生成器(Variant Generator),用不同尺寸(例如小、中、大、縮略圖)為圖片生成不同實例。這些變體會存儲在BlobStore中,這是一種專為圖片和視頻等大型載荷進行過優化的鍵值(key-value)類型存儲。隨后圖片將永遠存儲在這里。
在創建和保存推文的過程中,還涉及到很多其他服務。因為端點是單體的,如果將媒體與推文元數據結合在一起,就需要在所有服務之間傳輸這種綁定在一起的數據。這樣的大型載荷甚至會傳遞到原本在設計上并不用于直接處理圖片的服務,這些服務甚至并不是媒體傳遞渠道的一部分,但依然需要針對大型載荷的處理進行優化。這樣的做法導致內部帶寬使用效率嚴重降低。
問題4:存儲容量極度膨脹
數月甚至數年前發布的推文中所包含的圖片已無人問津,但依然需要永遠存儲在BlobStore中,這些內容耗費了寶貴的存儲空間。因為沒有垃圾回收機制,有時甚至在推文被刪除后,圖片依然會保存在BlobStore中。讀取路徑用戶看到一條包含圖片的推文。圖片來自哪里?
客戶端從CDN請求圖片的變體。CDN可能需要從原始位置或TFE處檢索該圖片。這一過程最終導致需要通直接查詢BlobStore的方式,使用URL請求某一特定尺寸的圖片。
問題5:無法引入新的變體
這種設計不是非常靈活。如果需要添加新的變體,也就是說需要為圖片創建一個新的尺寸,此時必須為BlobStore中的每個圖片創建一個新尺寸的版本。這種方式缺乏按需創建變體的便利機制。
缺乏靈活性意味著Twitter很難為客戶端添加新的功能。
新法 - 2016年的Twitter寫入路徑將上傳的媒體與推文去耦合。
上傳操作至此成為“一等公民”,并創建了專門用于將原始圖片存儲至BlobStore的上傳端點。
這種方法為上傳操作的處理提供了極大的靈活性。
客戶端聯系TFE,TFE隨后聯系圖片服務,圖片服務將圖片保存至BlobStore并將相關數據添加至一個元數據存儲。僅此而已。這一過程不會涉及任何隱藏的服務,不需要處理媒體,也不需要四處傳遞圖片。
隨后圖片服務會返回一個代表該媒體的唯一標識符,即mediaId。當客戶端需要創建推文,發布私信,或更新自己的頭像照片時,將使用這個mediaId作為引用該媒體的句柄,而不需要提供媒體的原始文件。
假設用戶想要使用剛上傳的圖片發布推文,過程將會是這樣:
客戶端聯系更新端點,在推文中包含mediaId,該請求將發送至Twitter前端,隨后TFE會將請求路由至對于所創建內容來說最為恰當的服務。對推文本身,最適宜的服務是TweetyPie,私信和用戶資料信息的處理也由不同服務進行,所有這些服務都能與圖片服務通信,圖片服務器中包含處理面孔檢測、兒童色情內容檢測等功能所需的推文處理隊列,當這些任務執行完畢后,圖片服務會與處理圖片的ImageBird或處理視頻的VideoBird服務通信。ImageBird負責生成變體,VideoBird則對視頻進行一定的轉碼,最終處理生成的媒體內容將保存至BlobStore。
不再需要將媒體內容四處傳輸,借此可節約大量本被浪費的帶寬。
分塊可續傳的上傳。
進入地鐵站,10分鐘后出來,上傳過程可從上次中斷的地方恢復進行。對用戶來說該過程是完全無縫的。
客戶端使用上傳API發起上傳會話,后端會為用戶提供一個mediaId,這個mediaId將在整個上傳會話中充當標識符。
圖片被拆分為多個小塊,例如拆分成三塊。這些文件塊可使用API附加到一起,每次調用的附加操作可提供必要的片段索引,所有附加操作都可作用于同一個mediaId。上傳完成后對上傳內容進行“定稿”,隨后這個媒體就可以使用了。
這種方法更容易適應網絡故障。每個獨立小塊可以重試,如果網絡因為任何原因中斷,用戶可以暫停并在網絡恢復后從暫停的位置繼續上傳。
方法簡單,效益巨大。對于體積超過50KB的文件,上文提到的三個國家中圖片上傳失敗率降低幅度分別為:巴西,33%;印度,30%;印度尼西亞,19%。
讀取路徑此處用到了一種名為MinaBird的CDN源服務器。
MinaBird可與ImageBird和VideoBird通信,這樣就算不存在,也可以即時生成不同尺寸圖片和不同格式視頻的變體。
在處理客戶端請求方面,MinaBird更流暢也更動態。舉例來說,假設有內容由于DMCA(數字千年版權法)的要求需要刪除,此時很容易便可阻止對相關內容的訪問,或重新允許對媒體特定片段的訪問。
按需即時生成變體和轉碼的方式使得Twitter在存儲容量的使用方面更為高效。
按需生成變體,意味著不需要將所有變體都存儲在BlobStore中,這是一個巨大的進步。
原始圖片在刪除前將一直保留,而變體只保留20天。媒體平臺團隊針對最佳過期時限進行了大量研究,發現在所有請求的圖片中,有大約50%的圖片都是在最多15天(左右)的時間內上傳的。繼續保留更早前上傳的圖片可以獲得的收益在逐漸下降。更老的媒體文件也有可能就此無人問津。15天后存在一條很長的長尾。
不設置存活時間(TTL)并且不過期的情況下,媒體文件的存儲導致數據存儲總量每天增加6TB,按需生成所有變體的“偷懶”做法會讓數據存儲總量每天增加1.5TB。20天存活時間所用的存儲空間并不像“偷懶”做法那么多,因此在存儲方面的成本并不高,但對計算的要求更高了。對于“偷懶”的做法,在讀取的同時生成所有變體,需要為每個數據中心提供150臺ImageBird服務器,而20天存活時間的做法只需要投入75臺。因此20天存活時間是一個甜區,可以在存儲和計算方面實現平衡。
由于節約存儲和計算資源等同于省錢,通過采取20天存活時間的做法,Twitter在2015年節約了6百萬美元。
客戶端的改進(Android)針對Google創建的圖像格式WebP執行了為期6個月的實驗。
相比PNG或JPEG圖片,這種格式的圖片體積平均減小25%。
用戶參與積極性有所提高,尤其是在減小圖片體積可以幫助網絡減壓的新興市場。
iOS 不支持該格式。
僅 Android 4.0 以上系統可支持。
平臺支持的缺乏使得WebP的支持代價不菲。
Twitter還嘗試過漸顯式JPEG。這種格式可以使用逐行掃描的方式進行渲染,首次掃描的圖片可能顯得斑駁不勻,但可通過逐行掃描的方式逐漸進行完善。
性能更好。
后端易于支持。
相比傳統JPEG編碼速度慢60%。但由于編碼工作只需要進行一次,隨后所有用戶都可從中受益,因此這不算什么大問題。
不支持透明,因此還需保留透明PNG,但漸顯式JPEG其他方面都很出色。
客戶端對該格式的支持是通過Facebook的Fresco庫實現的。Fresco庫的價值很值得大書特書,就算在2G網絡中也能實現讓人印象深刻的效果。PJPEG的首次掃描只產生10kb流量,因此很快就可以加載完成。當原生渠道還在等待加載,無法顯示任何內容的時候,PJPEG已經可以提供可分辨的圖片。
通過對推文詳細信息視圖的加載進行持續的實驗發現,p50加載時間降低9%,p95加載時間降低27%,出錯率降低了74%。網絡速度緩慢的用戶無疑能從中獲得不菲的收益。