为事业奋斗的人 發表於 2024-4-29 23:48:00

搭建MongoDB副本集

<p></p><div class="toc"><div class="toc-container-header">目录</div><ul><li>一、什么是MongoDB的副本集</li><li>二、副本集的架构</li><li>三、副本集的成员</li><li>四、部署副本集<ul><li>1、节点划分</li><li>2、安装MongoDB<ul><li>2.1、下载解压安装包</li></ul></li><li>3、创建主节点<ul><li>3.1、创建存储数据和日志的目录</li><li>3.2、新建配置文件</li><li>3.3、启动节点服务</li></ul></li><li>4、创建副本节点<ul><li>4.1、创建存储数据和日志的目录</li><li>4.2、新建配置文件</li><li>4.3、启动节点服务</li></ul></li><li>5、创建仲裁节点<ul><li>5.1、创建存储数据和日志的目录</li><li>5.2、创建配置文件</li><li>5.3、启动节点服务</li></ul></li><li>6、添加环境变量</li><li>7、初始化副本集<ul><li>7.1、客户端连接主节点</li><li>7.2、初始化副本集</li></ul></li><li>8、查看副本集配置信息</li><li>9、添加副本节点和仲裁节点</li><li>10、再次查看副本集配置信息</li><li>11、设置副本节点可读</li></ul></li><li>五、测试副本集的数据读写操作<ul><li>1、主节点测试</li><li>2、副本节点测试<ul><li>2.1、设置副本节点只能作为备份不能读取</li></ul></li><li>3、仲裁节点不存放任何数据</li></ul></li><li>六、主节点的选举原则<ul><li>1、主节点选举触发条件</li><li>2、选举规则</li></ul></li><li>七、集群故障分析<ul><li>1、主节点故障</li><li>2、副本节点故障</li><li>3、仲裁节点故障</li><li>4、主节点和仲裁节点故障</li><li>5、从节点和仲裁节点故障</li><li>6、主节点和从节点故障</li><li>7、所有节点故障</li></ul></li></ul></div><p></p>
<h2 id="一什么是mongodb的副本集">一、什么是MongoDB的副本集</h2>
<p><code>MongoDB</code>的副本集<code>(Replica Set)</code>是一种提供数据冗余和高可用性的架构。它是由多个维护相同数据集的<code>mongod</code>进程(即数据库实例)组成的一个集合,这些实例分布在不同的服务器上。</p>
<p>副本集的设计目标是为了确保在单个服务器发生故障时,数据库服务依然可以继续运作,从而提高了系统的可靠性和容错能力。</p>
<h2 id="二副本集的架构">二、副本集的架构</h2>
<blockquote>
<ul>
<li>
<p>一个副本集最多有50个节点。一个副本集最多有7个投票节点,其余节点必须是没有投票权的节点。</p>
</li>
<li>
<p>副本集的最小推荐配置是三个节点:</p>
<ul>
<li>一个主节点和两个从节点。</li>
<li>一个主节点、一个从节点和仲裁节点。</li>
</ul>
</li>
</ul>
</blockquote>
<p><img src="https://img2023.cnblogs.com/blog/3332572/202404/3332572-20240429233937604-988271542.png" alt="2270526-20220923193134773-2055031891" loading="lazy"></p>
<p><img src="https://img2023.cnblogs.com/blog/3332572/202404/3332572-20240429233937164-1183040631.png" alt="2270526-20220923185546781-845092680" loading="lazy"></p>
<h2 id="三副本集的成员">三、副本集的成员</h2>
<blockquote>
<p>副本集有两种类型三种角色</p>
</blockquote>
<ul>
<li>
<p>两种类型</p>
<ul>
<li>
<p>主节点(Primary)类型:数据操作的主要连接点,可读写</p>
</li>
<li>
<p>次要(辅助、从)节点(Secondaries)类型:数据冗余备份节点,可以读或选举</p>
</li>
</ul>
</li>
<li>
<p>三种角色</p>
<ul>
<li>
<p>主要成员(Primary):主要接收所有写操作。就是主节点。</p>
</li>
<li>
<p>副本成员(Replicate):从主节点通过复制操作以维护相同的数据集,即备份数据,不可写操作,但可以读操作(但需要配置)。是默认的一种从节点类型</p>
</li>
<li>
<p>仲裁者(Arbiter):不保留任何数据的副本,只具有投票选举作用,当然也可以将仲裁服务器维护为副本集的一部分,即副本成员同时也可以是仲裁者。也是一种从节点类型。</p>
</li>
</ul>
</li>
<li>
<p>建议</p>
<ul>
<li>
<p>如果你的副本+主节点的个数是偶数,建议加一个仲裁者,形成奇数,容易满足大多数的投票。</p>
</li>
<li>
<p>如果你的副本+主节点的个数是奇数,可以不加仲裁者。</p>
</li>
</ul>
</li>
</ul>
<h2 id="四部署副本集">四、部署副本集</h2>
<p><img src="https://img2023.cnblogs.com/blog/3332572/202404/3332572-20240429233936496-158978683.webp" alt="u=3763007939,3474838561&amp;fm=253&amp;fmt=auto&amp;app=138&amp;f=PNG" loading="lazy"></p>
<h3 id="1节点划分">1、节点划分</h3>
<blockquote>
<p>一台机器上部署三个mongodb节点</p>
</blockquote>
<table>
<thead>
<tr>
<th style="text-align: center">端口</th>
<th style="text-align: center">角色</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center">27017</td>
<td style="text-align: center">主节点</td>
</tr>
<tr>
<td style="text-align: center">27018</td>
<td style="text-align: center">副本节点</td>
</tr>
<tr>
<td style="text-align: center">27019</td>
<td style="text-align: center">仲裁节点</td>
</tr>
</tbody>
</table>
<h3 id="2安装mongodb">2、安装MongoDB</h3>
<h4 id="21下载解压安装包">2.1、下载解压安装包</h4>
<pre><code class="language-bash">wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-4.4.6.tgz
tar xzvf mongodb-linux-x86_64-rhel70-4.4.6.tgz -C /usr/local
cd /usr/local/
ln -s /usr/local/mongodb-linux-x86_64-rhel70-4.4.6 /usr/local/mongodb
</code></pre>
<h3 id="3创建主节点">3、创建主节点</h3>
<h4 id="31创建存储数据和日志的目录">3.1、创建存储数据和日志的目录</h4>
<pre><code class="language-bash">mkdir -p /usr/local/mongodb/replica_sets/myrs_27017/log
mkdir -p /usr/local/mongodb/replica_sets/myrs_27017/data/db
</code></pre>
<h4 id="32新建配置文件">3.2、新建配置文件</h4>
<pre><code class="language-bash">vim /usr/local/mongodb/replica_sets/myrs_27017/mongod.conf

