首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

数据库分区

Database Partitioning

要想在扩展数据库写能力时能采用和扩展读能力时相同的方式,就得像对Web服务所做的那样,把数据库划分成块。分出的每一个块都足以处理一定数目的写要求,能做得像最初的单个数据库服务器一样,因此每次倍增块的数目,就会倍增写的能力。

有两种划分数据的方式,它们的名称令人困惑,分别被称为横向分区和纵向分区。纵向分区,也叫聚类,易于进行扩展,但却有一定上限,横向扩展则是很不错的一个通用解决方案,能扩展到任意数目的块,但需要花更多的精力。我们会探讨如何实现它们,以及它们各自的优缺点。

聚类

Clustering

由于其扩展能力有限,聚类也叫做纵向分区,但它和纵向扩展的相似点也就仅此一处了。

和纵向扩展一样,聚类要将数据库划分成为多个块或者簇,它们每个都包含全部表格的一个子集,如图9-15所示。

图9-15:将数据分散到簇中

这样做往往导致大量的程序方面的改动,尽管这些改动是相当机械的。在确定了哪些查询会操作哪些表格之后,就可以根据查询的目标表格对数据库调度层进行修改,让它选择合适的主机集群查询。每个集群在结构上都可以如你所愿地进行配置——可以是一台单独的机器,可以是带有从属服务器的主服务器,也可以是主服务器-主服务器对。不同的集群可以使用不同的模型来满足它们所支持的各种不同表格的需求。

要将一个大的应用程序数据库划分成多个簇,首先得列出所有拥有的表。这很简单,使用SHOW TABLES命令即可:

mysql> SHOW TABLES;

+-----------------+

| Tables_in_myapp |

+-----------------+

| Frobs           |

| Payments        |

| Replies         |

| Topics          |

| Users           |

| Widgets         |

+-----------------+

6 rows in set (0.00 sec)

接下来的步骤要稍微困难一些——需要依次查看源代码中的每个SQL查询,理清表相互之间的关联关系。除非可以修改程序逻辑,来避免进行某个关联,否则就不能把关联的表格划分到不同的簇中。最终结果是一个列表,它包含可能的簇,还有这些簇相应可能包含的表:

Cluster 1: Payments, Users

Cluster 2: Replies, Topics

Cluster 3: Frobs

Cluster 4: Widgets

我们无需急于求成——可以根据当前硬件配备,按照需求一步一步进行聚类。一开始可能只是将一个独立的数据库分成两个簇,第一个包含有表簇1和3,而第二个含有表簇2和4。当需要再次扩展容量时,可以继续划分成三个或者四个簇。

在这个例子应用程序中,当最终达到四个簇时,就无法进一步分割了。聚类的这个限制,意味着在只有一个表的时候,或者只有需要进行很多读操作的一组关联表的时候,就总是只能使用一台服务器,只能享有一台服务器的能力。

这种方式还有其他不足。对簇的管理比对一个单独的数据库进行管理要困难得多,因为不同的机器现在带有不同的数据集,而且有不同的需求。随着更多不同的组件的加入,管理成本也会不断增加。

程序中的每个要使用多个表格的页面都需要建立多个MySQL的连接。随着簇的数目增加,连接负载也在增加。把表格划分到不同簇中,并没有提高连接上限。如果一台单独主机允许200个连接而不会性能下降,那么对于拥有两个簇的情况,上限就是400个连接。但是,因为每个页面都需要同时连接到这两个簇,所使用的连接数目也是原来的两倍,这就抵消了连接上限的增长。如果有一个单独的大表同时需要很多连接,聚类并不能帮上什么忙。

联合

Federation

联合是横向扩展在数据库领域的等价物。要能够扩展到任意的规模,就要做到能通过添加硬件来同时增加读和写的能力。想要对表也能做到这些就需要能把表中的数据切分成任意大小的块。在数据集大小和需要执行的查询的数目发生变化时,我们可以增加块的数目,在每个块上保持数据大小和查询数目不变。这些块中的数据和相应的容纳它们的机器往往被称作为shard或者cell,但有时也称为簇(这个名称只能让人感到困惑)。

MySQL 5的NDB存储引擎想在无需用户更改任何程序逻辑的条件下,在内部完成类似上述的工作。目前NDB还没有真正准备好用于高流量的生产环境,但这一点可能很快就能实现。对于非MySQL的路线,Oracle的RAC(Real Application Clusters)提供了类似的功能,但它有些贵。每台处理器授权需要$25,000,20台双处理器的服务器需要你在硬件之外,额外花费一百万美元。因为将来还需要继续扩展,使其最终将会变得非常昂贵。SQL Server也提供了类似的功能,但在相同硬件条件下速度相对缓慢,而且每台处理器要花费$30,000。除此之外还必须运行在Windows之下,这将导致额外的成本和管理问题出现,你应该足够聪明,知道要避免这类问题。

