搭建測試mongodb副本集

簡介

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

我司數(shù)據(jù)說多不多, 說少不少, 也到了搭個大數(shù)據(jù)系統(tǒng)的時候了. 更何況我們系統(tǒng)最重要的環(huán)節(jié)-風控系統(tǒng), 本來就需要OLAP類的數(shù)據(jù)庫對數(shù)據(jù)進行處理. 于是一把年紀的我也重新?lián)炱疬@個苦力活, 開始了技術(shù)選型和框架搭建.

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

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

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

以下內(nèi)容總結(jié)了搭建副本集和測試的過程, 祝君閱讀愉快.

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

搭建mongodb副本集

副本集模式的基礎(chǔ)知識

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

image-20210728163026525

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

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

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

自定義網(wǎng)絡(luò)

在docker里 創(chuàng)建自定義網(wǎng)絡(luò):

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

網(wǎng)關(guān)為 172.20.1.251 , 可用網(wǎng)段為 172.20.1.1 - 172.20.1.250 , 共250臺. (取個整數(shù))

docker規(guī)劃和啟動

名稱 數(shù)據(jù)存儲位置 主從/優(yōu)先級 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 仲裁節(jié)點 172.20.1.3 30003 : 27017

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

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

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

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

創(chuàng)建并啟動第一個mongo容器. 這個容器的幾個關(guān)鍵信息是:

節(jié)點名稱: mongo-1

用戶: admin

密碼: 123456

副本集名稱: MongoSet

數(shù)據(jù)目錄: ~/mongo-data/data01 (在之前創(chuàng)建)

映射端口: 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 鏡像的方便功能, 關(guān)于這個鏡像的更多功能, 可以參考官方文檔: https://hub.docker.com/_/mongo/

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

啟動其他容器

# 第二個
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

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

image-20210728113102579

初始化副本集信息

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

sudo docker exec -it mongo-1 bash

mongo
use admin

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

# 設(shè)置
# 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)

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

# 設(shè)置完之后, 退出
exit

設(shè)置完之后退出, 重新登錄容器:

sudo docker exec -it mongo-1 bash
mongo

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

image-20210728134215133

增加業(yè)務數(shù)據(jù)庫和用戶名

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

mongo 

use admin

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

# 數(shù)據(jù)庫不用創(chuàng)建, 使用use 即可
use ExampleDb

# 新增用戶
db.createUser({

    user: "test",

    pwd: "123456",

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

設(shè)置從節(jié)點可讀

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

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

sudo docker exec -it mongo-2 bash

mongo

use admin

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

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


設(shè)置了之后, 從節(jié)點會分擔主節(jié)點讀的壓力, 提高了系統(tǒng)的性能.

圖形化訪問工具

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 數(shù)據(jù)庫
use test

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

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

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

use test

db.users.find()

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

測試插入性能

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

#! /usr/bin/python3
# -*- coding: UTF-8 -*-
"""
 * 作者: 小肥爬爬
 * 簡書: http://www.itdecent.cn/u/db796a501972
 * gitee: https://gitee.com/xiaofeipapa
 * 郵箱: imyunshi@163.com
 * 您可以自由轉(zhuǎn)載此博客文章, 懇請保留原鏈接, 謝謝!
"""
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

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

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


# 測試插入10萬數(shù)據(jù)的時間
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()  # 記錄結(jié)束時間
    time_sum = time_end - time_start  # 計算的時間差為程序的執(zhí)行時間,單位為秒/s
    print('程序運行時間: %d 秒' % time_sum)

if __name__ == '__main__':
    test_1()


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

image-20210728150546547

測試可用性

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

步驟:

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

停止第一個容器:

sudo docker stop mongo-1 

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

  1. 即使主節(jié)點關(guān)了, 代碼還是順利運行
  2. compass 能看到10萬條數(shù)據(jù).

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

如果此時你登錄到第二臺容器, 運行mongo 命令. 你會發(fā)現(xiàn)這臺機器已經(jīng)成了主節(jié)點. 這表示在第一臺容器down掉之后, 第二臺容器成功地挑起了重擔.

測試數(shù)據(jù)丟失

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

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

sudo docker restart mongo-1

(此時, 此容器已經(jīng)成了從節(jié)點)

步驟:

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

我們期望的結(jié)果:

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

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

我的測試結(jié)果

查詢插入時間: 38 秒

compass 查詢結(jié)果: 500萬數(shù)據(jù) (沒有丟失!!)

主節(jié)點容器數(shù)據(jù): 500萬. (用 db.TestUser.count() 查總數(shù))

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

image-20210728160330556

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

db.getMongo().setSecondaryOk()

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

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

附錄

修改mongodb 密碼

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

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

sudo apt install pwgen
pwgen -s 20

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

sudo docker exec -it mongo-1 bash

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

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

防止日志文件過大

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

db.adminCommand({logRotate:1})

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

docker 便捷命令

查看正在運行的容器

sudo docker ps

查看創(chuàng)建沒有啟動的容器

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

作者簡介

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

歡迎探討技術(shù)領(lǐng)域的方方面面, 你可以在簡書, gitee和知乎找到他:

簡書: http://www.itdecent.cn/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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容