搭建測試mongodb副本集

簡介

(簡書木有目錄, 建議去gitee看: https://gitee.com/xiaofeipapa/docker_mongodb)

我司數據說多不多, 說少不少, 也到了搭個大數據系統的時候了. 更何況我們系統最重要的環節-風控系統, 本來就需要OLAP類的數據庫對數據進行處理. 于是一把年紀的我也重新撿起這個苦力活, 開始了技術選型和框架搭建.

大數據時代的技術棧讓人眼花繚亂. 我先是復習了一下hadoop(若干年前曾經淺嘗轍止使用過), 覺得技術棧實在太過繁瑣(純粹個人意見), 出于對mongodb 更熟悉的原因, 我最終選擇了mongodb 作為大數據的存儲架構, 后續打算用 mongodb + spark 的技術棧.

作為公司產品的基石, 肯定要考慮高可用, 擴展性, 維護性這幾個維度的平衡. 在先后搭建了分片副本集和僅副本集的集群模式之后, 我最終決定用副本集的模式. 因為:

  1. 我們的數據量沒大到需要sharding的程度.
  2. 現階段只要保證高可用, 數據不丟失即可.
  3. 未來數據增長了, 還可以再進行數據遷移的嘛.

以下內容總結了搭建副本集和測試的過程, 祝君閱讀愉快.

(關于更多mongodb的副本集和分片副本集概念, 請自行查詢網上資料)

搭建mongodb副本集

副本集模式的基礎知識

副本集集群模式的概念圖如下:

image-20210728163026525

每個副本集是由多臺機器組成的, 它的特點是:

  • 主節點(Primary): 所有寫入操作都在主節點上進行.
  • 從節點(Secondary): 作為數據的備份, 和主節點數據完全一致. 默認狀態下從節點不可讀(可以設置成可讀)
  • 仲裁節點(Arbiter): 當主節點發生故障時, 判斷選擇哪個從節點成為新的主節點. 如果有多個從節點, 可以設置各個節點的優先級(priority), 仲裁節點會優先選擇高優先級的節點.
  • 整個過程自動故障轉移.
  • 整個過程數據自動恢復.

看上去很美, 要實際試試.

自定義網絡

在docker里 創建自定義網絡:

sudo docker network create --subnet=172.20.1.0/24 mongo_net --gateway 172.20.1.250

網關為 172.20.1.251 , 可用網段為 172.20.1.1 - 172.20.1.250 , 共250臺. (取個整數)

docker規劃和啟動

名稱 數據存儲位置 主從/優先級 ip docker映射端口
mongo_1 ~/mongo-data/data01 172.20.1.1 30001 : 27017
mongo_2 ~/mongo-data/data02 172.20.1.2 30002 : 27017
mongo_3 ~/mongo-data/data03 仲裁節點 172.20.1.3 30003 : 27017

準備所需的文件夾和文件:

# 創建文件夾
mkdir -p ~/mongo-data/{data01,data02,data03,key,backup}

# 設置key文件. 此文件用于在集群機器間互相訪問. 
cd ~/mongo-data
openssl rand -base64 756 > key/mongo-rs.key
sudo chown 999 key/mongo-rs.key

# 不能是755, 權限太大不行. 
sudo chmod 600 key/mongo-rs.key

創建并啟動第一個mongo容器. 這個容器的幾個關鍵信息是:

節點名稱: mongo-1

用戶: admin

密碼: 123456

副本集名稱: MongoSet

數據目錄: ~/mongo-data/data01 (在之前創建)

映射端口: 30001

# 第一個
sudo docker run --name mongo-1 --network=mongo_net --ip=172.20.1.1 -p 30001:27017 -v ~/mongo-data/data01:/data/db -v ~/mongo-data/backup:/data/backup -v ~/mongo-data/key:/data/key -v /etc/localtime:/etc/localtime -e MONGO_INITDB_ROOT_USERNAME=admin -e MONGO_INITDB_ROOT_PASSWORD=123456 -d mongo:5.0.0 --replSet MongoSet --auth --keyFile /data/key/mongo-rs.key --bind_ip_all

MONGO_INITDB_ROOT_USERNAME 和 MONGO_INITDB_ROOT_PASSWORD 是 mongo 鏡像的方便功能, 關于這個鏡像的更多功能, 可以參考官方文檔: https://hub.docker.com/_/mongo/

現在, 用 sudo docker ps 來查看容器狀態, 應該能夠看到容器已經啟動了. 如果不能看到容器啟動, 那么可以將上述命令的 -d 參數去掉, 運行的時候在窗口查找原因.

啟動其他容器

# 第二個
sudo docker run --name mongo-2 --network=mongo_net --ip=172.20.1.2 -p 30002:27017 -v ~/mongo-data/data02:/data/db -v ~/mongo-data/backup:/data/backup -v ~/mongo-data/key:/data/key -v /etc/localtime:/etc/localtime -e MONGO_INITDB_ROOT_USERNAME=admin -e MONGO_INITDB_ROOT_PASSWORD=123456 -d mongo:5.0.0 --replSet MongoSet --auth --keyFile /data/key/mongo-rs.key --bind_ip_all

# 第三個
sudo docker run --name mongo-3 --network=mongo_net --ip=172.20.1.3 -p 30003:27017 -v ~/mongo-data/data03:/data/db -v ~/mongo-data/backup:/data/backup -v ~/mongo-data/key:/data/key -v /etc/localtime:/etc/localtime -e MONGO_INITDB_ROOT_USERNAME=admin -e MONGO_INITDB_ROOT_PASSWORD=123456 -d mongo:5.0.0 --replSet MongoSet --auth --keyFile /data/key/mongo-rs.key --bind_ip_all

現在你用 sudo docker ps , 應該能夠看到這3個容器:

image-20210728113102579

初始化副本集信息

登錄第一個容器, 設置副本集的信息

sudo docker exec -it mongo-1 bash

mongo
use admin

# 密碼 123456
db.auth("admin","123456")

# 設置
# MongoSet 是啟動容器時候的副本集名字
var config={
     _id:"MongoSet",
     members:[
         {_id:0,host:"172.20.1.1:27017"},
         {_id:1,host:"172.20.1.2:27017"},
         {_id:2,host:"172.20.1.3:27017",arbiterOnly:true}
]};
rs.initiate(config)

# 查看集群狀態
rs.status()

# 設置完之后, 退出
exit

設置完之后退出, 重新登錄容器:

sudo docker exec -it mongo-1 bash
mongo

這個時候可以看到, 這臺容器顯示的是副本集的主節點:

image-20210728134215133

增加業務數據庫和用戶名

保持第一臺容器的登錄狀態, 輸入命令如下:

mongo 

use admin

# 密碼 123456
db.auth("admin","123456")

# 數據庫不用創建, 使用use 即可
use ExampleDb

# 新增用戶
db.createUser({

    user: "test",

    pwd: "123456",

    roles: [ { role: "readWrite", db: "ExampleDb" } ]
})

設置從節點可讀

默認的情況下, 主節點負責讀寫, 副節點僅起到備份作用, 不能讀也不能寫. 所以還要進行如下設置:

登錄第2臺容器, 依次進行:

sudo docker exec -it mongo-2 bash

mongo

use admin

# 密碼 123456
db.auth("admin","123456")

# 注意:這條命令要在副節點上運行
# mongodb默認是從主節點讀寫數據,副本節點上不允許讀,設置副本節點可讀。
# 網上的文章基本都是 setSlaveOk, 這個方法已經是 deprecated 狀態. 
db.getMongo().setSecondaryOk()


設置了之后, 從節點會分擔主節點讀的壓力, 提高了系統的性能.

圖形化訪問工具

mongodb 的圖形化工具很多, 官方的mongo compass 就不錯, 下載地址: https://www.mongodb.com/try/download/compass

下載安裝這個工具之后, 在連接字符串輸入:

mongodb://test:123456@127.0.0.1:30001,127.0.0.1:30002,127.0.0.1:30003/ExampleDb?authSource=test&replicaSet=MongoSet

點擊連接, 就可以看到漂漂亮亮的界面了.

image-20210728141738896

至此, 副本集的搭建就算完成了.

測試副本集

接下來打算測試一下集群各類性能和可用能力, 先測試主從復制.

測試主從復制功能

這時候, 在第一臺容器的mongo 控制臺輸入如下代碼:

mongo

use admin
db.auth("admin","123456")

# test 使用test 數據庫
use test

# 插入一條數據
db.users.insert({name:"jack",age:0,addr:"guangzhou",country:"China"})

登錄第二臺容器, 看看是否有這條記錄:

use admin
db.auth("admin","123456")

use test

db.users.find()

此時你應該看到這條記錄, 證明我們的主從復制功能已經成功了.

測試插入性能

用python寫個簡單的程序, 往集群插入 10 萬條數據

#! /usr/bin/python3
# -*- coding: UTF-8 -*-
"""
 * 作者: 小肥爬爬
 * 簡書: http://www.lxweimin.com/u/db796a501972
 * gitee: https://gitee.com/xiaofeipapa
 * 郵箱: imyunshi@163.com
 * 您可以自由轉載此博客文章, 懇請保留原鏈接, 謝謝!
"""
from pymongo import MongoClient
import time

ip_list = [
    '127.0.0.1:30001',
    '127.0.0.1:30002',
    '127.0.0.1:30003',
]

conn = MongoClient(ip_list)
ExampleDb = conn.ExampleDb

# 用業務數據庫的用戶名密碼登錄
user = 'test'
pwd = '123456'
ExampleDb.authenticate(user, pwd)

# 使用 TestUser 這個Collection
TestUser = ExampleDb.TestUser


# 測試插入10萬數據的時間
def test_1():
    time_start = time.clock()  # 記錄開始時間
    count = 100000

    # 使用批量插入功能
    batch_list = []

    for i in range(0, count):

        data = {
            'index': i,
            'name': 'test-%d' % i
        }
        batch_list.append(data)

        if len(batch_list) > 1000:
            TestUser.insert_many(batch_list)
            batch_list.clear()

    # 防止還有值遺留
    if len(batch_list) > 0:
        TestUser.insert_many(batch_list)
        batch_list.clear()

    # -------------------------
    time_end = time.clock()  # 記錄結束時間
    time_sum = time_end - time_start  # 計算的時間差為程序的執行時間,單位為秒/s
    print('程序運行時間: %d 秒' % time_sum)

if __name__ == '__main__':
    test_1()


程序運行幾乎是一閃而過, 也可以看到"程序運行時間 0 秒", 證明速度非常快. 用compass 看看, 確實有數據了:

image-20210728150546547

測試可用性

(為了觀察方便, 在compass 里將之前的 TestUser 刪掉.)

步驟:

  1. 停止主節點(第一個容器)
  2. 再次運行python程序
  3. compass 檢查數據

停止第一個容器:

sudo docker stop mongo-1 

然后再次運行之前的python代碼. 可以觀察到如下現象:

  1. 即使主節點關了, 代碼還是順利運行
  2. compass 能看到10萬條數據.

這說明測試可用性也成功了.

如果此時你登錄到第二臺容器, 運行mongo 命令. 你會發現這臺機器已經成了主節點. 這表示在第一臺容器down掉之后, 第二臺容器成功地挑起了重擔.

測試數據丟失

(為了觀察方便, 在compass 里將之前的 TestUser 刪掉.)

先將第一臺容器重新啟動:

sudo docker restart mongo-1

(此時, 此容器已經成了從節點)

步驟:

  1. 用python插入 500 萬數據
  2. 插入途中停止主節點容器
  3. 看看程序的反應如何?
  4. 5秒后, 重新啟動"主節點"容器(重啟之后, 它其實變成了從節點)
  5. 程序運行完之后, 檢查 compass 到底插入了多少數據
  6. 分別進入第一個, 第二個容器, 看看他們的數據是否有差值?

我們期望的結果:

  1. 插入過程不能停. (這個已經驗證過了)
  2. 看看數據是否有丟失?

(這些過程你自己可以試試)

我的測試結果

查詢插入時間: 38 秒

compass 查詢結果: 500萬數據 (沒有丟失!!)

主節點容器數據: 500萬. (用 db.TestUser.count() 查總數)

從節點容器運行查詢語句的時候報這個錯:

image-20210728160330556

這個錯誤的意思是從節點不可讀. 在之前搭建集群的時候, 我們要在從節點這樣設置:

db.getMongo().setSecondaryOk()

這表明, 當某個節點down掉再重連之后, 它會恢復成mongodb 的默認從節點配置, 沒事, 再次運行這句就是了. 比起數據沒有丟失, 這不算多大的事吧?

至此, mongodb集群的搭建, 測試就算徹底完成了.

附錄

修改mongodb 密碼

為了安裝方便, 密碼都使用 123456 這樣的弱密碼. 在安裝好集群之后, 我們應該將它改掉.

我向你推薦 pwgen , 用這個小工具來生成密碼:

sudo apt install pwgen
pwgen -s 20

登錄主節點容器, 使用 db.changeUserPassword 來修改密碼:

sudo docker exec -it mongo-1 bash

use admin
db.auth('admin', '123456')

# 修改密碼, 假設你的是 xxxyyy
db.changeUserPassword('admin','xxxyyy')

防止日志文件過大

mongodb的日志膨脹非常快, 單個文件非常大, 可以通過這個命令來設置:

db.adminCommand({logRotate:1})

之后日志就會按日期分割成獨立的文件. 一些過期的日志, 刪了即可.

docker 便捷命令

查看正在運行的容器

sudo docker ps

查看創建沒有啟動的容器

sudo docker ps -a

一鍵停止所有容器

sudo docker ps -q |xargs sudo docker stop 

刪除全部容器

sudo docker ps -aq |xargs sudo docker rm 

springboot 配置

spring:
  data:
    mongodb:
      uri: mongodb://test:123456@127.0.0.1:30001,127.0.0.1:30002,127.0.0.1:30003/ExampleDb?authSource=test&replicaSet=MongoSet

作者簡介

藝名小肥爬爬(小肥耙耙/小肥巴巴), 一個喜歡閱讀/寫字/健身/踢球/吉他的程序員, 他和小田園犬肥花在深圳愉快地生活.

歡迎探討技術領域的方方面面, 你可以在簡書, gitee和知乎找到他:

簡書: http://www.lxweimin.com/u/db796a501972

gitee: https://gitee.com/xiaofeipapa

知乎: https://www.zhihu.com/people/chen-yun-shi-75

csdn(不常用): https://blog.csdn.net/m0_46322443

參考文章&感謝

https://blog.csdn.net/lzkIT/article/details/8146567

https://blog.csdn.net/zhanngle/article/details/105132527

https://www.cnblogs.com/zqyx/p/10169820.html

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,443評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,530評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,407評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,981評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,759評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,204評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,263評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,415評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,955評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,650評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,892評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,675評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,967評論 2 374

推薦閱讀更多精彩內容