1.3 使用分片和数据分配

本节您将了解基本可扩展性技术,例如数据库分片。分片被广泛应用于高端系统并提供一个简单而且可靠的扩展设置方式来向外扩展。近年来,分片已经成为一种扩大专业系统规模的标准方式。

1.3.1 理解分片的目的

如果您的数据量增长超过一台机器的处理能力将会发生什么事情?如果您要运行这么多的事务,一台服务器根本跟不上怎么办?我们假设您有百万级的用户,上万用户想在同一时间执行特定的任务。

显然,某些时候,您再也不能通过购买能够处理无限大的负载的足够大的服务器来解决问题。显然在单个服务器上运行一个类似Facebook或类似Google的应用是不可能的。有些时候,您必须拿出一个可伸缩策略来服务于您的需求。这就是分片应用的场景。

分片的想法很简单:要是您能在某种程度上分裂的数据可以驻留在不同的节点上会怎样?

设计一个分片系统的例子

为了表明分片的基本概念,我们假设一下情形:

我们要存储数百万用户的信息。每个用户都有一个唯一的用户ID。我们进一步假设,我们只有两台服务器。在这种情况下,我们可以存储偶数用户的ID到服务器1上,奇数用户的ID存储到服务器2上。

下图表明这是怎么实现的:

正如您所看到的,在我们的图中,我们已经很好地分发数据。一旦数据分发完成,我们就可以如下向系统发送一个查询:

SELECT * FROM t_user WHERE id = 4;

客户端可以很容易地计算出在哪里可以通过我们的查询检查过滤器找到数据。在我们的例子中,该查询将被发送到第一个节点,因为我们正在处理一个偶数。

正如我们已经基于一个键(key)(这里使用的是用户ID)所分布的数据,如果我们知道键(key)的话,我们可以很容易地搜索到任何人。在大型系统中,通过一个一个键(key)参考用户是常见的做法,因此这种方法是合适的。通过这种简单的方法,我们也可以容易地在我们的系统中使机器数量翻倍。

在设计系统时,我们可以容易地拿出任意数量的服务器;所有我们要做的就是创造一个漂亮的和聪明的分区功能来在我们的服务器集群内部分发数据。如果我们想要在十台服务器(不是问题)以内拆分数据,使用ID%10作为一个分区功能怎么样?

但您试图分布数据到不同的主机上时,必须确保您使用的是一个健壮的分区功能,在某种程度上,它可以非常出色地分布数据,每台主机都或多或少的有同样数量的数据。

用户按照字母顺序来分配数据可能不是一个好主意。其原因在于并不是所有的字母都有同样的可能。我们不能简单地假设从字母A到M发生的情况和字母从N到Z发生的情况一样。如果您想分发一个数据集到一千台服务器而且不仅仅是少数机器,这是一个大问题。如前所述,它必须是一个健壮的分区功能,其产生的分布均匀的效果。

[在大多情况下,哈希函数(散列函数)将为您提供很好且分布均匀的数据。处理字符字段时(例如名字,邮件地址等)特别有用。]

查询不同字段的例子

在上一节中,您已经看到我们如何容易地使用键(key)查询一个人。我们深入探究一下,看看下面的查询会发生什么:

SELECT * FROM t_test WHERE name = 'Max';

请记住,我们使用ID分发数据,在查询中,我们搜索名字。该应用程序将不知要使用哪个分区,因为没有规则告诉我们什么在哪里。

作为一个合乎逻辑的结果,应用程序必须要求每个分区的名字。如果要找的名字是一个真实的情况,这是可以接受的;然而,我们不能依赖这个事实。不得不询问多台服务器而不是一台服务器显然是一个严重的解优化(未优化)而且是不能接受的。

我们有两个选择来处理这个问题:

•提出一个比较智能的分区功能

•冗余存储数据

提出一个比较聪明的分区功能必定是最好的选择,但如果您想查询不同的字段,这几乎是不可能的。

这给我们留下了第二个选项,就是冗余地存储数据。对一个数据集存储两份,或甚至更多份是不太常见的,实际上确实是一个好的方法来解决这个问题。下面的图片显示了这是如何实现的:

正如您可以看到的,在这个场景我们有两个集群。当一个查询到来,系统必须决定哪些数据可以在哪个节点上找到。万一查询名字,我们(为简单起见)简单地按半字母顺序分割数据。在第一个集群,我们的数据仍然按用户ID分割。

1.3.2 分片的优点和缺点

