MongoDB集群介绍

高可用集群配置HA(High Availability Cluster)

主要有以下几种方法,了解即可

  • 主从方式
  • 双机双工方式
  • 集群工作方式

MongoDB集群配置的几种方案也遵循了这几种解决办法。

1.Master-Slave主从

在高版本的MongoDB(3.2以上)中,官方已经不推荐使用主从模式,取而代之的,是使用复制集(Replica Set)的方式做主备处理。

2.Relica Set复制集(副本集)

redis master slave

1)背景:

MongoDB,可以支持使用单机模式提供服务,但是在实际的生产环境中,单机模式将面临很大的风险,一旦这个数据库服务出现问题,就会导致线上的服务出现错误甚至崩溃。因此,在实际生产环境下,需要对MongoDB做相应的主备处理,提高数据库服务的可用性.所以使用Relica Set的形式

2)目的:

1.为了防止单点故障就需要引副本(Replication),当发生硬件故障或者其它原因造成的宕机时,可以使用副本进行恢复,最好能够自动的故障转移(failover)。

2.为了读写分离,将读的请求分流到副本上,减轻主(Primary)的读压力。

3)组成:

  • 主节点 primary
  • 从节点(副本节点) secondary
  • 复制集由一组mongod实例组成,它有且只有一个主节点(primary),可以包含一个或多个从节点(secondary).如下图. 只有主节点提供写操作,(它也是默认的读节点) 从节点只提供读操作,实现了读写分离提高了性能.

mongodb集群ip全部很改 mongodb 集群_数据库

应用程序通过驱动(也就是api或者shell)与Primary连接,所有的写操作都在Primary上进行,同时primary会将这些操作写到oplog(operation log mysql中binlog)中secondary通过异步复制oplog,然后在本地数据集上执行oplog中的操作 redo,这样就达到了数据的一致性。从这里可以看到,虽然secondaryprimary维护的上同一份数据,但是其变更是要迟于primary的

如果应用程序对数据的实时性要求不太高,比如评论数据、聚合数据等,那么可以从secondary读取,这样可以做到读写分离和高并发。

案例

主节点插入数据

use test
db.comment.insert({"articleid":"100000","content":"今天天气真好,阳光明媚","userid":"1001","nickname":"Rose","createdatetime":new Date()})

登录从节点查看数据,并尝试插入

mongodb集群ip全部很改 mongodb 集群_mongodb集群ip全部很改_02

  • 仲裁者 Arbiter
  • 从节点故障不影响主节点的读写
  • 当主节点突然故障后,MongoDB有自己的机制,会通过选举,在从节点中选出一个节点作为新的主节点。
  • 而仲裁者就起到了选举的作用,它不保留任何数据的副本,只具有选举作用。

4)选举规则

MongoDB在副本集中,会自动进行主节点的选举,主节点选举的触发条件:
1) 主节点故障 (软件故障,硬盘CPU等原因)
2) 主节点网络不可达(默认心跳信息为10秒 类似zookeeper的选举,定期监控
3) 人工干预(rs.stepDown(600))

选举规则是根据票数来决定谁获胜:

  • 票数最高,且获得了“大多数”成员的投票支持的节点获胜。
    “大多数”的定义为:假设复制集内投票成员数量为N,则大多数为 N/2 + 1。例如:3个投票成员,
    *则大多数的值是2。*当复制集内存活成员数量不足大多数时,整个复制集将无法选举出Primary,
    复制集将无法提供写服务,处于只读状态。
  • 若票数相同,且都获得了“大多数”成员的投票支持的,数据新的节点获胜。
    数据的新旧是通过操作日志oplog来对比的。

在获得票数的时候,优先级(priority)参数影响重大。

  • 可以通过设置优先级(priority)来设置额外票数。优先级即权重,取值为0-1000,相当于可额外增加
    0-1000的票数,优先级的值越大,就越可能获得多数成员的投票(votes)数。指定较高的值可使成员
    更有资格成为主要成员,更低的值可使成员更不符合条件。
    默认情况下,优先级的值是1
  • 默认可以认为都已经有了一票。但仲裁者节点,优先级是0,(要注意是,官方说了,仲裁者节点的优先级必须是0,不能是别的值。即不具备选举权,但具有
    投票权)
  • 关于仲裁者的额外说明:
  • 您可以将额外的mongod实例添加到副本集作为仲裁者。 仲裁者不维护数据集。 仲裁者的目的是通过
  • 响应其他副本集成员的心跳和选举请求来维护副本集中的仲裁。 因为它们不存储数据集,所以仲裁器可以是提供副本集仲裁功能的好方法,其资源成本比具有数据集的全功能副本集成员更便宜。
  • 如果您的副本集具有偶数个成员,请添加仲裁者以获得主要选举中的“大多数”投票。 仲裁者不需要专用硬件。
  • 仲裁者将永远是仲裁者,而主要人员可能会退出并成为次要人员,而次要人员可能成为选举期间的主要人员。
  • 如果你的副本+主节点的个数是偶数,建议加一个仲裁者,形成奇数,容易满足大多数的投票。
  • 如果你的副本+主节点的个数是奇数,可以不加仲裁者。

mongodb集群ip全部很改 mongodb 集群_副本集_03


【拓展】修改优先级

比如,下面提升从节点的优先级:

  • 1)先将配置导入cfg变量
myrs:SECONDARY> cfg=rs.conf()
  • 2)然后修改值(ID号默认从0开始):
myrs:SECONDARY> cfg.members[1].priority=2
  • 3)重新加载配置
myrs:SECONDARY> rs.reconfig(cfg)

稍等片刻会重新开始选举。

5)举例:

