关于片键
什么是分片?
--
>i分片就是将数据存储在多个机器上。当数据集超过单台服务器的容量,服务器的内存,磁盘IO都会有问题,即超过单台服务器的性能瓶颈。这时有两种解决方案,垂直和水平扩展,即为分片。
>1.垂直分片,就是增加CPU增加容量,但高性能系统的CPU和容量不成比例,这扩展成本大,并且有上限。
>2.水平分片,就是将数据分发到多个服务器,每个服务器是一个单独的数据库,各个服务器加起来组成一个逻辑数据量,把写压力和操作分流到不同服务器,提高容量和吞吐量。
>MongoDB的文档是无模式的,不固定结构因此只能进行水平分片,当块(Chunk)超过指定大小或者文档数超过最大文档数,MongoDB尝试分割这个块。若分割成功,把它标记为一个大块避免成分分割。拆分块的关键就是片键。
什么是MongoDB片键?
--
>w片键是文档的一个属性字段或者一个复合索引字段,一旦建立不能改变。片键是分片拆分数据的关键。片键的选择直接影响集群的性能。MongoDB首先根据片键划分chunks当块超过指定大小(默认64M),然后把块分到其他的分片上。**片键也是查询时常用的一个索引**,片键类型主要有以下几种:
>#### 1.递增片键
>这类片键比较常见,比如使用时间戳,日期,自增主键,object,_id等,此类片键的写入操作集中在一个分片服务器上,写入不具备分散性,这会导致单台服务器压力较大。但分割比较容易,这台服务器可能会成为性能瓶颈。
>#### 2.哈希片键
>使用一个哈希索引字段作为片键,优点是使数据在各个节点平均分布,数据写入可随机分发到每个分片的服务器上。把写入的压力分散到了各个服务器上,但读也是随机的,可能会命中更多的分片,一般具有**随机性的片键,查询隔离性能比较差**。
>#### 3.组合片键
>数据库中没有比较合适的片键时,或者是打算使用的片键基数太小(即变化少如星期只有7天可变化),可以选择另一个字段使用组合片键,甚至可以添加冗余字段来组合。一般是粗粒度+细粒度进行组合。
>#### 4.标签分片
>数据存储在指定的分片服务器上,可以为分片添加tag标签,然后指定响应的tag,比如10.\*.\*.\*(T)出现在shard0000上,11.\*.\*.\*(Q)出现在shard0001或shard0002上,就可以使用tag让均衡器指定分发
怎么选择,选择什么样的片键?
--
>s主要从以下几个方面来设计一个比较好的片键。
>#### 1.读和写的分布
>其中最重要的一点是读和写的分布,如果你总是往一台服务器中写,这台服务器将会成为写的瓶颈,则你的集群的写性能将会降低。这无关你的集群的节点多少。因为所有的写操作都在一个地方进行,因此,不应该使用单调的递增`_id`或时间戳作为片键,这将会导致一直往最后的副本集中添加数据。
>相类似的是如果读操作一直都在一个副本集上,那么最好祈祷你的任务能在机器内存的承受范围之内。通过副本集将读请求划分开能使你的工作数据集大小随着分片数线性扩展。这样的话能够将负载压力均分到各台机器的内存和磁盘上。
>#### 2.数据库的大小
>其次是数据块的大小,MongoDB能够将大的数据块划分成更小的,但这种情况仅仅在片键不同的情况下发生。如果你有巨量的数据文档都是用了相同的片键,那么你相应的会得到巨大的数据块,出现巨大块是非常不好的,不仅仅因为它会导致数据的不平均分布,还因为一旦这个数据块大小超过了某个值,那么就不能够在分片之间移动它了。
>#### 3.每个查询命中的分片数目
>最后一点,如果能够保证大部分的查询请求都能够命中尽可能少的分片,那最好。对于一个查询请求来说,其延迟直接取决于那个命中服务器的延迟,所以你命中的分片越少,理论上来说查询将会越快。这一点并不是硬性的规定,不过如果能充分考虑到那么应该是很有利的,因为数据块在分片上的分布,仅仅是近似的遵循片键的顺序,而不是严格的强制指定。