MongoDB伪分布式部署(mac M2)

1. 序言

  • 本博客是上一博客的进阶版:mac M2安装单机版 MongoDB 7.x,上一博客可以看做是单机、单节点部署MongoDB
  • 本博客将介绍单机、多服务部署MongoDB,实际就是伪分布式部署

2. 副本集(Replica Set)方式部署

2.1 什么是副本集?

  • 多节点部署、主从部署等其实都是为了 MongoDB 的高可用,支持数据多副本、读写分离等

  • 较新版本的MongoDB Master/slave 被废弃,通过副本集提供高可用和数据冗余

    bash 复制代码
    "msg":"Master/slave replication is no longer supported"
  • 一个副本集由多个节点组成,其中一个节点是主节点(Primary),其余是从节点(Secondary)

  • 主节点处理所有的写操作,从节点复制主节点的数据并可以处理读操作(如果启用了读偏好)

  • 副本集的特点:

    • 高可用性: 如果主节点发生故障,从节点会自动选举一个新的主节点。
    • 数据冗余:数据在多个节点上复制,提供数据冗余。
    • 读扩展:可以配置从节点处理读操作,以减轻主节点的负载。

2.2 副本集部署

2.2.1 启动3个MongoDB服务

  • 在本机以前台进程的方式启动3个 MongoDB 服务,且指定副本集为 rs0

    bash 复制代码
    mongod --replSet rs0 --dbpath /Users/bytedance/mongodb11/data --port 27031 --bind_ip_all
    
    mongod --replSet rs0 --dbpath /Users/bytedance/mongodb12/data --port 27032 --bind_ip_all
    
    mongod --replSet rs0 --dbpath /Users/bytedance/mongodb13/data --port 27033 --bind_ip_all
  • 如果想通过配置文件部署,服务1的配置文件如下

    yaml 复制代码
    # 数据存储相关配置
    storage:
      dbPath: /Users/bytedance/mongodb2/data
      journal:
        enabled: true
    
    # 网络相关配置
    net:
      port: 27030
      bindIp: 0.0.0.0  # 允许从所有IP地址访问
    
    # 副本集相关配置
    replication:
      replSetName: "rs0"
    
    # 日志相关配置
    systemLog:
      destination: file
      logAppend: true
      logRotate: rename
      path: /Users/xxx/mongodb11/log/mongo.log
    
    # 进程管理相关配置
    processManagement:
      fork: true  # 以守护进程方式运行(后台运行)
    
    # 安全相关配置
    security:
      authorization: disabled  # 关闭用户认证

2.2.2 初始化副本集

  • 通过mongosh登录访问其中一个服务:

    bash 复制代码
    mongosh --port 27032
  • 执行如下命令初始化副本集合:

    bash 复制代码
    rs.initiate({
      _id: "rs0",
      members: [
        { _id: 0, host: "localhost:27031" },
        { _id: 1, host: "localhost:27032" },
        { _id: 2, host: "localhost:27033" }
      ]
    })
  • 执行rs.status() 验证副本集状态

    bash 复制代码
    rs0 [direct: primary] test> rs.status()
    {
      set: 'rs0',
      ... # 其他信息省略
      members: [
        {
          _id: 0, # initiate 时指定的id
          name: 'localhost:27031',
          health: 1,
          state: 2,
          stateStr: 'SECONDARY', # 从节点
          ... # 其他信息省略
        },
        {
          _id: 1,
          name: 'localhost:27032',
          health: 1,
          state: 1,
          stateStr: 'PRIMARY', # 主节点
          ... # 其他信息省略
        },
        {
          _id: 2,
          name: 'localhost:27033',
          health: 1,
          state: 2,
          stateStr: 'SECONDARY', # 从节点
          ... # 其他信息省略
        }
      ],
      ok: 1,
      ... # 其他信息省略
    }
  • 还可以通过 rs.isMaster() 查看当前访问的服务是不是primary节点

    bash 复制代码
    rs0 [direct: primary] test> rs.isMaster()
    {
      ... # 其他信息省略
      hosts: [ 'localhost:27031', 'localhost:27032', 'localhost:27033' ],
      setName: 'rs0',
      setVersion: 1,
      ismaster: true, # 当前访问的是primary节点(服务)
      secondary: false,
      primary: 'localhost:27032',
      me: 'localhost:27032',
      .. # 其他信息省略
      readOnly: false,
      ... # 其他信息省略
      isWritablePrimary: true # 只能通过primary节点写入
    }