分片不是一个简单的单行道是需要理解的重要的事情。如果有人决定使用分片,必须要认识到技术的优点和缺点。与往常一样,不去思考,没有什么神能奇迹般地解决人类所有的问题。

每个实际使用情况都是不同的,没有替代的常识和深入思考。

首先,我们看一下下面列出来的拆分的优势:

• 它有扩展系统超过一台服务器的能力

• 它是一个简单的方法

• 它被许多框架支持

• 它可以与多种其它复制方法组合

• 它可以很好地支持PostgreSQL(例如使用PL/Proxy)

光与影子倾向于走在一起,因此分片也有其不足之处,如下:

•在运行的集群中添加服务器是非常麻烦的(取决于分区函数的类型)

•可能会严重降低您的灵活性。

•并非所有类型的查询将和在单台服务器上有相同的效果。

•增加了整体安装设置的复杂性(如故障转移等等)。

•备份需要更多的规划。

•您可能面临冗余和额外的存储需求。

•应用程序开发人员应该知道分片,以确保高效的查询被写入。

在第十三章,使用PL/Proxy扩展,我们将讨论如何和PostgreSQL一起能够高效地利用分片,如何最大性能和扩展性地设置PL/Proxy。

1.3.3 切分和冗余之间的选择

学习如何切分一个表只是设计一个可扩展系统架构的第一步。我们在前面章节已经展示的例子中,我们仅仅只有一张表,可以很容易地使用键(key)来拆分。但是,要是我们有不只一张表又会怎么样呢?假设我们有两张表:

•一张表名为t_user的表在我们的系统中存储用户

•一张表名为t_language存储我们的系统支持的语言

我们也许可以很好地通过某种拆分方式来拆分表t_user,这个表也可以分配到一个合理数目的服务器上。但是表t_language怎么办?我们的系统可能支持多达十种语言。

可以很好地分片和分发数以亿计的用户,但是拆分十种语言怎么样?这显然是无用的。除此之外,我们可能需要我们的语言表在所有的节点上以便我们可以进行连接。

解决这个问题的方法很简单:您需要语言表在所有节点上的一个完全的复制。这将不会引起存储浪费的相关问题,因为表是如此的小。

[确保只有大表被分片。对于小表的情况,表的完全复制可能更有效]

同样,每一种情况都必须深思熟虑。

1.3.4 增大和减小集群的大小

到目前为止,我们一直认为分片大小的设置是恒定不变的。我们已经设置了使我们能够利用一个在我们集群内部固定数目分区的分片方式。这种限制可能无法反应日常的需求。您怎么能够真正地说出在设计的时候某个特定时刻需要的节点的数目?人们可能对硬件需求有一个粗略的想法,但是实际上知道负荷的期望值是一门艺术而不是科学。

[为了反映这一点,您必须设计一个系统,他可以很容易地调整大小。]

一个常见的错误是人们往往会在不必要的小步中增加他们设置的的大小。有人可能会从五台机器增加到六台或七台机器。这可能非常棘手。我们假设在某一时刻我们拆分数据使用用户ID%5来作为分区函数。要是我们想使用用户ID%6又怎样?这不太容易,问题是我们必须在我们的集群内重新平衡数据来反映我们的新规则。

请记住,我们已经介绍了分片(即,分区)因为我们有这么大量的数据和这么多的负载,一台服务器无法处理这么多的请求了。如果我们想出来一个策略,现在需要重新平衡数据。我们已经在错误的轨道上了。您肯定不希望为了添加两台或三台服务器到您现有的服务器而重新平衡20TB的数据。

实际上,简单地加倍分区数目是比较容易的。加倍您的分区不需要重新平衡数据,因为您可以简单地按照后面的策略来做:

•创建每个分区的副本

•删除每个分区上一半的数据

如果之前您的分区函数是用户ID%5,而现在应该是用户ID%10。倍增的优点在于数据不能在两个分区之间移动。但谈到加倍,用户可能会认为您的集群大大小会增长的太快。这是事实,但是如果系统的运行能力达到了极限,增加系统资源的10%并不能解决可扩展性的问题。

不仅仅增加一倍的集群(这是用于大多数情况),您也可以把更多的心思投入到编写一个更复杂的分区功能保留旧的数据,但更智能地处理最新的数据。有时间依赖的分区函数可能导致它自身的问题,但它可能是值得研究的方法。

