Fundebug是這樣備份資料的
摘要:資料還是要備份的,萬一刪庫了呢?
- 本文程式碼倉庫: ofollow,noindex">fundebug-mongodb-backup
引言
今年8月,騰訊雲竟然把客戶前沿資料的資料弄沒了,Fundebug在第一時間進行了一些簡單的技術分析:
一方面,騰訊雲對這件事負有不可推卸的責任,他們剛開始說是什麼硬碟韌體版本bug (該宣告已刪),後來承認是人為操作失誤 導致的。
另一方面,前沿資料沒有備份業務資料,也是一種非常不專業的行為,導致業務無法恢復,必須完全重新開始。
因此,所有的開發者都應該從這個事件吸取教訓,不要偷懶,嚴格備份業務資料,否則資料一旦出問題,損失將無法挽回。
Fundebug資料備份方案
我們還分享了Fundebug的資料備份方案,供大家參考:
備份方案 | 時間粒度 | 細節 |
---|---|---|
MongoDB複製集 | 實時 | 搭建3個節點(1個Primary和2個Secondary)的MongoDB複製集,實時同步資料。 |
阿里雲磁碟快照 | 每天 | 每天凌晨自動快照所有磁碟,包括系統盤和備份資料盤。 |
mongodump匯出核心資料 | 每天 | 每天凌晨將MongoDB核心資料匯出到複製集之外的伺服器磁碟(該磁碟會每天進行快照)。 |
阿里雲物件儲存 | 每天 | 每天凌晨將mongodump匯出的資料使用gpg非對稱加密之後,上傳到阿里雲深圳資料中心的物件儲存,設定跨區域複製,自動同步到杭州資料中心,每份資料保留1個月。 |
本地硬碟備份 | 每週 | 每週六中午從阿里雲物件儲存下載加密的備份資料,儲存到本地磁碟。 |
大概是因為我們沒有公佈備份方案的技術細節,我們受到了質疑 :
要麼多重備份是假的
對於這種指責,我的原則是必須懟回去。那麼,這篇部落格我來詳細介紹一下我們資料備份方案吧~所有原始碼都在GitHub倉庫Fundebug/fundebug-mongodb-backup ,歡迎star。
MongoDB複製集
生產環境使用單節點的MongoDB資料庫,除非訪問量非常低或者不在乎服務可用性,否則基本上是不可能的,這輩子都不可能 。單節點MongoDB存在單點故障(single point of failure) ,一旦掛了,整個應用就掛了。更糟糕的是,如果資料損壞,恢復將非常麻煩。
MongoDB有多種可能性會掛掉,最常見的就是高峰期記憶體使用量飆升,導致Linux的Out of Memory (OOM) killer將mongod程序殺死,這種情況Fundebug遇見過不少次,那我們是如何安全渡過的呢?答案是 複製集(replica set) 。
複製集由多個MongoDB節點構成,它們的資料是實時同步的,因此資料幾乎完全相同。當某個節點掛掉時,應用可以自動切換到其他節點,這樣保證了服務的可用性。
Fundebug的MongoDB都執行在Docker容器中,其Docker Compose配置檔案如下:
version: '2.2' services: mongo: image: mongo:3.2 network_mode: "host" restart: always cpus: 7 mem_limit: 30g command: --replSet rs0--oplogSize 25600 volumes: - /mongodb/data:/data/db logging: driver: "json-file" options: max-size: "5g"
oplog
複製集一個非常重要 的引數是oplog 的大小,使用–oplogSize 選項可以指定。我們設定的值是25600MB,即25GB。oplog(operation log)是複製集節點同步資料的關鍵,Primary節點將資料庫寫操作記錄到oplog中,Secondary節點從Primary節點處複製oplog並應用到本地資料庫中。因此,oplog大小決定了Primary和Secondary節點可以接受的資料最大”時間差”。使用rs.printReplicationInfo() 可以檢視oplog資訊:
rs.printReplicationInfo() configured oplog size:25600MB log length start to end: 11409secs (3.17hrs) oplog first event time:Sat Sep 22 2018 12:02:04 GMT+0800 (CST) oplog last event time:Sat Sep 22 2018 15:12:13 GMT+0800 (CST) now:Sat Sep 22 2018 15:12:13 GMT+0800 (CST)
可知oplog中記錄了最近3.17小時的資料庫寫操作,假設複製集中某個節點由於宕機有4個小時沒有同步資料,則重啟該節點也無法與其他節點同步了!這時會出現“too stale to catch up – entering maintenance mode” 的錯誤,只能手動同步資料。
因此,我們建議oplog的值應該儘量設大一些,否則以後修改oplog 的步驟挺麻煩的。事實上,25GB的oplog大小對於Fundebug的MongoDB複製集來說已經不夠了,我們需要修改。
Fundebug的MongoDB複製集由1個Primary節點和2個Secondary節點構成,為保證我們服務可用性發揮了非常關鍵的作用!我之後所介紹的備份方案都是冗餘措施,我們從來沒有真正使用過那些備份資料,而複製集“拯救” 了我們不少次,強烈建議大家都配置一下。
關於MongoDB複製集的更多技術細節,以後我再單獨詳述,歡迎關注Fundebug微信公眾號。
阿里雲磁碟快照
快照能夠保留某一時間點的磁碟資料狀態,因此可以作為一種資料備份方式。很簡單,配置一下自動快照策略 就好了:
我備份了系統盤,萬一資料丟失比如被刪庫,至少還能回滾磁碟。每週快照1次,儲存7天。因為服務全部執行在Docker裡面,伺服器本身基本上沒有什麼配置,備份的需求不大,實際上我們也從來沒有回滾過磁碟。
另外,我沒有對MongoDB資料盤直接進行快照,因為發現快照後的資料無法恢復(這一點有待進一步確認)。
我只是將mongodump匯出的核心資料所在磁碟進行了快照。每天快照1次,儲存兩天。這樣做可以確保核心資料的安全性。
mongodump匯出核心資料
使用mongodump 命令,可以全量匯出MongoDB資料。對應的,之後可以使用mongorestore 命令將備份資料匯入MongoDB。
匯出資料的指令碼dump-data.sh 如下:
#!/bin/sh # 刪除前一天匯出的資料 rm -rf /data/mongodb_backup DIR=`date +%Y%m%d%H%M` OUT=/data/mongodb_backup/$DIR mkdir -p $DEST # 全量匯出MongoDB資料(排除部分集合) mongodump --host "rs0/192.168.59.11:27017,192.168.59.12:27017,192.168.59.13:27017" \ --db fundebug-production \ --excludeCollection events \ --out $OUT
使用–excludeCollection 選項,可以排除部分不需要備份的集合。例如,Fundebug累計處理了6億+ 的錯誤事件,存在event集合中,因為我們已經聚合過了,所以沒有必要備份,而且資料量太大,備份也不現實。
使用crontab指令碼定期執行dump-data.sh 指令碼:
# 每天凌晨4點匯出資料 0 4 * * * /root/fundebug-mongodb-backup/dump-data.sh
阿里雲物件儲存
使用mongodump匯出的資料儲存在測試伺服器的資料磁碟上,從地域層面上來說都在同一個地方,即阿里雲深圳資料中心。如果要做到異地備份,可以藉助阿里雲的物件儲存服務的跨區域複製 功能,將備份資料自動同步到阿里雲杭州資料中心。
在上傳備份資料之前,使用gpg命令進行非對稱加密,可以保證資料安全性。加密匯出資料的指令碼encrypt-data.sh 指令碼如下:
#!/bin/bash DIR=`find /data/mongodb_backup/ -maxdepth 1 -type d ! -path /data/mongodb_backup/` source=$DIR/fundebug-production cd $source # 將匯出資料加密 for file in * ; do gpg --batch --yes -v -e -r fundebug --output $source/$file.gpg --always-trust $file done ;
除了加密,gpg還有一定的壓縮效果,這樣可以減少備份資料量,一舉兩得。關於gpg命令的細節,可以檢視參考部落格。
使用阿里雲提供的Node.js客戶端ali-oss ,可以將加密之後的.gpg檔案上傳到阿里雲的物件儲存服務中。使用multipartUpload 方法即可,upload.js 部分程式碼如下:
// 上傳單個檔案 async function uploadFile(fileName, filePath) { try { const result = await store.multipartUpload(fileName, filePath, { parallel: 4, partSize: 1024 * 1024, progress: function(p) { logger.info("Progress: " + p); } }); if (result.res.statusCode === 200) { logger.info(`upload file success! ${fileName}`); } else { const message = `upload file fail! ${fileName}`; logger.error(message); logger.error(result); fundebug.notifyError(new Error(message), { metaData: { message: message, result: result } }); } } catch (error) { const message = `upload file fail! ${fileName}`; logger.error(message); logger.error(error); fundebug.notifyError(error, { metaData: { message: message, error: error } }); } }
程式碼執行在Docker容器中,使用curl命令訪問HTTP介面/upload即可觸發執行上傳操作,使用crontab定期執行:
# 每天凌晨4點備份資料 0 4 * * * /root/mongodb-backup/dump-data.sh && /root/mongodb-backup/encrypt-data.sh && docker restart mongodb-backup && sleep 1m && curl http://127.0.0.1:9160/upload
備份資料通過資料卷(volume)對映到容器中,每天需要重啟容器,才能訪問每天匯出的新資料。
在阿里雲上為備份資料的儲存空間配置跨區域複製 ,即可實現自動異地備份,非常方便。其他物件儲存雲服務應該也支援這種功能吧。
本地磁碟備份
前文提到的備份方式,其實都是在阿里雲內部COPY資料。那麼問題來了,阿里雲掛了怎麼辦?這種事情當然基本上不可能發生,畢竟我們有多處備份,甚至實現了異地備份。
既然備份資料都上傳到阿里雲物件儲存了,下載到本地也不是什麼難事。使用ali-oss 的list 和get 方法即可實現,download.js 部分程式碼如下:
// 獲取當天上傳到阿里OSS的檔案列表 async function listFilesToDownload(day) { const result = await store.list({ prefix: day }); return result.objects; } // 將阿里雲OSS中的檔案下載到本地 async function downloadFile(fileName, path) { try { const file = fileName.split("/")[1]; const filepath = `${path}/${file}`; await store.get(fileName, filepath); } catch (error) { const message = `download file fail! ${fileName}`; logger.error(message); logger.error(error); fundebug.notifyError(error, { metaData: { error: error, message: message } }); } }
程式碼執行在Docker容器中,部署在本地機器,使用curl命令訪問HTTP介面/download即可觸發執行下載操作,使用crontab定期執行:
# 每週六中午從阿里雲下載備份資料 0 12 * * 6 curl http://127.0.0.1:9160/download
結論
本文提到的所有的資料備份方式完全自動化執行,沒有什麼技術難度,成本也不高,可以極大提高資料安全性。
參考
- MongoDB被Linux OOM Kill
- 理解和配置 Linux 下的 OOM Killer
- MongoDB文件 - Replication
- 阿里雲MongoDB備份恢復功能說明和原理介紹
- MongoDB文件 - mongodump
- GPG Encryption Guide - Part 1
- GPG Encryption Guide - Part 2 (Asymmetric Encryption)
關於Fundebug
Fundebug專注於JavaScript、微信小程式、微信小遊戲、支付寶小程式、React Native、Node.js和Java實時BUG監控。 自從2016年雙十一正式上線,Fundebug累計處理了6億+錯誤事件,得到了Google、360、金山軟體等眾多知名使用者的認可。歡迎免費試用!