search
尋找貓咪~QQ 地點 桃園市桃園區 Taoyuan , Taoyuan

eBay購物車三種方式處理丟失的網路I/O

作者|Venkatesh Ramaswamy編輯|麥克周eBay 的員工 Venkatesh Ramaswamy 於 2017 年 1 月發表了一篇文章,文章發表在 eBay 技術博客上,文章主要講了針對購物車緩存數據丟失情況,eBay 思考的三種解決方案,以及最終採用的解決方案。

背景

eBay 的購物車信息存儲依賴於兩個不同的數據存儲介質,MongoDB 存儲用戶完整的購物車信息,Oracle 僅存儲購物車的大致信息,但是可以通過關鍵信息查找所有的購物車信息。在 eBay 的這套系統里,MongoDB 更多被用來充當「緩存」,Oracle 資料庫作為存儲副本。如果數據在 MongoDB 裡面找不到了,服務會從 Oracle 裡面重新抽取(恢復)數據,然後重新計算用戶的購物車。

所有的購物車數據都是 JSON 格式的,JSON 數據在 Oracle 里被存儲在 BLOB 格式的欄位里。這些 Oracle 裡面的數據只能被用於 OLTP 交易。

這篇文章並不是討論資料庫技術的選擇(Oracle vs MongoDB,或者其他數據),而是希望能夠讓大家在巨量訪問系統(每天上百萬次調用)中找到技術債,理解如何解決問題。

問題描述

2016 年秋天開始,購物車服務出現了緩存層丟失數據的情況,同時,運維團隊報告 MongoDB 的備份機制多次出現失敗(MongoDB 運行在主從模式)。eBay 的這個服務已經運行了 5 年時間,一直沒有出現問題,沒有做過任何架構調整和大規模代碼改變,需要儘快找到原因和防治辦法。針對實際問題進行反覆檢查,發現 MongoDB 的 oplog(實時性要求極高的寫日誌記錄)正在達到網路 I/O 限制。每一次的數據丟失,都會觸發保護措施(再次從 Oracle 讀取數據后重複計算),並進一步加長用戶的等待時間。

解決方案

在我們具體討論特定的解決方案前,我們希望去儘可能多地討論解決方案。例如,一旦備份機制沒有啟用,是否可以通過隱藏一些副本方式讓系統能夠正常運行,而不要在系統特別繁忙的時候去嘗試重新備份。我們可以嘗試超時機制和階段性副本方式,但是這些方式並不會引起我們本文說的問題發生。

方案一:切片(MongoDB)

團隊成員提出對 JSON 數據進行切分,即對原先存儲在 MongoDB 里的原子化的購物車信息(一個 JSON 字元串),切分為多個字元串,這樣做的好處是可以減少單一 MongoDB 中心節點的寫入次數和網路開銷。

對於數據切分后的關聯方式,遠比數據切分、負載均衡複雜,因此,第 1 種方案的選擇會引入其他技術難點,需要我們自己能夠尋找被切分后的數據的關聯性,這就是為什麼 eBay 放棄了這個方案。

方案二:有選擇的寫入

使用 MongoDB 的 set 命令,只針對當特定值發生更改后,才啟動寫入操作。這種方式理論上也是可行的。

但是如果你真正考慮一下,這種做法沒有從根本上確保減少 oplogs 寫入次數,但是它很有可能會造成整個文檔的更新。

了解一下 MongoDB 的 Set 操作模式。Set 操作可以用於使用特定值替換欄位值:

{$Set{:,…}}

假如你考慮一下描述產品的文檔如下所示:

{ _id:100, sku:」abc123」, quantity:250, instck:true, reorder:false, details:{model:」14Q2」,make:」xyz」}, tags:[「appeal」,」clothing」], ratings:[{by:」ijk」,rating:4}] }

對於滿足 _id 等於 100 的文檔,執行 set 操作更新 quantity 欄位、details 欄位和 tags 欄位的值。

db.products.update( {_id:100}, {$set: { quantity:500, details:{model:」14Q3」,make:」xyz」}, tags:[「coats」,」outerwear」,」clothing」] } } )

以上這個操作替換 quantity 的值為 500,details 欄位的值為一個新的嵌入式文檔,tags 值為一個數組。

