# 分片

* [分片概览](#分片概览)
  * [什么是分片](#什么是分片)
  * [为什么要分片](#为什么要分片)
  * [分片式集群](#分片式集群)
  * [分片键](#分片键)
  * [数据块](#数据块)
  * [数据均衡器](#数据均衡器)
  * [分片的策略](#分片的策略)
  * [分片的优点](#分片的优点)
    * [读/写](#读写)
    * [存储容量](#存储容量)
    * [高可用](#高可用)
  * [分片应该做的的思考](#分片应该做的的思考)

## 什么是分片

分片就是将一个大数据集切割成多个小数据集， 并将这些小数据集分发到不同机器/服务器上的一种方法， 从而能够存储更多的数据及提高吞吐量。

## 为什么要分片

对单个服务器而言，当数据量比较大，或者吞吐量比较大，都会给其带来极大的挑战。例如，高查询率会耗尽服务器的CPU容量。

解决上述情况的方法有两种：垂直和水平扩展。

垂直扩展通过增加单个服务器的容量和性能来提高性能，例如使用更强大的CPU，添加更多RAM或增加存储空间量。但是这种方式具有一定的局限性，一是具有技术的局限性，毕竟不可能无限制地增加单个机器的配置，其二是现在一般都是采用云服务器，而云提供商提供的硬件配置也是会有上限的。

水平扩展（分片是水平扩展的一种）是通过将数据集进行划并分发到多台机器上来提高性能。虽然单个机器的总体速度或容量可能不高，但每台机器只需处理整个数据集的的子集，所以可能会提供比单个高速大容量服务器更高的效率，而且机器的数量只需要根据数据集大小来进行扩展，这可能比单个机器的高端硬件的总体成本更低。不过这种方式会提高维护和部署的复杂度。

## 分片式集群

一个MongoDB的分片式集群包含以下的组件：

* shard：每个shard包含的是整个数据集的一个子集。每个shard都能被部署成副本集（replica set）的形式。
* mongos：mongos扮演的是“查询路由”的角色， 提供了一个让客户端和分片集群通信的接口。
* config servers：配置服务器的作用是存储集群的元数据和配置信息。从MongoDB3.4开始，配置服务器必须部署为副本集（CSRS）

架构图如下：

![](http://darouwan.com/wp-content/uploads/2018/12/2018120201552076.png)

为了更好地说明，博猪又重新画了一个图（画得不好的话请见谅）

![](http://darouwan.com/wp-content/uploads/2018/12/2018120201584442.png)

## 分片键

我们知道， 数据库包含集合，集合包含文档，文档里面有很多字段/键， 如上图。

对于分片键，它也不是什么高级的东东，它就是文档里面的一个字段，但是这个字段不是普通的字段，有一定的要求

* 它必须在所有文档中都出现
* 它必须是集合的一个索引，可以是单索引或复合索引的前缀索引（后面会讲到）
* 它的值一但定下，就不能改变，或者修改

当然，分片键还不止这些限制，详情可以查看下一篇文章

**那分片键有什么作用呢？** 它是数据分区，或者数据切割的前提， 从而实现数据分发到不同服务器上，减轻服务器的负担。

MongoDB通过分片键的范围来对数据进行分区，每一个区域的数据被视作一个数据块，分片架构如下： ![](http://darouwan.com/wp-content/uploads/2018/12/201812011353583.png)

如上图，x就是我们的分片键，它的范围是 minKey\~maxKey, MongoDB根据它的范围把整个数据集分成了四个数据块。

注：MongoDB分片的级别是**精确到文档的，**， 所以不一定所有的集合都需要分片，允许分片集合和非分片集合共存。

## 数据块

如上图， 我们知道，数据块就是文档的集合。

那为什么会出现数据块这个东东呢？ 首先，MongoDB分片的级别是**精确到文档的，** 也就是说，一个集合如果有100个文档，就可以切割成100份，再把这100份分发到不同机器上，但这样做是没意义的，还不如直接存储在单机上。所以就有了数据块这个东东，通过一定的策略，把100个文档切割成4个数据块，也就是4分，这样检索和分发的时候不就更为简便？

**注： MongoDB数据的迁移是以数据块的数量为单位的，不是以文档的大小或数量。**

## 数据均衡器

数据均衡器扮演的是数据块迁移的角色。

因为一开始由于切割策略的不同，必然会导致每台机器上的数据块的数量不同（当然大牛不会出现）， 这时，均衡器就会不断检测每台机器上数据块的数量，并把数据块多移到数据块少的，从而实现数据的均匀分布（均匀分布才不会造成单台机器负担过重）

详情参见[这里](https://docs.mongodb.com/manual/core/sharding-data-partitioning/)在后台运行以跨分片迁移块。

## 分片的策略

* 哈希分片
* 范围分片

详情查看下一篇文章

## 分片的优点

### 读/写

可以把读请求，写请求都分发到不同机器上，不像副本集写请求是在单台机器上的，所以吞吐量会比较高

### 存储容量

副本集是把一份数据复制三份放到三台机器上，分片是把一份数据切割成三份放到三台机器上，所以存储的数据量更大。

### 高可用

副本集相对于分片可用性更高，但是分片也具有一定的可用性，这是因为即使一个或多个分片不可用，剩余可用的分片也可以继续执行部分读/写操作。

注：在生产环境中，应将各个分片部署为副本集，从而提供更高的冗余和可用性。

## 分片应该做的的思考

* 分片键要认真选择，这关系到整个集群的性能和效率（分片键要修改的话，需要推倒重来）
* 分片集群基础架构要求和复杂性需要仔细规划，执行和维护。
* 等等..

补充：<https://www.cnblogs.com/Jtianlin/p/5128977.html>
