OPC数据采集DCOM配置指南-转载

OPC数据采集DCOM配置指南

https://rtcloud.ipcsun.com/cms/docs/reader/OPC数据采集DCOM配置指南(500)#Bmc1Q-PGbk

开放平台通信Open Platform Communications)简称OPC
,旧称“用于过程控制OLE
”,是用于工业自动化
的一种通信标准。设备制造商(特别是PLC)如果遵从这一标准,则实时数据可提供给OPC
Server,上位机的软件(称为OPC Client)直接访问OPC Server就可以获取到设备数据,从而对不同的设备的差异透明化。

1996年首次发布后,由OPC基金会
维护这一标准。[1]
2011年名字从“用于过程控制的OLE”改为“开放平台通信”,[2]
以反映OPC已经从过程控制领域推广到智能建筑离散制造
等。OPC也超出了传统的OLE技术
,采用了.NET FrameworkXML
、OPC基金会的二进制编码TCP格式。

起源与使用

开放平台通信(OPC)规范是以微软
所开发,针对Microsoft Windows
操作系统下的对象链接与嵌入
(DDE)、组件对象模型
(COM)及Distributed COM
(DCOM)技术为基础。规格定义了过程控制及工厂自动化需要的对象接口
方法,目的是为了达到互操作性
。最常见的OPC规范是读写实时资料用的OPC资料存取
(OPC DA)。许多制造商提到OPC时,所指的其实就是OPC Data Access。OPC DA在初版发行起,已有三个主要的版本,所有版本都向后兼容。第一版OPC
DA的客户端仍可以存取第三版OPC DA的服务器,各版本会增加机能,但原有的机能仍然要支持。不过若客户端允许资料写入,就不支持旧版的服务器,例如DA
3 相同的客户端不一定支持DA 1.0的服务器。

除了OPC
DA规范外,OPC基金会也维护OPC Historical Data Access
(OPC HDA)的规范。OPC DA存取的是实时的资料,OPC HDA允许存取及检索已存档的历史资料。

OPC基金会还维护OPC Alarms and
Events的规范,定义警告及事件型式的消息信息,类似变量状态及状态管理的消息[3]

设计

开放平台通信的设计目的是提供Windows-based软件应用程序以及程序控制硬件共同的桥梁。规范中定义从车间楼层设备存取现场设备的一致性方法。不论资料的来源及类型如何,方法都是不变的。某一硬件设备的OPC服务器提供OPC
Client存取资料的方式,和其他设备的OPC服务器提供的方式都是一样的。目的是为了减少硬件设计者、软件合作厂商、SCADA
HMI
厂商花在处理这类问题,创建相关接口上的心力。只要硬件制造商针对其硬件设备开发了OPC服务器,他们的工作就已经完成,任何设备都可以存取其信息,只要SCADA制造商开发了OPC
client,就可以存取OPC相同的硬件。

OPC服务器提供方法给许多不同的软件包(前提是这些软件要是OPC
client),让程序控制设备(例如PLCDCS
)来存取资料。传统上,若软件需要从一个设备存取资料,需要撰写客制的界面(驱动程序)。OPC的目的就是定义共同的接口,只要开发一次,任何SCADA、人机界面或是电脑软件都可以用此接口存取资料。

OPC规格没有限制服务器提供哪些资料给程序控制设备。OPC服务器可以发送MCU的内部温度,也可以发送某一地区目前的温度。

只要某个设备已经有了OPC服务器,其他可以作为OPC
client的软件就可以存取此一设备。OPC服务器使用微软的OLE技术(也称为组件对象模型,COM)来和client通信。COM技术提供在软件应用程序以及程序硬件之间即时的资料交换。

OPC规范中有一些已经出版发行,其他一部分只开放给OPC协会的成员,没有一家公司拥有OPC规范,任何一家公司就算不是OPC协会的成员,也可以开发OPC服务器,非成员不一定要使用到最新的规范。任何人都可以集成OPC产品,系统集成商也不需要属于任何组织。每家需要OPC产品的公司可以自行决定其产品是否要经过认证,其系统集成商是否有需要接受必要的训练。

未来

OPC UA(OPC Unified Architecture)已经有对应的规范,并且其早期Adopters版本已经部署并且进行测试。OPC
UA可以用JavaMicrosoft .NETC语言
实现,避免了早期OPC版本需要用Microsoft Windows
为基础的系统才能实现的问题。UA结合了现有OPC接口的功能,又加入了像XML
Web Services
等技术,来支持高阶的制造执行系统
(MES)及企业资源计划(ERP)等应用。

OPC组织和MTConnect
组织在2010年9月16日宣布会彼此合作,让两个标准之间有一致性及互操作性[4]

分布式COM(DCOM)

是一项Microsoft技术,可为Windows应用程序提供在LAN(局域网),WAN(广域网)或Internet(互联网)
连接上从一台计算机连接到另一台计算机的能力。例如,DCOM允许OPC客户端应用程序从一台计算机与另一台计算机上的OPC服务器通信。

img

DCOM

DCOM作为上世纪主流分布式应用技术占据了企业应用的巨大市场份额,导致了目前自动控制领域设备(DCS,PLC等)普遍支持OPC数据采集标准,但由于DCOM基于微软Windows操作系统的二进制标准,底层实现技术封闭,与Windows操作系统安全机制紧密耦合,DCOM配置繁琐,且过程极易失败等诸多问题也普遍为业界所诟病。

OPC DOM 配置方案

RtCloud(实时云平台)总结出一套行之有效的OPC DCOM配置解决方案。

如何顺利的配置OPC相关的DCOM?首先需要了解OPC DA的工作模式及相关程序(组件、服务)以及Windows的DCOM组件工作机制,然后才能正确的配置OPC
DCOM。

OPC DCOM 的工作机制

Client和Server在同一台计算机

