《MongoDB扩展技术》读书笔记之二(完)

3.2  进行数据分片

配置服务器

配置服务器只是普通的mongod实例。shell

生产环境中,建议采用3个配置服务器,分布在不一样的故障域(failure domain)。数据库

不能运行任意个数的配置服务器,由于它们之间的交互是复杂的。缓存

另外,配置服务器并不使用“普通”mongod所采用的复制机制,并且也不该该按副本集或主从设置启动。只要把配置服务器看成未链接的普通mongod启动就好了。安全

$mongod
服务器


mongos

一个分片配置须要至少一个mongos(但无上限),它就像派对上的主人,会介绍宾客(即分片)相互认识。网络

集群管理都是经过mongos完成的!
架构

要记住:必须监视全部mongos进程。因此启动太多mongos也是麻烦,通常每一个应用程序服务器一个mongos进程就挺好。dom

$mongos --configdb ny-01,sf-01,moon-01工具


分片

设置分片须要在admin数据库中执行命令post

$mongo ny-02:27017/admin

添加一台服务器分片:> db.runCommand({"addShard" : "sf-02:27017", "name" : "this is shard1", "maxSize" : 20000}) #添加分片时,加上name字段,能够随意命名分片。#限制分片大小:默认状况下,MongoDB会在分片间均匀地分配数据。但若是一台是10T,另外一台是500G,应该使用maxSize来指定分片能增加到的最大存储量,单位MB。要记住maxSize更像是一个建议而非规定。MongoDB不会从maxSize处截断一个分片,或是组织它再增长哪怕一个字节,而是会中止将数据移动到该分片,固然还可能会挪走一部分数据。

添加一个副本集分片:> db.runCommand({"addShard" : "rs/rs1-a,rs1-c", "name" : "replicaSet1"})  #副本集叫作rs,mongos会连上任意一个集合成员来推出其余成员。因此只填一个成员也是能够的({"addShard" : "rs/rs1-a"})


启用分片:> db.adminCommand({"enableSharding" : "blog"})

对集合分片:> db.adminCommand({"shardCollection" : "blog.posts", key : {"date" : 1, "author" : 1}})#注意,命令里包含了数据库名blog.posts,而非posts。

若是要对一个已经包含数据的集合进行分片,数据片键上必须有索引。全部文档也都必须有片键(且值不能为null)。在集合分片完成后,才能够插入片键值为null的文档。


3.3  增减容量

无论MongoDB多么轻巧地操做,移动数据块仍然会加剧负载。即意味着,若是当前服务器容量耗尽时再添加分片可能会致使应用程序在一系列连锁反应下逐步瘫痪。(简单的例子,当前分片1的内存刚够容纳应用程序,而平衡器却让它往新分片2上发送一个数据块,使得分片A把数据块加载到内存,致使应用程序不得不开始访问磁盘)

添加更多分片(扩容)的教训:要尽早(在还有足够空间作调度时)添加分片,要在非忙时段再添加分片。

被添加的分片没必要是空的,但不能包含集群中已有的数据库。

移除分片:> db.runCommand({removeShard : "this is shard1"}) #注意!命令会当即返回“started successfully”。须要多运行几回,确认state从“ongoing”变为“completed”才意味着分片已经彻底清空,能够安全关闭。

要修改某个集群中的副本集,就假定它是独立运行的来进行:链接主服务器(而非经过mongos)并修改相应配置


第4章 使用集群

查询:读负载的同时,意味着你必需要接受过期的数据。(CAP原则)

#要经过mongos查询一台从机,必须设置“slave okay”就像:> db.getMongo().setSlaveOk()


使用集群时,就不能把整个集合看作是一个“即时快照”(snapshot in time)。例如:

【计数】mongos将count发送给每一个分片各自执行,mongos把结果累加后返回。若是有一个迁移正在进行,许多文档就会同时存在(进而被归入计数)于多个分片上。

