介绍
前言:
mongodb 因为高性能、高可用性、支持分片等特性,作为非关系型数据库被大家广泛使用。其高可用性主要是体现在 mongodb 的副本集上面(可以简单理解为一主多从的集群),本篇文章主要从副本集介绍、docker搭建副本集、副本集读写数据这三个方面来带大家认识下 mongodb 副本集。
mongodb 副本集介绍
mongodb 副本集(Replica Set)包括主节点(primary)跟副本节点(Secondaries)。
主节点只能有一个,所有的写操作请求都在主节点上面处理。副本节点可以有多个,通过同步主节点的操作日志(oplog)来备份主节点数据。
在主节点挂掉后,有选举权限的副本节点会自动发起选举,并从中选举出新的主节点。副本节点可以通过配置指定其具体的属性,比如选举、隐藏、延迟同步等,最多可以有50个副本节点,但只能有7个副本节点能参与选举。虽然副本节点不能处理写操作,但可以处理读请求。搭建一个副本集集群最少需要三个节点:一个主节点,两个备份节点,如果三个节点分布合理,基本可以保证线上数据99.9%安全。如果只有一个主节点,一个副本节点,且没有资源拿来当第二个副本节点,那就可以起一个仲裁者节点(arbiter),不存数据,只用来选举用。当主节点挂掉后,那么两个副本节点会进行选举,从中选举出一个新的主节点。
对于副本集成员属性,特别需要说明下这几个:priority、hidden、slaveDelay、tags、votes。
- priority
对于副本节点,可以通过该属性来增大或者减小该节点被选举成为主节点的可能性,取值范围为0-1000(如果是arbiters,则取值只有0或者1),数据越大,成为主节点的可能性越大,如果被配置为0,那么他就不能被选举成为主节点,而且也不能主动发起选举。 - hidden
隐藏节点会从主节点同步数据,但对客户端不可见,在mongo shell 执行 db.isMaster() 方法也不会展示该节点,隐藏节点必须Priority为0,即不可以被选举成为主节点。但是如果有配置选举权限的话,可以参与选举。 - slaveDelay
延迟同步即延迟从主节点同步数据,比如延迟时间配置的1小时,现在时间是 09:52,那么延迟节点中只同步到主节点 08:52 之前的数据。另外需要注意延迟节点必须是隐藏节点,且Priority为0。 - tags
支持对副本集成员打标签,在查询数据时会用到,比如找到对应标签的副本节点,然后从该节点读取数据,这点也非常有用,可以根据标签对节点分类,查询数据时不同服务的客户端指定其对应的标签的节点,对某个标签的节点数量进行增加或减少,也不怕会影响到使用其他标签的服务。 - votes
节点是否有权限参与选举,最大可以配置7个副本节点参与选举。
副本集的搭建
下载MongoDB镜像
首先,你需要从Docker Hub或其他Docker镜像仓库下载MongoDB的镜像。这里假设你使用的是MongoDB 4.4.0版本。
docker pull mongo:4.4.0
创建数据目录
在宿主机上创建用于存储MongoDB数据的目录。这些目录将被映射到Docker容器的/data/db目录。
mkdir -p /home/docker/mongodb/data1
mkdir -p /home/docker/mongodb/data2
# 如果有更多副本集成员,可以继续创建更多目录
启动MongoDB容器实例
启动多个MongoDB容器实例,每个实例都映射到不同的宿主机端口和数据目录。同时,通过–replSet参数指定副本集的名称。
docker run -d --name mongo1 -p 27017:27017 -v /home/docker/mongodb/data1:/data/db mongo:4.4.0 --replSet rs0
docker run -d --name mongo2 -p 27018:27017 -v /home/docker/mongodb/data2:/data/db mongo:4.4.0 --replSet rs0
# 如果有更多副本集成员,继续启动更多容器
注意:在上面的命令中,rs0是副本集的名称,你可以根据需要更改它。
初始化副本集
选择其中一个MongoDB容器实例作为主节点(primary),并初始化副本集。通常,你可以通过连接到MongoDB的admin数据库,并使用rs.initiate()命令来初始化副本集。 首先,你需要进入MongoDB容器实例的shell环境。假设你使用mongo1作为主节点:
docker exec -it mongo1 mongo admin
然后,在MongoDB shell中执行以下命令初始化副本集:
rs.initiate({ _id: "rs0", members: [ { _id: 0, host: "localhost:27017" }, { _id: 1, host: "localhost:27018" } // 如果有更多副本集成员,继续添加 ]
})
注意:在上面的命令中,_id是副本集的名称,members数组包含了副本集成员的地址信息。由于MongoDB容器实例运行在Docker中,所以你需要使用容器内部的地址(在这个例子中是localhost)和端口(这里是27017和27018)。但在实际的生产环境中,你可能需要使用容器的服务名称或Docker网络的IP地址。
添加副本集成员
如果在初始化副本集时没有包含所有成员,你可以通过rs.add()命令添加它们。但是,在上面的步骤中,我们已经在rs.initiate()命令中包含了所有成员,所以这一步可能是可选的。
验证副本集状态
使用rs.status()命令来查看副本集的状态,确认所有成员都已正确加入并处于正确的角色(如主节点、从节点等)。
docker-compose部署
配置文件
- 生成key文件
openssl rand -base64 20 > keyfile
chmod 400 keyfile
- 配置文件
# mongod.conf# 指定存储数据文件的目录
storage:dbPath: /data/db# 指定日志文件的位置和日志等级
systemLog:destination: filelogAppend: truepath: /var/log/mongodb/mongod.log# 网络配置
# net:
# bindIp: 0.0.0.0# 设置复制集的名称
replication:replSetName: rs0# 安全性和认证配置
#security:
# authorization: enabled
- 存储文件和日志文件
D:\SF\DOCKER\mongo\data1
D:\SF\DOCKER\mongo\data2
D:\SF\DOCKER\mongo\data3
D:\SF\DOCKER\mongo\logs1
D:\SF\DOCKER\mongo\logs2
D:\SF\DOCKER\mongo\logs3
容器配置文件
docker-compose.yml 是 Docker Compose 使用的配置文件,用于定义和运行多容器的 Docker 应用程序。在 docker-compose.yml 文件中,你可以定义应用程序的服务(containers)、网络、卷和其他 Docker 特性。
- version: ‘3’ 指定了 Compose 文件的版本。
- services 定义了应用程序的服务。在这个例子中,有两个服务:web 和 db。
- web 服务:
- 使用当前目录下的 Dockerfile 构建镜像(通过 build: . 指定)。
- 映射主机上的 5000 端口到容器的 5000 端口(通过 ports 指定)。
- 依赖于 db 服务(通过 depends_on 指定)。
- 设置环境变量 DATABASE_URL(通过 environment 指定)。
- db 服务:
- 使用官方的 postgres:13 镜像。
- 设置环境变量 POSTGRES_USER、POSTGRES_PASSWORD 和 - - POSTGRES_DB(通过 environment 指定)。
- 挂载一个卷 db_data 到容器的 /var/lib/postgresql/data 目录(通过 - volumes 指定)。
- volumes 定义了卷,其中 db_data 卷被 db 服务使用。
可以使用 Docker Compose 命令(如 docker-compose up)来启动、停止和重启这个多容器的应用程序。
version: '3.7'services:mongo-primary:image: mongo:latestports:- "27017:27017"volumes:- D:\SF\DOCKER\mongo\config\mongod.conf:/etc/mongod.conf- D:\SF\DOCKER\mongo\config\mongodb.key:/etc/mongodb.key- D:\SF\DOCKER\mongo\data1:/data/db- D:\SF\DOCKER\mongo\logs1:/var/log/mongodbenvironment:MONGO_INITDB_ROOT_USERNAME: rootMONGO_INITDB_ROOT_PASSWORD: 123456command: mongod --replSet rs0 --dbpath /data/db --keyFile /etc/mongodb.key --config /etc/mongod.confentrypoint:- bash- -c- |chmod 400 /etc/mongodb.keychown 999:999 /etc/mongodb.keyexec docker-entrypoint.sh $$@mongo-secondary1:image: mongo:latestports:- "27018:27017"volumes:- D:\SF\DOCKER\mongo\config\mongod.conf:/etc/mongod.conf- D:\SF\DOCKER\mongo\config\mongodb.key:/etc/mongodb.key- D:\SF\DOCKER\mongo\data2:/data/db- D:\SF\DOCKER\mongo\logs2:/var/log/mongodbdepends_on:- mongo-primaryenvironment:MONGO_INITDB_ROOT_USERNAME: rootMONGO_INITDB_ROOT_PASSWORD: 123456command: mongod --replSet rs0 --dbpath /data/db --keyFile /etc/mongodb.key --config /etc/mongod.conf entrypoint:- bash- -c- |chmod 400 /etc/mongodb.keychown 999:999 /etc/mongodb.keyexec docker-entrypoint.sh $$@mongo-secondary2:image: mongo:latestports:- "27019:27017"volumes:- D:\SF\DOCKER\mongo\config\mongod.conf:/etc/mongod.conf- D:\SF\DOCKER\mongo\config\mongodb.key:/etc/mongodb.key- D:\SF\DOCKER\mongo\data3:/data/db- D:\SF\DOCKER\mongo\logs3:/var/log/mongodbdepends_on:- mongo-primaryenvironment:MONGO_INITDB_ROOT_USERNAME: rootMONGO_INITDB_ROOT_PASSWORD: 123456command: mongod --replSet rs0 --dbpath /data/db --keyFile /etc/mongodb.key --config /etc/mongod.conf entrypoint:- bash- -c- |chmod 400 /etc/mongodb.keychown 999:999 /etc/mongodb.keyexec docker-entrypoint.sh $$@
容器启动
# 进入docker-compose.yml 文件所在目录
# 启动部署
docker-compose up -d
# 暂停删除
docker-compose down
mongo用户、权限、分片配置
- 进入一个容器
docker exec -it mongo /bin/mongosh
//或
docker exec -it mongodb bash
- 用户创建
// 登录mongo
mongo admin -u admin -p 123456 -u 后面的是创建容器指定的账号 -p 后面跟的是创建容器指定的密码
// 使用 admin数据库
use admin
// 创建一个用户
创建一个用户,赋予用户root权限
db.createUser({user:"root",pwd:"123456",roles:[{role:"userAdminAnyDatabase",db:"admin"}]}
);
//尝试使用上面创建的用户信息进行连接。
db.auth('root', '123456');
// 配置副本集
rs.initiate({_id: "rs0",members: [{ _id: 0, host: "192.168.1.12:27017" },{ _id: 1, host: "192.168.1.12:27018" },{ _id: 2, host: "192.168.1.12:27019" }]});
// 移除副本集
host.docker.internal
rs.remove("host.docker.internal:27017")
// 添加副本集
rs.add("192.168.1.12:27017") // 切换节点查看同步状态
rs.printReplicationInfo()// 查看副本集配置信息
rs.conf()// 查看副本集运行状态
rs.status()// 节点权重设置// 主节点设置 docker exec --user mongodb -it mongo1 bashmongosh -u root -p mongodb@evescncfg = rs.conf()// 修改权重cfg.members[0].priority=5cfg.members[1].priority=3
// 从新配置
rs.reconfig(cfg)
代码DEMO
from pymongo import MongoClient
from datetime import datetime, timedelta def find_paged_data(collection, page_num, page_size):start = (page_num -1) * page_sizeend = start + page_size# 设置时间范围start_time = datetime(2023, 10, 1, 0,0,0)end_time = datetime(2023, 10, 31, 23, 59, 59, 999999)# 查询时间范围内的文档query = {"time": {"$gte": start_time, "$lte": end_time}}result = collection.find(query).skip(start).limit(page_size)return resultif __name__=="__main__":loc_client = MongoClient('mongodb://root:123456@localhost:27017,localhost:27018,localhost:27019/?replicaSet=rs0&authSource=admin')loc_db = loc_client['wfg']loc_col = loc_db['wfgInfoCollection'] page_num = 1data = find_paged_data(collection=collection, page_num=page_num, page_size=100000)for d in datas:print(d["_id"])