網易視頻雲:基於Hadoop山寨Amazon S3

網易視頻雲是網易傾力打造的一款基於雲計算的分佈式多媒體處理集羣和專業音視頻技術,提供穩定流暢、低時延、高併發的視頻直播、錄製、存儲、轉碼及點播等音視頻的PAAS服務,在線教育、遠程醫療、娛樂秀場、在線金融等各行業及企業用戶只需經過簡單的開發即可打造在線音視頻平臺。現在,網易視頻雲的技術專家給大家分享一則技術文:基於Hadoop山寨Amazon S3。

S3( http://aws.amazon.com/s3/)是amazon提供的高可用、高可靠、高可擴展的對象存儲服務, 單桶支持無限存儲空間, 每個對象最大5TB。 雖然實現這麼一個大型的對象存儲系統非常有挑戰性, 但是用開源軟件山寨一個對象存儲也並沒有這麼複雜, 本文將嘗試基於Hadoop的HDFS和Hbase構建一個這麼系統HOS(Humor Object Storage), HOS能擴展到千臺服務器規模, 足以滿足中小型雲計算的對象存儲需求。當然, HOS純屬娛樂, 切勿模仿, 以免被坑。
HOS-storage
上圖展示了HOS對象的存儲模型, HOS對象存儲於HDFS文件, 小對象連續存放, 而大型對象則拆分爲多個片段存儲。 對象元數據包括對象名,對象位置信息等存儲於Hbase。 HOS的核心Hbase表如下:

  • ObjectTable記錄對象元數據信息,定義爲 < ObjectName, Locations, CreateTime>, 主鍵是ObjectName。 ObjectName格式爲”BucketName/ObjectName”, ObjectName也可以包含”/”字符, 有點像是文件系統路徑。 Locations是數組, 每一項代表一個對象片段的物理存放位置。
  • DeletedObjectTable是已經刪除的對象, 定義爲< ObjectName, DeleteTime, Locations, CreateTime>, 主鍵是ObjectName, DeleteTime組合, 主鍵要加上DeleteTime的原因是回收站有可能存在同名對象。
  • FileObjectIndex是HDFS文件的對象索引, 記錄HDFS文件中存儲的有效對象信息,其主要用於垃圾回收。定義爲 < FileName, Offset, Length, ObjectName, ObjectOffSet>, FileName是HDFS文件名, Offset, Length是HDFS文件內偏移, ObjectOffset是Object內偏移,主鍵是FileName, Offset。
  • FileTable, 記錄HDFS文件信息, 定義爲< FileName, Status, Free, Size>, Status狀態有pending和closed, pending狀態代表正在往文件追加數據, closed狀態代表文件已經關閉。HDFS文件長度超過閾值,或者HDFS文件append出錯時, 文件狀態設置爲close, close狀態的文件是隻讀的。 Size是文件長度,Free是由於數據刪除導致的文件空閒空間, 當空閒率Free/Size大於一定閾值時, 系統執行垃圾回收。

HOS-arch
HOS服務器架構如上圖所示, 主要有兩種進程:

  • 應用服務器負責實現所有業務邏輯, 每個應用服務器啓動時,創建多個HDFS文件, 用戶上傳的對象儘量均衡的分散到這些文件中;
  • 清道夫是一個後臺程序, 主要功能是:
    • (1) 關閉長久不用的pending狀態HDFS文件。 應用服務器宕機時遺留一些pending狀態的文件, 系統不再往這些文件寫入數據。
    • (2) 回收站清理。 對象刪除之後先進入回收站, 再過一段時間之後對象才被物理刪除。
    • (3) HDFS文件數據垃圾回收。 HDFS只能追加寫, 刪除對象之後空間並不能重複利用。垃圾回收算法從HDFS文件中拷貝 出有效數據,寫入到新的文件中, 其目的是控制空間的浪費比率。

S3的核心操作由PUT_OBJECT/GET_OBJECT/DELETE_OBJECT/GET_BUCKET, 我們來看看HOS的實現。

操作(一):上傳對象PUT_OBJECT(key, value)的流程:

1. 打開(或者獲取)一個HDFS文件句柄
2. 將value拆分爲數個分片, 分片的長度不超過4MB
3. 追加每個分片到HDFS文件, 記錄分片在HDFS文件中的偏移off和長度len, 分片在對象中的偏移objoff
4. 插入記錄< filename, off, len, key, objoff> 到FileObjectIndex
5. 插入記錄 到ObjectTable,Locations是對象分片的存儲位置信息
6. 若文件長度超過閾值,則關閉文件,設置文件狀態爲closed

上述流程只能處理key不存在情況, 若key存在, HOS先執行刪除流程,再執行上述流程, 已達到替換的效果。
上傳過程錯誤處理: 任何一個步驟出錯, 對象都是創建失敗, 所有已分配資源最終都被回收利用。出錯可能遺留兩種垃圾信息, 一是文件數據, 二是文件數據和FileObjectIndex中的索引記錄。 第一種情況下, 文件數據沒有被引用, 能被清道夫的垃圾回收流程處理。
第二種情況發生時必須刪除FileObjectIndex中的索引記錄。 當錯誤發生時, 應用服務器暫時往HDFS文件追加數據, 開啓後臺線程,異步清理FileObjectIndex中的記錄。 當應用服務器工作正常時, 索引記錄能被刪除,但是萬一應用服務器發生宕機, 怎麼清理索引記錄? 清道夫程序會定期掃描pending狀態文件, 若文件很長時間都沒有寫入,則 以文件名和文件長度爲key逆序掃描FileObjectIndex, 比對FileObjectIndex記錄與ObjectTable記錄, 清理不匹配的FileObjectIndex記錄。 掃描和比對的FileObjectIndex數目,取決於HDFS上最大的併發寫入量, 由於併發量通常比較小, 清理代價非常小。

操作(二):讀取對象GET_OBJECT(key)

1. 根據key查詢ObjectTable得到對象存放位置信息, 位置信息是一個數組, [< file1, off1, len1>, < file2, off2, len2>, …, ]
2. 根據位置信息讀取對象。

操作(三): 刪除對象DELETE_OBJECT(key)

1. 插入記錄到DeletedObjectTable
2. 刪除ObjectTable記錄,通知客戶端刪除成功。

錯誤處理

1. 第1步失敗,則返回刪除失敗
2. 第2步失敗,則重試幾次操作。無論重試是否成功,都認爲刪除操作已經成功。 雖然刪除操作已經成功,由於ObjectTable記錄未刪除, 後臺刪除操作執行之前, 此對象仍然是可以訪問的。這聽起來怪怪的,不過爲了簡化問題, HOS準備容忍這個問題。

操作(四): 後臺刪除操作。 DELETE_OBJECT只是把對象移動到了DeletedObjecTable表中。 DeletedObjectTable相當於是回收站, 清道夫會定期掃描回收站,找到過期對象, 執行刪除操作。

1. 清理程序定期掃描DeletedObjectTable
2. 針對已經過期的對象,找到對象的分片存儲位置
3. 針對每個分片,增加File表中的相關記錄的Free字段
4. 刪除分片對應的FileObjectIndex記錄
5. 刪除DeletedObjectTable表當前對象。

錯誤處理: 後臺刪除操作是冪等的, 過程中任意步驟出錯, 不影響正確性。

操作(五):垃圾回收

1. 清道夫掃描File表, 找出空閒率(Free/Size)大於閾值,且狀態爲closed的文件集合
2. 針對每個滿足要求的HDFS文件, 以文件名爲鍵值, 升序掃描FileObjectIndex表
3. 針對掃描得到的每條記錄R, 根據R從文件讀取有效數據, 追加一個新的HDFS文件。
4. 生成新文件的FileObjectIndex表記錄,插入。
5. 更新ObjectTable的Locations字段, 指向新文件
6. 刪除當前記錄R。
7. 每處理完一個HDFS文件之後, 刪除該文件。

錯誤處理: 垃圾回收過程發生錯誤時, 可從發生錯誤的記錄開始重做, 最多導致新文件中遺留一段垃圾數據, 不影響正確性。

操作(六): LS目錄操作GET_BUCKET(path)。 對象的key允許包含”/”, 譬如 “MyBucket/a” , “MyBucket/a/b”, “MyBucket/a/b/c”, “MyBucket/a/d”, 都是合法的對象名稱。因此用戶可以把桶當做一個文件系統來用, 而GET_BUCKET操作的非常類似目錄LS。 GET_BUCKET(“MyBucket/a”) 返回 “MyBucket/a/b”和 “MyBucket/a/d”。 GET_BUCKET可以用coprocessor查詢ObjectTable實現, 不再詳細展開。

總結:
HOS利用HDFS/Hbase, 實現簡單, 且穩定性、可靠性、可伸縮性有保障, 但是Hadoop是用於離線業務的, 性能難以保證,多租戶也支持不好。 當然HOS還不是實現s3最簡單的辦法, 或與直接用Ceph就解決了問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章