摘要:可以發現,整個同步過程是依賴于來進行的。不考慮導致的問題,正常的應用升級也會導致應用中斷運行。注意事項為了避免被回滾的更新被發布出去,選擇只在一個變更到達大多數節點不可能被回滾時,才會將這些變更發布到應用。
Change Stream是MongoDB從3.6開始支持的新特性。這個新特性有哪些奇妙之處,會給我們帶來什么便利?本次的文章將就這個主題進行初步討論。
Change Stream是什么?顧名思義,Change Stream即變更流,是MongoDB向應用發布數據變更的一種方式。即當數據庫中有任何數據發生變化,應用端都可以得到通知。我們可以將其理解為在應用中執行的觸發器。至于應用想得到什么數據,以什么形式得到數據,則可以通過聚合框架加以過濾和轉換。這點將在后文中討論。
Change Stream的原理我們先來回顧一下MongoDB復制集大致是如何工作的:
應用通過驅動向數據庫發起寫入請求;
在同一個事務中,MongoDB完成oplog和集合的修改;
oplog被其他從節點拉走;
從節點應用得到的oplog,同樣在一個事務中完成對oplog和集合的修改;
至此,復制集同步完成。可以發現,整個同步過程是依賴于oplog來進行的。也就是說oplog實際上已經包含了我們需要的所有變更數據。如果觀測oplog的變化,是否就能夠得到所有變更的數據了呢?對,change stream正是基于這個原理實現的。但事情并沒有這么簡單!我們來看一下問題有可能出在什么地方。
如何從斷點恢復現實世界中,沒有哪個應用是可以不間斷運行的。不考慮bug導致的問題,正常的應用升級也會導致應用中斷運行。那么在應用恢復的時候,從哪里開始繼續獲取變更呢?oplog當然是可以幫我們做到這點的,但你必須對MongoDB足夠了解,才知道有oplogReplay這樣的參數,以及其他一些問題。
如何有效地處理訂閱假設在一個應用中需要訂閱10個不同集合的變更情況,是否需要開10個tailable cursor去獲取oplog的變更呢?如果是100個集合呢?出于效率考慮顯然不應該這么做。那么整個過程就會變成一個生產者-消費者模式,由一個線程負責從oplog獲取變更,由訂閱的線程負責消費這些變更。雖然實現也不是那么復雜,并且多半可以找到開源實現,但是涉及多線程就已經足夠讓初學者頭疼一陣的了。
公平地說,上面這些還不算嚴重的問題,下面這些問題可能會更讓人頭疼。
想要tail oplog,必須對local.oplog.rs有讀權限。實際上這相當于對整個數據庫都有了讀權限,因為所有的變更都會在這里體現出來。DBA可能會阻止你這么做,因為這實在不是一個很安全的做法。
如何數據回滾極端情況下,如果應用處理不當,MongoDB中可能發生數據回滾rollback的問題。如果僅僅通過跟蹤oplog,則會出現已經通知出去的變更被回滾的情況。
幸運的是上面這些問題現在都不是問題了,因為change stream幫我們規避了這些復雜的細節。
使用方法由于各種驅動都會有不同的語法和API,從shell中嘗試使用change stream可能是最簡便的方法。這并不妨礙你隨后在各種驅動中的使用,因為shell中能實現的功能在驅動中一定有對應的語法。下面就以shell為例看看change stream應該如何使用。
打開一個shell,訂閱你需要關注的集合
比如:
var cursor = db.bar.watch();
為了便于演示,我們在這個shell中不斷遍歷這個游標以獲取新數據:
while(true) { if (cursor.hasNext()) { print(JSON.stringify(cursor.next())); } }
打開另一個shell,向bar集合中插入一條數據:
db.bar.insert({y: 1})
此時第一個shell中會立即輸出變更數據:
{"_id":{"_data":{"$binary":"glzquiIAAAACRmRfaWQAZFzquiK0lDNo+K0DpwBaEARUMrm0ruVACoftuxjt1RtCBA==","$type":"00"}},"operationType":"insert","fullDocument":{"_id":{"$oid":"5ceaba22b4943368f8ad03a7"},"y":1},"ns":{"db":"test","coll":"bar"},"documentKey":{"_id":{"$oid":"5ceaba22b4943368f8ad03a7"}}}
這里的一些字段的簡單介紹。更完整的介紹請查閱文檔change events:
_id: 用于恢復斷點時使用。即知道這個值,應用斷開后下次重啟里就可以從這個斷點之后開始恢復獲得變更;
operationType: 操作類型,常見的值包括:
insert
update
delete
ns: 正在操作的命名空間
fullDocument: 完整的文檔
從斷點恢復
var cursor = db.bar.watch([], {resumeAfter: <\_id>})
此時使用hasNext()/next()即可獲取到隨后的變更。
注意事項 {readConcern: "majority"}為了避免被回滾的更新被發布出去,change stream選擇只在一個變更到達大多數節點(不可能被回滾)時,才會將這些變更發布到應用。使用的方式即{readConcern: "majority"}。因此以下這些情況下change stream都是不會向應用通知任何變更的:
禁用了readConcern;
從舊版本升級,但沒有更新featureCompatibilityVersion;
PSA架構中S宕機;
斷點可恢復時間因為change stream是依賴于oplog工作的,自然也會面臨oplog面臨的所有問題。問題之一就是oplog被覆蓋。因此想要保證斷點可以恢復,必須保證應用在oplog window的時間內請求斷點。
刪除集合如果在訂閱集合變更過程中集合被刪除,則會收到一條invalid信息通知,表示集合已不再可用:
{ "_id" : { "_data" : BinData(0,"glzqxCcAAAACFFoQBFQyubSu5UAKh+27GO3VG0IE") }, "operationType" : "invalidate" }參考資料
Tailable cursor: https://docs.mongodb.com/manual/core/tailable-cursors/
生產者-消費者模式: https://zh.wikipedia.org/wiki/%E7%94%9F%E4%BA%A7%E8%80%85%E6%B6%88%E8%B4%B9%E8%80%85%E9%97%AE%E9%A2%98
關于回滾: https://docs.mongodb.com/manual/core/replica-set-rollbacks/
變更事件: https://docs.mongodb.com/manual/reference/change-events/
Change Stream介紹文檔:https://docs.mongodb.com/manual/changeStreams/
作者簡介張耀星,MongoDB亞太區首席技術咨詢服務顧問。在MongoDB的開發、應用和咨詢服務上有多年實踐經驗。作為MongoDB認證專家,曾經為不同行業的各類大型客戶提供過培訓、性能調優、架構設計等各類MongoDB相關技術服務。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/19547.html
摘要:第一個函數生成一個新的實例第二個函數接受兩個參數,第一個是前面生成的對象,二個是中包含的元素,函數體就是把中的元素加入對象中。 感謝同事【天錦】的投稿。投稿請聯系 tengfei@ifeve.com 上篇文章[Java8初體驗(一)lambda表達式語法]()比較詳細的介紹了lambda表達式的方方面面,細心的讀者會發現那篇文章的例子中有很多Stream的例子。這些Stream的例子可...
摘要:原文來源全棧初體驗前言據說現在不會點后臺的前端都找不到工作了嚇得我這幾天看起了和并且做了一個應該算是最簡單的前后端例子,如圖輸入賬戶密碼,提交表單,保存信息到數據庫再重定向到頁面獲取數據庫中的信息,渲染在瀏覽器上具體代碼主要技術前端模板后臺 原文來源: 全棧初體驗 前言 據說現在不會點后臺的前端都找不到工作了嚇得我這幾天看起了Nodejs和MongoDB并且做了一個應該算是最簡單的前后...
摘要:原文來源全棧初體驗前言據說現在不會點后臺的前端都找不到工作了嚇得我這幾天看起了和并且做了一個應該算是最簡單的前后端例子,如圖輸入賬戶密碼,提交表單,保存信息到數據庫再重定向到頁面獲取數據庫中的信息,渲染在瀏覽器上具體代碼主要技術前端模板后臺 原文來源: 全棧初體驗 前言 據說現在不會點后臺的前端都找不到工作了嚇得我這幾天看起了Nodejs和MongoDB并且做了一個應該算是最簡單的前后...
摘要:原文來源全棧初體驗前言據說現在不會點后臺的前端都找不到工作了嚇得我這幾天看起了和并且做了一個應該算是最簡單的前后端例子,如圖輸入賬戶密碼,提交表單,保存信息到數據庫再重定向到頁面獲取數據庫中的信息,渲染在瀏覽器上具體代碼主要技術前端模板后臺 原文來源: 全棧初體驗 前言 據說現在不會點后臺的前端都找不到工作了嚇得我這幾天看起了Nodejs和MongoDB并且做了一個應該算是最簡單的前后...
摘要:前言筆者的前端開發已經有些時日了,對于一直保留著最初的恐懼,倘若一座不可跨越的高山,思前想后終于邁出最后一步,踏入了開拓自己視野的新視界,希望在看這篇文章的你可以一起跟我動手嘗試。面向的下一代框架。由團隊打造,特點優雅簡潔靈活體積小。 showImg(https://segmentfault.com/img/bVbuorM?w=1514&h=568); 前言 ?????筆者的前端開發已...
閱讀 1868·2021-11-22 09:34
閱讀 1141·2021-10-09 09:44
閱讀 3001·2021-09-29 09:35
閱讀 3617·2021-09-14 18:01
閱讀 1465·2021-08-16 10:49
閱讀 1084·2019-08-29 14:11
閱讀 849·2019-08-29 12:47
閱讀 3068·2019-08-26 13:47