当Client和Server在同一台计算机时,首先,Client向OpeEnum组件(CLSID:
{13486D51-4821-11D2-A494-3CB306C10000})发起查询本机已注册的所有OPC服务器(包括2.0标准(GUID :
{63D5F431-CFE4-11D1-B2C8-0060083BA1FB})的及1.0标准(GUID : {63D5F430-CFE4-11d1-B2C8-0060083BA1FB})
的服务器。OpcEnum组件负责返回所有已注册的OPC服务器信息。

第二步,OPC Client获取已注册OPC服务器信息后,确定需要连接的OPC服务器,并通过ConnectionPoint接口及AdviseSink接口获取服务器的各种配置信息、数据项(Tag)实时数据及其它通知(如服务器关闭)。

img

OPC Clientt/Server安装在同一台计算机

Client和Server在不同的计算机

img

OPC Client/Server安装在不同的计算机

首先,OPC客户端软件访问OPC服务器所在计算机上注册的OPCEnum.exe,查询服务器所在计算机上已注册的所有OPC服务器。OpcEnum组件负责返回所有已注册的OPC服务器信息。

第二步,OPC Client获取已注册OPC服务器信息后,确定需要连接的OPC服务器,并通过ConnectionPoint接口及AdviseSink接口获取服务器的各种配置信息、数据项(Tag)实时数据及其它通知(如服务器关闭)。

在简单了解OPC客户端与服务器的通讯过程后,可以得出一个结论,无论是在同一台计算机还是不同的计算机,OPC客户端和服务器之间的通讯主要涉及三个部分:
OPC ClientOPCEnumOPC Server

步骤1 配置访问账号

配置方案要求在采集侧(OPC客户端)和OPC服务端同时配置一个就有相同账号名称和密码的具有DCOM访问权限的账号,这里假设配置的账号名称为OPCUser,密码为OPCUser*。

调用Windows账号管理器,控制台命令:lusrmgr.msc

img

特别提示

账号要在OPC服务计算机和OPC客户端计算机同样配置

步骤2 设置系统和默认DCOM访问权限

调用DCOM配置管理器,控制台命令:dcomcnfg

img

img

img

img

确认 SystemOPCUser两个账号具有本地和远程访问的权限。

img

img

同样确认 SystemOPCUser两个账号具有本地和远程访问的权限。

img

img

确认 SystemOPCUser两个账号具有本地和远程访问的启动和激活的权限。

img

img

同样确认 SystemOPCUser两个账号具有本地和远程访问的启动和激活的权限

特别提示

上述设置系统和默认DCOM访问权限需要在OPC服务计算机和OPC客户端采集计算机同样进行。

步骤3 OPC服务器设置 OPCEnum 的DCOM访问权限

在OPC服务计算机调用DCOM配置管理器,控制台命令:dcomcnfg

img

img

img

img

img

img

步骤4 OPC服务器设置 OPCDA服务 的DCOM访问权限

在OPC服务计算机调用DCOM配置管理器,控制台命令:dcomcnfg

img

img

img

提示

上述DCOM设置完成后,应重启OPCEnum和OPC服务,使配置生效

步骤5 重启OPCEnum 和OPC服务

在OPC服务计算机调用服务配置管理器,控制台命令:services.msc

img

img

步骤6 设置网络访问安全策略

调用服务配置管理器,控制台命令:secpol.msc

img

img

img

img

特别提示

上述安全策略设置需要在OPC服务计算机和OPC客户端采集计算机同样进行。

步骤7 OPC服务计算机网络防火墙设置

调用防火墙管理器,控制台命令:firewall.cpl

img

配置DCOM 135端口的入站规则

img

img

img

img

配置OPCEnum 的入站规则

img

img

img

img

img

配置OPC 服务的入站规则

img

img

img

img

img

配置OPC 服务的出站规则

img

步骤8 OPC客户端采集计算机网络防火墙设置

配置DCOM 135端口的入站规则

同上述OPC服务计算机135端口的入账规则配置流程。

配置OPC 客户端(采集程序)的入站规则

img

img

img

img

img

img

配置OPC 客户端(采集程序)的出站规则

img

完成

(Chrome开机自启动)Ubuntu 20.04 上安装 Google Chrome 网络浏览器

Chrome开机自启动

使用 systemd 创建服务

创建一个新的服务文件,输入命令 sudo vim /etc/systemd/system/google-chrome.service

在文件中输入以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[Unit]
Description=Google Chrome Service
After=network.target

[Service]
ExecStart=/usr/bin/chromium-browser --password-store=basic --disable-background-networking --kiosk --noerrdialogs --start-fullscreen "http://192.168.0.190/hmi/dsfq"
User=root
Group=root
Environment="DISPLAY=:0"
LimitNOFILE=65536
Restart=always
RestartSec=5s

[Install]
WantedBy=graphical.target # 只有当系统准备好进入图形界面时,该服务才会被启动

保存并退出编辑器,终端输入以下命令启用并启动服务:

1
2
3
4
5
sudo systemctl daemon-reload
sudo systemctl enable google-chrome.service
sudo systemctl restart google-chrome.service

sudo systemctl status google-chrome.service

创建桌面启动文件

这种方法适合需要自定义启动参数的场景:

  1. 打开终端,运行以下命令创建启动文件:
1
2
3
mkdir -p ~/.config/autostart
cd ~/.config/autostart
vim chromium.desktop
  1. 在文件中输入以下内容:
1
2
3
[Desktop Entry]
Type=Application
Exec=/usr/bin/chromium-browser --start-maximized --disable-infobars --password-store=basic --disable-background-networking --kiosk "http://192.168.0.190/hmi/dsfq"
  • --start-maximized:启动时最大化窗口。
  • --password-store=basic --disable-background-networking --kiosk:全屏模式。
  • "http://www.example.com":替换为你希望打开的网页地址。

Ubuntu AMD的CPU安装

执行下面的步骤,在你的 Ubuntu 系统上安装 Chrome 浏览器:

1.1 下载 Google Chrome

使用Ctrl+Alt+T快捷键或者点击终端图标,打开你的终端。

使用wget来下载 Google Chrome .deb 软件包:

1
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb

1.2 安装 Google Chrome

在 Ubuntu 系统上安装软件包需要管理员权限。以 sudo 用户身份在你的系统上运行下面的命令来安装 Chrome .deb软件包:

1
sudo apt install ./google-chrome-stable_current_amd64.deb

在被提示时,输入你的密码,安装将会开始。

此时,你已经在你的 Ubuntu 系统上安装好了 Chrome。

Ubuntu ARM的CPU安装

  • chrome安装(root安装)

    1
    sudo snap install chromium
  • 浏览器字体安装

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    sudo apt update && sudo apt upgrade -y
    sudo apt install language-pack-zh-hans -y

    sudo apt update && sudo apt upgrade -y

    sudo apt install language-pack-zh-hans -y

    sudo apt install fonts-wqy-zenhei fonts-wqy-microhei fonts-noto-cjk -y
    sudo apt install fonts-wqy-zenhei fonts-wqy-microhei -y -y
    sudo apt install fonts-wqy-zenhei fonts-wqy-microhei fonts-noto-cjk fonts-arphic-ukai fonts-arphic-uming fonts-droid-fallback -y

    sudo locale-gen zh_CN.UTF-8 # 生成中文 locale
    sudo update-locale LANG=zh_CN.UTF-8 # 设置系统默认语言

    export LANG=zh_CN.UTF-8
    sudo apt install fonts-wqy-zenhei fonts-wqy-microhei fonts-noto-cjk -y

环境变量设置

Ubuntu默认的中文字符编码为zh_CN.UTF-8

输入命令:sudo vim /etcenvironment
修改内容如下:

1
2
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games"
LANG="zh_CN.UTF-8"

设置环境变量

1
2
3
sudo locale-gen zh_CN.UTF-8   # 生成中文 locale
sudo update-locale LANG=zh_CN.UTF-8 # 设置系统默认语言
export LANG=zh_CN.UTF-8

Ubuntu系统配置中文显示

win11专业版激活密钥

https://zhuanlan.zhihu.com/p/637930518

1
2
3
4
5
6
7
8
9
BCQNW-3VWYB-4V7QD-M6R2B-7MH26

第一个可以

3JMNH-HBQ2K-C7VYP-4KGFR-DJ3GY

J8WVF-9X3GM-4WVYC-VDHQG-42CXT

7Y64F-88DCY-Y6WTC-H33D2-64QHF
1
还是无法激活成功的看过来:打开终端管理员,输入irm massgrave.dev/get | iex,出现的窗口选7 Extras,弹出的窗口中选1 change windows edition,再弹出窗口选1 Professional,这时候会重启电脑。重启后,设置中显示没有激活,输入key,还是失败,不管它。再次打开终端管理员,输入irm massgrave.dev/get | iex,然后选择1 permanent,就激活成功啦。
1
2
3
4
5
6
7
8
9
密匙:J8WVF-9X3GM-4WVYC-VDHQG-42CXT
(1)到系统输入密匙

(2)win+R, 输入powershell, 回车, 再在弹出的窗口内输:
irm massgrave.dev/get.ps1 | iex
(3)弹出窗口选[1]
(4)回到系统查看会显示”激活成功“

先脱机在输入密钥,更新完成后联网,在按照步骤1-4操作。

Git Tag打标签功能

标签tag(Git Tag)

当开发到一定阶段时,给程序打标签是非常棒的功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
git tag -a v0.1 -m 'my version 1.4' # 新建带注释标签   
git push origin --tags # 一次性推送所有分支
git push origin v1.5 # 推送单个tag到orgin源上
git tag -v v1.4.2.1 # 验证标签,验证已经签署的标签
git show v1.5 # 看到对应的 GPG 签

git tag # 列出现有标签
git tag v0gi.1 # 新建标签
git checkout tagname # 切换到标签
git tag -d v0.1 # 删除标签
git push origin :refs/tags/v0.1 # 删除远程标签
git pull --all # 获取远程所有内容包括tag
git --git-dir='<绝对地址>/.git' describe --tags HEAD # 查看本地版本信息

KEPServerEX IotGateWay配置Modbus采集并发送MQTTClient消息

Iot GateWay Agent配置注意事项

Iot GateWay Agent依赖JRE1.8环境,需要配置JRE环境后,IOT GateWay配置的Agent才会生效和有效!
Iot GateWay Agent依赖JRE1.8环境,需要配置JRE环境后,IOT GateWay配置的Agent才会生效和有效!
Iot GateWay Agent依赖JRE1.8环境,需要配置JRE环境后,IOT GateWay配置的Agent才会生效和有效!

日志信息 KEPServerEX\IoT Gateway IoT Gateway using JRE at [C:\Program Files (x86)\Java\jre-1.8].
日志信息 KEPServerEX\IoT Gateway IoT Gateway using JRE at [C:\Program Files (x86)\Java\jre-1.8].
日志信息 KEPServerEX\IoT Gateway IoT Gateway using JRE at [C:\Program Files (x86)\Java\jre-1.8].

Iot GateWay依赖JRE加载日志(需jie加载成功)

1
2
3
4
5
6
7
8
9
日期       时间       级别     源                        事件
2025/5/26 18:18:24 信息 KEPServerEX\Runtime IoT Gateway V6.5.829.0
2025/5/26 18:18:25 信息 KEPServerEX\IoT Gateway IoT Gateway service starting.
2025/5/26 18:18:25 信息 KEPServerEX\IoT Gateway IoT Gateway using JRE at [C:\Program Files (x86)\Java\jre-1.8].
2025/5/26 18:18:26 信息 KEPServerEX\IoT Gateway Running with Java 1.8.0_401 [Oracle Corporation Java HotSpot(TM) Client VM version 25.401-b10].
2025/5/26 18:18:41 错误 KEPServerEX\Runtime MQTT agent 'Agent-bak' failed to connect - reason: 'connect timed out'.
2025/5/26 18:21:41 安全性 KEPServerEX\Runtime 配置会话由 Administrator as Default User (R/W) 启动。
2025/5/26 19:36:50 信息 KEPServerEX\Runtime MQTT agent 'Agent-bak' is connected to broker 'tcp://192.168.0.203:1883'
2025/5/26 19:51:48 错误 KEPServerEX\Runtime MQTT agent 'Agent-bak' disconnected - reason 'Software caused connection abort: recv failed'

如何配置Iot GateWay

  • 点击图标【KEPServerEX 6 Administration】 或者【KEPServerEX 6 Configuration】
  • 在右下角,选择小图标,右键【设置(E)……】
  • 选择标签【Iot Gateway】
  • 配置Java Use the JRE at: 【C:\Program Files (x86)\Java\jre-1.8\jre】配置到jre目录,不要到bin目录
  • 选择【应用】或者【确认】选择即可

示例

配置选项

配置JRE环境

配置Modbus设备采集

确认MQTT 上发是否有效

KepEX6 V6.8时间限制破解

【破解说明】时间限制破解版

1
2
3
4
1、把 KEPServerEX V6.x Crack.exe 放在 C:\Program Files\Kepware\KEPServerEX *\ 文件夹中
2、运行 KEPServerEX V6.x Crack.exe 点击 CRACK 按钮
3、删除 KEPServerEX V6.x Crack.exe
4、重启软件即可
1
2
3
4
1:把 KEPServerEX V5.xV6.x Crack.exe 放在 C:\Program Files (x86)\Kepware\KEPServerEX 6
2:运行 KEPServerEX V5.xV6.x Crack.exe 点击 CRACK 按钮
3:删除 KEPServerEX V5.xV6.x Crack.exe
4:重启.

示例

M250401-MongoDBHA-MongoDB集群-(Replica Set)副本集集群搭建


初始化Init副本集

1
2
3
4
5
6
7
8
rs.initiate({
_id: "rs0",
members: [
{ _id: 0, host: "192.168.0.245:27017" },
{ _id: 1, host: "192.168.0.246:27017" },
{ _id: 2, host: "192.168.0.247:27017", arbiterOnly: true }
]
})

MongoDB-(Replica Set)副本集-集群搭建

副本集概述

  • MongoDB的副本集(Replica Set)是一种提供数据冗余和高可用性的架构。它是由多个维护相同数据集的mongod
    进程(即数据库实例)组成的一个集合,这些实例分布在不同的服务器上。

  • 副本集的设计目标是为了确保在单个服务器发生故障时,数据库服务依然可以继续运作,从而提高了系统的可靠性和容错能力。

副本集的架构

  • 一个副本集最多有50个节点。一个副本集最多有7个投票节点,其余节点必须是没有投票权的节点。
  • 副本集的最小推荐配置是三个节点:
    • 一个主节点和两个从节点。
    • 一个主节点、一个从节点和仲裁节点。

副本集的成员

副本集有两种类型三种角色

  • 两种类型
    • 主节点(Primary)类型:数据操作的主要连接点,可读写
    • 次要(辅助、从)节点(Secondaries)类型:数据冗余备份节点,可以读或选举
  • 三种角色
    • 主要成员(Primary):主要接收所有写操作。就是主节点。
    • 副本成员(Replicate):从主节点通过复制操作以维护相同的数据集,即备份数据,不可写操作,但可以读操作(但需要配置)。是默认的一种从节点类型
    • 仲裁者(Arbiter):不保留任何数据的副本,只具有投票选举作用,当然也可以将仲裁服务器维护为副本集的一部分,即副本成员同时也可以是仲裁者。也是一种从节点类型。
  • 建议
    • 如果你的副本+主节点的个数是偶数,建议加一个仲裁者,形成奇数,容易满足大多数的投票。
    • 如果你的副本+主节点的个数是奇数,可以不加仲裁者。

集群部署

节点划分

一台机器上部署三个mongodb节点

IP地址 端口 角色
192.168.0.245 27017 主节点
192.168.0.246 27018 副本节点
192.168.0.247 27019 仲裁节点

测试脚本

1
2
3
sudo /opt/data/mongodb-27017/bin/mongod -f /opt/data/mongodb-27017/mongod-27017.yaml
sudo /opt/data/mongodb-27018/bin/mongod -f /opt/data/mongodb-27018/mongod-27018.yaml
sudo /opt/data/mongodb-27019/bin/mongod -f /opt/data/mongodb-27019/mongod-27019.yaml

数据库需配置密钥链接

配置 MongoDB 副本集时,启用了认证(authorization),但没有指定密钥文件(keyFile)。在 MongoDB
副本集中,如果启用了认证功能,密钥文件是必需的,用于成员之间的身份验证。

密钥文件必须具有适当的权限,以防止未经授权的访问。

1
2
3
4
5
6
7
8
9
10
openssl rand -base64 756 > /opt/data/mongodb-27017/keyfile

运行以下命令设置权限:
sudo chown mongodb:mongodb /opt/data/mongodb-27017/keyfile
sudo chmod 400 /opt/data/mongodb-27017/keyfile

## mongo.cnf配置密钥
security:
authorization: enabled
keyFile: /opt/data/mongodb-27017/keyfile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Where and how to store data.
storage:
dbPath: /var/lib/mongodb
wiredTiger:
engineConfig:
cacheSizeGB: 12
replication:
replSetName: replicaset

# where to write logging data.
systemLog:
destination: file
logAppend: true
path: /var/log/mongodb/mongod.log

security:
authorization: enabled
keyFile: /opt/data/mongodb-27017/keyfile

# network interfaces
net:
port: 27017
bindIp: 0.0.0.0

配置文件

(主节点 mongod-27017.yaml)

vim /opt/data/mongodb-27017/mongod-27017.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
systemLog:
destination: file
path: "/opt/data/mongodb-27017/log/mongod.log"
logAppend: true
storage:
dbPath: "/opt/data/mongodb-27017/data"
journal:
# 启用持久性日志
enabled: true
wiredTiger:
engineConfig:
cacheSizeGB: 12
replication:
replSetName: replicaset
processManagement:
fork: true
pidFilePath: "/opt/data/mongodb-27017/log/mongod.pid"
net:
bindIp: localhost,192.168.0.204
port: 27017
security:
authorization: enabled
keyFile: /opt/data/mongodb-27017/keyfile

System 服务命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
[Unit]
Description=mongodb-27017.service
After=network.target
StartLimitIntervalSec=0

[Service]
ExecStart=/opt/data/mongodb-27017/bin/mongod -f /opt/data/mongodb-27017/mongod-27017.yaml
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/opt/data/mongodb-27017/bin/mongod --shutdown -f /opt/data/mongodb-27017/mongod-27017.yaml
User=root
Group=root
PrivateTmp=true
LimitNOFILE=65536
Restart=always
RestartSec=5s
# file size
LimitFSIZE=infinity
# cpu time
LimitCPU=infinity
# virtual memory size
LimitAS=infinity
# open files
# processes/threads
LimitNPROC=64000
# locked memory
LimitMEMLOCK=infinity
# total threads (user+kernel)
TasksMax=infinity
TasksAccounting=false

[Install]
WantedBy=multi-user.target
Alias=mongodb-27017.service

(副本节点 mongod-27018.yaml)

vim /opt/data/mongodb-27018/mongod-27018.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
systemLog:
destination: file
path: "/opt/data/mongodb-27018/log/mongod.log"
logAppend: true
storage:
dbPath: "/opt/data/mongodb-27018/data"
journal:
# 启用持久性日志
enabled: true
wiredTiger:
engineConfig:
cacheSizeGB: 2
processManagement:
fork: true
pidFilePath: "/opt/data/mongodb-27018/log/mongod.pid"
net:
bindIp: localhost,192.168.0.204
port: 27018
replication:
replSetName: replicaset
security:
authorization: enabled
keyFile: /opt/data/mongodb-27017/keyfile

System 服务命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
[Unit]
Description=mongodb-27018.service
After=network.target
StartLimitIntervalSec=0

[Service]
ExecStart=/opt/data/mongodb-27018/bin/mongod -f /opt/data/mongodb-27018/mongod-27018.yaml
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/opt/data/mongodb-27018/bin/mongod --shutdown -f /opt/data/mongodb-27018/mongod-27018.yaml
User=root
Group=root
PrivateTmp=true
LimitNOFILE=65536
Restart=always
RestartSec=5s
# file size
LimitFSIZE=infinity
# cpu time
LimitCPU=infinity
# virtual memory size
LimitAS=infinity
# open files
# processes/threads
LimitNPROC=64000
# locked memory
LimitMEMLOCK=infinity
# total threads (user+kernel)
TasksMax=infinity
TasksAccounting=false

[Install]
WantedBy=multi-user.target
Alias=mongodb-27018.service

(仲裁节点 mongod-27019.yaml)

vim /opt/data/mongodb-27019/mongod-27019.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
systemLog:
destination: file
path: "/opt/data/mongodb-27019/log/mongod.log"
logAppend: true
storage:
dbPath: "/opt/data/mongodb-27019/data"
journal:
# 启用持久性日志
enabled: true
wiredTiger:
engineConfig:
cacheSizeGB: 2
processManagement:
fork: true
pidFilePath: "/opt/data/mongodb-27019/log/mongod.pid"
net:
bindIp: localhost,192.168.0.204
port: 27019
replication:
replSetName: replicaset
security:
authorization: enabled
keyFile: /opt/data/mongodb-27017/keyfile

System 服务命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
[Unit]
Description=mongodb-27019.service
After=network.target
StartLimitIntervalSec=0

[Service]
ExecStart=/opt/data/mongodb-27019/bin/mongod -f /opt/data/mongodb-27019/mongod-27019.yaml
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/opt/data/mongodb-27019/bin/mongod --shutdown -f /opt/data/mongodb-27019/mongod-27019.yaml
User=root
Group=root
PrivateTmp=true
LimitNOFILE=65536
Restart=always
RestartSec=5s
# file size
LimitFSIZE=infinity
# cpu time
LimitCPU=infinity
# virtual memory size
LimitAS=infinity
# open files
# processes/threads
LimitNPROC=64000
# locked memory
LimitMEMLOCK=infinity
# total threads (user+kernel)
TasksMax=infinity
TasksAccounting=false

[Install]
WantedBy=multi-user.target
Alias=mongodb-27019.service

副本集命令配置

初始化副本集 rs.initiate()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
rs.initiate({
_id: "rs0",
members: [
{ _id: 0, host: "192.168.0.245:27017" },
{ _id: 1, host: "192.168.0.246:27017" },
{ _id: 2, host: "192.168.0.247:27017", arbiterOnly: true }
]
})

rs.initiate({
_id: "replicaset",
members: [
{ _id: 0, host: "192.168.0.245:27017" },
{ _id: 1, host: "192.168.0.246:27017" },
{ _id: 2, host: "192.168.0.247:27017", arbiterOnly: true }
]
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
test> show dbs;
MongoServerError[NotPrimaryOrSecondary]: node is not in primary or recovering state

test> rs.initiate()
{
info2: 'no configuration specified. Using a default configuration for the set',
me: '192.168.0.204:27017',
ok: 1,
'$clusterTime': {
clusterTime: Timestamp({ t: 1748312432, i: 1 }),
signature: {
hash: Binary.createFromBase64('AAAAAAAAAAAAAAAAAAAAAAAAAAA=', 0),
keyId: Long('0')
}
},
operationTime: Timestamp({ t: 1748312432, i: 1 })
}

查看副本集的配置内容 rs.config()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
replicaset [direct: primary] test> rs.config()
{
_id: 'replicaset',
version: 1,
term: 1,
members: [
{
_id: 0,
host: '192.168.0.204:27017',
arbiterOnly: false,
buildIndexes: true,
hidden: false,
priority: 1,
tags: {},
secondaryDelaySecs: Long('0'),
votes: 1
}
],
protocolVersion: Long('1'),
writeConcernMajorityJournalDefault: true,
settings: {
chainingAllowed: true,
heartbeatIntervalMillis: 2000,
heartbeatTimeoutSecs: 10,
electionTimeoutMillis: 10000,
catchUpTimeoutMillis: -1,
catchUpTakeoverDelayMillis: 30000,
getLastErrorModes: {},
getLastErrorDefaults: { w: 1, wtimeout: 0 },
replicaSetId: ObjectId('6835216fb987ae743956e082')
}

查看副本集状态 rs.status()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
replicaset [direct: primary] test> rs.status()
{
set: 'replicaset',
date: ISODate('2025-05-27T02:22:02.694Z'),
myState: 1,
term: Long('1'),
syncSourceHost: '',
syncSourceId: -1,
heartbeatIntervalMillis: Long('2000'),
majorityVoteCount: 1,
writeMajorityCount: 1,
votingMembersCount: 1,
writableVotingMembersCount: 1,
optimes: {
lastCommittedOpTime: { ts: Timestamp({ t: 1748312514, i: 1 }), t: Long('1') },
lastCommittedWallTime: ISODate('2025-05-27T02:21:54.468Z'),
readConcernMajorityOpTime: { ts: Timestamp({ t: 1748312514, i: 1 }), t: Long('1') },
appliedOpTime: { ts: Timestamp({ t: 1748312514, i: 1 }), t: Long('1') },
durableOpTime: { ts: Timestamp({ t: 1748312514, i: 1 }), t: Long('1') },
writtenOpTime: { ts: Timestamp({ t: 1748312514, i: 1 }), t: Long('1') },
lastAppliedWallTime: ISODate('2025-05-27T02:21:54.468Z'),
lastDurableWallTime: ISODate('2025-05-27T02:21:54.468Z'),
lastWrittenWallTime: ISODate('2025-05-27T02:21:54.468Z')
},
lastStableRecoveryTimestamp: Timestamp({ t: 1748312484, i: 1 }),
electionCandidateMetrics: {
lastElectionReason: 'electionTimeout',
lastElectionDate: ISODate('2025-05-27T02:20:33.610Z'),
electionTerm: Long('1'),
lastCommittedOpTimeAtElection: { ts: Timestamp({ t: 1748312432, i: 1 }), t: Long('-1') },
lastSeenWrittenOpTimeAtElection: { ts: Timestamp({ t: 1748312432, i: 1 }), t: Long('-1') },
lastSeenOpTimeAtElection: { ts: Timestamp({ t: 1748312432, i: 1 }), t: Long('-1') },
numVotesNeeded: 1,
priorityAtElection: 1,
electionTimeoutMillis: Long('10000'),
newTermStartDate: ISODate('2025-05-27T02:20:34.121Z'),
wMajorityWriteAvailabilityDate: ISODate('2025-05-27T02:20:34.469Z')
},
members: [
{
_id: 0,
name: '192.168.0.204:27017',
health: 1,
state: 1,
stateStr: 'PRIMARY',
uptime: 688,
optime: { ts: Timestamp({ t: 1748312514, i: 1 }), t: Long('1') },
optimeDate: ISODate('2025-05-27T02:21:54.000Z'),
optimeWritten: { ts: Timestamp({ t: 1748312514, i: 1 }), t: Long('1') },
optimeWrittenDate: ISODate('2025-05-27T02:21:54.000Z'),
lastAppliedWallTime: ISODate('2025-05-27T02:21:54.468Z'),
lastDurableWallTime: ISODate('2025-05-27T02:21:54.468Z'),
lastWrittenWallTime: ISODate('2025-05-27T02:21:54.468Z'),
syncSourceHost: '',
syncSourceId: -1,
infoMessage: 'Could not find member to sync from',
electionTime: Timestamp({ t: 1748312433, i: 1 }),
electionDate: ISODate('2025-05-27T02:20:33.000Z'),
configVersion: 1,
configTerm: 1,
self: true,
lastHeartbeatMessage: ''
}
],
ok: 1,
'$clusterTime': {
clusterTime: Timestamp({ t: 1748312514, i: 1 }),
signature: {
hash: Binary.createFromBase64('AAAAAAAAAAAAAAAAAAAAAAAAAAA=', 0),
keyId: Long('0')
}
},
operationTime: Timestamp({ t: 1748312514, i: 1 })
}

添加副本集 rs.add("192.168.0.204:27018")

可以看到是 (not reachable/healthy) ,说明添加的副本节点是有问题的,正常的应该是 SECONDARY ,查看日志

1
rs.add("192.168.0.204:27018")

先将添加的副本节点删除 rs.remove("192.168.0.204:27018")

1
2
rs.remove("192.168.0.204:27018")

配置仲裁节点 rs.addArb("192.168.0.204:27019")

1
rs.addArb("192.168.0.204:27019")

异常信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1. Reconfig attempted to install a config that would change the implicit default write concern. Use the setDefaultRWConcern command to set a cluster-wide write concern and try the reconfig again.

需要在主节点设置一下,命令如下:

db.adminCommand({
"setDefaultRWConcern" : 1,
"defaultWriteConcern" : {
"w" : 2
}
})

再次添加
rs.addArb("192.168.0.204:27019")

查看状态:
rs.status()

在 MongoDB 中,db.adminCommand 是一个用于执行管理命令的方法,而你提到的命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
db.adminCommand({
"setDefaultRWConcern": 1,
"defaultWriteConcern": {
"w": 2 // 表示写操作需要在主节点和至少一个从节点上成功确认
}
})

db.adminCommand({
"setDefaultRWConcern": 1,
"defaultWriteConcern": {
"w": 1 // 实际可配置成1,保证单节点OK即可
}
})

是用于设置默认的写关注(Write Concern)配置的命令。以下是详细解释:

1. 命令的作用

  • setDefaultRWConcern: 这是一个管理命令,用于设置默认的读写关注(Read/Write Concern)配置。
    • 1 表示启用此功能。
  • defaultWriteConcern: 这是设置默认的写关注配置。
    • w: 2 表示写操作需要在至少两个节点上成功确认后才返回成功。

2. 写关注(Write Concern)

写关注(Write Concern)定义了写操作需要在多少个节点上成功确认后才返回成功。它主要用于控制数据的持久性和一致性。

  • w: 1: 默认值,表示写操作只需在主节点上成功即可。
  • w: 2: 表示写操作需要在主节点和至少一个从节点上成功确认。
  • w: "majority": 表示写操作需要在大多数节点上成功确认。

3. 在 MongoDB 集群中的作用

在 MongoDB 集群(如副本集或分片集群)中,写关注配置非常重要,因为它直接影响数据的持久性和性能:

  • 高可用性和一致性:设置较高的写关注(如 w: 2w: "majority")可以确保数据在多个节点上持久化,从而提高数据的可用性和一致性。
  • 性能:较高的写关注会增加写操作的确认时间,从而可能降低写性能。因此,需要根据实际需求权衡。

创建MongoDB数据库密码模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
use admin

db.createUser({
user: 'db_reader',
pwd: 'A123456',
mechanisms: ["SCRAM-SHA-1"],
roles: [{
role: "read",
db: "my-app"
}]
});

db.createUser({
user: "db_manager",
pwd: "A456789",
mechanisms: ["SCRAM-SHA-1"],
roles: ['readWriteAnyDatabase', 'dbAdminAnyDatabase', {
role: "dbAdmin",
db: 'my-app'
}, {
role: "readWrite",
db: 'my-app'
}, {
role: "dbAdmin",
db: 'my-app'
}]
});

db.createUser({
user: 'db_root',
pwd: 'A10111213',
mechanisms: ["SCRAM-SHA-1"],
roles: [{
role: "dbAdminAnyDatabase",
db: "admin"
}, {
role: "root",
db: "admin"
}]
});

数据库需配置密钥链接

配置 MongoDB 副本集时,启用了认证(authorization),但没有指定密钥文件(keyFile)。在 MongoDB
副本集中,如果启用了认证功能,密钥文件是必需的,用于成员之间的身份验证。

密钥文件必须具有适当的权限,以防止未经授权的访问。

1
2
3
4
5
6
7
8
9
10
openssl rand -base64 756 > /opt/data/mongodb-27017/keyfile

运行以下命令设置权限:
sudo chown mongodb:mongodb /opt/data/mongodb-27017/keyfile
sudo chmod 400 /opt/data/mongodb-27017/keyfile

## mongo.cnf配置密钥
security:
authorization: enabled
keyFile: /opt/data/mongodb-27017/keyfile

异常信息 keyfile are too open

1
{"t":{"$date":"2025-05-27T03:01:21.276+00:00"},"s":"I",  "c":"ACCESS",   "id":20254,   "ctx":"main","msg":"Read security file failed","attr":{"error":{"code":30,"codeName":"InvalidPath","errmsg":"permissions on /opt/data/mongodb-27017/keyfile are too open"}}}

这个错误信息表明 MongoDB 无法启动,因为密钥文件 /opt/data/mongodb-27017/keyfile 的权限设置不正确。MongoDB
要求密钥文件的权限必须严格限制,以确保只有 MongoDB 进程可以访问它。

错误解释

  • **Read security file failed**:MongoDB 无法读取密钥文件。
  • **permissions on /opt/data/mongodb-27017/keyfile are too open**:密钥文件的权限设置过于宽松,MongoDB 不允许这种情况。

解决方法

你需要确保密钥文件的权限正确设置,具体步骤如下:

1. 检查密钥文件的当前权限

运行以下命令查看密钥文件的当前权限:

1
ls -l /opt/data/mongodb-27017/keyfile

你可能会看到类似以下的输出:

1
-rw-r--r-- 1 mongodb mongodb 756 May 27 03:00 /opt/data/mongodb-27017/keyfile

这表示当前权限是 644(所有者可读写,组可读,其他用户也可读)。

2. 设置正确的权限

MongoDB 要求密钥文件的权限必须是 600(只有所有者可以读写,其他用户无权限)。运行以下命令设置正确的权限:

sudo chmod 600 /opt/data/mongodb-27017/keyfile

. 验证权限

再次运行 ls -l 命令,确保权限已正确设置:

SpringBoot 配置数据库连接(副本集模式)

无密码模式

1
spring.data.mongodb.uri=mongodb://192.168.0.204:27017,192.168.0.204:27018,192.168.0.204:27019/my-app?replicaSet=replicaset

有密码模式

1
spring.data.mongodb.uri=mongodb://db_manager:db_manager@192.168.0.204:27017,192.168.0.204:27018,192.168.0.204:27019/my-app?replicaSet=replicaset&authSource=admin

正常状态的 rs.status()

name: ‘192.168.0.204:27017’ stateStr: ‘PRIMARY’

name: ‘192.168.0.204:27018’ stateStr: ‘SECONDARY’

name: ‘192.168.0.204:27019’ stateStr: ‘ARBITER’

主节点的选举原则

1、主节点选举触发条件

  • MongoDB在副本集中,会自动进行主节点的选举,主节点选举的触发条件
    • 主节点故障
    • 主节点网络不可达(默认心跳信息为10秒)
    • 人工干预(rs.stepDown(600))primary直接降级在600s内不会把自己选为primary
  • 一旦触发选举,就要根据一定规则来选择主节点。

2、选举规则

  • 选举规则是根据票数来决定谁获胜
    • 票数最高,且获得了“大多数”成员的投票支持的节点获胜。
    • “大多数”的定义为:假设复制集内投票成员时N,则大多数为N/2+1。例如:3个投票成员,则大多数的值是2。当复制集内存活成员数量不足大多数时,整个复制集将无法选举primary,复制集将无法提供写服务,处于只读状态。
    • 若票数相同,且都获得了“大多数”成员的投票支持的,数据新的节点获胜。
    • 数据的新旧是通过操作日志oplog来对比的。
  • 在获得票数的时候,优先级(priority)参数影响重大。

可以通过设置优先级(priority)来设置额外票数。优先级即权重,取值为0-1000,相当于增加0-1000的票数,优先级的值越大,就越可能获得多数成员的投票(votes)数。指定较高的值可使成员更有资格成员主要成员,更低的值可使成员更不符合条件。

  • 默认情况下,优先级的值是1

主节点的选举原则

MongoDB在副本集中,会自动进行主节点的选举,主节点选举的触发条件:

  • 1.主节点故障
  • 2.主节点网络不可达(默认心跳信息为10秒)
  • 3.人工干预(rs.stepDown(600))

一旦触发选举,就要根据一定规则来选主节点。

选举规则是根据票数来决定谁获胜:

  • 票数最高,且获得了“大多数”成员的投票支持的节点获胜。
    “大多数”的定义为:假设复制集内投票成员数量为N,则大多数为 N/2 +
    1。例如:3个投票成员,则大多数的值是2。当复制集内存活成员数量不足大多数时,整个复制集将无法选举出Primary,复制集将无法提供写服务,处于只读状态。

  • 若票数相同,且都获得了“大多数”成员的投票支持的,数据新的节点获胜。数据的新旧是通过操作日志oplog来对比的。

在获得票数的时候,优先级(priority)参数影响重大。可以通过设置优先级(priority)来设置额外票数。优先级即权重,取值为0-1000,相当于可额外增加0-1000的票数,优先级的值越大,就越可能获得多数成员的投票(votes)数。指定较高的值可使成员更有资格成为主要成员,更低的值可使成员更不符合条件。默认情况下,优先级的值是1

可以看出,主节点和副本节点的优先级各为1,即,默认可以认为都已经有了一票。但选举节点,优先
级是0,(选举节点的优先级必须是0,不能是别的值。即不具备选举权,但具有投票权)

故障测试

1. 副本节点故障测试

提升主节点的优先级

关闭27018副本节点,主节点和仲裁节点对27018的心跳失败。因为主节点还在,因此,没有触发投票选举。

在主节点写入数据

db.comment.insert({})

再启动从节点,会发现,主节点写入的数据,会自动同步给从节点。

如果此时,在主节点写入数据。

2. 主节点故障测试

关闭27017节点后发现,从节点和仲裁节点对27017的心跳失败,当失败超过10秒,此时因为没有主节点了,会自动发起投票。

而副本节点只有27018,因此,候选人只有一个就是27018,开始投票。27019向27018投了一票,27018本身自带一票,因此共两票,超过了“大多数”27019是仲裁节点,没有选举权,27018不向其投票,其票数是0.最终结果,27018成为主节点。具备读写功能。在27018写入数据查看。

db.comment.insert({})

再启动27017节点,发现27017变成了从节点,27018仍保持主节点。登录27017节点,发现是从节点了,数据自动从27018同步。从而实现了高可用。

3. 仲裁节点和主节点故障测试

先关掉仲裁节点27019,关掉现在的主节点27017。

登录27018节点后发现,27018仍然是从节点,副本集中没有主节点了,导致此时副本集是只读状态,无法写入。

为啥不选举了?因为27018的票数,没有获得大多数,即没有大于等于2,它只有默认的一票(优先级是1)如果要触发选举,随便加入一个成员即可。

  • 如果只加入27019仲裁节点成员,则主节点一定是27018,因为没得选了,仲裁节点不参与选举,但参与投票。
  • 如果只加入27017节点,会发起选举。因为27017和27018都是两票,则按照谁数据新,谁当主节点。

4. 仲裁节点和从节点故障测试

先关掉仲裁节点27019,关掉现在的副本节点27018。10秒后,27017主节点自动降级为副本节点。(服务降级)副本集不可写数据了,已经故障了。

集群故障分析

序号 故障类型 是否影响使用
1 主节点故障 不影响正常使用
2 副本节点故障 不影响正常使用
3 仲裁节点故障 不影响正常使用
4 主节点和仲裁节点故障 影响正常使用,需要处理
5 从节点和仲裁节点故障 影响正常使用,需要处理
6 主节点和从节点故障 影响正常使用,需要处理
7 所有节点故障 影响正常使用,需要处理

1、主节点故障

  • 从节点和仲裁节点对主节点的心跳失败,当失败超过10秒,此时因为没有主节点了,会自动发起投票。
    • 而副本节点只有一台,因此,候选人只有一个就是副本节点,开始投票。
    • 仲裁节点向副本节点投了一票,副本节点本身自带一票,因此共两票,超过了”大多数”。
    • 27019是仲裁节点,没有选举权,27018不向其投票,其票数是0。
    • 最终结果,27018成为主节点。具备读写功能。
  • 再启动 27017主节点,发现27017变成了从节点,27018仍保持主节点。
  • 登录27017节点,发现是从节点了,数据自动从27018同步。
  • 此时:不影响正常使用

2、副本节点故障

  • 主节点和仲裁节点对副本节点的心跳失败。因为主节点还在,因此,没有触发投票选举。
    如果此时,在主节点写入数据。再启动从节点,会发现,主节点写入的数据,会自动同步给从节点。
  • 此时:不影响正常使用

3、仲裁节点故障

  • 主节点和副本节点对仲裁节点的心跳失败。因为主节点还在,因此,没有触发投票选举。
  • 此时:不影响正常使用

4、主节点和仲裁节点故障

副本集中没有主节点了,导致此时,副本集是只读状态,无法写入。

因为27017的票数,没有获得大多数,即没有大于等于2,它只有默认的一票(优先级是1)
如果要触发选举,随便加入一个成员即可。

  • 如果只加入 27019仲裁节点成员,则主节点一定是27017,因为没得选了,仲裁节点不参与选举,但参与投票。
  • 如果只加入 27018节点,会发起选举。因为27017和27018都是两票,则按照谁数据新,谁当主节点。

此时:影响正常使用,需要处理

5、从节点和仲裁节点故障

10秒后,27017主节点自动降级为副本节点。(服务降级)
副本集不可写数据了,已经故障了。

此时:影响正常使用,需要处理

6、主节点和从节点故障

集群将处于不完全状态,无法执行写操作,因为剩余的副本节点不足以立即选出新的主节点(假设只剩一个副本节点和仲裁节点)。直到至少有一个额外的副本节点在线并同步,以便选举出新的主节点

此时:影响正常使用,需要处理

7、所有节点故障

  • 整个集群不可用,既不能执行读也不能执行写操作。
  • 这种情况需要手动干预,逐一排查并恢复各个节点,确保至少一个主节点和多数节点(包括仲裁节点)在线,以恢复集群服务。
  • 此时:影响正常使用,需要处理