02-Mongo 副本集

副本集

A replica set in MongoDB is a group of mongod processes that maintain the same data set. Replica sets provide redundancy and high availability, and are the basis for all production deployments.

  • 一个副本集是一组mongo实例, 它们维护着相同的数据集。
  • 副本集提供数据冗余和高可用, 是生产环境部署的基本环境。
  • 只能解决数据安全和高可用, 不能解决高负载

副本集中的成员

  • primary 主节点, 接受所有的写操作
  • secondary 从结点,维护与主节点一致的数据副本, 可以承载读操作。
  • arbiter 仲裁者, 在选举primary时参与投票, 自己不承载数据,也不会成为primary

Mongo中的副本集是一组mongo实例,它们维护着相同的数据集。一个副本集包含多个数据承载结点和一个可选的仲裁结点。在多个数据承载结点中,只有一个结点是primary结点, 其余都是secondary结点。 primary结点接受所有 write 操作。

在副本集中使用{w:'majority'}写注意策略时,只有一个primary有能力去确认写操作,虽然某些情况下其他mongod实例会短暂地任务自己也是primary。primary会记录所有对数据集的变更操作, 例如 oplog。 secondary 会复制primary的oplog并应用其中的操作到自己的数据集上。当primary不可用时,有资格成为primary的secondary结点会选举新的primary。

副本集的同步

  • secondary异步地复制primary的oplog并将其操作应用到当前数据集

自动故障转移

  • 当primary与副本集中共其他成员失去通信(默认10s)一段时间后, 一个有资格的secondary发起选举并提名自己作为primary。 集群会尝试完成新primary的选举并恢正常
  • 在副本集没有完成选举时,无法执行写操作。在primary离线期间,如果配置为在secondary中读则副本集仍然可以提供读操作
  • 在默认配置下,集群完成选举前的中间时间不会超过12s。 这其中包括标记primary不可用的时间以及发起选举并完成选举。
  • 将 electionTimeoutMillis 修改地更小会导致更频繁的故障转移和选举,即使只是网络延迟。

读操作

read perference

  • 副本集默认在primary上执行读操作。 但是可以手动指定 readPerference 为 secondary 将读操作发送到secondary结点
  • 由于secondary是异步复制,这意味着读操作可能读取的数据不是primary中的最新数据
  • Multi-documnet transactions 控制读操作必须使用 readPerference 为 primary. 给定事务中的所有操作必须路由到相同的结点。

数据可见性

副本集搭建

集群配置

# 在三台服务器上配置, 用相同的名称
vim /etc/mongod.conf
# 同一个副本集的名称要一致
replication:
  replSetName: 'rs0'

初始化集群

mongosh test.mongo1.db
rs.initiate( {
 : "rs0",
   members: [
      { _id: 0, host: "test.mongo1.db:27017" }, #一定要使用域名或局域网IP
      { _id: 1, host: "test.mongo2.db:27017" },
      { _id: 2, host: "test.mongo3.db:27017" }
   ])
    
{ ok: 1 }

查看集群配置

rs.conf();
rs.status();#查看副本集状态
{
  _id: 'rs0',
  version: 1,
  term: 0,
  members: [
    {
      _id: 0,
      host: 'test.mongo1.db:27017',
      arbiterOnly: false,
      buildIndexes: true,
      hidden: false,
      priority: 1,
      tags: {},
      secondaryDelaySecs: Long("0"),
      votes: 1
    },
    {
      _id: 1,
      host: 'test.mongo2.db:27017',
      arbiterOnly: false,
      buildIndexes: true,
      hidden: false,
      priority: 1,
      tags: {},
      secondaryDelaySecs: Long("0"),
      votes: 1
    },
    {
      _id: 2,
      host: 'test.mongo3.db: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("65410a4fb993537e930c3cc2")
  }
}

写入数据

在一个结点写入数据,在其他结点查询数据

db.movies.insertOne(
  {
    title: "人猿泰山",
    genres: [ "大山", "卡档夫" ],
    runtime: 121,
    rated: "R",
    year: 2018,
    directors: [ "Yorgos Lanthimos" ],
    cast: [ "Olivia Colman", "Emma Stone", "Rachel Weisz" ],
    type: "movie"
  }
)

db.movies.find( { title: "The Favourite" } )

在 secondary 结点上执行查询操作出错:

MongoServerError: not primary and secondaryOk=false - consider using db.getMongo().setReadPref() or readPreference in the connection string

需要在 seconda 结点上执行 db.getMongo().setReadPref('secondary')

db.getMongo().setReadPref('secondary')

灾备测试

  1. 停止 primary 结点, 其他结点自动选举为 primary
  2. 在新的 primary 上写入数据
  3. 启动停止的结点, 数据会同步到新的结点上

compass/springdata 使用

mongodb://test.mongo1.db:27017,test.mongo2.db:27017,test.mongo3.db:27017/{dbname}/?replicaSet={replicaName}&readPreference=secondary

posted @ 2024-04-20 09:07  Dreamsrj  阅读(15)  评论(0)    收藏  举报