banner
bladedragon

bladedragon

關於S3A的一些踩坑和思考

最近工作中架構升級,將原來的 EMR 集群遷移到基於開源的自建集群上,原來使用的一些組件自然也需要改造,其中就包括 s3。在我們的自建集群中,選用的開源 hadoop 中 s3a client(或者 s3a connector,下面簡寫成 s3a,意義基本相同)來連接原有的 s3 存儲。接下來我就會分享我在用 s3a client 時總結的一些經驗
ACG.GY_06

s3 協議的類型#

首先介紹一下 s3,s3 全稱應該叫AWS S3,又稱AWS Amazon Simple Storage Service,是亞馬遜公司開發的對象存儲服務,廣義上講是一款包含了 Web 服務在內的完整存儲產品,狹義上也能特指 AWS 的對象存儲。它通過自定的 s3 協議訪問存儲上的文件,其路徑類似:s3://xxx/yyy/zzz

鑒於 AWS 在雲市場的占有地位,s3 存儲在各個行業也有廣泛的應用。然而 s3 協議是 AWS 的私有協議,只有 AWS 產品可用,為了能鞏固和擴大 s3 在市場的地位,讓用戶能任何地方連上 s3 存儲,放心地把數據存儲到 s3 上,AWS 向 Hadoop 提供了開源版本的 s3 client 來連接 s3,也即是s3n client,在 s3n 協議上的文件路徑類似:s3n://xxx/yyy/zzz

後來 Hadoop 在升級中淘汰了 s3n client,採用了全新的s3a client,在 s3a 協議下的文件路徑類似:s3a://xxx/yyy/zzz