2.3 副本集中数据的读写

  • 从上面的信息就可以看出, 副本集的可以支持设置读写偏好、支持读写分离

  • 例如,isWritablePrimary: true 只能在primary节点写入,若在非primary节点插入数据将报错

    bash 复制代码
    Uncaught:
    MongoBulkWriteError[NotWritablePrimary]: not primary
  • 在primary节点插入数据

    bash 复制代码
    db.test_data.insertMany([
      { name: "Bob", age: 25, sex: "male", city: "Los Angeles" },
      { name: "Carol", age: 28, sex: "female", city: "Chicago" },
      { name: "Dave", age: 35, sex: "male", city: "San Francisco" }
    ])
  • 在任意节点查询数据

    bash 复制代码
    db.test_data.find({'name':"Bob"})

3. 部署分片(Sharding)集群

3.1 什么是分片?

  • 在数据存储系统中,除了支持副本集(多副本存储全量数据),还支持分片(Sharding),MongoDB也不例外
  • 分片是 MongoDB 提供的一种水平扩展机制,用于将数据分布在多个服务器上
  • 分片具备以下特性:
    • 水平扩展:通过将数据分布在多个分片上,解决单个服务器的存储和性能限制。
    • 负载均衡:数据和请求可以在多个分片之间均匀分布。
    • 高可用性:结合副本集使用,每个分片可以是一个副本集,从而提供高可用性。

3.2 副本集 vs 分片

  • 相对副本集,分片会按照某种规则将数据拆分成多个split,每个split存储到相应的分片
  • 以销售数据为例,形象化比喻:
    • 副本集就是一个机房有多台机器,每台机器都将存储中国市场的销售数据
    • 分片就是存在多个机房,每个机房存储只存储所在区域的销售数据。例如,华北机房只存储华北地区的销售数据,西南机房只存储西南地区的销售数据
    • 同时,为了提供高可用和数据冗余,分片存储时,每个机房需要有多台机器,支持多副本储存该区域的销售数据
    • 也就是说,一个分片就是一个副本集,分片内部通过副本集实现高可用和数据冗余机制

3.3 部署分片集群(副本集与分片的结合使用)

  • 分片集群由配置服务器(Config Servers)、分片服务器(Shards)、和路由服务器(mongos)组成
    • 配置服务器作为副本集:配置服务器存储集群的元数据,为了确保配置服务器的高可用性,配置服务器也通常设置为一个副本集
    • 每个分片作为一个副本集:在分片集群中,每个分片通常是一个副本集。这意味着每个分片不仅能存储数据的一部分,还能提供高可用性和数据冗余。
    • 路由服务器(mongos):mongos不存储数据,而是作为路由器将客户端请求路由到适当的分片,可以部署多个mongos实例以提供高可用性和负载均衡

3.3.1 部署配置服务器

  • 使用如下命令,在本地启动三个配置服务器,注意提前创建好data目录

    • --configsvr:表示这是一个配置服务器

    • --replSet rs0:设置副本集,配置服务器的本质是一个副本集

      bash 复制代码
      mongod --configsvr --replSet rs0 --dbpath /Users/xxx/mongodb1/data/configdb --port 27019 --bind_ip_all
      
      mongod --configsvr --replSet rs0 --dbpath /Users/xxx/mongodb2/data/configdb --port 27020 --bind_ip_all
      
      mongod --configsvr --replSet rs0 --dbpath /Users/xxx/mongodb3/data/configdb --port 27021 --bind_ip_all
  • 访问某个配置服务,初始化副本集

    bash 复制代码
    mongosh --port 27019 # 访问配置服务
    
    rs.initiate({
      _id: "rs0",
      configsvr: true,
      members: [
        { _id: 0, host: "localhost:27019" },
        { _id: 1, host: "localhost:27020" },
        { _id: 2, host: "localhost:27021" }
      ]
    })
  • PS: 若以后台服务方式启动,上述启动方式对应的配置文件如下

    yaml 复制代码
    storage:
      dbPath:  /Users/xxx/mongodb1/data/configdb
      journal:
        enabled: true
    # 网络相关配置
    net:
      port: 27010
      bindIp: 0.0.0.0  # 允许从所有IP地址访问
    # 复制集相关配置
    replication:
      replSetName: "rs0"
    # 设置role:分片集群中的配置服务器
    sharding:
      clusterRole: "configsvr"
    # 日志相关配置
    systemLog:
      destination: file
      logAppend: true
      logRotate: rename
      path: /Users/xxx/mongodb1/log/configd/mongo.log
    # 进程管理相关配置
    processManagement:
      fork: true  # 以守护进程方式运行(后台运行)
    # 安全相关配置
    security:
      authorization: disabled  # 关闭用户认证

