搭建测试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 -*-
"""
 * 作者: 小肥爬爬
 * 简书: https://www.jianshu.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和知乎找到他:

简书: https://www.jianshu.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阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容