当前位置: 首页 > ai >正文

【最后203篇系列】033 Mongo副本集修复过程

今天又经历了一次修复Mongo副本集的过程,我觉得得写下来。

大约在3年前搭建了Mongo集群(Mongo5),然后我使用ip代理的方式让集群的机器可以公网访问。ip代理机器一般只能租3年,所以到期就会更换,此时就会出现问题:集群的机器不能通信,访问失败

首先,肯定是要登录到终端。

docker exec -it Mongo_Rep_Container
use admin
db.auth("user","password")

在查询db.isMaster()大概会是这样的: Does not have a valid replica set config

{"topologyVersion" : {"processId" : ObjectId("68a282f5dd03af7c246cded7"),"counter" : NumberLong(1)},"ismaster" : false,"secondary" : false,"info" : "Does not have a valid replica set config",
...
}

此时整个集群已经属于不可用状态, node1, node2和node3都已经失联了。

Step1 将某个节点升级为PRIMARY

此时,先选一个节点重新初始化集群,副本集已经初始化过,所以直接 rs.initiate() 会报 “AlreadyInitialized”

rs.initiate({_id : "xxx",members: [{ _id : 0, host : "YOURIP:THE_PORT",priority:1 }]})

强制执行又会报一个错,这是因为如果节点存在过,即使重新初始化也不可以改变NodeID

mymeta:SECONDARY> rs.reconfig(cfg, {force: true})
{"ok" : 0,"errmsg" : "New and old configurations both have members with host of IP:PORT but in the new configuration the _id field is MemberId(0) and in the old configuration it is MemberId(12) for replica set mymeta","code" : 103,"codeName" : "NewReplicaSetConfigurationIncompatible"
}

保持NodeID不变,重新强制初始化