【惟一索引】一般状况下,只有每次执行写操做时锁住整个集群(直到写操做确认成功),才能保证分片间不存在重复。所以,除片键之外任何键都难以保证惟一性(由于特定文档只能属于一个数据块,因此它只需在那个分片惟一,就能保证整个集群惟一)。

【更新】和惟一索引面临相同的麻烦,即无法保证操做在多个分片间只发生一次。所以更新单个文档时,必定要在条件中使用片键(update的第一个参数)。若是碰到奇怪的错误信息,考虑一下执行的操做是否对整个集群必须是原子化的。


1.6版里,除非声明了“out”参数,不然MapReduce会建立临时集合。mongos会维护本身的链接池并且从不关闭对分片的链接,所以,临时集合永远不会被清除(由于建立他们的链接从未被关闭)。


第5章  管理

对于单个MongoDB实例来讲,对集群的大部分管理工做均可以经过mongo shell来完成。

> db.printShardingStatus() #收集全部与集群有关的重要信息


应该链接什么?

若是执行的只是正常的读写或管理操做,答案永远是“mongos”,而不是分片,也不是配置服务器。

若是操做并不是寻常(为了直接查看某个分片的数据或是手动修改一个被搞乱的配置),可能就要链接配置服务器或分片了。

记住配置服务器和分片都只是通常的mongod而已。


5.2  监控

全部对监控单个节点的建议都试用于监控多个节点。

当机器数量变多时,网络会变得愈来愈重要。

若是可能,请保留一个已经连上集群的shell。建立一个链接要求MongoDB暂时给链接一个锁,假如mongod正好卡在写锁上,shell会一直尝试获取锁,进而永远不能完成链接。

mongostat:可用监控工具中最全面的,它能返回负载、页错误、链接数等信息。在集群中,能够每台服务器单独启动一个mongostat,也能够在某个mongos上运行mongostat --discover来分析出集群的全部成员并显示其状态。

Web管理界面:若是使用副本集,请确保使用 --rest 选项启动他们。http://localhost:28017/_replSet(mongod运行端口号27017+1000)


5.3  备份

在运行的集群上作备份实际上是很是有难度的。由于数据不停地被应用修改,并且被平衡器搬来搬去。若是要从备份中恢复,首先查看下配置服务器,明确哪些数据库应该在要被恢复的分片上,而后只从备份中恢复这些块的数据(还有mongorestore)

so,有条件的话,每一个分片都作replica  set吧!


5.4 关于架构的建议

建立应急站点:名字暗示了正在运行的是一个Web站点,很少对多数类型应用都适用。可让它经过缓存提供数据,或者直接把站点作成静态的。

挖一条‘虚拟护城河“:经过队列控制对集群的访问,阻止或最小化各种问题。队列可让应用程序在计划的中断时继续处理写入,或者至少避免丢失中断时还没有完成的写入。队列能够吸取短期内爆发的大量请求并释放一个和缓稳定的请求流,也就是俗称的削峰,而不是让洪流淹没集群。常见的队列包括Amazon SQS、RabbitMQ,甚至就是一个MongoDB集合(固然必定得把它和被保护的集群分开来)。当前,此方案的前提是,应用能够忍受微小的延迟。


5.5  错误处理

分片停机:全部命中该分片的读写都会返回错误。应用程序应该处理这种错误,以便平滑的保持有损服务,而不是完全宕机。

多数分片停机:若是副本集失去了多数成员,则没有服务器能自动成为主机,集合会变成只读。要确保应用程序仅发送给它带有slaveOkay选项的请求。

配置服务器停机:全部配置服务器必须协同工做。一台配置服务器停机不会当即对集群性能产生影响,可是会致使没法修改任何配置,好比添加mongos服务器。惟一特殊的是在数据迁移时,最后几步之一即是更新配置服务器,任何配置服务器宕机(即没法更新配置),都会让迁移回退。

mongos进程死掉:推荐在每一个应用服务器上跑一个mongos而且让每一个应用程序服务器和它本地的mongos通讯。同时,大部分驱动容许声明一组可链接的mongos,并会按顺序尝试链接。