自己来实现联合是很难的。如果一张表已经被分到多台服务器之上,要在其中选出一个范围内的数据,会变成将多次获取数据再合并和排序的操作。联合化了的表格之间的关联操作变得难以置信得复杂。一般情况下,这些困难是确实存在的,但是在我们的程序中,如果能小心仔细地绕开跨shard查询和联合方面的需求,就可以避免这些缺陷。

免于跨shard查询的关键在于数据联合化的方式,要保证所有需要一起取得的记录都在同一个shard上。如果需要在一张页面上向一个用户显示他们所有的frobs,那么就可根据用户将frobs表切片,把一组用户的frobs放置在同一个shard中,另一组在另一个shard中,依此类推。接着把shard的ID存放在用户帐户记录中,这样在需要的时候,就能精确知道到哪儿去找用户的frobs。如果还要从其他角度来观察相同的数据,比如属于所有用户的绿色的frobs,那么也需要用同样的方式来切分数据。实现这一个目的的具体方法是一个已经提到过的朋友——逆范式化。我们会持有一个规范化的表“Frobs”,它是按照用户来切分的,还有一张逆范式化的表“FrobsByColor”,它是按照颜色切分的。这样就得存放两倍的数据,但我们可以创建任意数目的shard,保证每个shard上记录的数目都比较少。

将逆范式化和shard访问逻辑存放在查询逻辑层会产生复杂的代码,并且更容易带来错误。要减轻这个问题,可以把联合逻辑放在它自己的概念层次中,如图9-16所示。

图9-16:将联合逻辑单独划为一层

通过创建这个数据访问中间件,可以把所有shard和逆范式化逻辑放在同一处,让它更为简单和不那么容易出错。当我们需要得到一列frobs时,就传递user ID到这个中间件。中间件知道哪个shard包含这个用户的frobs,它就继续传递查询,并且返回结果集给应用程序层。应用程序不需要知道有多少个shard,数据是如何分布在它们之上的,或者哪个用户是分配给哪个shard的。所有要做的就是请求想要的数据,由存储层具体负责如何变戏法。

多台机器上的逆范式化数据经常受指责的一点是,由于缺少事务一致性,最终很容易产生

不一致的数据。因为同时在向两台机器写数据,我们无法保证事务一致性,其中任何一台机器都可能在操作时崩溃。通过使用一对事务来处理写操作,可以稍微减轻不一致的可能性。比如说,当要写一条记录到服务器A上的Frobs表和服务器B上的FrobsByColor表时。一开始在A服务器上打开一个事务,执行变更,但并不提交它。接着在B服务器上打开一个进程,执行变更并提交。最后提交第一个事务。如果第一台服务器在我们开始操作之前就出故障了,那么就可以在相同的shard的其他服务器上尝试,或者退出整个进程。如果第二台服务器出现故障,那么可以在它所在的shard的其他服务器上进行尝试,或者回滚第一个打开的事务并且取消整个进程。唯一的危险,是在第二个事务提交结束和第一个事务准备提交(尚未提交)的这段时间内,A死机了。这个方案并不完美——但采用这种方式来使用一个事务对,可以把危险的可能性降低到毫秒级别,并且避免更大的问题——其中一个shard在整个进程开始的时候出了故障。

当有多个shard时,就需要一组新工具来管理它们。也就是我们需要构建工具,用于shard特定的管理任务,比如检查每个shard上的模式是否一致,还有每个shard中的每台机器有没有得到有效使用。Shard管理工具集应该包含一些工具来帮助添加和删除额外的shard。随着系统增长,需要增加shard的时刻总会来的。添加新的shard,让它们准备妥当,可以向其中写入新的对象(比如说新的用户数据,你会据此联合数据)是很好的,但并不是在添加新硬件之后,立即就能充分利用新的硬件——整个数据集合只有小部分会驻留在新的shard上。而且,当一个shard负载过重时(比如这个shard上的用户的数据集大小与日俱增),这种方法也无法赐予我们扩展这个shard的能力,最终结果就是早期建立的shard超负荷使用,而后期建立的却没有充分使用。如果有在shard之间移动对象的能力,就可以在有新的shard加入而且老的shard负担过重的时候转移数据。要达成这个目标,就需要构建工具,让它能够根据特定组件移动联合化的记录集,将它们从一个shard移动到另一个。有了这个工具,就可以有选择地在shard之间移动数据部分,让每个shard都能恰如其分地得以使用。

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论