Mongo

一、副本集

1.复制

一个mongod服务器挂了就完了,使用复制可以把数据副本保存在多台服务器。在MongoDB里,创建一个副本集就可以使用复制功能。副本集是一组服务器,主服务器用来处理客户端请求,备份服务器用来保存主服务器的数据副本,如果主服务器崩了,备份服务器会自动把一个成员升级成主。

2.建立副本集

mongo --nodb                                //启动mongo shell,但不连接到任何mongod
replicaSet  = new ReplSetTest({"nodes":3})  //创建3个节点的副本集
replicaSet.startSet()                       //启动3个mongod进程
replicaSet.initiate()                       //配置复制功能

现在有三个mongod进程,分别运行在31000,31001,31002

conn1 = new Mongo("localhost:31000")        //连接运行在31000的mongod。

提示符变成testReplSet:primary,说明连上了主节点。
备份节点的数据可能会落后于主节点,所以如果在备份节点上做查询,可能会得到错误提示,说当前不是主节点。这样做为了保护应用程序,以免连接到备份节点读到过期数据。如果你非要允许从备份节点读:conn2.slaveOk()。这个语句是为conn2这个连接设置的,而不是这个库。

而且,备份节点不能执行写操作,它只通过复制功能写入数据。副本集也支持自动故障转移,主节点挂了后,第一个检测到它挂了的节点可以成为新的主节点。

primaryDB.adminCommand({"shutdown":1})  //关掉主节点
secondaryDB.isMaster()                  //上从节点执行下看看谁是新的主节点。

3.副本集的组成

1.同步
复制是用于在多台服务器之间备份数据,复制功能是使用操作日志oplog实现,操作日志包含主节点的每一次写操作。每个备份节点都维护着自己的oplog,记录着每一次从主节点复制数据的操作。
如果备份节点挂掉了,下次恢复的时候再从最后一个oplog开始同步,如果oplog有重复也没有关系,oplog中的操作执行一次和执行多次是一样的,但也要保证顺序。
对于同步,副本集刚开始是要做初始化同步,在这个时间段内是不可以成为正常的副本的,只有初始化完成了才可以进入普通同步状态,初始化同步就是选一个副本把oplog复制过来。
2.心跳
为了维护副本的最新视图,每隔2s每个成员就会向其他成员发送心跳。他们需要知道谁是主节点,谁挂掉了,谁可以是同步源。
3.选举
当一个成员无法连接到主节点,就发起成为主节点的请求给他能连接到的所有节点。

二、分片

1.什么时候需要分片?

当一个单机的存储容量无法支撑的时候,可以用分片做水平扩容;还有一种就是单机qps扛不住,可以把请求分散到多个分片上去。

2. 分片集群都包含什么?

多个mongos,多个config server,多个分片。
mongos负责接收client请求,然后去config server去找数据所在的位置,再去某一个分片请求数据,返回给client。
mongos的存在提供了一种单点连集群的方式,看起来和单点一样,让用户对分片无感知,mongos是没有持久化的,所以不保存任何配置信息。config server存储集群元数据,包含全局集群的配置信息,每个数据库集合、特定数据的范围的位置,以及保存了跨片数据迁移历史的一个修改日志。配置服务器不是可复制集群,它们需要比异步复制更强大的东西,当mongos进程写入它们时,使用的是两端提交协议。而且,必须在分片集群生产环境下部署3太配置服务器,而且必须部署在单独的冗余机器上。

3.分片中的数据

分片中的数据是以chunk为单位,一个chunk中可能包含多个document,它是根据分片健分出来的,所以,mongo的分区是基于collection的,从一个集合里面选择部分文档组合成一个chunk,这就相当于mysql从一个表里面选择几行作为一块。
下面就说一下,mongoDB自动分片,自动分片说的是给单个集合分片,不需要应用参与。就为了分片单个集合,定义出了块的概念,它是一个分片健的逻辑分组文档。

4. MongoDB自动分片

MongoDB分片是基于范围的,也就是每个块表示一个范围的健值。比如你先在有个文档有个age字段,然后你用age做分片键值(正常不太可能),分片有A和B两个。你分出来可能这样:
开始-------结束---片
负无穷-----10-----A
10-----------20-----B
20-----------30-----A
30-----------40-----B
这样就可以确定文档所属的块,然后决定它应该被发到哪个分片。
虽然分片是自动的,但前提是你要在数据库里提前为集合做好设置开启才行。

5.分割与迁移

你把数据存储到mongo上,它会自动按照分片健做把document分到不同的chunk,但是如果有的chunk是有大小限制的,如果10-20的数据太多了,chunk超出阈值了怎么办?就要分割了。那么迁移,就是说,可能各个分片之间,数据不均衡,很多chunk集中在一个分片上,那么分片之间就要做迁移了。

6. 分片集群中的查询

虽然对于用户来说mongo分不分片,用起来都是一样的,但实际执行起来肯定是不同的,下面看一下使用了分片的mongo是怎么查询的。
首先,我要查的文档可能是分布在多个分片,也可能是一个分片,那么我要求请求哪些分片呢?记住配置服务器维护了分片键值到分片服务器的信息,如果查询语句包含片健,就能快速定位到分片,如果不包含片健,那完了,要遍历所有分片了。

7. 分片中的索引

无论你插入定位的多么完美,其实,最终所有的数据都只是在一个分片上,如果你这个分片查的慢,整个集群都慢。
未分片模式下,索引是优化查询的手段。
关于分片集群的索引记住下面:每个分片维护自己的索引,它遵循分片集合在每个分片上都应该建立相同的索引原则,分片集合只允许在_id字段和分片健上建立唯一索引。

8.分片健的选择

如果你分片健选择的不好,很多性能都会变得很差,而且你分片健一旦选择,后面是不能修改的,选择分片键可能出现的糟糕情况:
热点 某些分片会造成数据都分在同一个chunk或者同一个分片上,所有流量还是打到一个分片上。
不可分割的数据块 过于粗粒度的分片健导致许多文档使用相同的分片健,这些文档可能不能分散到不同的数据块??chunksize也不控制不了吗?是的,比如你按照username做分片健,如果一个username直接插入了10GB数据,正常情况超过chuncksize会给你分,但如果你的分片健都是一样的,它也没办法给你分了。

如果你按照objectId作为分片健,因为ObjectID完全自增,比如你插入了1000条文档了,那你插入1001,1002,1003的时候,因为mongo根本没有见过1000到maxKey之间的数字,它根本不知道怎么给你分,只能继续插入,所以不管你怎么插入,都只会插在这一个分片里。你可以给ObjectID做一个hash,让mongo用这个hash去分,虽然数据可以均匀的分布在不同的分片上,但是你做范围查询的时候可能就要去请求所有分片了。

你可能感兴趣的:(Mongo)