3.3.2 部署分片服务器

shard1
  • 使用如下命令,在本地启动三个分片服务器,注意提前创建好data目录

    bash 复制代码
    mongod --shardsvr --replSet shard1 --dbpath /Users/bytedance/mongodb1/data/shard --port 27022 --bind_ip_all
    
    mongod --shardsvr --replSet shard1 --dbpath  /Users/bytedance/mongodb2/data/shard --port 27023 --bind_ip_all
    
    mongod --shardsvr --replSet shard1 --dbpath  /Users/bytedance/mongodb3/data/shard --port 27024 --bind_ip_all
  • 访问其中某个分片服务器,初始化分片信息

    bash 复制代码
    mongosh --port 27022
    
    rs.initiate({
      _id: "shard1",
      members: [
        { _id: 0, host: "localhost:27022" },
        { _id: 1, host: "localhost:27023" },
        { _id: 2, host: "localhost:27024" }
      ]
    })
shard2
  • 使用如下命令,在本地启动三个分片服务器,注意提前创建好data目录

    bash 复制代码
    mongod --shardsvr --replSet shard2 --dbpath /Users/bytedance/mongodb1/data/shard2 --port 27025 --bind_ip_all
    
    mongod --shardsvr --replSet shard2 --dbpath  /Users/bytedance/mongodb2/data/shard2 --port 27026 --bind_ip_all
    
    mongod --shardsvr --replSet shard2 --dbpath  /Users/bytedance/mongodb3/data/shard2 --port 27027 --bind_ip_all
  • 访问其中某个分片服务器,初始化分片信息

    bash 复制代码
    mongosh --port 27025
    
    rs.initiate({
     _id: "shard2",
     members: [
       { _id: 0, host: "localhost:27025" },
       { _id: 1, host: "localhost:27026" },
       { _id: 2, host: "localhost:27027" }
     ]
    })

3.3.4 部署mongos

  • 先创建好mongos所需的相关目录

    bash 复制代码
    mkdir /Users/xxx/mongos
    cd /Users/xxx/mongos
    mkdir data log etc
  • 在etc目录下创建mongos的配置文件,mongos-config.yaml

    bash 复制代码
    net:
      bindIp: 0.0.0.0
      port: 27017
    
    sharding:
      configDB: rs0/localhost:27019,localhost:27020,localhost:27021
  • 以前台方式启动mongos

    bash 复制代码
    mongos --config /Users/xxx/mongos/etc/mongos-config.yaml
  • 访问mongos,添加分片(之前部署好的分片服务器)

    bash 复制代码
    mongosh --port 27017
    
    sh.addShard("shard1/localhost:27022,localhost:27023,localhost:27024")
    sh.addShard("shard2/localhost:27025,localhost:27026,localhost:27027")
  • 通过 sh.status() 查看shard信息

    bash 复制代码
    # 关键信息
    shards
    [
      {
        _id: 'shard1',
        host: 'shard1/localhost:27022,localhost:27023,localhost:27024',
        state: 1,
        topologyTime: Timestamp({ t: 1727872634, i: 3 })
      },
      {
        _id: 'shard2',
        host: 'shard2/localhost:27025,localhost:27026,localhost:27027',
        state: 1,
        topologyTime: Timestamp({ t: 1727939236, i: 4 })
      }
    ]

3.5 启用分片