(Hadoop 最初推出的 s3 client,也採用 s3 協議,即文件路徑類似:s3://,但是年代久遠,早已廢棄,這裡就不提了)

總結一下三種文件協議的區別

  • s3 協議是 AWS 最初也是私有的協議,廣泛用在 AWS 的產品中,例如 EMR,EC2 等等。如果你們公司使用的是 AWS 全家桶,基本都是通過 s3 協議訪問 s3
  • s3n 和 s3a 是 hadoop 上基於 AWS s3 SDK 開發的開源 s3 client,能夠擺脫 AWS 產品的限制,在自建的服務中自由訪問 s3 存儲,適用於僅使用了 AWS 的 s3 存儲服務,需要和多方產品交互的場景
  • 在性能上,三者差別不大,考慮到 s3 由 AWS 自己維護,在版本迭代的速度上可能要快於開源的 s3n 和 s3a
  • 在兼容性上,作為 s3 協議的派生,原則上 s3n 和 s3a 都是兼容 s3 協議的;而 s3n 和 s3a 之間一般情況也是兼容(即原來採用的 s3n 協議,後來升級到了 s3a),但是 s3n 和 s3a 之間在目錄創建上存在一些區別(下一 part 會提及),在一些場景中需要注意

s3a 在目錄處理上的不同#

實際上很多人並不認同 s3 為文件系統,因此 s3 是對象存儲,和傳統的文件系統有較大的區別。在官方的文檔也說:

Amazon S3 is not a filesystem, it is an object store.

兩者的一個重要區別就是對目錄概念的解釋。

  • 傳統的 Unix 風格的文件系統,例如 HDFS,其文件系統的組成是目錄文件樹,即生成的目錄都是 “一直存在” 的,無論目錄內是否存在文件。
  • s3 “文件系統”,由於其底層是通過對象存儲(或者稱之為塊存儲),其目錄是 “虛擬” 的,舉個例子:如果兩個對象有相同的路徑前綴:a/b/file1a/b/file2,那麼 s3 會認為這裡存在目錄 a/b/

兩者在這方面的差異就會導致在實際使用中可能出現各種坑

在具體場景的區別#

讓我們再細分一下場景:
創建目錄

  • HDFS 等目錄文件樹會創建一個空目錄,可以往裡面添加文件和目錄,也可以在任意時候(無論目錄中有沒有文件或其他目錄)通過 ls 來發現這個目錄
  • 實際上,要是 s3 也能做到這一點,那它也可以被視為實現了目錄文件樹,可惜它做不到。由於目錄是 s3 是通過前綴來識別目錄,因此當目錄中沒有任何文件時,需要通過目錄標記(Directory Marker,後面簡稱 DM)來標記目錄。當目錄中創建了文件後,就會刪除這個 DM;反之,當目錄刪除成為空目錄時,又會添加這個 DM
    • 在 s3a 中,會在空目錄的場景中生成以 path_name+/ 為名稱的文件來作為 DM,例如執行mkdir(s3a://bucket/a/b)會創建一個標記對象 a/b/
    • 在更老的 s3n 中,則是以path_name_$folder$方式作為 DM

相信從這裡就能看出一絲不妙了吧,當新老版本的產品在某些約定上存在分歧時,往往會出問題。簡單舉個例子,當你用aws s3命令創建了目錄,但是卻用 s3a 去連接時,往往會找不到該目錄,因為在aws s3工具中創建的目錄沒有創建 s3a 的 DM,因此在 s3a 協議中找不到目錄。同理,當一個集群從低版本的 hadoop 升級到高版本時,也需要格外留意空目錄的存在問題,因為有可能升級的同時將 s3n 升級到了 s3a,識別的 DM 發生變化,就檢查不到原來的空目錄。

創建文件

  • 在一般目錄文件樹的文件系統中,只需要按照目錄所在路徑,創建單一文件即可
  • 在 s3 中,創建文件的操作可能會伴隨著一系列 DM 的刪除操作,s3a 需要在一個請求中包含刪除所有父級 DM 的請求

刪除目錄和文件

  • HDFS 目錄文件樹的刪除目錄操作和刪除文件操作基本相同,其刪除的語義也更符合一般邏輯
  • 在 s3 中,由於 DM 的存在,當刪除文件 / 目錄的時候如果父級目錄變成了空目錄,則需要將 DM 補充添加

存在的問題#

s3 對目錄的處理雖是無奈之舉,但也確實成為了許多問題的源頭

  1. s3n 和 s3a 上採用的 DM 不同,意味著 s3a 所在的 hadoop 版本無法向下兼容
  2. 用 s3a 創建或刪除文件的時候一般會需要刪除或創建一批 DM,這會導致實際的請求量較大。而且,s3 中每個對象的讀寫視為一次操作,因此可能會帶來較大的開銷(結合 s3 的讀寫限制,這是 s3 性能不佳的主要原因,具體內容下節討論)
  3. 在使用 list 操作的時候,由於每個請求中列出的對象的數量是父目錄的數量,因此目錄層級越深,請求越長。
  4. 在正式版本的 s3 桶中,即使沒有對象沒刪除,邏輯刪除的標記也會寫進索引裡,這對使大型目錄的查詢變慢

s3a 的性能問題#

在 s3a 的官方文檔上,展示了 s3a 和 HDFS 的一些不同,我將它貼了過來:
image

總的來說,以下幾點原因導致了 s3a 的性能問題

  • 由於桶分片導致 IOPS 被限制。
  • 不同類型的 AWS EC2 虛擬機可能進行網絡 IO 進行不同的限制。
  • 對象和數據越多,目錄重命名和複製操作花費的時間就越長。rename () 的性能更加緩慢。
  • 在讀取 s3 時使用 seek () 操作會強制新的 HTTP 請求。這可能會增大使讀取 Parquet/ORC 文件的開銷。

另外,還需要注意的是,由於 AWS s3 在讀寫上做出了頻率限制,按照一般約定,當對 s3 的一個分區每秒超過讀 5500 次或寫 3500 次時,s3 就會拒絕請求,顯示錯誤 503
可見,若是使用 s3 進行大量讀寫還是存在著不小的挑戰,在大數據領域中使用 s3 還是更多看重的是它的計費成本和性價比。如果你的場景追求性能,那我的建議是:快跑

image

解決方法
當然,實際場景下很多選擇往往不是我們能左右的,假如我們必須要在一些 OLAP 或者其他大規模數據處理場景中使用 s3,這裡依然會有一些優化建議。

  1. 使用 s3a committer。hadoop 內置了多種 s3a commiter 來優化 s3 文件的提交,其核心思路就是利用 s3 的 multipart Upload 機制來加速文件上傳,同時不同的 committer 也有不同的優化思路,具體可以參考這篇文檔
  2. 一些參數的調優,例如合理配置線程數和連接數,加大塊讀取的大小等等
    更多優化的場景和細節,可以查看官方文檔

總結#

總的來說,s3 本身在某些場景還是很有優勢的,作為 AWS 生態的重要一環,人們更看重它的安全可靠,物美價廉,以及與 AWS 其他雲產品之間聯動帶來的疊加優勢。但我們也要承認在不適當的場景中使用 s3 依然會不小的副作用。在實際生產中,也可能存在各種妥協因素,無法做到釜底抽薪,但我們至少可以了解產品特性,盡最大可能優化性能。
因此我就簡單寫了一些 s3a 常見的可能會踩坑的點以及如何採取措施,其實大多來自於官方文檔的整理,希望對你有所幫助~

參考文檔#

  1. Hadoop-AWS module: Integration with Amazon Web Services
  2. Experimental: Controlling the S3A Directory Marker Behavior
  3. Maximizing Performance when working with the S3A Connector
  4. Committing work to S3 with the “S3A Committers”
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。