上篇文章中开启了Mongodb的分布式大门,虽然对其内含并不很清楚,但已大概知其意。提到分片(shard),从字面意思上看就是将某个东西切片,在程序中就是将某个数据集,按某个逻辑分成多个子集。而上面的逻辑即是分片时片键所依赖的准则,即Mongodb会根据片键(key)来决定数据应该存放到哪个片键中。另外,在分片中会用到数学中的区间,包括开区间闭区间等。
举个例子来说,当数据库中存在一张Student表,该表有个字段SID(自增主键,不会重复)时,将这个字段作为主键:
[a, g),[g, t)....... 片键暂时按这个逻辑进行划分进行解释一下(当然,实际中是不会取这样的片键的,这块是有个坑的,后续再解释):
按上面的区间[a, g)对应shard1,[g, t)对应shard2......,即数据中SID大于等于a并且小于g会被分配到shard1中,SID为hdfag的数据会被存放到shard2中,这是因为mongodb会基于上述区间来对数据进行分块。当然这种一个分片一个区间的划分方式是最简单的划分方式,在实际中使用到的也是比较少的。为什么呢,假设一下如果系统中数据量变的非常大,达到几个G几百个G甚至上T级,按上诉的分配方式看起来不会出现问题,但是如果后续添加的数据多在g到t之间,那么很容易导致shard2负载过大,而由于Mongodb是拥有自动平衡负载的特性的,一旦出现负载失衡的情况而且又达到一定程度后就会触发数据在块之间的复制,而数据量又比较大,这样的数据复制或者移动会对服务器造成很大的压力、甚至会导致宕机,到时候的情况就不是可以预料的了。还有一种情况就是在集群中添加新的分片时,mongodb为保证集群的负载均衡也可能触发数据的移动(而且这种情况虽然通过选择添加shard位置能有缓解,但并不是有效的)仍旧会对服务器造成非常大的压力。
(集合的分片详解:mongo中初始时集合是only一个区间,在数据量达到一定程度之后,mongo会在该集合的接近中点处进行分片[a , m)与[m , z],假设后续数据多存于[a , m)区间中,当该片数据量到达mongo默认或者用户设置的临界比例后,会将[a , m)区间从中点继续切分。即当数据库中数据量越来越多时,mongo会产生更多的分片)
由此,引出了一分片中多区间的划分方式。即一个分片中可以有多个区间,按上面的例子,在shard1对应的区间为[a,d)和[d,g),假设系统到后期[a,d)区间的数据为300G,[d,g)区间的数据为100G,此时的该片中数据分为两片。则无论此时需要添加新的分片还是解决数据负载,都会发现情况会有一定的改善,如下图:
这种情况下,只需要移动将每个分片中的小数据块分别移动到新分片中即可(共移动数据300G),相比之前的单分区有了很大的改善,单分区情境图如下:
上面所提到的mongo自动平衡分片间数据的技术即是"平衡"也称为数据迁移,其核心为平衡器。这也是mongo的一大优势,可以自动化进行数据迁移实现负载均衡。但这也是它的一个权限,为什么呢?想想啊,一是因为这种自动化很容易出现一种情况就是一些数据非常不稳定,即在不同的分片间由于负载均衡的自动化被来回移动,给服务器造成很大的压力;二是如果某些用户场景下,如果需要某些数据保存到分片A中,但是不知不觉它已经被移动到了分片B中。针对这些情况,可以关闭mongo的平衡器或者重新进行分片。