3.5.1 启用数据库分片和集合分片

  • 启用数据库分片和集合分片

    bash 复制代码
    use admin # 一定要先切换到admin,
    sh.enableSharding("test")
    
    use test
    sh.shardCollection("test.test_data", {user_id: 1}) # user_id作为分片的key
  • 验证是否成功开启集合分片

    bash 复制代码
    use test
    db.test_data.getShardDistribution()
  • 若有如下输出,说明开启成功

3.5.2 插入数据并查看

  • 插入100条数据

    bash 复制代码
    # 数据示例 -- user_id: id000001; name: name1
    for (let i = 1; i <= 2000; i++) {
     let user_id = `id${String(i).padStart(6, '0')}`;  
     let name = `name${i}`;  
     db.test_data.insertOne({ user_id: user_id, name: name });
    }
  • 执行sh.status()查看分片信息,但数据只分布到了shard2,要么是集群部署存在问题,要么跟公司的 "chatGPT" 回答一样

    • 分片键选择不当:如果分片键的值分布不均匀,可能会导致数据集中在一个分片上。例如,如果您的分片键是一个递增的字段(如时间戳或自增 ID),那么所有新插入的数据都会集中在同一个分片上
    • 数据量不足 :在数据量较小的情况下,MongoDB 可能不会立即将数据分布到多个分片上。MongoDB 需要一定的数据量来决定何时进行分片 (笔者倾向于该原因)
    bash 复制代码
       ... # 其他信息省略,可以看到 'test.test_data' 集合成功开启了分片
       collections: {
          'test.test_data': {
            shardKey: { user_id: 1 },
            unique: false,
            balancing: true,
            chunkMetadata: [ { shard: 'shard2', nChunks: 1 } ],
            chunks: [
              { min: { user_id: MinKey() }, max: { user_id: MaxKey() }, 'on shard': 'shard2', 'last modified': Timestamp({ t: 1, i: 0 }) }
            ],
            tags: []
          }
        }
  • PS: 公司的 "chatGPT" 还给出了其他的查看分片信息的方法,但无任何输出

    bash 复制代码
    use config
    db.chunks.find({ ns: "testDB.test_data" }).sort({ min: 1 }).pretty()

3.5.3 在shard2的各服务器查询数据

  • 由于上面的集合只分布在shard2,现在连接shard2的任意服务器,执行如下查询命令

    bash 复制代码
    use test
    db.test_data.find({'name':"name1"})
  • 均能从shard2的每个服务器查到数据,这也说明了,shard2分片自身就是一个副本集


4. 后记

相关推荐
2501_916008892 小时前
iOS 26 系统流畅度实战指南|流畅体验检测|滑动顺畅对比
android·macos·ios·小程序·uni-app·cocoa·iphone
cookqq2 小时前
MongoDB源码delete分析oplog:从删除链路到核心函数实现
数据结构·数据库·sql·mongodb·nosql
小雨青年3 小时前
基于 MacOS 的Rokid 开发本地环境搭建指南
macos
时光追逐者6 小时前
一款由网易出品的免费、低延迟、专业的远程控制软件,支持手机、平板、Mac 、PC、TV 与掌机等多设备远控电脑!
macos·电脑·远程控制工具
二王一个今6 小时前
Python打包成exe(windows)或者app(mac)
开发语言·python·macos
一勺菠萝丶6 小时前
Mac 上用 Homebrew 安装 JDK 8(适配 zsh 终端)完整教程
java·python·macos
周杰伦_Jay6 小时前
【Homebrew安装 MySQL 】macOS 用 Homebrew 安装 MySQL 完整教程
数据库·mysql·macos
小萌新上大分6 小时前
Typora 配置 PicGo 使用 Gitee 图床实现图片自动上传(Mac 详细教程)
macos·gitee·typora图床·gitee图床·picgo配置gitee·typora配置图床·typora的图床gitee
林鸿群6 小时前
Apple M3 MacOS arm64 编译QGroundControl5.0.8(base on Qt 6.8.3)
macos·ios·qgc·qgroundcontrol
Someone_sky6 小时前
Color Wheel for Mac:一键解锁专业配色,设计效率翻倍
macos