systemLog:
    destination: file
    path: "/usr/local/mongodb/replica_sets/myrs_27017/log/mongod.log"
    logAppend: true
storage:
    dbPath: "/usr/local/mongodb/replica_sets/myrs_27017/data/db"
    journal:
    # 启用持久性日志
      enabled: true
processManagement:
    fork: true
    pidFilePath: "/usr/local/mongodb/replica_sets/myrs_27017/log/mongod.pid"
net:
    bindIp: localhost,192.168.112.40
    port: 27017
replication:
    replSetName: myrs
</code></pre>
<h4 id="33启动节点服务">3.3、启动节点服务</h4>
<pre><code class="language-bash"># /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/replica_sets/myrs_27017/mongod.conf
about to fork child process, waiting until server is ready for connections.
forked process: 8177
child process started successfully, parent exiting
</code></pre>
<h3 id="4创建副本节点">4、创建副本节点</h3>
<h4 id="41创建存储数据和日志的目录">4.1、创建存储数据和日志的目录</h4>
<pre><code class="language-bash">mkdir -p /usr/local/mongodb/replica_sets/myrs_27018/log
mkdir -p /usr/local/mongodb/replica_sets/myrs_27018/data/db
</code></pre>
<h4 id="42新建配置文件">4.2、新建配置文件</h4>
<pre><code class="language-bash">vim /usr/local/mongodb/replica_sets/myrs_27018/mongod.conf

