# 分片或数据分区

数据分区(也称为分片)是一种将大数据库(DB)分解为许多较小部分的技术。它是将一个DBtable分割到多台机器上，以提高应用程序的可管理性、性能、可用性和负载平衡的过程。使用数据分片的理由是，在一定的扩展点之后，通过增加更多的机器来实现水平扩展比通过增加更强大的服务器来实现垂直扩展更便宜、更可行。

## 1. 分区方法

可以使用许多不同的方案来决定如何将应用程序数据库分解为多个较小的数据库。以下是各种大规模应用程序使用的三种最流行的方案。

a. 水平分区:在这种方案中，我们将不同的行放入不同的表中。例如，如果我们在一个表中存储不同的位置，我们可以决定将ZIP编码小于10000的位置存储在一个表中，而ZIP编码大于10000的位置存储在一个单独的表中。这也被称为基于范围的分片，因为我们将不同范围的数据存储在不同的表中。

这种方法的关键问题是，如果没有仔细选择用于分片的范围的值，那么分区方案将导致服务器不平衡。在前面的示例中，根据邮政编码划分位置假设地方将均匀地分布在不同的邮政编码中。这种假设是不成立的，因为在像曼哈顿这样人口稠密的地区，与其郊区城市相比，会有很多地方。

b. 垂直分区(Vertical Partitioning):在这个方案中，我们将数据划分为与特定特性相关的表存储到它们自己的服务器上。例如，如果我们正在构建一个类似Instagram的应用程序，我们需要存储与用户相关的数据，他们上传的所有照片和他们关注的人，我们可以决定将用户的个人信息放在一个数据库服务器上，朋友列表放在另一个服务器上，照片放在第三个服务器上。

垂直分区易于实现，对应用程序的影响很小。这种方法的主要问题是,如果我们的应用程序的经验更多的增长,然后可能需要进一步的分区特性具体DB跨各种服务器(例如,单个服务器不可能处理所有的元数据由1.4亿用户查询100亿张照片)。

c. 基于目录的分区:解决上述方案中提到的问题的一种松散耦合的方法是创建一个查找服务，它知道当前的分区方案，并将其从数据库访问代码中抽象出来。因此，为了找出特定的数据实体驻留在哪里，我们查询保存每个元组键到其DB服务器之间映射的目录服务器。这种松散耦合的方法意味着我们可以在不影响应用程序的情况下执行诸如将服务器添加到DB池或更改分区方案等任务。

## 2. 划分的标准

a. 基于键或基于哈希的分区:在此方案下，我们将哈希函数应用于我们所存储的实体的某些键属性，从而产生分区号。例如，如果我们有100个DB服务器，我们的ID是一个数字值，每次插入一条新记录都会增加1。在本例中，哈希函数可以是' ID % 100 '，这将为我们提供可以存储该记录的服务器号。这种方法应该可以确保在服务器之间统一分配数据。这种方法的基本问题是，它有效地修复了DB服务器的总数，因为添加新服务器意味着更改哈希函数，这将需要重新分配数据和服务的停机时间。解决这个问题的一种方法是使用一致的哈希。

b. 列表分区:I在这个方案中，每个分区都被分配了一个值列表，所以每当我们想要插入一个新记录时，我们会看到哪个分区包含我们的键，然后将它存储在那里。例如，我们可以决定居住在冰岛、挪威、瑞典、芬兰或丹麦的所有用户将存储在一个北欧国家的分区中。

c. 轮循分区(Round-robin partitioning): 这是一种非常简单的分区策略，可以保证数据的均匀分布。对于' n '分区，' i '元组被赋值给partition (i mod n)。

d. 复合划分:在这种划分方案下，我们将上述任何一种划分方案组合起来，设计出一种新的划分方案。例如，首先应用列表分区，然后应用基于哈希的分区。一致的哈希可以被认为是哈希和列表分区的组合，其中哈希将键空间减少到可以列出的大小。

## 3. 切分的常见问题

在一个分片数据库上，可以执行的不同操作有一些额外的约束。这些限制大多是由于这样一个事实，即跨多个表或同一表中的多个行进行的操作将不再在同一服务器上运行。下面是一些由分片引入的约束和额外的复杂性:

a. 连接和去正规化: 对运行在一台服务器上的数据库执行连接是简单的，但一旦数据库被分区并分布在多台机器上，那么执行跨越数据库碎片的连接通常是不可行的。这样的连接不会提高性能，因为数据必须从多个服务器编译。这个问题的一种常见的解决方案是对数据库进行非规范化处理，这样就可以从单个表执行以前需要的连接查询。当然，服务现在必须处理所有非正规化的风险，如数据不一致。

b. 引用完整性: 正如我们所看到的，在一个分区数据库上执行跨分片查询是不可行的，类似地，试图在一个分片数据库中强制数据完整性约束(如外键)可能是极其困难的。

大多数RDBMS不支持跨不同数据库服务器的数据库的外键约束。这意味着要求分片数据库上的引用完整性的应用程序通常必须在应用程序代码中强制执行它。通常在这种情况下，应用程序必须运行常规的SQL作业来清理悬空引用。

c. 再平衡: 我们需要改变分片方案的原因有很多:

1. 数据的分布不是统一的，例如，有很多地方是用于特定的邮政编码的，这些地方不能放进一个数据库分区中。
2. 在一个shard上有很多的负载，例如，有太多的请求被专门用于用户照片的DB shard处理。 在这种情况下，我们要么必须创建更多的DB分片，要么必须重新平衡现有的分片，这意味着分区方案改变，所有现有数据移动到新的位置。做到这一点而不引起停机时间是非常困难的。使用基于目录的分区这样的方案，以增加系统的复杂性和创建新的单点故障(例如查找服务数据库)为代价，使重新平衡成为一种更令人满意的体验。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://vagrant.gitbook.io/grokking-system-design/fen-pian-huo-shu-ju-fen-qu.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
