在以前的文章,MySQL的水平可伸缩性的心态,我讨论了周围的担忧日益增长的个人MySQL实例太大,一些基本的策略:
- 优化/最小化大小与适当的数据类型
- 删除未使用的/重复的索引
- 保持你的主键很小
- 修剪的数据
最后,如果这些方法已经筋疲力尽,我谈到了水平分片的方法保持个体实例在一个合理的大小。在讨论我的想法在我们的内部团队,有很多反馈,我们需要深入详细分片主题。这篇文章的目的是提供更多的理论和考虑切分连同一个轻量级ProxySQL示例实现。
切分是什么?
分片一词经常使用但经常被误解。经典的垂直扩展(通常称为“缩放”)是当你增加在一台服务器上的资源来处理更多的数据和/或负载。水平扩展(又名分片)是当你真正把你的数据分成更小的,独立的桶和保留根据需要添加新桶。
分片环境中有两个或多个组的MySQL服务器的孤立和独立于彼此。虽然具体的实现细节依赖于您的环境,这里有一些一般准则:
- 可以单独的服务器或复制碎片的层次结构
- 每个碎片都有相同的模式,您可以运行相同的查询模式对任何碎片和期望得到一个结果集的WHERE子句(当然不同的标识符)
- 特定标识符确切地仅属于一个碎片——你不应该客户ID生成碎片(除非只是暂时在迁移过程中碎片例如-这是一个极端例子,需要特殊处理)
这对分片的理解,让我们来看看一些实际实现的关键问题和挑战。
切分问题和挑战
尽管分片经常成为管理爆炸数据的唯一方法,大多数专家和架构师建议尽可能长时间推迟了。如果是这样一个伟大的方式来处理数据,那么这是为什么呢?主要原因是复杂性。而垂直扩展是微不足道的(只是增加更多的硬件和没有其他变化),分片需要大量的思考和规划。的主要挑战分为几个主要桶:
- 我该如何把我的数据?
- 如果我的数据跨越碎片?
- 我如何找到我需要的数据吗?
每个桶都有自己的挑战,但也可以全面拦截器在实现分片。
我如何把我的数据?
挑选碎片关键是实现分片中最重要的部分。主要概念是选择跨记录共享一个标识符,比如CustomerID, ClientID或标识。一般来说,你想要挑选最小单元可能在UserID级别(一般),但这也取决于需要什么程度的聚合(后面详细讨论)。这里的风险是关键不够选择性和你最终不均匀分割数据。然而,如果你太挑剔,你分手的风险单位,逻辑上应该保持在一起(认为分片ForumPostID vs UserID)。
如果我的数据跨越碎片?
这通常是一个决定性因素,防止组织分片。把数据和检索单个记录,而不是微不足道的,相对简单。在许多工作负载,这就足够了。找到我的小子集的数据和获取它。总查询用例规定,然而,这个工作流分解。把这个通用查询找到最新的用户在平台:
|
1
|
选择
user_id
,
date_created
从
用户
订单
通过
date_created
DESC
限制
10
;
|
当所有的用户存储在一个单独的服务器,这个查询的方法是微不足道的。然而,当跨越多个数据碎片,我们现在需要一种方法来聚合数据。实现这是超出了本文的范围,但是一般方法是这样的:
- 问题查询每一个碎片
- 收集每个切分的结果在一个中央聚合服务
- /过滤个人结果合并成一个单独的结果集
如果你的用例严重依赖聚合查询,实现这种聚合层至关重要,往往很复杂。这也阻碍了很多从分片的用例,即使它是必要的。
在一个理想的场景中,主动的OLTP工作负载可以包含在单独的碎片。报告和数据仓库需要分布式查询的实现,可以通过不同的管理系统,或通过自定义聚合使用多源MySQL异步复制。
我如何找到我的数据?
现在,假设你选择了一个分片键,您需要能够检索记录。这是下一个需要克服的主要障碍。这个问题有两种截然不同的组件的挑战:
- 确定哪些碎片保存数据
- 如何连接,碎片从我的应用程序
找到ShardID
确定哪些碎片认为,数据可以是简单或复杂。然而,每种方法有权衡。简单的方法使用一个简单的散列/模数确定碎片看起来像这样:
|
1
2
|
shardID
=
标识符
%
numShards
返回
shardID
|
最基本的例子将分片userID跨2个碎片。用户id,甚至将切分0和奇怪的用户id将切分1。虽然非常简单,我做什么当两个碎片不是足够了吗?这种体系结构的目的就是增加更多的碎片当个别碎片太大了。现在,当我添加新的碎片,碎片的数量增加的shardID可能改变的许多记录。
更灵活的方法是使用一个目录服务。在这种方法中,有一个非常简单的数据存储,将一个标识符映射到一个碎片。要确定哪些碎片保存数据,只需查询与标识符,它会返回shardID数据存储。这给了难以置信的灵活性之间移动数据碎片,还增加了系统的复杂性。自然,这服务本身需要高度可用,但没有MySQL。除了复杂性,你有可能会引入额外的延迟和额外的查询系统。
连接到碎片
一旦我们有了适当的shardID,我们需要连接到数据库集群的问题。再一次,我们可以选择和实现是依赖于应用程序。我们可以看看两种主要方法:
- 为每个碎片使用不同的连接字符串
- 利用智能代理层,路线
使用不同的连接字符串通常是不言而喻的:我有一个shardIDs及其相应的连接字符串的集合。当我知道shardID,然后我获取连接字符串,连接到集群,我们走。
但我们知道开发人员不想和不应该惹连接字符串和凭证。所以代理层,可以根据查询路线查询本身或一些元数据查询中是理想的。被一层7服务,ProxySQL能够检查查询自己和做出决定基于定义的规则。虽然肯定不是唯一的方法,让我们看一个示例ProxySQL实现使用查询注释路由到正确的切分。
样本ProxySQL实现
在我们的例子中,这是基本的架构:
- 分片用户标识
- 目录服务,简单的路由基于模量
- ProxySQL已经用于哈
- 数据是跨越3碎片
一个典型的用户查询可能看起来像这样:
|
1
2
3
|
SELECT *
从
用户
在哪里
user_id
=
5
|
UserID是分片键和简单的模量分片策略,我们可以轻松地识别shardID查询:
|
1
2
|
标识符
%
numShards
=
shardID
<
强大的
>
5
%
3
=
2
<
/
强大的
>
|
定义shardID后,我们现在可以注入评论的原始查询可以使用ProxySQL正确路线查询到正确的切分:
|
1
2
3
4
|
选择
<
强大的
>
/ *碎片= shard_2 * /
<
/
强大的
>
*
从
用户
在哪里
user_id
=
5
|
ProxySQL内部使用hostgroups定义路由的概念。在很多公顷情况下,这只是一个读者和作家hostgroup。分片的架构,然而,我们可以扩大hostgroups定义为真正的碎片:
|
1
2
3
4
5
|
插入
成
mysql_servers
(
hostgroup_id
,
主机名
,
评论
)
值
(
1
,
“10.0.0.1”表示
,
“切分0”
)
,
(
2
,
“10.0.0.2”
,
“切分1”
)
(
3
,
“10.0.0.3”
,
《碎片2》
)
;
|
hostgroups到位,我们只需要添加一个ProxySQL规则选择hostgroup基于注入的评论:
|
1
2
3
4
5
|
插入
成
mysql_query_rules
(
rule_id
,
活跃的
,
match_pattern
,
destination_hostgroup
,
应用
)
值
(
5
,
1
,
“\ S * \ S * * \ \ / \ S *碎片= shard_0 \ S * \ \ * \ \ / \ S * *”
,
1
,
1
)
,
(
6
,
1
,
“\ S * \ S * * \ \ / \ S *碎片= shard_1 \ S * \ \ * \ \ / \ S * *”
,
2
,
1
)
,
(
7
,
1
,
“\ S * \ S * * \ \ / \ S *碎片= shard_2 \ S * \ \ * \ \ / \ S * *”
,
3
,
1
)
;
|
现在,在我们发出一些查询,你可以看到在ProxySQL统计,我们相应地匹配shardID和路由:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20.
21
22
|
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
1。
行*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
活跃的
:
1
支安打
:
3
rule_id
:
6
match_digest
:
零
match_pattern
:
\
*
\
*
\
/
\
*
\
*
碎片
=
shard_1
\
*
\
*
\
/
\
*
\
*
replace_pattern
:
零
cache_ttl
:
零
应用
:
1
flagIN
:
0
flagOUT
:
零
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
2。
行*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
活跃的
:
1
支安打
:
5
rule_id
:
7
match_digest
:
零
match_pattern
:
\
*
\
*
\
/
\
*
\
*
碎片
=
shard_2
\
*
\
*
\
/
\
*
\
*
replace_pattern
:
零
cache_ttl
:
零
应用
:
1
flagIN
:
0
flagOUT
:
零
|
显然,这是一个巨大的简化,你想要更通用的、更复杂的hostgroups的规则。例如,您的部署需要考虑查询没有提供碎片提示或无效的情况shardID供应。然而,它显示的潜力编写自定义路由层内ProxySQL非常轻量级的工具。这种方法,虽然它需要一些额外的思考和逻辑,可能是一个可行的水平分割数据的第一步。
再一次,这只是一个概念验证样本实现。每个用例都是不同的。这篇文章的主要结论是,人工切分是可能的,但需要大量的规划和实施工作。
雷竞技下载官网MySQL Percona分布是最完整的,稳定的,可伸缩的,和安全,开源MySQL解决方案,提供企业级的数据库环境最关键业务应用程序…和它的免费使用!强大的>






恕我直言,维塔斯是分片MySQL的解决方案,它支持增加与减少的碎片没有停机时间和还支持改变分片键。还支持分散收集SQL模式。
在我看来ProxySQL维塔斯是一个劣质分片解决方案。
嗨@Neo感谢你的回复!你强调一个非常有用的切分工具MySQL在维塔斯,这是一个产品,Percona爱,经常为客户推荐和部署解决方案。雷竞技下载官网我们不否认在维塔斯有巨大的价值。在博客上我们要做的是突出许多选项,并在我们看来ProxySQL更容易部署数据库是微创堆栈(至少相比于维塔斯,这是一个真正的,操作)。
再次感谢你的反馈,这使得迈克尔和我考虑做(另一个)的帖子,我们探索更复杂的解决方案,比如维塔斯!
将会是很有趣的一篇文章TiDB。