systemLog:
    destination: file
    path: "/usr/local/mongodb/replica_sets/myrs_27018/log/mongod.log"
    logAppend: true
storage:
    dbPath: "/usr/local/mongodb/replica_sets/myrs_27018/data/db"
    journal:
      enabled: true
processManagement:
    fork: true
    pidFilePath: "/usr/local/mongodb/replica_sets/myrs_27018/log/mongod.pid"
net:
    bindIp:localhost,192.168.112.40
    port: 27018
replication:
    replSetName: myrs
</code></pre>
<h4 id="43启动节点服务">4.3、启动节点服务</h4>
<pre><code class="language-bash"># /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/replica_sets/myrs_27018/mongod.conf
about to fork child process, waiting until server is ready for connections.
forked process: 18263
child process started successfully, parent exiting
</code></pre>
<h3 id="5创建仲裁节点">5、创建仲裁节点</h3>
<h4 id="51创建存储数据和日志的目录">5.1、创建存储数据和日志的目录</h4>
<pre><code class="language-bash">mkdir -p /usr/local/mongodb/replica_sets/myrs_27019/log
mkdir -p /usr/local/mongodb/replica_sets/myrs_27019/data/db
</code></pre>
<h4 id="52创建配置文件">5.2、创建配置文件</h4>
<pre><code class="language-bash">vim /usr/local/mongodb/replica_sets/myrs_27019/mongod.conf

systemLog:
    destination: file
    path: "/usr/local/mongodb/replica_sets/myrs_27019/log/mongod.log"
    logAppend: true
storage:
    dbPath: "/usr/local/mongodb/replica_sets/myrs_27019/data/db"
    journal:
    # 启用持久性日志
      enabled: true
processManagement:
    fork: true
    pidFilePath: "/usr/local/mongodb/replica_sets/myrs_27019/log/mongod.pid"
net:
    bindIp:localhost,192.168.112.40
    port: 27019
replication:
    replSetName: myrs
</code></pre>
<h4 id="53启动节点服务">5.3、启动节点服务</h4>
<pre><code class="language-bash"># /usr/local/mongodb/bin/mongod -f /usr/local/mongodb/replica_sets/myrs_27019/mongod.conf
about to fork child process, waiting until server is ready for connections.
forked process: 18314
child process started successfully, parent exiting
</code></pre>
<h3 id="6添加环境变量">6、添加环境变量</h3>
<pre><code class="language-bash">vim /etc/profile

export PATH=/usr/local/mongodb/bin/:$PATH

