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).如下图. 只有主节点提供写操作,(它也是默认的读节点) 从节点只提供读操作,实现了读写分离提高了性能.
应用程序通过驱动(也就是api或者shell)与Primary连接,所有的写操作都在Primary
上进行,同时primary
会将这些操作写到oplog(operation log mysql中binlog)中,secondary
通过异步复制oplog
,然后在本地数据集上执行oplog
中的操作 redo,这样就达到了数据的一致性。从这里可以看到,虽然secondary
和primary
维护的上同一份数据,但是其变更是要迟于primar
y的
如果应用程序对数据的实时性要求不太高,比如评论数据、聚合数据等,那么可以从secondary读取,这样可以做到读写分离和高并发。
案例
主节点插入数据
use test
db.comment.insert({"articleid":"100000","content":"今天天气真好,阳光明媚","userid":"1001","nickname":"Rose","createdatetime":new Date()})
登录从节点查看数据,并尝试插入
- 仲裁者 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实例添加到副本集作为仲裁者。 仲裁者不维护数据集。 仲裁者的目的是通过
- 响应其他副本集成员的心跳和选举请求来维护副本集中的仲裁。 因为它们不存储数据集,所以仲裁器可以是提供副本集仲裁功能的好方法,其资源成本比具有数据集的全功能副本集成员更便宜。
- 如果您的副本集具有偶数个成员,请添加仲裁者以获得主要选举中的“大多数”投票。 仲裁者不需要专用硬件。
- 仲裁者将永远是仲裁者,而主要人员可能会退出并成为次要人员,而次要人员可能成为选举期间的主要人员。
- 如果你的副本+主节点的个数是偶数,建议加一个仲裁者,形成奇数,容易满足大多数的投票。
- 如果你的副本+主节点的个数是奇数,可以不加仲裁者。
【拓展】修改优先级
比如,下面提升从节点的优先级:
- 1)先将配置导入cfg变量
myrs:SECONDARY> cfg=rs.conf()
- 2)然后修改值(ID号默认从0开始):
myrs:SECONDARY> cfg.members[1].priority=2
- 3)重新加载配置
myrs:SECONDARY> rs.reconfig(cfg)
稍等片刻会重新开始选举。
5)举例:
登录仲裁者节点,查看
故障测试:副本节点故障
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(横向扩展)方法。
如上图所示,一个集合(Collection1)有1T的数据,原本放在一个单独的数据库中,通过sharding,将这个集合的数据放在四个独立的shard中,每一个shard存储这个集合256G的数据。每个shard物理上是独立的数据库,但逻辑上共同组成一个数据库。
2)MongoDB的Sharding架构
- 查询路由(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,就达到了一个均衡的状态。
分裂(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)})}