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可以正常使用了

集群(副本集)

进阶版使用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(); 

集群(副本集+仲裁)

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

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(); 

集群(分片)

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

在这里插入图片描述

  • 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" })

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
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
MongoDB 是一种文档型数据库,它可以通过分片来实现高可用性和扩展性。MongoDB 分片是将一个大的 MongoDB 数据库分成多个部分,每个部分称为一个 Shard。一个 MongoDB 分片集群通常由多个 Shard、多个复制集和多个配置服务器组成。 下面是MongoDB数据库集群的基本架构: 1. 分片(Sharding):将数据划分成多个片段,每个片段称为一个Shard。Shard是MongoDB中存储数据的最小单位,每个Shard可以是单台服务器或是一个复制集。 2. 复制集(Replica Set):MongoDB中的复制集是一组维护相同数据副本的MongoDB服务器。每个复制集包含一个Primary节点和多个Secondary节点,Primary节点负责处理所有的写操作,Secondary节点负责复制Primary节点的数据。 3. 配置服务器(Config Server):配置服务器维护了整个集群的元数据信息,包括分片信息、复制集信息等。每个配置服务器都保存了所有集群的元数据信息的一份拷贝。 4. Mongos路由器(Mongos Router):Mongos路由器是一个轻量级的进程,用于将客户端请求路由到正确的Shard上。 在MongoDB集群中,每个Shard都存储了部分数据,Mongos路由器根据某种规则将请求路由到相应的Shard上,Shard接收到请求后将数据返回给Mongos路由器,最终路由器将结果返回给客户端。配置服务器用于记录集群的元数据信息,包括Shard信息、数据分布信息等等。 通过分片来实现数据的水平扩展,可以将数据存储在多台服务器上,提高数据的可扩展性和可用性。同时,MongoDB还提供了复制集实现数据的高可用性,确保数据不会因为单点故障而丢失。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值