方案三:壓縮傳輸數據

考慮到需要儘快解決問題,所以需要盡量避免重寫業務邏輯,壓縮方式看起來是比較好的一中了。減少進入 MongoDB 的 Master 節點的數據量,這樣可以減少寫入 oplog 的數據規模。但是,這種方式會將 JSON 字元串轉變為二進位文章,操作時也需要解壓縮。

常用的壓縮演算法主要有:deflate、gzip、bzip2、lzo、snappy 等。差別如下所示:

  • deflate、gzip 都是基於 LZ77 演算法與哈夫曼編碼的無損數據壓縮演算法,gzip 只是在 deflate 格式上增加了文件頭和文件尾;

  • bzip2 是 Julian Seward 開發並按照自由軟體 / 開源軟體協議發布的數據壓縮演算法,Apache 的 Commons-compress 庫中進行了實現;

  • LZO 致力於解壓速度,並且該演算法也是無損演算法;

  • LZ4 是一種無損數據壓縮演算法,著重於壓縮和解壓縮速度;

  • Snappy 是 Google 基於 LZ77 的思路用 C++ 語言編寫的快速數據壓縮與解壓程序庫,2011 年開源。它的目標並非最大程度地壓縮,而是針對最快速度和合理的壓縮率。

目標和考慮

在我們開始做這一功能性測試之前,我們需要明確幾個目標。

  • 允許購物車被壓縮並持久化到 MongoDB(數據不會有改變)。

  • 允許壓縮編碼方式的選擇,支持採用一種編碼方式讀取,另一種編碼方式寫入。

  • 允許讀到老的、新的、中間狀態的購物車信息,新老前後可以互相兼容。

  • 壓縮和解壓縮的操作可以同時進行。

  • 確保沒有針對 MongoDB 資料庫的實時 JSON 數據檢索查詢請求。

JSON 字元串例子

這是老的 JSON 字元串:

{ "_id" : ObjectId("560ae017a054fc715524e27a"), "user" : "9999999999", "site" : 0, "computeMethod" : "CCS_V4.0.0", "cart" : "...JSON cart object...", "lastUpdatedDate" : ISODate("2016-09-03T00:47:44.406Z") }

這是壓縮之後的 JSON 字元串:

{ "_id" : ObjectId("560ae017a054fc715524e27a"), "user" : "9999999999", "site" : 0, "computeMethod" : "CCS_V4.0.0", "cart" : "...JSON cart object...", "compressedData" : { "compressedCart" : "...Compressed cart object..." "compressionMetadata" : { "codec" : "LZ4_HIGH", "compressedSize" : 3095, "uncompressedSize" : 6485 }, }, "lastUpdatedDate" : ISODate("2016-09-03T00:47:44.406Z") }

測試結果

通過使用相同的購物車數據進行測試,觀察 CPU 或者 I/O 情況,數據如圖所示:

結論

oplog 的寫入速率,從 150GB/ 小時下降為大約 11GB/ 小時,下降了 1300%!文檔的平均對象大小從 32KB 下降為 5KB,600% 的下降。此外,服務的響應時間也有所改善。數據如圖所示:

下面這張圖顯示的是 MongoDB 的 Ops Manager UI 工具信息,特別標註了壓縮和解壓縮數據的耗時,以及文檔的平均對象大小的下降數據。

最終,對於生產環境下的隨機一小時數據壓縮,eBay 團隊也收集了一些指標圖,用於更多的深入觀察。

2017 年 8 月 10-11 日,聽雲聯合極客邦科技、InfoQ 將共同主辦國內第二屆應用性能管理大會 -APMCon 2017,會議的演講內容聚焦行業內最新的技術和最接地氣的實踐案例,共同探討 APM 相關的性能優化、技術方案以及創新思路,為更多的行業從業者指點應用效能提升的迷津。

為回饋 InfoQ 讀者,特奉上優惠碼:APMCon_0810,立減 99 元!

進入大會官網 www.apmcon.cn,了解更多專家信息吧!



熱門推薦

本文由 yidianzixun 提供 原文連結

寵物協尋 相信 終究能找到回家的路
寫了7763篇文章,獲得2次喜歡
留言回覆
回覆
精彩推薦