mongodb集群ip全部很改 mongodb 集群_hadoop_04

登录仲裁者节点,查看

故障测试:副本节点故障

mongod -f /mongodb/replica_sets/myrs_27018/mongod.conf

故障测试:主节点故障

3.Sharding分片模式 (Share dis)

1)分片模式

MongoDB分片技术类似MySQL的水平切分和垂直切分,数据库主要由两种方式做Sharding:垂直扩展和横向切分。

  • 垂直扩展的方式就是进行集群扩展,添加更多的CPU,内存,磁盘空间等。
  • 横向切分则是通过数据分片的方式,通过集群(多台机器)统一提供服务,线性可扩展性

redis 中 slots 到各个master实现数据的分片

所谓sharding就是将同一个集合的不同子集分发存储到不同的**机器(shard)**上,Mongodb使用sharding机制来支持超大数据量,将不同的CRUD路由到不同的机器上执行,提到了数据库的吞吐性能。由此可见,sharding是非常常见的scale out(横向扩展)方法。

mongodb集群ip全部很改 mongodb 集群_副本集_05

如上图所示,一个集合(Collection1)有1T的数据,原本放在一个单独的数据库中,通过sharding,将这个集合的数据放在四个独立的shard中,每一个shard存储这个集合256G的数据。每个shard物理上是独立的数据库,但逻辑上共同组成一个数据库。

2)MongoDB的Sharding架构

mongodb集群ip全部很改 mongodb 集群_数据库_06

  • 查询路由(Query Routers)
  • 路由就是mongos的实例,客户端直接连接mongos,由mongos把读写请求路由到指定的Shard上去。
  • 一个Sharding集群,可以有一个mongos,也可以有多mongos以减轻客户端请求的压力。
  • 配置服务器(Config servers)**
  • 保存集群的元数据(metadata),即数据的哪一部分放在哪一个shard上,router将会利用这些元数据将请求分发到对应的shards上,shards上chunk的迁移也是config server来控制的。
  • 从MongoDB 3.4开始,必须将配置服务器部署为副本集(CSRS)。

类似于NameNode,Hbase中的 Hmaster,Zookeeper

  • 数据分片(Shards)
  • 用来保存数据,保证数据的高可用性和一致性。可以是一个单独的mongod实例,也可以是一个副本集。
  • 在生产环境下Shard一般是一个Replica Set,以防止该数据片的单点故障。存储在mongod上的数据以chunk为基本单位,默认的大小为64M,后面会介绍shard上数据的分裂(split)与迁移(migration)

**类似于hdfs 中的 block --> 128M **

hbase region

3)数据分割(data partition)

从前文知道,MongoDB在collection这个级别进行数据的切块,称之为sharding。块的最小粒度是chunk,其大小(chunkSize)默认为64M

当一个集合的数据量超过chunkSize的时候,就会被拆分成两个chunk,这个过程称为分裂(splitting)。那么按照什么原则将一个chunk上的数据拆分成两个chunk,这就是片键(Sharding key)的作用,MongoDB使用 基于哈希的分片方式(随机平均分配)或者基于范围的分片方式(数值大小分配) 。

  • 分片规则一:哈希策略
  • 对于 基于哈希的分片 ,MongoDB计算一个字段的哈希值,并用这个哈希值来创建数据块.
    在使用基于哈希分片的系统中,拥有”相近”片键的文档 很可能不会 存储在同一个数据块中,因此数据的分
    离性更好一些.
    eg:使用nickname作为片键,根据其值的哈希值进行数据分片
  • 分片规则二:范围策略
  • 对于 基于范围的分片 ,MongoDB按照片键的范围把数据分成不同部分.假设有一个数字的片键:想象一个
    从负无穷到正无穷的直线,每一个片键的值都在直线上画了一个点.MongoDB把这条直线划分为更短的不
    重叠的片段,并称之为 数据块 ,每个数据块包含了片键在一定范围内的数据.
    在使用片键做范围划分的系统中,拥有”相近”片键的文档很可能存储在同一个数据块中,因此也会存储在同
    一个分片中.
    eg:如使用作者年龄字段作为片键,按照点赞数的值进行分片:

Sharding key是被索引的字段,通过sharding key,就可以把数据均分到两个chunk,每一个document在哪一个chunk上,这就是元数据信息。元数据信息存放在config server上,方便router使用。

如果sharding cluster中有多个shard,那么不同shard上的chunk数目可能是不一致的,这个时候会有一个后台进程(balancer)来迁移(migrate)chunk,从chunk数目最多的shard迁移到chunk数目最少的chunk,直到达到均衡的状态。迁移的过程对应用程序来说是透明的。

如下图所示,迁移之前ShardA ShardB上都有3个chunk,而Shard C上只有一个Chunk。通过从ShardB上迁移一个chunk到ShardC,就达到了一个均衡的状态。

mongodb集群ip全部很改 mongodb 集群_副本集_07

分裂(plitting)和迁移(migration)的目的是为了让数据在shards之间均匀分布,其根本目标是为了将对数据的CRUD操作均衡地分发到各个shard,提高集群的并发性能。

4)举例:

在这里插入图片描述

sh.shardCollection("articledb.result",{"nickname":"hashed"})
for(var i=1;i<=1000;i++){db.result.insert({_id:i+"",nickname:"zqq"+i})}
use config
db.settings.save({ _id:"chunksize", value: 1 })
sh.shardCollection("articledb.people",{"age":1})
for(var i=1;i<=20000;i++){db.people.save({"name":"TTYTTYTTYTTYTTYTTYTTYTTYTTYTTYTTYTTYTTYTTYTTYTTYTTYTTYTTY"+i,"age":NumberInt(i%120)})}