非关系型数据库Mongodb(三):集群之复制集和分片集

MongoDB集群之复制集

1.简介

  • 一组Mongodb复制集,就是一组mongod进程,这些进程维护同一个数据集合。复制集提供了数据冗余和高等级的可靠性,这是生产部署的基础。
  • 目的
    • 保证数据在生产部署时的冗余和可靠性,通过在不同的机器上保存副本来保证数据的不会因为单点损坏而丢失。能够随时应对数据丢失、机器损坏带来的风险。
    • 还能提高读取能力,用户的读取服务器和写入服务器在不同的地方,而且,由不同的服务器为不同的用户提供服务,提高整个系统的负载。
  • 机制
    • 一组复制集就是一组mongod实例掌管同一个数据集,实例可以在不同的机器上面。实例中包含一个主导(Primary),接受客户端所有的写入操作,其他都是副本实例(Secondary),从主服务器上获得数据并保持同步。
    • 主服务器很重要,包含了所有的改变操作(写)的日志。但是副本服务器集群包含有所有的主服务器数据,因此当主服务器挂掉了,就会在副本服务器上重新选取一个成为主服务器。
    • 每个复制集还有一个仲裁者(Arbiter),仲裁者不存储数据,只是负责通过心跳包来确认集群中集合的数量,
      并在主服务器选举的时候作为仲裁决定结果。

2.架构

  • 基本的架构由3台服务器组成:一个三成员的复制集

    • 三个有数据
    • 或者两个有数据,一个作为仲裁者。
  • 三个存储数据的复制集

    • 一个主,两个从库组成,主库宕机时,这两个从库都可以被选为主库。
  • 存在arbiter节点的复制集

    • 一个主库,一个从库,可以在选举中成为主库,一个arbiter节点,在选举中,只进行投票,不能成为主库。

3.Primary选举

  • 复制集通过replSetInitiate命令(或mongo shell的rs.initiate())进行初始化,初始化后各个成员间开始发送心跳消息,并发起Priamry选举操作,获得『大多数』成员投票支持的节点,会成为Primary其余节点成为Secondary。
    • 『大多数』的定义:
      假设复制集内投票成员数量为N,则大多数为 N/2 + 1,当复制集内存活成员数量不足大多数时,整个复制集将无法选举出Primary,复制集将无法提供写服务,处于只读状态。

4.成员说明
在这里插入图片描述

5.搭建复制集

  • 创建3个mongo容器
    • –replSet:集群名称
docker create --name mongo01 -p 27017:27017 -v mongo-data-01:/data/db mongo:4.0.3 --replSet "rs0" --bind_ip_all
docker create --name mongo02 -p 27018:27017 -v mongo-data-02:/data/db mongo:4.0.3 --replSet "rs0" --bind_ip_all
docker create --name mongo03 -p 27019:27017 -v mongo-data-03:/data/db mongo:4.0.3 --replSet "rs0" --bind_ip_all
  • 启动容器
docker start mongo01 mongo02 mongo03
  • 进入容器操作
docker exec -it mongo01 /bin/bash
  • 登录到mongo服务
mongo 192.168.56.132:27017
  • 初始化复制集集群
