• MongoDB单机集群方案及详解


    帮助文档

    MongoDB官方更新速度过快,语法不断更新,shell命令也不断更新,建议直接看官方版。

    • 国内帮助文档:https://docs.mongoing.com/the-mongodb-manual-cn
    • 官方文档(海外):https://www.mongodb.com/developer/
    • docker官方提供的MongoDB安装文档:https://hub.docker.com/_/mongo(mongo更新过快,某些命令可能不是最新)

    本文主要从docker角度出发安装MongoDB

    MongoDB在企业级网站中的定位

    在这里插入图片描述
    如图MongoDB是在关系型与非关系数据库之间,目前企业级网站面临3V(海量Volume,多样variety,实时velocity),3高(高并发,高可扩,高性能),通过数据冗余,在一条数据中存储父子的表数据来解决不能联查的问题。
    举个例子:

    • 当每秒写入的数据超过了数据库所能写入的上限时,我们改怎么办?

    将数据暂存在MongoDB中,再通过定时任务,写入数据库中。虽然MongoDB存在丢失数据风险的,但如果服务器稳定遍不会出现这种问题

    • redis缓存不能满足统计分析等场景时,我们改怎么办?

    将数据通过冗余的方式写入MongoDB中,通过MongoDB丰富的查询方式解决这个问题。

    单机MongoDB部署

    最基础的使用MongoDB,无法使用事务功能

    //下载镜像
    docker pull mongo
    //创建容器并持久化数据
    docker run --name 容器名称 -p 对外端口:27017 --restart=always -v /app/docker/mongo/db:/data/db -v /etc/localtime:/etc/localtime -d mongo   --bind_ip_all
    //进入docker 容器
    docker exec -it 容器名称 bash
    //进入docker 容器并登录MongoDB
    docker exec -it 容器名称 mongosh
    //登录进MongoDB后需要重置Mongo
    rs.initiate()
    //至此MongoDB可以正常使用了
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    集群(副本集)

    进阶版使用MongoDB
    注:原复制集因主节点挂掉,不能继续写入数据被淘汰,更新为副本集
    一个主库;两个从库组成,主库宕机时,这两个从库都可以被选为主库。但数据通过主库写入时,副本库会将数据抓取到副本集中进行存储。主库负责写入数据,副本节点负责读取数据。我们写代码时不需要区分主节点与副本节点,可以连接所有ip,MongoDB会自己分辨
    在这里插入图片描述
    通过心跳检测,如果主节点挂掉,优先发现主节点挂掉的副本节点会成为主节点,但主节点再恢复后不能再成为主节点,只能成为副本节点。但这里会出现一个问题,副本节点并不一定是计算能力最强的节点。而且主节点只能有一个
    在这里插入图片描述

    docker pull mongo
    
    mkdir -p /app/docker/mongo1/db   #创建挂载的db目录
    mkdir -p /app/docker/mongo2/db   #创建挂载的db目录
    mkdir -p /app/docker/mongo3/db   #创建挂载的db目录
    #第一台:
    docker run --name mongo-server1 -p 30001:27017 --restart=always -v /app/docker/mongo1/db:/data/db -v /etc/localtime:/etc/localtime -d mongo  --replSet "rs0"  --bind_ip_all
    #第二台:
    docker run --name mongo-server2 -p 30002:27018 --restart=always -v /app/docker/mongo2/db:/data/db -v /etc/localtime:/etc/localtime -d mongo  --replSet "rs0"  --bind_ip_all
    #第三台:
    docker run --name mongo-server3 -p 30003:27019 --restart=always -v /app/docker/mongo3/db:/data/db -v /etc/localtime:/etc/localtime -d mongo  --replSet "rs0"  --bind_ip_all
    
     
    
    #进入容器 进入主的容器
    docker exec -it mongo-server1 bash 
    #连接客户端
    docker exec -it 容器名称 mongosh
    //这里localhost是因为我都是在同一个服务器上装的,都换成各自的ip就好
    //初始化
    rs.initiate()
    //注册副本集
    rs.add("localhost:30002") 
    #如果想要在从节点查询(默认是客户端直连是不可查询的)
    如果想要在端口30002 从服务上执行查询,则连接上之后需要执行 db.getMongo().setSlaveOk(); 
    
    • 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

    集群(副本集+仲裁)

    仲裁节点不存储数据,仲裁会帮助选举出主节点,但如果仲裁集群挂掉,主节点也挂掉了,那就完蛋了。因为副本集群只能读取不能写入。而且主节点只能有一个
    在这里插入图片描述

    docker pull mongo
    
    mkdir -p /app/docker/mongo1/db   #创建挂载的db目录
    mkdir -p /app/docker/mongo2/db   #创建挂载的db目录
    mkdir -p /app/docker/mongo3/db   #创建挂载的db目录
    #第一台:
    docker run --name mongo-server1 -p 30001:27017 --restart=always -v /app/docker/mongo1/db:/data/db -v /etc/localtime:/etc/localtime -d mongo  --replSet "rs0"  --bind_ip_all
    #第二台:
    docker run --name mongo-server2 -p 30002:27018 --restart=always -v /app/docker/mongo2/db:/data/db -v /etc/localtime:/etc/localtime -d mongo  --replSet "rs0"  --bind_ip_all
    #第三台:
    docker run --name mongo-server3 -p 30003:27019 --restart=always -v /app/docker/mongo3/db:/data/db -v /etc/localtime:/etc/localtime -d mongo  --replSet "rs0"  --bind_ip_all
    
     
    
    #进入容器 进入主的容器
    docker exec -it mongo-server1 bash 
    #连接客户端
    docker exec -it 容器名称 mongosh
    //这里localhost是因为我都是在同一个服务器上装的,都换成各自的ip就好
    //初始化
    rs.initiate()
    //注册副本集
    rs.add("localhost:30002")
    //注册仲裁
    rs.addArb("localhost:30003")
    #如果想要在从节点查询(默认是客户端直连是不可查询的)
    如果想要在端口30002 从服务上执行查询,则连接上之后需要执行 db.getMongo().setSlaveOk(); 
    
    • 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

    集群(分片

    架构师必备,搞不懂分片完全有情可原,相当的复杂。大家创建分片时切记画好图再创建,不然会弄乱。
    在这里插入图片描述
    分片的意思就是将一个集合中的数据,拆成不同的分片集群来存储数据。接下来忘记副本集的概念,分片和副本集架构关系并不大

    在这里插入图片描述

    • App Server 就是某一个分片集群,其中包含很多分片(Shard)和一个主节点 。实际生产环境中的一个分片服务可以由好几台服务组成reclica set,防止单点故障。(详见下图)
    • Shard 为数据存储分片,用来将分割后的数据储存起来。可以是集群,实现高负载,高可用。每一片都可以是复制集(replica set)
    • Router 路由进程 也叫mongos,用来外部访问。从整体看来,无论有多少个app server,访问时只连接Router即可,Router只需要一个。应用程序接入 mongos 再查询到具体分片
    • Config Service 路由表,每一台都具有全部 chunk 的路由信息,用来存储分割的信息,比如XXX存到哪里去,XXX要从哪里读取。也可以搭建集群。
      任何集群里面都可以有仲裁
      在这里插入图片描述

    当然问题也会存在,比如某个分片挂掉,就会影响该分片内数据的读取,但只需要重启就好。如果 App Server,Config Service 任何一个整体挂掉,就不可用了,但都可以集群分布在不同机器上,问题不大。

    192.168.1.201:
    
    ~~~shell
    docker run --name shardsvr00 -p 10031:27018 -d -v /home/mongodb/data/sh/shardsvr00:/data/db mongo --shardsvr --replSet "rs_shardsvr0" --bind_ip_all
    
    docker run --name shardsvr10 -p 10041:27018 -d -v /home/mongodb/data/sh/shardsvr10:/data/db mongo --shardsvr --replSet "rs_shardsvr1" --bind_ip_all
    
    
    ~~~
    
    192.168.1.202:
    
    ~~~shell
    docker run --name shardsvr01 -p 10032:27018 -d -v /home/mongodb/data/sh/shardsvr00:/data/db mongo --shardsvr --replSet "rs_shardsvr0" --bind_ip_all
    docker run --name shardsvr11 -p 10042:27018 -d -v /home/mongodb/data/sh/shardsvr11:/data/db mongo --shardsvr --replSet "rs_shardsvr1" --bind_ip_all
    ~~~
    
    192.168.3.203:
    
    ~~~shell
    docker run --name shardsvr02 -p 10033:27018 -d -v /home/mongodb/data/sh/shardsvr00:/data/db mongo --shardsvr --replSet "rs_shardsvr0" --bind_ip_all
    docker run --name shardsvr12 -p 10043:27018 -d -v /home/mongodb/data/sh/shardsvr12:/data/db mongo --shardsvr --replSet "rs_shardsvr1" --bind_ip_all
    ~~~
    
    ### 2.5初始化副本集
    
    192.168.1.201执行
    
    docker exec -it shardsvr00 bash
    mongo --host 192.168.1.201 --port 10031
    
    ~~~shell
    rs.initiate(
       {
          _id: "rs_shardsvr0",
          members: [
             { _id: 0, host : "192.168.1.201:10031" },
             { _id: 1, host : "192.168.1.202:10032" },
             { _id: 2, host : "192.168.1.203:10033" }
          ]
       }
    );
    ~~~
    
    docker exec -it shardsvr10 bash
    mongo --host 192.168.1.201 --port 10041
    
    ~~~shell
    rs.initiate(
       {
          _id: "rs_shardsvr0",
          members: [
             { _id: 0, host : "192.168.1.201:10041" },
             { _id: 1, host : "192.168.1.202:10042" },
             { _id: 2, host : "192.168.1.203:10043" }
          ]
       }
    );
    ~~~
    
    ### 2.6.创建mongos,连接mongos到分片集群
    
    192.168.1.201:
    
    docker run --name mongos0 -d -p 10011:27017 --entrypoint "mongos" mongo --configdb rs_configsvr/192.168.1.201:10021,192.168.1.202:10022,192.168.1.203:10023 --bind_ip_all
    
    192.168.3.202:
    
    docker run --name mongos1 -d -p 10012:27017 --entrypoint "mongos" mongo --configdb rs_configsvr/192.168.1.201:10021,192.168.1.202:10022,192.168.1.203:10023 --bind_ip_all
    
    ### 2.7添加分片到集群
    
    192.168.3.201:
    
    docker exec -it mongos0 bash
    mongo --host 192.168.1.201 --port 10011
    
    sh.addShard("rs_shardsvr0/192.168.1.201:10031,192.168.1.202:10032,192.168.1.203:10033")
    sh.addShard("rs_shardsvr1/192.168.1.201:10041,192.168.1.202:10042,192.168.1.203:10043")
    
    ## 数据库 启用 分片
    
    sh.enableSharding("test")
    
    ## 分片集合
    
    对 test.order 的 _id 字段进行哈希分片:
    
    sh.shardCollection("test.order", {"_id": "hashed" })
    
    • 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
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89

    mongo运行原理

    在这里插入图片描述

    • 当数据data需要写入时,会先存入私有内存空间Journal内存中,随后通过定时任务journal log 每100ms刷一次存入journal log对于的硬盘中 。同时也会通过异步的方式将数据每60s一次,写入硬盘中,完成存储
    • 当数据需要读取时,不会直接读取硬盘中的数据,而是读取journal log 中的数据,并返回。
    • 当然journal log 功能是可以通过配置关闭的,定时存储时间也可以自定义设置(一般都不会动)。但是 这样的模式当MongoDB挂掉时,丢失的数据不仅仅是100ms内的数据,而是取决于数据存入journal log 内存后,定时任务有没有办法在100ms内将数据写入硬盘。如果100ms内能解决,那么只会丢最近100ms内的数据。如果不能解决,那么丢失的就会因为延迟的问题,丢失超过100ms的数据。

    mongo管理小工具推荐

    docker run -it --rm \
        --name mongo-express \
        -p 8081:8081 \
        -e ME_CONFIG_OPTIONS_EDITORTHEME="ambiance" \
        -e ME_CONFIG_MONGODB_SERVER="192.168.1.201" \
    	-e ME_CONFIG_MONGODB_PORT="10011"          \
        -e ME_CONFIG_BASICAUTH_USERNAME="admin" \
        -e ME_CONFIG_BASICAUTH_PASSWORD="admin" \
        mongo-express
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  • 相关阅读:
    六大科研工具推荐,外文文献阅读管理全都搞定!
    如何调试一个C++程序?以Visual Studio 2019为例的保姆级教程。
    洛谷P4316 绿豆蛙的归宿
    Jenkins-Blue Ocean应用教程,一看就会
    如何在服务器中安装anaconda
    简单聊聊Integer
    python查找算法_顺序查找
    sqlite3命令行工具无法退出问题处理
    sql语句中distinct的用法
    【Windows】RPC调用过程实例详解
  • 原文地址:https://blog.csdn.net/tx1721110240/article/details/128008729