cfg = rs.conf()
cfg.members = [{_id: 12,                 // 保持原来的 _idhost: "IP:PORT",priority: 1,votes: 1}
]rs.reconfig(cfg, {force:true})

此时节点会完成变化,正式转为PRIMARY节点

rs.status()
{"set" : "REPLICA NAME",
...},"members" : [{"_id" : 12,"name" : "IP:PORT","health" : 1,"state" : 1,"stateStr" : "PRIMARY",mymeta:PRIMARY>

Step2 将其他节点加入

我之前的三个节点,其中一个已经重新成为主节点,且网络中只有一个节点。一个节点被我弄坏了(被大模型骗的),另一个除了失联,别的没问题。

处理弄坏的节点

先把对应的数据部分删除(/data/...replica)

重新初始化项目:在opt下方配置和秘钥,在data下放文件夹

# 1 在data目录创建文件夹proc_path=/opt/MongoReplica/
data_path=/data/MongoReplica/sh ${proc_path}/create_shard_folder.sh ${data_path}/replica# 修改秘钥文件
chown 999 ${proc_path}replica/mongo.key
chmod 600 ${proc_path}replica/mongo.key

其中create_shard_folder.sh的目的是创建副本文件夹并修改权限。

#!bin/bashmkdir -p $1mkdir $1/dbmkdir $1/logtouch $1/log/mongod.logchmod -R 777 $1

启动容器

image_name="MONGOIMAGE"
port=PORTdocker run -d \--restart=always \--name='CONTAINERNAME' \-v /etc/localtime:/etc/localtime  \-v /etc/timezone:/etc/timezone\-e "LANG=C.UTF-8"\-m 2g \-v ${proc_path}replica/mongo.key:/etc/mongo.key \-v ${data_path}/replica:/home/mongod \-v ${proc_path}replica/mongod.conf:/etc/mongod.conf \-p ${port}:27017 \${image_name} \-f /etc/mongod.conf

在PRIMARY节点执行:

rs.add("IP:PORT2")
rs.status()"_id" : 13,"name" : "IP:PORT2","health" : 1,"state" : 5,"stateStr" : "STARTUP2",
...

到这里"stateStr" : "STARTUP2",节点已经在同步数据了

处理没坏的节点

这个过程很顺利,并没有发生问题。当然最坏的情况也就是重新同步一次。

日志问题

因为集群是依靠oplog来进行同步的,这个日志会随着时间越来越大。一些所谓的控制方法我都试过,似乎不太灵光。然后之前我做好过轮转日志,但是只会轮转主节点,不会作用在从节点,这就比较麻烦。
毕竟如果集群搭建起来,总不能隔三差五的去删节点,加节点吧。

这次也解决了这个问题:主节点用Rotate,从节点用SIGUSR1

SIGUSR1 是什么
SIGUSR1 是 Unix/Linux 系统里的一个 用户自定义信号(Signal)
MongoDB 对这个信号有特殊处理:
当 mongod 进程收到 SIGUSR1 时,会 安全地关闭当前日志文件并重新打开日志
不会影响数据库的读写,也不会触发重启
换句话说,这是 MongoDB 官方推荐的 日志轮转方式,尤其适合 Secondary 或通过 Docker 启动的节点。

直接执行命令可以测试

副本日志清理
docker exec -it CONTAINER pgrep mongod // 一般是1
docker exec -it CONTAINER kill -USR1 1

考虑到是低频操作,而且节点可能会随着选举变化

import subprocess
import pymongo# -------------------------------
# 配置
# -------------------------------
container_name = "CONTAINER"
mongo_host = "127.0.0.1"
mongo_port = PORT
mongo_user = "fff"
mongo_pwd = "ff"
auth_db = "admin"# -------------------------------
# 1️⃣ 连接 MongoDB
# -------------------------------
client = pymongo.MongoClient(host=mongo_host,port=mongo_port,username=mongo_user,password=mongo_pwd,authSource=auth_db,authMechanism='SCRAM-SHA-1'
)db = client['admin']# -------------------------------
# 2️⃣ 判断是否主节点
# -------------------------------
ismaster = db.command("isMaster")
if ismaster.get("ismaster", False):# 主节点,用 logRotate 命令db.command({'logRotate': 1})print("Primary 节点日志轮转完成")
else:# 从节点,用 SIGUSR1# 找 PIDpid_cmd = f"docker exec -i {container_name} pgrep mongod"pid = subprocess.check_output(pid_cmd, shell=True).decode().strip()kill_cmd = f"docker exec -i {container_name} kill -USR1 {pid}"subprocess.run(kill_cmd, shell=True)print(f"Secondary 节点日志轮转完成,发送 SIGUSR1 给 PID {pid}")

然后日志可以被轮转,另外再写一个简单的sh脚本,把对应目录下包含日期的文件取出来,然后再删除。
clear_mongo_rep.sh

#!/bin/bash
LOG_DIR="/data/aprojects/MongoReplica/replica/log"# 删除所有带日期的日志文件(只保留 mongod.log)
find "$LOG_DIR" -type f -name "mongod.log.2*" -deleteecho "✅ 已清理所有历史日志文件"

Mongo5集群作为一个基础部件,以后应该也不太改了。以后有需要还可以搭建Mongo8集群。

http://www.xdnf.cn/news/18060.html

相关文章:

  • 【论文阅读】-《GeoDA: a geometric framework for black-box adversarial attacks》
  • 如何在 Ubuntu 24.04 安装 Python 3.12 ?
  • C语言篇:猜数字游戏的实现教程
  • 【图像算法 - 17】慧眼识“果”:基于深度学习与OpenCV的苹果智能检测系统(附完整代码)
  • 【Linux系统】进程间通信:System V IPC——消息队列和信号量
  • 「三维共振」:重构实体零售的破局模式
  • HTML应用指南:利用POST请求获取上海黄金交易所金价数据
  • 折扣大牌点餐api接口对接适合本地生活吗?
  • OVS:除了Geneve和VXLAN,还有哪些虚拟化网络协议?
  • OpenCV Python——Numpy基本操作(Numpy 矩阵操作、Numpy 矩阵的检索与赋值、Numpy 操作ROI)
  • 隐秘参数APP:全面了解手机硬件信息与优化性能
  • Redis——Redisson篇
  • Oracle algorithm的含义
  • 【Unity3D实例-功能-拔枪】角色拔枪(二)分割上身和下身
  • 【前端面试题】JavaScript核心面试题解析
  • 计算机网络---跳板机与堡垒机
  • Pytorch模型复现笔记-VGG讲解+架构搭建(可直接copy运行)+冒烟测试
  • 三维重建-动手学计算机视觉19(完结)
  • openEuler等Linux系统中如何复制移动硬盘的数据
  • 豆包 Java的23种设计模式
  • 力扣3:无重复字符的最长子串
  • 【LeetCode题解】LeetCode 33. 搜索旋转排序数组
  • Java研学-SpringCloud(二)
  • 从零到一:打包并发布你的第一个MCP AI工具服务
  • DNS总结
  • 从CVPR到NeurIPS,可变形卷积+可变形空间注意力如何斩获最佳论文
  • python+flask后端开发~项目实战 | 博客问答项目--模块化文件架构的基础搭建
  • 灰色预测模型
  • matlab tlc的文件、字符串操作
  • 【力扣热题100】双指针—— 接雨水