[一些NoSQL系统采用范围分区传播数据。范围分区意味着一个给定的时间帧每个服务器有固定的数据切片。如果您想要做时间序列分析或相似的工作可能有益。但是,如果您要确保数据被均匀分割可能会适得其反。]

如果您期望您的集群规模扩大,我们建议从开始就设置比最初需要较多的分区,在一台服务器上打包不只一个分区。稍后,移动单个分区到添加到集群的硬件就会很容易。有些云服务能够做到这一点,但是本书不包含这些内容。

要缩小集群是您可以简单地套用反向策略和移动多于一个分区到单个服务器。为将来服务器的增加留下并敞开大门很容易做到。

1.3.5 结合分片和复制

一旦数据被拆散成有用的组块,可以被一个服务器或分区处理,我们必须考虑如何使整个设置更可靠和故障安全。

在您的设置中服务器越多,这些服务器中的一台服务器越容易由于别的原因宕机或不可用。

[这是设计一个高可扩展的系统时总是要避免单点故障。]

为了确保最大的吞吐量和最大可用性,我们可以再次转向冗余。该设计方法可以归纳为一个简单的公式,这应该永远印在一个系统架构师的脑海里:

One is none and two is one

一台服务器远远不够为我们提供高可用性。每个系统需要一个备份系统,它可以在非常紧急的情况下接管过来。仅通过拆分一组数据,我们绝对没有改善可用性,因为我们有较多的服务器可能也在这个时间点出故障。为了解决这个问题,我们可以为我们每个分区(碎片)增加副本,正如下图所示:

每个分区是一个独立的PostgreSQL数据库实例,每个实例有它自己的副本(或多个副本)。

请记住,您可以从全部武器特性和本书中所讨论的特性(例如,同步和异步复制)选择。本书中所介绍的所有策略可以灵活地组合;单一的技术通常是不够的,因此要以不同的方式自由组合各种技术来实现您目标。

1.3.6 各种分片解决方案

近几年,分片已经作为一种工业标准融入到许多可扩展性相关的问题。因此,许多编程语言,框架和产品已经提供了即插即用来支持拆分。

实现分片时,您基本上可以在两种策略之间进行选择:

•依靠一些框架/中间件

•依靠PostgreSQL方法解决问题

在接下来的两节中,我们将简要讨论这两个选择。这个小概述并不意味着一个全面的指南,而是一个让您开始分片的概括。

基于PostgreSQL的分片

PostgreSQL本身不能对数据进行分片,但是它有通过附加组件来实现分片所有的接口和方法。其中的一个被广泛使用的附加组件是PL/Proxy。它已经存在好多年了,并提供卓越透明度以及良好的扩展性。

PL/Proxy背后的思想基本上是使用一个本地虚拟表隐藏一个服务器组组成的表。

PL/Proxy将在第十三章进行深入地讨论,使用PL/Proxy扩展。

外部框架/中间件

您也可以使用外部工具来替代依靠PostgreSQL。一些使用的最广泛和知名的工具是:

• Hibernate shards (Java)

• Rails (Ruby)

• SQLAlchemy (Python)

1.4 总结

本章,您已经了解了基本的复制相关的概念,以及有关物理限制。我们已经处理了理论概念,这是基础的东西,在本书的后面仍然会出现。

下一章,您将通过PostgreSQL事务日志的指导,我们将概述这一重要组成部分的所有重要方面。您将学会事物日志对什么是有益的,它是如何被应用的。

