<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        Mailbox:日支撐過億信息數據庫的性能調優及集群遷移

        來源:懂視網 責編:小采 時間:2020-11-09 08:04:31
        文檔

        Mailbox:日支撐過億信息數據庫的性能調優及集群遷移

        Mailbox:日支撐過億信息數據庫的性能調優及集群遷移:在之前的文章中,我們分享了 Mailbox如何在六星期實現從零到百萬用戶及日處理億條消息。其中我們提過Mailbox以14個人的小團隊,在6個星期內實現0到百萬用戶的壯舉,而服務日承載信息破億條。隨后在App發布不到3周,他們將自己以1億美元的價格賣給了Dropb
        推薦度:
        導讀Mailbox:日支撐過億信息數據庫的性能調優及集群遷移:在之前的文章中,我們分享了 Mailbox如何在六星期實現從零到百萬用戶及日處理億條消息。其中我們提過Mailbox以14個人的小團隊,在6個星期內實現0到百萬用戶的壯舉,而服務日承載信息破億條。隨后在App發布不到3周,他們將自己以1億美元的價格賣給了Dropb

        在之前的文章中,我們分享了 Mailbox如何在六星期實現從零到百萬用戶及日處理億條消息。其中我們提過Mailbox以14個人的小團隊,在6個星期內實現0到百萬用戶的壯舉,而服務日承載信息破億條。隨后在App發布不到3周,他們將自己以1億美元的價格賣給了Dropbox。

        在之前的文章中,我們分享了 Mailbox如何在六星期實現從零到百萬用戶及日處理億條消息。其中我們提過Mailbox以14個人的小團隊,在6個星期內實現0到百萬用戶的壯舉,而服務日承載信息破億條。隨后在App發布不到3周,他們將自己以1億美元的價格賣給了Dropbox。這次我們帶來的是,Mailbox在快速擴展過程中,MongoDB所遭遇的性能瓶頸及解決途徑。

        以下為譯文:

        在Mailbox快速擴展過程中,其中一個性能問題就是MongoDB的數據庫級別寫鎖,在鎖等待過程中耗費的時間,直接反應到用戶使用服務過程中的延時。為了解決這個長期存在的問題,我們決定將一個常用的MongoDB集合(儲存了郵件相關數據)遷移到獨立的集群上。根據我們推斷,這將減少50%的鎖等待時間;同時,我們還可以添加更多的分片,我們還期望可以獨立的優化及管理不同類型數據。

        我們首先從MongoDB文檔開始,很快的就發現了 cloneCollection命令。然而隨后悲劇的發現,它不可以在分片集合中使用;同樣, renameCollection也不能在分片集合中使用。在否定了其它可能性之后(基于性能問題),我們編寫了一個Python腳本用以復制數據,和另一個用于比較原始和目標數據的腳本。在這個過程中,我們還發現了許多有意思的事情,比如 gevent及 pymongo復制大數據集的時間是 mongodump(C++編寫)的一半,即使MongoDB客戶端和服務器在同臺主機上。通過最終努力,我們開發了 Hydra,用于MongoDB遷移的工具集,現已開源首先,我們建立了MongoDB集合的原始快照。

        問題1:悲劇的性能

        早期我做了一個實驗以測試MongoDB API運作所能達到的極限速度——啟用一個簡單的使用MongoDB C++ 軟件開發工具包的速度。一方面對C++ 感覺厭煩,一方面希望我大多數熟練使用Python的同事可以在其他用途上使用或適應這種代碼,我沒有更進一步的探索C++的使用,而是發現,如果是針對少量數據,在處理相同任務上,簡單的C++應用速度是簡單Python應用的5-10倍。

        所以,我的研究方向回到了Python,這個Dropbox默認語言。此外,進行了諸如對mongod查詢等的一系列遠程網絡請求時,客戶端往往需要耗費大量時間等待服務器響應;似乎也沒有很多copy_collection.py (我的MongoDB集合復制工具)需要的CPU密集型操作(部分)。initialcopy_collection.py占很少的CPU使用率也證實了這一點。

        然后,MongoDB請求到copy_collection.py.。最初的工作線程實驗結果并不理想。但接下來,我們通過Python Queue對象來實現工作線程通信。這樣的性能依舊不是很好,因為IPC上的開銷讓并發帶來的提升黯然失色。使用Pipes和其他IPC機制也并沒有多大幫助。

        接下來,我們嘗試了使用單線程Python進行MongoDB異步查詢,看看可以有多少性能結余。其中Gevent是實現這個途徑常用庫之一,我們對它進行了嘗試。Gevent 修改了標準Python模塊以實現異步操作,比如socket。比較好的一點是,你可以簡單的編寫異步讀取代碼,就像同步代碼一樣。

        通常情況下,兩個集合之間復制文檔的異步代碼會是:

        import asynclib
        
        def copy_documents(source_collection, destination_collection, _ids, callback):
         """
         Given a list of _id's (MongoDB's unique identifier field for each document),
         copies the corresponding documents from the source collection to the destination
         collection
         """
        
         def _copy_documents_callback(...):
         if error_detected():
         callback(error)
        
         # copy documents, passing a callback function that will handle errors and
         # other notifications
         for _id in _ids:
         copy_document(source_collection, destination_collection, _id,
         _copy_documents_callback)
        
         # more error handling omitted for brevity
         callback(None)
        
        def copy_document(source_collection, destination_collection, _id, callback):
         """
         Copies document corresponding to the given _id from the source to the
         destination.
         """
         def _insert_doc(doc):
         """
         callback that takes the document read from the source collection
         and inserts it into destination collection
         """
         if error_detected():
         callback(error)
         destination_collection.insert(doc, callback) # another MongoDB operation
        
         # find the specified document asynchronously, passing a callback to receive
         # the retrieved data
         source_collection.find_one({'$id': _id}, callback=_insert_doc)

        有了gevent,這些代碼不再需要使用callback:

        import gevent
        gevent.monkey.patch_all()
        
        def copy_documents(source_collection, destination_collection, _ids):
         """
         Given a list of _id's (MongoDB's unique identifier field for each document),
         copies the corresponding documents from the source collection to the destination
         collection
         """
        
         # copies each document using a separate greenlet; optimizations are certainly
         # possible but omitted in this example
         for _id in _ids:
         gevent.spawn(copy_document, source_collection, destination_collection, _id)
        
        def copy_document(source_collection, destination_collection, _id):
         """
         Copies document corresponding to the given _id from the source to the
         destination.
         """
         # both of the following function calls block without gevent; with gevent they
         # simply cede control to another greenlet while waiting for Mongo to respond
         source_doc = source_collection.find_one({'$id': _id})
         destination_collection.insert(source_doc) # another MongoDB operation

        這種簡單的代碼可以根據它們的_idfields,從MongoDB源集合拷取代碼到目標位置,它們的_idfields是每個MongoDB文檔的唯一標識符。opy_documents 會產委派greenlets運行runcopy_document()做文檔復制。當greenlets執行一項阻塞操作,比如對MongoDB的任何需求,它會將控制放給其它準備執行的greenlet。因為所有greenlets都在相同的線程和進程中執行,你一般不需要任何形式的內部鎖定。

        有了gevent,就能夠找到比工作者線程池或工作者進程池更快的方法。下面總結了每種方法的性能:

        Approach Performance (higher is better)
        single process, no gevent 520 documents/sec
        thread worker pool 652 documents/sec
        process worker pool 670 documents/sec
        single process, with gevent 2,381 documents/sec

        綜合gevent和工作者進程(每個分片一個)可以在性能上得到一個線性提升。有效使用工作進程的關鍵是盡可能使用更少的IPC。

        問題2:快照后的復制修改

        因為MongoDB不支持事務,如果你對正在執行修改的大數據集進行讀取,你得到的結果可能會因時而異。舉個例子,你使用MongoDB find()進行整個數據集上的讀取,你的結果集可能是:

      1. ncluded: document saved before your find()
      2. included: document saved before your find()
      3. included: document saved before your find()
      4. included: document inserted after your find() began
      5. 此外,為了在Mailbox后端指向新副本集時能最小化故障時間,盡可能減少從源集群應用到新集群過程中所耗費的時間則至關重要。

        類似多數的異步復制存儲,MongoDB使用了操作日志oplog記錄下了mongod實例上發生的增、改、刪操作,用以分配給這個mongod實例的所有副本。鑒于快照,oplog記錄下快照發生后的所有改變。

        所以這里的工作就變成了在目標集群上應用源集群的oplog記錄,從 Kristina Chodorow的教學博客上,我們清楚了oplog的格式。鑒于序列化的格式,增和刪都非常容易執行,而改則成為了其中的難點。

        改操作的oplog日志記錄結構并不是非常友好:在MongoDB 2.2中使用了duplicate key,然而這些duplicate key并 不能通過Mongo shell呈現,更不必說大部分的MongoDB驅動。深思熟慮之后,選擇了一個簡單的變通方案:將_id嵌入修改源文檔,以觸發其它的文檔副本。因為只是針對修改,雖然不能做到副本集和源實例的完全同步,但是卻可以盡可能的減少副本集實時狀態與快照之間的差距。下面這個圖表顯示為何中間版本(v2)并不一定完全相同,但是源副本與目的副本仍能保持最終一致:

        在這里同樣出現了目標集群的性能問題:雖然為每個分片的ops使用了獨立的進程,但是連續的ops性能仍然匹配不了Mailbox的需求。

        這樣ops的并行就成了必選之路,然而其中的正確性保證卻并不容易。特別的是,同_id操作必須被順序執行。這里采用了一個Python集去維持正在執行修改ops的_id集:當copy_collection.py上發生一個請求正在執行修改操作的文檔時,系統會阻塞后申請的所有ops(不管是修改或者是其它),直到舊的操作結束。如圖所示:

        >

        驗證復制數據

        比較副本集與源實例數據通常是個簡單的操作,但是在多進程與多命名空間中進行卻是個非常大的挑戰。同時基于數據正在不斷的被修改,需要考慮的事情就更多了:

        首先使用compare_collections.py(為對比數據開發的工具)對最近修改的文檔進行數據校驗,如果出現不一致則進行提醒,隨后再進行復查。然而這對文檔的刪除并不有效,因為沒有最后修改的時間戳。

        其次想到的是“ 最終一致性”,因為這在異步場景中非常流行,比如MongoDB的副本集和MySQL的主/從復制。經過非常多的嘗試之后(除下大故障情景下),源數據和副本都會保持最終一致。因此又進行了一些反復對比,在連續的重試中不斷的增加backoff。發現仍然有一些問題存在,比如數據在兩個值之間搖擺不定;然而在修改模式下,遷移的數據并不會出現任何問題。

        在執行新舊MongoDB集群的最終轉換之前,必須確保最近ops已經被應用,因此我們在compare_collections.py增加了命令行選項,用以對比文檔被修改的最近N個操作,這樣可以有效的避免不一致性。這個操作并不用耗費太多的時間,單分片執行數十萬的ops對比只需短短的幾分鐘,還能緩和對比和重試途徑的壓力。

        意外情況處理

        盡管使用了多種途徑去處理錯誤(重試、發現可能的異常、日志),在產品遷移之前的最終測試中仍然出現了許多未預計的錯誤。出現了一些不定期的網絡問題,一個特定的文檔集會一直導致mongos斷開與copy_collection.py連接,以及與mongod的偶然連接重置。

        而在嘗試之后,我們發現針對這些問題制定出專門的解決方案,所以快速的轉到了故障恢復方面。我們記錄了這些compare_collections.py 檢測出的文檔_id,然后專門建立了針對這些_id的文檔重復制工具。

        最終遷移時刻

        在產品遷移過程中,copy_collection.py建立了一個上千萬電子郵件的原始快照,并且重現了過億的MongoDB ops。執行原始快照、建立索引,整個復制過程持續了大約9個小時,而我們設定的時限是24個小時。期間我們又使用copy_collection.py重復3次,對需要復制的數據核查了3次。

        全部轉換直到今日才完成,與MongoDB相關的工作其實很少(只有幾分鐘)。在一個簡潔的維護窗口中,我們使用compare_collections.py對比每個分片的最近的50萬個ops。在確保最后操作中沒有不一致后,我們又做了一些相關測試,然后將Mailbox后端指向了新集群,并將服務重新為用戶開放。而在轉換之后,我們未收到任何用戶反饋的問題。讓用戶感覺不到遷移,就是最大的成功。遷移后的提升如下圖所示:

        寫鎖上的時間減少遠高于50%(原預計)

        開源Hydra

        Hydra是上文操作所用到的所有工具合集,現已在 GitHub上開源。

        Scaling MongoDB at Mailbox(編譯/仲浩 審校/周小璐)

        更多內容請關注CSDN云計算頻道 及@CSDN云計算微博

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        Mailbox:日支撐過億信息數據庫的性能調優及集群遷移

        Mailbox:日支撐過億信息數據庫的性能調優及集群遷移:在之前的文章中,我們分享了 Mailbox如何在六星期實現從零到百萬用戶及日處理億條消息。其中我們提過Mailbox以14個人的小團隊,在6個星期內實現0到百萬用戶的壯舉,而服務日承載信息破億條。隨后在App發布不到3周,他們將自己以1億美元的價格賣給了Dropb
        推薦度:
        標簽: 信息 遷移 數據
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 亚洲第一男人天堂| 亚洲人成毛片线播放| 九九九国产精品成人免费视频| 岛国片在线免费观看| 2019亚洲午夜无码天堂| 成年女人毛片免费播放人| 亚洲国产无线乱码在线观看 | 777亚洲精品乱码久久久久久| 国产永久免费高清在线| 亚洲国产精品一区二区久久| 97av免费视频| 亚洲看片无码在线视频| 日本高清免费中文字幕不卡| 一区二区免费国产在线观看| 亚洲日本乱码在线观看| 少妇无码一区二区三区免费| 亚洲伊人久久精品| 国产99视频精品免费视频7| 人妻仑乱A级毛片免费看| 久久精品国产亚洲av麻豆 | 久久亚洲AV成人无码国产电影 | 国产亚洲av片在线观看播放| 日韩电影免费观看| 亚洲剧场午夜在线观看| 国产精品久免费的黄网站| 国产JIZZ中国JIZZ免费看| 久久亚洲精精品中文字幕| 成人au免费视频影院| 香蕉免费一级视频在线观看| 亚洲黑人嫩小videos| 免费国产不卡午夜福在线| 两个人日本WWW免费版| 亚洲第一页在线视频| 四虎永久精品免费观看| 久久久久久国产精品免费免费男同| 亚洲婷婷第一狠人综合精品| 久久久久久久亚洲精品| 香蕉97超级碰碰碰免费公| 一级毛片在线免费视频| 亚洲一区二区三区亚瑟| 久久精品国产亚洲一区二区三区|