rs.initiate( {
	_id : "rs0",
	members: [
		{ _id: 0, host: "192.168.56.132:27017" },
		{ _id: 1, host: "192.168.56.132:27018" },
		{ _id: 2, host: "192.168.56.132:27019" }
	]
})
  • 响应
{
	"ok" : 1, #成功
	"operationTime" : Timestamp(1551619334, 1),
	"$clusterTime" : {
		"clusterTime" : Timestamp(1551619334, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	}
}

6.测试复制集群

  • 在主库插入数据
rs0:PRIMARY> use test

rs0:PRIMARY> db.user.insert({"id":1001,"name":"zhangsan"})
WriteResult({ "nInserted" : 1 })

rs0:PRIMARY> db.user.find()
{ "_id" : ObjectId("5c7bd5965504bcd309686907"), "id" : 1001, "name" : "zhangsan" }
  • 在复制库查询数据
#登陆其他mongodb
mongo 192.168.56.132:27018

rs0:SECONDARY> use test

rs0:SECONDARY> db.user.find()

#出错,默认情况下从库是不允许读写操作的
Error: error: { 
	"operationTime" : Timestamp(1551619556, 1),
	"ok" : 0,
	"errmsg" : "not master and slaveOk=false",
	"code" : 13435,
	"codeName" : "NotMasterNoSlaveOk",
	"$clusterTime" : {
		"clusterTime" : Timestamp(1551619556, 1),
		"signature" : {
			"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
			"keyId" : NumberLong(0)
		}
	}
}

#设置允许从库读取数据
rs0:SECONDARY> rs.slaveOk()

rs0:SECONDARY> db.user.find()
{ "_id" : ObjectId("5c7bd5965504bcd309686907"), "id" : 1001, "name" : "zhangsan" }

7.故障转移

  • 测试一:从节点宕机
    集群依然可以正常使用,可以读写操作。
  • 测试二:主节点宕机
    选举出新的主节点继续提供服务
  • 测试三:停止集群中的2个节点
    当前集群无法选举出Priamry,无法提供写操作,只能进行读操作

8.增加arbiter节点
当集群中的节点数为偶数时,如一主一从情况下,任意一节点宕机都无法选举出Priamry,无法提供写操作,加入arbiter节点后即可解决该问题。

  • 创建容器
docker create --name mongo04 -p 27020:27017 -v mongo-data-04:/data/db mongo:4.0.3 --replSet "rs0" --bind_ip_all
  • 启动容器
docker start mongo04
  • 在主节点执行
rs0:PRIMARY> rs.addArb("192.168.56.132:27020")
{
	"ok" : 1,
	"operationTime" : Timestamp(1551627454, 1),
	"$clusterTime" : {
	"clusterTime" : Timestamp(1551627454, 1),
	"signature" : {
		"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
		"keyId" : NumberLong(0)
	}
	}
}
  • 查询集群状态
rs.status()

通过测试,添加 arbiter节点后,如果集群节点数不满足N/2+1时,arbiter节点可作为“凑数”节点,可以选出主节点,继续提供服务。

MongoDB集群之分片集群

  • 分片(sharding)是MongoDB用来将大型集合分割到不同服务器(或者说一个集群)上所采用的方法。尽管分片起源于关系型数据库分区,但MongoDB分片完全又是另一回事。
  • 和MySQL分区方案相比,MongoDB的最大区别在于它几乎能自动完成所有事情,只要告诉MongoDB要分配数据,它就能自动维护数据在不同服务器之间的均衡。

1.简介
高数据量和吞吐量的数据库应用会对单机的性能造成较大压力,大的查询量会将单机的CPU耗尽,大的数据量对单机的存储压力较大,最终会耗尽系统的内存而将压力转移到磁盘IO上。

为了解决这些问题,有两个基本的方法: 垂直扩展和水平扩展。

  • 垂直扩展:增加更多的CPU和存储资源来扩展容量。
  • 水平扩展:将数据集分布在多个服务器上。水平扩展即分片。

分片为应对高吞吐量与大数据量提供了方法。使用分片减少了每个分片需要处理的请求数,因此,通过水平扩展,集群可以提高自己的存储容量和吞吐量。举例来说,当插入一条数据时,应用只需要访问存储这条数据的分片.

使用分片减少了每个分片存储的数据。例如,如果数据库1tb的数据集,并有4个分片,然后每个分片可能仅持有256GB的数据。如果有40个分片,那么每个切分可能只有25GB的数据。
在这里插入图片描述

2.优势

  • 对集群进行抽象,让集群“不可见”
    • MongoDB自带了一个叫做mongos的专有路由进程。mongos就是掌握统一路口的路由器,其会将客户端发来的请求准确无误的路由到集群中的一个或者一组服务器上,同时会把接收到的响应拼装起来发回到客户端。
  • 保证集群总是可读写
    • MongoDB通过多种途径来确保集群的可用性和可靠性。
    • 将MongoDB的分片和复制功能结合使用,在确保数据分片到多台服务器的同时,也确保了每分数据都有相应的备份,这样就可以确保有服务器换掉时,其他的从库可以立即接替坏掉的部分继续工作。
  • 使集群易于扩展
    • 当系统需要更多的空间和资源的时候,MongoDB使我们可以按需方便的扩充系统容

3.架构
在这里插入图片描述

组件说明
Config Server存储集群所有节点、分片数据路由信息。默认需要配置3个Config Server节点。
Mongos提供对外应用访问,所有操作均通过mongos执行。一般有多个mongos节点。数据迁移和数据自动平衡。
Mongod存储应用数据记录。一般有多个Mongod节点,达到数据分片目的。
  • Mongos本身并不持久化数据,Sharded cluster所有的元数据都会存储到Config Server,而用户的数据会分散存储到各个shard。Mongos启动后,会从配置服务器加载元数据,开始提供服务,将用户的请求正确路由到对应的分片。
  • 当数据写入时,MongoDB Cluster根据分片键设计写入数据。当外部语句发起数据查询时,MongoDB根据数据分布自动路由至指定节点返回数据。

4.集群中数据分布

  • 在一个shard server内部,MongoDB会把数据分为chunks,每个chunk代表这个shard server内部一部分数据。chunk的产生,会有以下两个用途:

    • Splitting:当一个chunk的大小超过配置中的chunk size时,MongoDB的后台进程会把这个chunk切分成更小的chunk,从而避免chunk过大的情况
    • Balancing:在MongoDB中,balancer是一个后台进程,负责chunk的迁移,从而均衡各个shard server的负载,系统初始1个chunk,chunk size默认值64M,生产库上选择适合业务的chunk size是最好的。mongoDB会自动拆分和迁移chunks。
  • chunk分裂及迁移

    • 随着数据的增长,其中的数据大小超过了配置的chunk size,默认是64M,则这个chunk就会分裂成两个。数据的增长会让chunk分裂得越来越多。
      在这里插入图片描述
    • 这时候,各个shard 上的chunk数量就会不平衡。mongos中的一个组件balancer 就会执行自动平衡。把chunk从chunk数量最多的shard节点挪动到数量最少的节点。

    在这里插入图片描述

  • chunksize

    • chunk的分裂和迁移非常消耗IO资源;chunk分裂的时机:在插入和更新,读数据不会分裂。
      • 小的chunksize:数据均衡是迁移速度快,数据分布更均匀。数据分裂频繁,路由节点消耗更多资源。
      • 大的chunksize:数据分裂少。数据块移动集中消耗IO资源。
    • chunkSize 对分裂及迁移的影响
      • MongoDB 默认的 chunkSize 为64MB,如无特殊需求,建议保持默认值;chunkSize 会直接影响到 chunk 分裂、迁移的行为。
      • chunkSize 越小,chunk 分裂及迁移越多,数据分布越均衡;反之,chunkSize 越大,chunk 分裂及迁移会更少,但可能导致数据分布不均。
      • chunk 自动分裂只会在数据写入时触发,所以如果将 chunkSize 改小,系统需要一定的时间来将 chunk 分裂到指定的大小。
      • chunk 只会分裂,不会合并,所以即使将 chunkSize 改大,现有的 chunk 数量不会减少,但 chunk 大小会随着写入不断增长,直到达到目标大小。

5.搭建集群
搭建1个config server集群

  • 创建3个config节点
    • –configsvr:设置节点类型为config server
    • –replSet :设置config server集群的名字
docker create --name configsvr01 \
-p 17000:27019 \
-v mongoconfigsvr-data01:/data/configdb \
mongo:4.0.3 \
--configsvr \
--replSet "rs_configsvr" \
--bind_ip_all

docker create --name configsvr02 \
-p 17001:27019 \
-v mongoconfigsvr-data02:/data/configdb \
mongo:4.0.3 \
--configsvr \
--replSet "rs_configsvr" \
--bind_ip_all

docker create --name configsvr03 \
-p 17002:27019 \
-v mongoconfigsvr-data03:/data/configdb \
mongo:4.0.3 \
--configsvr \
--replSet "rs_configsvr" \
--bind_ip_all
  • 启动服务
docker start configsvr01 configsvr02 configsvr03
  • 进去容器进行操作
docker exec -it configsvr01 /bin/bash
mongo 192.168.56.132:17000
  • 集群初始化
    • " configsvr: true " : 为true说明该集群是config server集群
rs.initiate(
{
	_id: "rs_configsvr",
	configsvr: true,
	members: [
		{ _id : 0, host : "172.16.55.185:17000" },
		{ _id : 1, host : "172.16.55.185:17001" },
		{ _id : 2, host : "172.16.55.185:17002" }
	]
	}
)

搭建2个shard集群
创建2个shard集群,每个集群都有3个数据节点

  • 集群一
    • –shardsvr:集群是 shard 集群
    • –replSet :第一个shard集群的名字
docker create --name shardsvr01 \
-p 37000:27018 \
-v mongoshardsvr-data-01:/data/db \
mongo:4.0.3 \
--replSet "rs_shardsvr1" \
--bind_ip_all \
--shardsvr

docker create --name shardsvr02 \
-p 37001:27018 \
-v mongoshardsvr-data-02:/data/db \
mongo:4.0.3 \
--replSet "rs_shardsvr1" \
--bind_ip_all \
--shardsvr

docker create --name shardsvr03 \
-p 37002:27018 \
-v mongoshardsvr-data-03:/data/db \
mongo:4.0.3 \
--replSet "rs_shardsvr1" \
--bind_ip_all \
--shardsvr
  • 集群二
docker create --name shardsvr04 -p 37003:27018 -v mongoshardsvr-data-04:/data/db mongo:4.0.3 --replSet "rs_shardsvr2" --bind_ip_all --shardsvr
docker create --name shardsvr05 -p 37004:27018 -v mongoshardsvr-data-05:/data/db mongo:4.0.3 --replSet "rs_shardsvr2" --bind_ip_all --shardsvr
docker create --name shardsvr06 -p 37005:27018 -v mongoshardsvr-data-06:/data/db mongo:4.0.3 --replSet "rs_shardsvr2" --bind_ip_all --shardsvr
  • 启动容器
docker start shardsvr01 shardsvr02 shardsvr03
docker start shardsvr04 shardsvr05 shardsvr06
  • 进去容器初始化集群一
docker exec -it shardsvr01 /bin/bash

mongo 192.168.56.132:37000

rs.initiate(
{
	_id: "rs_shardsvr1",
	members: [
		{ _id : 0, host : "192.168.56.132:37000" },
		{ _id : 1, host : "192.168.56.132:37001" },
		{ _id : 2, host : "192.168.56.132:37002" }
	]
	}
)
  • 进去容器初始化集群二
docker exec -it shardsvr04 /bin/bash

mongo 192.168.56.132:37003
rs.initiate(
{
	_id: "rs_shardsvr2",
	members: [
		{ _id : 0, host : "192.168.56.132:37003" },
		{ _id : 1, host : "192.168.56.132:37004" },
		{ _id : 2, host : "192.168.56.132:37005" }
	]
	}
)

创建mongos节点

  • 创建mongos节点容器(需要指定config服务)
    • –entrypoint:指定节点类型
    • –configdb:指定所有config server集群的节点(rs_configsvr是config server集群的名称)
docker create --name mongos \
-p 6666:27017 \
--entrypoint "mongos" \
mongo:4.0.3 \
--configdb rs_configsvr/192.168.56.132:17000,192.168.56.132:17001,192.168.56.132:17002 \
--bind_ip_all
  • 启动容器
docker start mongos
  • 进入mongos节点容器加入shard集群
docker exec -it mongos bash
mongo 192.168.56.132:6666

#添加shard节点
sh.addShard("rs_shardsvr1/192.168.56.132:37000,192.168.56.132:37001,192.168.56.132:37002")
sh.addShard("rs_shardsvr2/192.168.56.132:37003,192.168.56.132:37004,192.168.56.132:37005")
  • 在mongos节点中启动指定数据库的表的分片
#shard集群中有一个库test 
#给test表启用分片
sh.enableSharding("test")

#test库有一个表order,order表中有一个字段_id 通过_id的hash值进行分片
#设置分片规则,按照_id的hash进行区分
sh.shardCollection("test.order", {"_id": "hashed" })

#插入测试数据
use test
for (i = 1; i <= 1000; i=i+1){
	db.order.insert({'id':i , 'price': 100+i})
}
  • 分别在2个shard集群中查询数据进行测试
    • 两个集群中的数据和应该是1000条
mongo 192.168.56.132:37000
#使用test库
use test
#查看test库中order表的数据量 
db.order.count()
  • 集群其他操作(在mongos节点中的config库中执行)
    • use config:使用config库
      • db.databases.find() :列出所有数据库分片情况
      • db.collections.find() :查看分片的片键
      • sh.status() :查询分片集群的状态信息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值