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. 后记

相关推荐
fishmemory7sec3 小时前
Koa2+mongodb项目实战1(项目搭建)
数据库·mongodb·koa
GEEKVIP4 小时前
iPhone/iPad技巧:如何解锁锁定的 iPhone 或 iPad
windows·macos·ios·智能手机·笔记本电脑·iphone·ipad
超爱找事12 小时前
iMazing只能苹果电脑吗 Win和Mac上的iMazing功能有区别吗
windows·macos·电脑·数据备份·苹果·imazing
代吗喽12 小时前
Macos终端常用的命令行指令总结
macos·命令行
无名草鸟13 小时前
macOS终端配置自动补全功能
macos
Nyingchi-X13 小时前
Navicat Premium 12 for Mac中文永久版
mysql·macos
栗筝i13 小时前
MacOS 终端执行安装 Brew
macos
颜淡慕潇13 小时前
【数据库】Java 集成mongodb— MongoTemplate 详解
java·数据库·sql·mongodb·nosql
我是水怪的哥13 小时前
mac配置python出现DataDirError: Valid PROJ data directory not found错误的解决
开发语言·python·macos