PostgreSQL Replication之第一章 理解复制概念(3)的更多相关文章

  1. PostgreSQL Replication之第一章 理解复制概念(1)

    PostgreSQL Replication系列翻译自PostgreSQL Replication一书 在本章中,将会介绍不同的复制概念,您会了解哪些类型的复制对哪一种实用场景是最合适的. 在本章的最 ...

  2. PostgreSQL Replication之第一章 理解复制概念(2)

    1.2不同类型的复制 现在,您已经完全地理解了物理和理论的局限性,可以开始学习不同类型的复制了. 1.2.1 同步和异步复制 我们可以做的第一个区分是同步复制和异步复制的区别. 这是什么意思呢?假设我 ...

  3. PostgreSQL Replication之第二章 理解PostgreSQL的事务日志(1)

    在前面的章节中,我们已经理解了各种复制概念.这不仅仅是一个为了接下来将要介绍的东西而增强您的意识的理论概述,还将为您介绍大体的主题. 在本章,我们将更加接近实际的解决方案,并了解PostgreSQL内 ...

  4. PostgreSQL Replication之第二章 理解PostgreSQL的事务日志(3)

    2.3 理解一致性和数据丢失 挖掘PostgreSQL事务日志而不考虑一致性是不可能的.在本章的第一部分,我们已经大体上解释了事务日志的基本思想.您已经知道,无需事先的日志改变的能力,使数据处于一种好 ...

  5. PostgreSQL Replication之第二章 理解PostgreSQL的事务日志(5)

    2.5 XLOG的内部结构 我们将使用事务贯穿本书,并让您在技术层面上更深地洞察事情是如果工作的,我们已经增加了这部分专门处理XLOG的内部工作机制.我们会尽量避免前往下降到C级,因为这将超出本书的范 ...

  6. PostgreSQL Replication之第二章 理解PostgreSQL的事务日志(4)

    2.4 调整检查点和XLOG 目前为止,这一章已经提供深入洞察PostgreSQL如何写入数据,一般来说,XLOG是用来干什么的.考虑到这方面的知识,我们现在可以继续并学习我们能做些什么来使我们的数据 ...

  7. PostgreSQL Replication之第二章 理解PostgreSQL的事务日志(2)

    2.2 XLOG和复制 在本章中,您已经了解到PostgreSQL的事务日志已经对数据库做了所有的更改.事务日志本身被打包为易用的16MB段. 使用这种更改集来复制数据的想法是不牵强的.事实上,这是在 ...

  8. 20190813 On Java8 第一章 对象的概念

    第一章 对象的概念 抽象 Alan Kay 总结了对象的五大基本特征 万物皆对象. 程序是一组对象,通过消息传递来告知彼此该做什么. 每个对象都有自己的存储空间,可容纳其他对象. 每个对象都有一种类型 ...

  9. PostgreSQL Replication之第九章 与pgpool一起工作(1)

    在前面的章节中,我们已经能够深入地理解了pgbouncer,同时也学会了如何使用它来尽可能地优化复制设置.在本章我们将了解一个经常被称作与pgbouncer相对应的工具.尽管pgpool的思想与pgb ...

随机推荐

  1. [转] CentOS 7 为firewalld添加开放端口及相关资料

    转自http://www.cnblogs.com/hubing/p/6058932.html 1.运行.停止.禁用firewalld 启动:# systemctl start  firewalld 查 ...

  2. poj1170 - 转换成背包

    题目链接 有5种物品,给出每个物品的单价. 给出几个这些物品的组合和这个组合的价格.买组合要比一件件的买便宜. 问给定的购买计划最少花多少钱. ---------------------------- ...

  3. shell简单监控脚本模板

    #!/bin/bash host=127.0.0.1user=adminpassword='xx'port=6032x=0check_proxy(){v=$(mysql -N -u$user -p$p ...

  4. 运维派 企业面试题6 防dos攻击

    Linux运维必会的实战编程笔试题(19题) 企业实战题6:请用至少两种方法实现! 写一个脚本解决DOS攻击生产案例 提示:根据web日志或者或者网络连接数,监控当某个IP并发连接数或者短时内PV达到 ...

  5. Mateclass

    Mateclass 一切皆对象: Eg: class Foo: pass f=Foo() In [60]: print(type(f)) <class '__main__.Foo'> In ...

  6. python3安装xadmin失败

    环境win7 旗舰版.python3 使用pip install xadmin命令的时候出现了错误>:\ (⊙o⊙) 解决方法如下: 使用pip download xadmin 现将xadmin ...

  7. ES 新增字符串方法

    话不多说,直接开鲁 1. startsWith() 作用: 检测字符串以什么开头 实例: let str = "www.qjzzj.top"; console.log(str.st ...

  8. Jtester使用

    1.在Jtester中使用DataMap 为什么要使用DataMap? 早先的jTester中提供了dbFit方式来准备和验证数据库数据,应该来说,这个工具解决了很多问题.实际使用过程中,开发同学反映 ...

  9. 【Henu ACM Round#24 A】k-String

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 如果是一个k-string的话. 考虑最后的串假设形式为sss..ss(k个s) 则s中出现的字母,整个串中最后出现的次数肯定为k的 ...

  10. (原创)VS2017 C# 运行 Javasrcipt RSA 加密用户名登录 Java开发的服务器

    第一次写博客. 最近想做一个Web的自动登录,用户名和密码是RSA加密过的,后台是用的JAVA,我只会点C#,抓包什么都搞定了(使用的是Fiddler),不过由于C#和RSA的加密方式不同,我搞了N天 ...