zoukankan      html  css  js  c++  java
  • Mongodb 分片

    分片(Sharding)

       

    在Mongodb里面存在另一种集群,就是分片技术,可以满足MongoDB数据量大量增长的需求。

    分片是将数据拆分后分发到各个节点上,所以它的各个节点上的数据是不一样的,这是跟副本集最大的差别。

    分片好处之一是将数据拆分到不同节点,这样可以减少写的压力。

    当MongoDB存储海量的数据时,一台机器可能不足以存储数据,也可能不足以提供可接受的读写吞吐量。这时,我们就可以通过在多台机器上分割数据,使得数据库系统能存储和处理更多的数据。

    下图展示了在MongoDB中使用分片集群结构分布:

    上图中主要有如下所述三个主要组件:

    • Shard:

    用于存储实际的数据块,实际生产环境中一个shard server角色可由几台机器组个一个replica set承担,防止主机单点故障

    • Config Server:

    mongod实例,存储了整个 ClusterMetadata,其中包括 chunk信息。

    • Query Routers:

    前端路由,客户端由此接入,且让整个集群看上去像单一数据库,前端应用可以透明使用。

       

    sharding是MongoDB进行横向扩容的方法,sharding把一个集合的不同部分存储到不同的机器上,当一个数据库集合变得很大时,你只需要加入新的机器即可。sharding自动把集合的数据分布到新的服务器上,sharding自动实现数据和读写负载均衡。

    为了使集群具有sharding功能,首先需要建立一个sharding集群。然后就可以在集群内指定某个数据库是否启用sharding,在启用sharding的数据库内,可以选择哪个集合(collection)可以sharding,每个sharding的集合要有一个shard key。shard key用于决定该集合内的所有文档如何在集群内的机器上分布。shard key是一个字段,存在于每一个文档中。一个给定的分片保存了所有key值在其范围内的文档。shard key如同indexes一样,可以使单字段或多字段的。

    在一个shard内,mongodb还把文档分为chunks,每个chunk代表本shard内的一个小的范围。当一个chunk的大小超过chunk size时,mongodb把chunk切分为更小的chunk,但依然属于这个shard。

    MongoDB使用划分的群集平衡器迁移分片集群中的chunks。平衡器试图在群集中的所有分片上实现均匀的块。

    shard key的选择

    shard key的好坏直接影响到集群的性能,容量和能力。选择shard key要考虑数据的模式和你的应用程序读写数据库的方式。

    理想的shard key具有以下特点:

        1. 易于切分,最好是无限的。

        2. 具有高度的随机性。

        3. 应该是你的请求的主要字段。

    mongodb使用balancing进行分布式数据均衡。当一个shard与其它shard相比具有太多的chunk时,mongodb自动在shard间均衡数据,但应用层对此无感知。

    sharding会给集群带来一些负载,在以下情况发生时,可以考虑使用sharding:

    1. 数据接近或超过单个节点的存储容量。

    2.系统中活动working set的大小很快将要超过系统RAM的最大容量。

    3.系统有大量的写请求,单个mongodb实例不足以支持。

    设计系统时,如果预见到最终需要扩容时,考虑哪个集合需要sharding,并为其设计shard key。

    所有分片的集合在片键上都必须建索引,这是MongoDB自动执行的,所以如果选择某个字段作为片键但是基本不在这个字段做查询那么等于浪费了一个索引,而增加一个索引总是会使得插入操作变慢。

    唯一索引问题 如果集群在_id上进行了分片,则无法再在其他字段上建立唯一索引:之所以出现这个错误是因为MongoDB无法保证集群中除了片键以外其他字段的唯一性(验证了CAP理论),能保证片键的唯一性是因为文档根据片键进行切分,一个特定的文档只属于一个分片,MongoDB只要保证它在那个分片上唯一就在整个集群中唯一。

    mongos

     

    在集群中, mongos 负责将查询与写入分发到 分片 中.使用 mongos,应用有了访问集群的统一入口,而不需要直接访问集群的每个分片.

    通过缓存 配置服务器 中集群的元信息, mongos 可以得知数据所位于的分片. mongos 使用这些元信息将应用的读写请求分发到不同的分片, mongos 不存储集群 持续 的状态(意思是, mongos 可以随时被重启或者添加,而不会造成集群的数据丢失,也不会造成集群的异常.),并且占有较少的系统资源.

     

    查询隔离

    通常,分片环境中最快的查询是使用分片Key和配置服务器中的集群元数据进行路由到单个分片的查询。 这些目标操作使用分片键值来定位满足查询文档的Shard。

    为了获得更好的性能,最好在任何可能的时候都使用具有特定目标的操作。虽然有些操作不得不使用广播发送的形式,你也应该尽可能在进行操作时带有片键来尽可能使用具有特定目标的操作。

    广播查询:

    mongos实例向所有分片广播查询,除非mongos可以确定哪些分片存储此数据。

    片键:

    • 通常,一个经过计算的片键会有一定的"随机性",比如一个包含了其他字段加密哈希(例如 MD5或者SHA1)的片键,会使集群具有较好的写扩展性能.不过,随机的片键通常不会提供 查询隔离 的特性,而查询隔离同样是片键一个很重要的特性.

      片键决定了集群中一个集合的 documents 在不同 shards 中的分布.片键字段必须被索引,且在集合中的每条记录都不能为空,可以是单个字段或复合字段.

      片键在写入后不能被改变

      哈希片键使用单字段上的 哈希索引 进行数据在分片之间的分发.被选为片键的字段必须有足够大的基数,或者足够多的不同的值,对于单调递增的字段,如 ObjectId 或者时间戳,哈希索引效果更好.

      对于分片集合,只有_id字段索引和分片键上的索引或分片键是前缀的复合索引可以是唯一的:您不能在分片集合的其他字段上创建唯一索引。

      一些片键会使应用程序能够达到集群能够提供的最大的写性能,有一些则不能,比如使用默认的 _id 做片键的情况:

      在插入文档时,MongoDB会生成一个全局唯一的 ObjectId 标识符_id,不过,需要注意的一点是, 这个标识符的前几位代表时间戳,这意味着_id是以常规的并且可预测的方式增长。

      哈希分片

      散列分片使用单个字段的散列索引作为分片键,用于在分片集群中分割数据。

      散列分片以减少查询隔离为代价,在分片集群中提供更均匀的数据分发。 散列后,具有"关闭"分片键值的文档不太可能在同一个块或分片上 - 这个mongos更有可能执行广播发送的操作来完成给定的远程查询。 mongos可以将具有相等匹配的查询定位到单个分片。

      您选择作为散列分片键的字段应具有良好的基数或大量不同的值。 哈希键是分片键的理想选择,字段与ObjectId值或时间戳单调变化。 一个很好的例子是默认的_id字段,假设它只包含ObjectID值。

      范围分片

      基于范围的分片包括将数据划分为由分片键值确定的连续范围。 在此模型中,具有"关闭"分片键值的文档可能处于相同的块或分片中。 这允许在连续范围内读取目标文档的高效查询。 但是,读取和写入性能可能会随着较差的分片密钥选择而降低。

      Mongodb如何分散数据

      Mongodb分散数据的粒度不是文档,是块(chunk),块是根据一个片键或者一组片键所对应的文档的集合。Config Server中存储的是片键范围到块的对应关系。而不是每个片键到文档的对应关系(如果这样,数据量将非常庞大,这也是设计"块"的原因)。

      分片哪些集合?

      我的理解:为了优化写的压力的集合是我们要分片的。因为不支持join,所以这些分片的集合相关的集合是否在整个分片上,是没有影响的。

      分片键选择

      当分片键显示以下特征时,范围分片最有效:

      • 大的分片Key基数
      • 低的分片Key频率
      • 非单调变化分片键

      下图显示了使用字段X作为分片键的分片集群。 如果X显示的值具有较大的范围,低频率和非单调速率的变化,则插入的分布可能类似于以下内容:

       

      分片键选择:

      某些分片键会导致大多数的读或者写操作都集中在少数的分片上。这可能会导致单个分片负重不堪,其他分片无所事事。

      分片键不是查询的一部分,会导致大量的广播查询,也会影响性能。

      使用递增的序列(包含Mongodb自动生成的ID),最好使用hash分片。

      可以使用多个列的做范围分片,但是hash分片支持一个列。

      一般来说:

      • 作为第一个方案,你可以使用数据文档_id的哈希作为片键。在存在大量的不包含ID的查询中,还是不够完美,因为这样的话对多个文档的查询必将命中所有的分片。
      • 使用经常查询的业务字段进行范围分片,如,根据用户ID进行范围分片。但是如果存在这种情况:部分用户的数据量非常庞大,但是另外一部分用户几乎没有数据。那么将会导致分片分布不均衡。
      • 使用经常查询的业务字段+_id进行范围分片:这样既平均分布分片。又可以最大程度的保证查询的数据基本上可以分布在同一个分片上,即使不在同一个也不会很多。
  • 相关阅读:
    正交相机下实现滚轮按钮拖动,滚动滚轮缩放的功能
    C#标记 [已弃用] 的方法
    JDBC-Mybatis-Hibernate
    Data Structures and Algorithm Analysis in Java
    Maven
    Java面试
    Bootstrap
    CSS3
    HTML5
    JSON
  • 原文地址:https://www.cnblogs.com/xiaolang8762400/p/7257246.html
Copyright © 2011-2022 走看看