source /etc/profile
</code></pre>
<pre><code class="language-bash"># which mongo
/usr/local/mongodb/bin/mongo
</code></pre>
<h3 id="7初始化副本集">7、初始化副本集</h3>
<h4 id="71客户端连接主节点">7.1、客户端连接主节点</h4>
<pre><code class="language-bash">mongo --host 192.168.112.40 --port=27017
</code></pre>
<h4 id="72初始化副本集">7.2、初始化副本集</h4>
<blockquote>
<p>当前并未选举主节点(primary),并且操作没有设置为允许从辅助节点(secondary)上读取。</p>
<p>所以很多命令无法使用,必须初始化副本集</p>
</blockquote>
<pre><code class="language-bash">&gt; show dbs
uncaught exception: Error: listDatabases failed:{
      "topologyVersion" : {
                "processId" : ObjectId("662f9e53d74e84faba8865bc"),
                "counter" : NumberLong(0)
      },
      "ok" : 0,
      "errmsg" : "not master and slaveOk=false",
      "code" : 13435,
      "codeName" : "NotPrimaryNoSecondaryOk"
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs/&lt;@src/mongo/shell/mongo.js:147:19
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:99:12
shellHelper.show@src/mongo/shell/utils.js:937:13
shellHelper@src/mongo/shell/utils.js:819:15
@(shellhelp2):1:1
</code></pre>
<blockquote>
<p>初始化副本集</p>
</blockquote>
<pre><code class="language-bash">&gt; rs.initiate()
{
      "info2" : "no configuration specified. Using a default configuration for the set",
      "me" : "192.168.112.40:27017",
      "ok" : 1
}
myrs:SECONDARY&gt;
</code></pre>
<p><img src="https://img2023.cnblogs.com/blog/3332572/202404/3332572-20240429233935754-1628748039.png" alt="image-20240429215626296" loading="lazy"></p>
<ul>
<li>
<p>"ok"的值为1,说明创建成功。</p>
</li>
<li>
<p>命令行提示符发生变化,变成了一个从节点角色,此时默认不能读写。</p>
</li>
<li>
<p>稍等片刻,发现副本集只有自己一个,变成主节点。</p>
</li>
</ul>
<h3 id="8查看副本集配置信息">8、查看副本集配置信息</h3>
<pre><code class="language-bash">myrs:PRIMARY&gt; rs.conf()
{
      "_id" : "myrs",
      "version" : 1,
      "term" : 1,
      "protocolVersion" : NumberLong(1),
      "writeConcernMajorityJournalDefault" : true,
      "members" : [
                {
                        "_id" : 0,
                        "host" : "192.168.112.40:27017",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" : 1,
                        "tags" : {

                        },
                        "slaveDelay" : NumberLong(0),
                        "votes" : 1
                }
      ],
      "settings" : {
                "chainingAllowed" : true,
                "heartbeatIntervalMillis" : 2000,
                "heartbeatTimeoutSecs" : 10,
                "electionTimeoutMillis" : 10000,
                "catchUpTimeoutMillis" : -1,
                "catchUpTakeoverDelayMillis" : 30000,
                "getLastErrorModes" : {

                },
                "getLastErrorDefaults" : {
                        "w" : 1,
                        "wtimeout" : 0
                },
                "replicaSetId" : ObjectId("662fa69cd74e84faba8865e0")
      }
}
</code></pre>
<blockquote>
<ul>
<li>
<p>"_id" : "myrs" :副本集的配置数据存储的主键值,默认就是副本集的名字</p>
</li>
<li>
<p>"members" :副本集成员数组,此时只有一个:"host" : "192.168.112.40:27017"</p>
</li>
<li>
<p>该成员不是仲裁节点:"arbiterOnly" : false</p>
</li>
<li>
<p>优先级(权重值): "priority" : 1</p>
</li>
<li>
<p>"settings" :副本集的参数配置。</p>
</li>
</ul>
</blockquote>
<h3 id="9添加副本节点和仲裁节点">9、添加副本节点和仲裁节点</h3>
<blockquote>
<p>添加副本节点</p>
</blockquote>
<pre><code class="language-bash">myrs:PRIMARY&gt; rs.add("192.168.112.40:27018")
{
      "ok" : 1,
      "$clusterTime" : {
                "clusterTime" : Timestamp(1714399646, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
      },
      "operationTime" : Timestamp(1714399646, 1)
}
</code></pre>
<blockquote>
<p>添加仲裁节点</p>
</blockquote>
<pre><code class="language-bash">myrs:PRIMARY&gt; rs.addArb("192.168.112.40:27019")
{
      "ok" : 1,
      "$clusterTime" : {
                "clusterTime" : Timestamp(1714399738, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
      },
      "operationTime" : Timestamp(1714399738, 1)
}
</code></pre>
<h3 id="10再次查看副本集配置信息">10、再次查看副本集配置信息</h3>
<pre><code class="language-bash">myrs:PRIMARY&gt; rs.conf()
{
      "_id" : "myrs",
      "version" : 3,
      "term" : 1,
      "protocolVersion" : NumberLong(1),
      "writeConcernMajorityJournalDefault" : true,
      "members" : [
                {
                        "_id" : 0,
                        "host" : "192.168.112.40:27017",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" : 1,
                        "tags" : {

                        },
                        "slaveDelay" : NumberLong(0),
                        "votes" : 1
                },
                {
                        "_id" : 1,
                        "host" : "192.168.112.40:27018",
                        "arbiterOnly" : false,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" : 1,
                        "tags" : {

                        },
                        "slaveDelay" : NumberLong(0),
                        "votes" : 1
                },
                {
                        "_id" : 2,
                        "host" : "192.168.112.40:27019",
                        "arbiterOnly" : true,
                        "buildIndexes" : true,
                        "hidden" : false,
                        "priority" : 0,
                        "tags" : {

                        },
                        "slaveDelay" : NumberLong(0),
                        "votes" : 1
                }
      ],
      "settings" : {
                "chainingAllowed" : true,
                "heartbeatIntervalMillis" : 2000,
                "heartbeatTimeoutSecs" : 10,
                "electionTimeoutMillis" : 10000,
                "catchUpTimeoutMillis" : -1,
                "catchUpTakeoverDelayMillis" : 30000,
                "getLastErrorModes" : {

                },
                "getLastErrorDefaults" : {
                        "w" : 1,
                        "wtimeout" : 0
                },
                "replicaSetId" : ObjectId("662fa69cd74e84faba8865e0")
      }
}
</code></pre>
<blockquote>
<ul>
<li>成员信息:
<ul>
<li>成员1(_id: 0)和成员2(_id: 1)都是数据承载节点,它们位于同一台机器的不同端口(27017 和 27018)。两者都有相同的优先级("priority" : 1),意味着它们都可以成为主节点。它们都没有延迟复制("slaveDelay" : NumberLong(0)),并且都参与选举投票("votes" : 1)。</li>
<li>成员3(_id: 2)是一个仲裁者(arbiterOnly: true),位于端口27019。仲裁者的角色是在选举新主节点时起到决定性的一票作用,但它不存储实际数据,也没有优先级,不参与数据复制。</li>
</ul>
</li>
</ul>
</blockquote>
<h3 id="11设置副本节点可读">11、设置副本节点可读</h3>
<pre><code class="language-bash">rs.slaveOk()
</code></pre>
<h2 id="五测试副本集的数据读写操作">五、测试副本集的数据读写操作</h2>
<h3 id="1主节点测试">1、主节点测试</h3>
<pre><code class="language-bash"># mongo --port 27017

myrs:PRIMARY&gt; show dbs
admin   0.000GB
config0.000GB
local   0.000GB
myrs:PRIMARY&gt; use test1
switched to db test1
myrs:PRIMARY&gt; db.q1.insert({"id":"1000","content":"学习部署副本集","userid":"001","name":"zhangsan","createdatatime":new Date(),"state":null})
WriteResult({ "nInserted" : 1 })
myrs:PRIMARY&gt; db.q1.find().pretty()
{
      "_id" : ObjectId("662fb0d727a6cea3c847b26e"),
      "id" : "1000",
      "content" : "学习部署副本集",
      "userid" : "001",
      "name" : "zhangsan",
      "createdatatime" : ISODate("2024-04-29T14:38:15.243Z"),
      "state" : null
}
</code></pre>
<h3 id="2副本节点测试">2、副本节点测试</h3>
<pre><code class="language-bash"># mongo --port 27018

myrs:SECONDARY&gt; show dbs
admin   0.000GB
config0.000GB
local   0.000GB
test1   0.000GB
myrs:SECONDARY&gt; use test1
switched to db test1
myrs:SECONDARY&gt; show tables;
q1
myrs:SECONDARY&gt; db.q1.find().pretty()
{
      "_id" : ObjectId("662fb0d727a6cea3c847b26e"),
      "id" : "1000",
      "content" : "学习部署副本集",
      "userid" : "001",
      "name" : "zhangsan",
      "createdatatime" : ISODate("2024-04-29T14:38:15.243Z"),
      "state" : null
}
myrs:SECONDARY&gt; db.q1.insert({"id":"1001","content":"学习部署副本集","userid":"002","name":"lisi","createdatatime":new Date(),"state":null})
WriteCommandError({
      "topologyVersion" : {
                "processId" : ObjectId("662fa148dfb1efa1f75795c3"),
                "counter" : NumberLong(4)
      },
      "operationTime" : Timestamp(1714402027, 1),
      "ok" : 0,
      "errmsg" : "not master",
      "code" : 10107,
      "codeName" : "NotWritablePrimary",
      "$clusterTime" : {
                "clusterTime" : Timestamp(1714402027, 1),
                "signature" : {
                        "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
                        "keyId" : NumberLong(0)
                }
      }
})
</code></pre>
<blockquote>
<ul>
<li>
<p>无法写入数据</p>
<ul>
<li>
<p>"errmsg" : "not master"</p>
</li>
<li>
<p>"codeName" : "NotWritablePrimary"</p>
</li>
</ul>
</li>
</ul>
</blockquote>
<h4 id="21设置副本节点只能作为备份不能读取">2.1、设置副本节点只能作为备份不能读取</h4>
<pre><code class="language-bash">#设置从节点有读取权限
rs.slaveOk()
# 取消从节点的数据读取权限
rs.slaveOk(false)
</code></pre>
<h3 id="3仲裁节点不存放任何数据">3、仲裁节点不存放任何数据</h3>
<pre><code class="language-bash"># mongo --port 27019

myrs:ARBITER&gt; show dbs
uncaught exception: Error: listDatabases failed:{
      "topologyVersion" : {
                "processId" : ObjectId("662fa25360629ad0a0f05cc1"),
                "counter" : NumberLong(1)
      },
      "ok" : 0,
      "errmsg" : "not master and slaveOk=false",
      "code" : 13435,
      "codeName" : "NotPrimaryNoSecondaryOk"
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs/&lt;@src/mongo/shell/mongo.js:147:19
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:99:12
shellHelper.show@src/mongo/shell/utils.js:937:13
shellHelper@src/mongo/shell/utils.js:819:15
@(shellhelp2):1:1
myrs:ARBITER&gt; rs.slaveOk()
WARNING: slaveOk() is deprecated and may be removed in the next major release. Please use secondaryOk() instead.
myrs:ARBITER&gt; show dbs
uncaught exception: Error: listDatabases failed:{
      "topologyVersion" : {
                "processId" : ObjectId("662fa25360629ad0a0f05cc1"),
                "counter" : NumberLong(1)
      },
      "ok" : 0,
      "errmsg" : "node is not in primary or recovering state",
      "code" : 13436,
      "codeName" : "NotPrimaryOrSecondary"
} :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
Mongo.prototype.getDBs/&lt;@src/mongo/shell/mongo.js:147:19
Mongo.prototype.getDBs@src/mongo/shell/mongo.js:99:12
shellHelper.show@src/mongo/shell/utils.js:937:13
shellHelper@src/mongo/shell/utils.js:819:15
@(shellhelp2):1:1
</code></pre>
<blockquote>
<p>"errmsg" : "node is not in primary or recovering state"</p>
<p>仲裁节点(Arbiter)在MongoDB副本集中仅用于选举过程中的投票,并不存储数据</p>
</blockquote>
<h2 id="六主节点的选举原则">六、主节点的选举原则</h2>
<h3 id="1主节点选举触发条件">1、主节点选举触发条件</h3>
<ul>
<li>
<p>MongoDB在副本集中,会自动进行主节点的选举,主节点选举的触发条件</p>
<ul>
<li>
<p>主节点故障</p>
</li>
<li>
<p>主节点网络不可达(默认心跳信息为10秒)</p>
</li>
<li>
<p>人工干预(<code>rs.stepDown(600)</code>)primary直接降级在600s内不会把自己选为primary</p>
</li>
</ul>
</li>
<li>
<p>一旦触发选举,就要根据一定规则来选择主节点。</p>
</li>
</ul>
<h3 id="2选举规则">2、选举规则</h3>
<ul>
<li>
<p>选举规则是根据票数来决定谁获胜</p>
<ul>
<li>
<p>票数最高,且获得了“大多数”成员的投票支持的节点获胜。</p>
</li>
<li>
<p>"大多数"的定义为:假设复制集内投票成员时N,则大多数为N/2+1。例如:3个投票成员,则大多数的值是2。当复制集内存活成员数量不足大多数时,整个复制集将无法选举primary,复制集将无法提供写服务,处于只读状态。</p>
</li>
<li>
<p>若票数相同,且都获得了“大多数”成员的投票支持的,数据新的节点获胜。</p>
</li>
<li>
<p>数据的新旧是通过操作日志oplog来对比的。</p>
</li>
</ul>
</li>
<li>
<p>在获得票数的时候,优先级(priority)参数影响重大。</p>
</li>
<li>
<p>可以通过设置优先级(priority)来设置额外票数。优先级即权重,取值为0-1000,相当于增加0-1000的票数,优先级的值越大,就越可能获得多数成员的投票(votes)数。指定较高的值可使成员更有资格成员主要成员,更低的值可使成员更不符合条件。</p>
</li>
<li>
<p>默认情况下,优先级的值是1</p>
</li>
</ul>
<h2 id="七集群故障分析">七、集群故障分析</h2>
<h3 id="1主节点故障">1、主节点故障</h3>
<ul>
<li>从节点和仲裁节点对主节点的心跳失败,当失败超过10秒,此时因为没有主节点了,会自动发起投票。
<ul>
<li>而副本节点只有一台,因此,候选人只有一个就是副本节点,开始投票。</li>
<li>仲裁节点向副本节点投了一票,副本节点本身自带一票,因此共两票,超过了"大多数"。</li>
<li>27019是仲裁节点,没有选举权,27018不向其投票,其票数是0。</li>
<li>最终结果,27018成为主节点。具备读写功能。</li>
</ul>
</li>
<li>再启动 27017主节点,发现27017变成了从节点,27018仍保持主节点。</li>
<li>登录27017节点,发现是从节点了,数据自动从27018同步。</li>
<li>此时:不影响正常使用</li>
</ul>
<h3 id="2副本节点故障">2、副本节点故障</h3>
<ul>
<li>主节点和仲裁节点对副本节点的心跳失败。因为主节点还在,因此,没有触发投票选举。<br>
如果此时,在主节点写入数据。再启动从节点,会发现,主节点写入的数据,会自动同步给从节点。</li>
<li>此时:不影响正常使用</li>
</ul>
<h3 id="3仲裁节点故障">3、仲裁节点故障</h3>
<ul>
<li>主节点和副本节点对仲裁节点的心跳失败。因为主节点还在,因此,没有触发投票选举。</li>
<li>此时:不影响正常使用</li>
</ul>
<h3 id="4主节点和仲裁节点故障">4、主节点和仲裁节点故障</h3>
<p>副本集中没有主节点了,导致此时,副本集是只读状态,无法写入。</p>
<p>因为27017的票数,没有获得大多数,即没有大于等于2,它只有默认的一票(优先级是1)<br>
如果要触发选举,随便加入一个成员即可。</p>
<ul>
<li>如果只加入 27019仲裁节点成员,则主节点一定是27017,因为没得选了,仲裁节点不参与选举,但参与投票。</li>
<li>如果只加入 27018节点,会发起选举。因为27017和27018都是两票,则按照谁数据新,谁当主节点。</li>
</ul>
<p>此时:影响正常使用,需要处理</p>
<h3 id="5从节点和仲裁节点故障">5、从节点和仲裁节点故障</h3>
<p>10秒后,27017主节点自动降级为副本节点。(服务降级)<br>
副本集不可写数据了,已经故障了。</p>
<p>此时:影响正常使用,需要处理</p>
<h3 id="6主节点和从节点故障">6、主节点和从节点故障</h3>
<p>集群将处于不完全状态,无法执行写操作,因为剩余的副本节点不足以立即选出新的主节点(假设只剩一个副本节点和仲裁节点)。直到至少有一个额外的副本节点在线并同步,以便选举出新的主节点</p>
<p>此时:影响正常使用,需要处理</p>
<h3 id="7所有节点故障">7、所有节点故障</h3>
<ul>
<li>
<p>整个集群不可用,既不能执行读也不能执行写操作。</p>
</li>
<li>
<p>这种情况需要手动干预,逐一排查并恢复各个节点,确保至少一个主节点和多数节点(包括仲裁节点)在线,以恢复集群服务。</p>
</li>
<li>
<p>此时:影响正常使用,需要处理</p>
</li>
</ul><br><br>
来源:https://www.cnblogs.com/misakivv/p/18166888
頁: [1]
查看完整版本: 搭建MongoDB副本集