随着应用系统规模的增长,成本会变的越来越高,而且又是偶无法实现使用单台机器来处理负载压力,这种问题的一个解决方案就是汇聚大量低价且低处理能力的机器来解决问题。
MongoDB的分片就是为解决这种问题而设计的,把超大量数据使用更小的片进行分区存储,这样就不需要在单个机器上存储所有的数据或者承担全部压力。
为什么需要分片集群扩展系统而不是复制集???
MongoDB2.0的时候,复制集支持最多12个节点,7个可以投票。
MongoDB3.0的时候,复制集支持最多50个节点,7个可以投票。
如果需要更多的节点,可以选择主从复制,但是如果不想牺牲自动化灾备和故障转移机制而又需要超过最大可复制集限制,就需要使用”分片集群”
应用如果是高写入压力,从节点必须跟上写请求的节奏,发送请求给写满负载的从节点可能影响复制功能
复制伸缩无法解决读一致性的问题,由于复制是异步的,复制无法反映主节点最新的写入数据,因此,如果应用任意从 从节点读取数据,就无法保证最终用户看到的数据是一致性的。
此时我们有两个选择
分离一致性读到主节点和分离不一致性读的操作到从节点
分片
什么是分片集群???
分片是把大型数据通过分区成更小的可管理的片的过程。
对于大部分应用系统来说,在每个服务器上完成保存全部的数据是可以接受的,但随着数据量的增长,应用系统需要更大的读/写吞吐量,单台服务器可能无法满足需求
如果需要继续使用单台服务器,则解决方案是在多台服务器上分散存储这些数据,此方法在MongoDB中叫做”分片”
什么时候需要分片???
存储分布式:
MongoDB会把所有数据存储在最初dbpath参数指定的文件中,使用系统里的实用工具来监控MongoDB的使用情况。活着在mongo shell脚本里运行db.status()和db.collection.stats(),会分别输出当前数据库和集合的存储使用信息
负载分布式:
如果应用的数据量持续增长时,当超过最大可用内存时就会触发门栏。
首先要确定服务器和处理负载量以及可用内存的关系,例如使用SSD磁盘可以增加磁盘处理的每秒输入/输出操作
注意点:
预留空间: 不要等到磁盘100%用完并且机器过载的时候使用分片,因为分片本身就会被系统产生一定的额外压力。
因为自动化负载均衡的过程必须从过载的机器上转移压力到别的机器,如果系统已经过载,而没有发生负载均衡,则空的分片还是空的,过载的分片还是过载的,系统就会出现无法响应的情况。
理解分片集群的组件
只有在组件协同工作才可以让分片管理正常工作,当它们都正常工作时,这个整体就叫做分片集群,要理解MongoDB分片集群的工作原理,就需要了解所有组件分片集群的组件以及每个组件在集群中角色。
(最上方中间)的两个shard存储了应用程序的数据,在分片集群中,只有mongos路由器或者系统管理员才可以直接连接分片服务器节点。与不分片的结群一样,每个分片可以单独作为开发和测试的节点,但是生产环境下应该是个可复制集
mongos路由器(最中心):缓存了集群的元数据并使用它来路由操作到正确的分片服务器
配置服务器(最右):一直存储集群的元数据,包括那个分片包含哪些数据集
分片:存储应用程序数据
如上图所示:或者是单个mongod服务器或者是一个存储部分应用数据的可复制集。事实上,分片是分片集群中应用程序存储的唯一位置,用于测试,一个片可以是单个的mongod服务器,但是在生产环境中应该是可复制集,因为它会有自己的复制机制并且可以自动灾备和故障转移。可以连接到一个片,也可以连接到单个服务器节点或者可复制集。但是如果尝试在这个片上直接运行操作,则只能看到整个集群数据中的一部分。
mongos路由:路由操作
因为每个分片包含的只是总数据的一部分,所以需要某个东西来路由操作到适当的分片上。这就是mongos的作用所在。mongos路由是个可以直接转发所有读和写命令到正确的分片上的路由器。mongos提供给客户端单点连续集群的方式,这使得整个集群看起来就像单个节点一样。
mongos进程是轻量级的,不持久化的。因此,它们通常部署到应用程序服务器上,以确保只有一个网络来转发请求,也就是mongos管理每个分片的服务器连接
配置服务器:存储元数据
mongos进程是非持久化的,这意味着必须有某个东西来存储集群的元数据。这个工作就有配置服务器来做。这些元数据包含全局的集群配置信息,每个数据库,集合,特定数据的范围的位置,以及保存了跨片数据迁移历史的一个修改日志。
配置服务器保存的元数据是集群正常工作和更新维护的关键。每次mongos启动,mongos都会从配置服务器获取一份元数据拷贝。没有这些胡数据,就没有办法完整预览整个集群。这些元数据的重要性体现在通过配置服务器来保存分片集群设计和部署的策略数据。
上图中使用了三台配置服务器,但不是可复制集,它们需要比异步复制更强大的东西。当mongos进程写入它们时,使用的是两阶段提交协议。
什么是两阶段提交协议?
mongos服务器在本地内存里缓存了配置服务器的元数据。这些元数据有版本标识,当元数据修改的时候,它也会跟着改变。当带有旧数据的mongos尝试连接新版本元数据的分片时,它就会收到一个更新本地源数据拷贝的提醒。
如何在分片集群中分散数据?
MongoDB中数据的分组级别:
文档:
MongoDB中最小的数据单元。
{ name: “张三”, age: 18, address: “北京朝阳” }
块
根据某个字段值集群的一组文档,也叫做分片键
集合
数据库中一组命名的文档
数据库
包含文档的集合,系统最顶级的命名组
我们已经知道了数据的逻辑组织方式,那么如何与分片集群交互?在哪个分片上分区数据?
数据库级别,每个数据库的所有集合都存在自己的分片上
分区或者集合分块级别,集合里的文档被分散到多个片上,根据某个或者多个字段(分片键)进行分片
例如如下文档:
{
_id:ObjectId(“45354354354”),
username: “lisi”
}
如果集合中的所有文档都包含这种格式,就可以选择_id和username字段作为分片键,然后MongoDB就会使用每个文档中的这些信息来决定存储在哪个块中。
那么MongoDB如何决定的呢?
在底层核心中,MongoDB的分片时基于范围的,这意味着每个块表示一个范围的键值。当MongoDB查看某个文档以确定它属于哪个块时,首选会抽取分片键的值,然后找出包含分片键所在的块