注:原文已发表于《程序员》杂志关系型数据库60周年特刊
随着信息量飞涨,信息的存储成为了这个时代至关重要的一项技术。如何来保证数据存储技术能够适应信息量的增长速度和我们对信息的高度依赖,成为一个非常重要的课题。本文将从数据库架构的层面,通过以开源的数据存储软件来构建分布式数据层的思路,期望实现一个低成本的高可用可扩展的数据层架构。
传统数据库架构
纵观各传统商业数据库软件,多以集中式架构为主,鲜有以分布式为设计理念的架构。这些传统数据库软件的最大特点就是将所有的数据都集中在一个数据库中,依靠大型高端设备来提供高处理能力和扩展性。
集中式数据库架构在扩展性方面主要依赖于主机和存放数据的存储设备的扩展能力,也就是说依赖硬件本身的纵向扩展能力,很难做到较好的横向扩展。而其可靠性也同样是以硬件设备为依托,主要通过Share Storage的方式来实现。如大家所熟知的传统商业数据库代表厂商Oracle的RAC,就是一个非常典型的Share Everything 的集中式架构。
我们可以通过图1来简单地描绘一下传统数据库的典型架构:传统架构在主机端大多通过两台主机共享存储设备,平时其中一台主机使用存储通过数据库软件来管理。这样的架构只能有一台主机(RAC除外)上的数据库能够提供服务,另一台主机只能是作为热备冗余,不能启动数据库实例提供服务。所以,其处理能力就完全取决于这台主机的最大扩展能力,很难通过增加主机数量来增加处理能力。而单台主机的扩展能力毕竟是有限的,即使是某些厂商的大型机,同样也有其扩展限制。此外,传统架构对高端设备的依赖,无疑将直接导致系统成本的大幅度增加,甚至可能会导致系统被主机和硬件厂商所“绑架”,不得不持续增加投入成本。

图1 传统数据库的典型架构
基于MySQL的可扩展和高可靠
MySQL 作为开源数据库的佼佼者,无论是软件本身的设计思想,还是推崇给广大使用者们常用的架构思路都和传统的商业数据库软件大相径庭。MySQL弃用了传统的 Share-Everything的思想,而采用了Share-Nothing的思想。MySQL的Replication实现机制,以及 MySQL Cluster的架构设计,都体现了这一思想。也正因如此,给MySQL在可扩展性和高可靠性方面带来了非常灵活的架构设计思路,也让我们的数据库可以摆脱对高端设备的依赖,使用上性价比高很多的PC Server。
可扩展性
在提升扩展性方面,最为常用的是通过MySQL自身的Replication功能,将同一份MySQL的数据以异步的方式同时复制到另外的一台或多台 MySQL主机上,并让这些MySQL主机同时对外提供查询服务。每增加一个复制的节点,查询处理能力也得到相应的增加,新增节点的处理能力就是整个系统增加的处理能力。由于MySQL Replication主要是逻辑方式,同一个集群中可有多家厂商的硬件,也可以使用不同的OS,所以可以做到完全不受任何软/硬件平台限制,摆脱对单一平台的依赖。
人们可能会对MySQL Replication的功能特性不满意,进而通过第三方开源软件,甚至是通过解析其开源的通信协议自行开发出来的复制软件来进行数据实时(或者异步)复制来达到 Replication完全相同甚至更好的效果。传统数据库可能也具有某项功能实现数据的复制,但与MySQL相比,由于只依靠数据库本身特性来完成,在架构的灵活性和可控性方面存在一些不足。
最后,在提升扩展性方面不得不说的数据切分(横向/纵向)的思想,同样可以在MySQL数据库上得到灵活的发挥,无论是以功能模块的方式进行纵向的切分,还是以某个特定键(字段)的类HASH分段的方式进行横向的切分,抑或是通过数据库本身的Partition功能进行切分,都可以在MySQL上得到很好的实现。当然,无论是切分前的数据分散,还是切分后的数据路由和合并都离不开应用层的协作与配合,除非通过MySQL Cluster来实现。对于提升扩展性的架构,通过图2会有一个更为直观的展现。

图2 能够提升扩展性的架构
图中以“Master”为核心,通过不同的方式以三条“路线”将数据复制到相应的 MySQL 集群中对外提供服务。实际的架构中,Master就是一个数据写入点,复制出去的集群则可以对外提供相应的查询请求。常见的Web应用系统中,查询请求远远大于写入请求,所以非常适合通过MySQL 数据库使用类似的架构思想来解决实际的扩展性问题。
高可靠性
在保证高可靠性方面,同样可以通过MySQL的 Replication 为基础,加以应用层架构的简单配合或一些开源的第三方HA管理软件来设计出多种非常灵活的高可靠架构。
对于数据写入点,可以通过MySQL的Replication功能,将两台MySQL主机设置成双A的状态,并通过HA管理软件,对MySQL的状态检测,来判定MySQL的状态,并对外提供供单一的服务 IP 地址,以确保在任何时候有一台MySQL崩溃后马上切换到另外一台MySQL上提供服务。这样自动的方式非常方便地让我们的写入点拥有高可靠性。如果我们的应用程序也可以自动判断当一个点失效后马上自动切换到另外一个点就更好,基本上可以做到对外部完全透明的切换,对可用性的影响之小,比现在一些知名厂商的专业HA管理都要好很多。
对于数据查询点,高可靠性的实现就更容易了,可从双A的两台Master端中的任意一台上通过数据复制搭建多个具有完全相同数据拷贝的MySQL节点,来保证任何时刻都可以有多台MySQL对外提供数据查询服务。当一台MySQL崩溃,系统马上将该节点从可以服务的节点中剔除出去。通过应用架构的帮助这是非常容易做到的事情。
图 3是高可靠性实例图。1描绘了基本架构,2、3和4分别描绘了当读节点失效以及写节点中的任何一个失效后的高可靠性实现。在高可靠性方面,除了自行控制将数据复制到多个MySQL主机上的方式之外,MySQL还提供了更为高级的方案——MySQL Cluster,一个完全的分布式数据库集群,而且是一个非常典型的Share-Nothing的分布式数据库架构。数据层和SQL层分离,每份数据都以两份或更多份拷贝存放在不同的数据节点上,整个数据层的所有节点以分布式计算的思想共同处理整个数据库的数据,在保证高并发的处理能力的同时,以数据冗余的方式保证了高可靠性。

图3 高可靠性实例图
构建基于MySQL、Cache 和Search的数据层
随着Web应用系统负载的增速越来越快,常让系统不堪重压,数据库系统尤甚。而随着对用户体验关注度的提高,响应速度和使用的便利性则成为不可避免的话题。无论如何优化都不可能避免磁盘物理I/O的响应速度与内存中的I/O速度不匹配的问题,所以很自然地想到了通过内存Cache的方式来提高响应速度。
在使用的便利性方面最为典型的就是数据搜索。关系型数据库的特性,决定了它很难提供类似于Google那样的可以全文检索的搜索系统。我们再次以借助“外力”的方式来完善服务,将数据库中的数据通过利用Lucene或者Egothor等类似的搜索引擎系统,或者是利用Sphinx之类的软件和数据库集成,为数据库增加全文检索的能力。
可以设计出一个以数据库(My-SQL)来完成持久化和常规的数据访问功能,以分布式内存Cache系统来提供对响应速度和并发能力极高的数据的访问,以第三方或者自行研发的分布式全文搜索系统来提供全文检索服务的全方位的分布式数据服务层,中间则通过应用架构的帮助实现一个统一的数据访问层,来控制数据的读取写入检索等操作,如图4所示:让MySQL中的数据同步(或异步)写入到Cache和Search系统的实现方式很多,如对实时性要求不是很高,也不希望Data Proxy Layer中有太多的控制逻辑,完全可以通过队列的方式以异步的方式实现;如对实时性要求较高,也可以通过 Data Proxy Layer这一层应用来控制Cache和Search中的数据更新;甚至还可以通过MySQL的用户自定义函数,以 Trigger的方式将数据实时地更新到Cache集群。类似的方式可以想出很多,关键是要根据应用场景,来选择最合适、最简单的方式来实现。

图4 数据写入Cache和Search系统的实现方式
架构无所谓最好的,只有最合适的。任何架构都有其适用的场景,也有其相应的生命周期。应用场景或业务量的变化,都可能导致架构不足以应对的现象。引用一句电影台词:“出来混,迟早要还的!”

, , ,

之前说起 将参加 2010 数据库技术大会,今天将这次参会使用的 PPT 贴出来,或许会对大家有点用。
先大概介绍下大会的几本情况吧,满满2天的大会,共安排了 29 场演讲,内容涵盖了 Oracle,MySQL,DB2,SQL Server ,Sybase,达梦(国产数据库) 等多种数据库,演讲数量之多,主题内容之丰富,实数罕见,哈哈。演讲嘉宾的阵容也非常庞大,国内14个 ACE / ACE Director,其中9位到场演讲。
各个主题内容的 PPT 可以到 此处下载 ,这里我大概介绍下“高可用可扩展数据库架构” 这个话题吧:
在主题中,我从数据库的 高可用 和 可扩展 两个方面来进行了分享探讨:
高可用

软/硬件高可用(热/冷备)
数据高可用(共享,同/异步复制)

单独的硬件高可用除了冗余之外本身没有太多可以讲的,所以一笔带过。
基于共享设备的数据高可用只是大概的介绍了可能的方案,由于各方案的实施都比较昂贵,更适合于Oracle,DB2等,所以也没有深入探讨。
所以,这部分重点介绍了一下利用 MySQL 的 Replication 技术和应用程序的共同配合来实现 Share Nothing 方式的高可用。
可扩展

向上扩展(Scale Up)

硬件扩容(增加CPU数量,增加内存容量,增加磁盘数量…)
硬件升级(更换更高端的主机,更换更高端的存储设备,更换更高端CPU,更换转速更快的磁盘…)

向外扩展(Scale Out)

数据拷贝分发(一处写入多处读取,读写分离…)
数据垂直/水平切分(功能模块切分(vertical sharding),水平分片切分(horizontal sharding),两者综合)
Cache 和 Search(应用程序更新Cache,数据库更新 Cache,利用Search全文搜索…)

对于扩展性,Scale Up基本上就是各个厂商自身单台设备扩容能力的比拼,我们没有太多能力干预,所以我也只是简单分析了一下。
而对于 Scale Out,我想肯定是大家最关心的问题了。而Scale Out 中的 Sharding ,我想大家肯定也不是第一次听到,毕竟不是什么新东西了。
我这里重点介绍的是Sharding过程中如何选择合适的Sharding方法,如何解决Sharding之后的数据合并问题(其实没有解决,囧…),以及如何利用数据库外部资源(Cache,Search)来解决数据层的扩展性问题。
其实架构这个东西本身就是 仁者见仁智者见智,没有万能的架构,也没有长久适用的架构。架构和业务场景息息相关密不可分,离开了实际业务场景谈架构,可以说就是纸上谈兵,那如果离开了架构仅仅追求快速的业务实现呢?呵呵,出来混,迟早要还的。
注:我本身不是什么架构师,占用大家那么多宝贵时间听我扯淡架构,挺感动的…
高可用可扩展数据库架构方案探讨
View more presentations from Sky Jian.

, , , ,

刚刚忙完了一个持续了近一年的核心数据库相关的项目,过几天将会去北京参加 IT168 举办的“2010数据库技术大会”(DTCC),并受邀有个小的主题交流分享(高可用可扩展数据层架构探讨)。
这个小主题以 MySQL 数据库为主。当然,高可用可扩展的数据库架构层自然不可能离得开 Cache,所以也插入了部分 Cache 相关的内容,以及最后扩展出了少量全文检索也就是Search相关的内容,来构成 OLTP 类型应用的高可用可扩展数据库层架构。
欢迎大家到时候一起探讨。当然,不便现场参加DTCC,我想在会后一段时间应该能够见到相关 PPT 吧:)

, , ,

From Ryam:
p26
倒数第二行:
原文:“逻辑层与存储引擎实现层的过度解偶”
-> :“逻辑层与存储引擎实现层的过度解耦”
p82
第9行:
原文:“这样就省略了分页程序在分以前实时计算”
-> :“这样就省略了分页程序在分页前实时计算”
p118
第5行:
原文:“如果系统须要有限保证”
-> :“如果系统须要优先保证”
p123
第1行:
原文:“并不一定完全按照系数据库的元信息”
-> :“并不一定完全按照数据库的元信息”
p85
倒数第2行:
原文:“然后再瓶装展现对象”
-> :“然后再拼装展现对象”
p139
第8行:
原文:“那么将会存在大量记录指针信息存于同一Hash值相关联”
-> :“那么将会存在大量记录的指针信息与同一Hash值相关联”
p142
倒数第6行:
原文:“当然,并不是存在更新的字段就适合创建索引”
-> :“当然,并不是存在更新的字段就不适合创建索引”
p171
第3行:
原文:“但是当遇到一些自查询或较为复杂的join时”
-> :“但是当遇到一些子查询或较为复杂的join时”
第11行:
原文:“group_message_bad是优化前的表,优化后为group_message表),如示例代码9-1所示:…”
-> :这里的示例代码中group_message更换成group_message_bad
p194
第3行
原文:“这样不仅可以让变化频繁的Table的Query浪费Query Cache的内存”
-> :“这样不仅可以避免变化频繁的Table的Query浪费Query Cache的内存”
p196
倒数第1行:
原文:“先看一下与网络连接的性能配置项及对性能的影响”
-> :“先看一下与网络连接相关的性能配置项及其对性能的影响”
p202
倒数第2行:
原文:“在数据库上进行线后的参数调整”
-> :“在数据库上线后进行的参数调整”
p208
倒数第6行:
原文:“还是将页节点也加载进来”
-> :“还是将叶节点也加载进来”
p237
第2行:
原文:“还须要提一下系统高可用及数据安这两方面”
-> :“还须要提一下系统高可用及数据安全这两方面”
p246
第13行:
原文:“只有Master和Slave的server-id参数值比不一致时”
-> :“只有Master和Slave的server-id参数值不一致时”
p249
第2行:
原文:“最大的好处就是既可以避免主Master的写操作不会受到Slave集群的复制所带来的影响”
-> :“最大的好处就是既可以避免主Master的写操作受到Slave集群的复制所带来的影响”
p261
倒数第9行:
原文:“主要是将某个访问极其平凡的表”
-> :“主要是将某个访问极其频繁的表”
p264
图14-3
原文:“hprizontal sharding”
-> :“horizontal sharding”
问题:photo albums数据库的水平切分示例中,每个切分库的切分条件都是album_id % n = 0,应该依次为album_id % n = 0, album_id % n = 1 …
p279
倒数第15行:
原文:“当Innodb在本地的Buffer Pool(…)的时候”
-> :“当Innodb在本地的Buffer Pool(…)找不到所需数据的时候”
From 云水馋心:
P153
原文:“c_rec.group_msg_id = c_rec.id{”
-> :“c_rec.group_msg_id=m_rec.id”
From mysqlkumao
P201
原文:“10.4.3 Sort Buffer、Join Buffer 和 Read Buffer”
-> : “10.4.3 [...]

, , ,

《MySQL性能调优与架构设计》从最开始网上书店上架(2009.06.11)到现在才35天时间,库存量就已经很少了。接到出版社通知,需要今天完成勘误信息的整理,马上出片进行第二次印刷了。
这次印刷会订正掉目前位置已知的所有编写及出版过程中出现的错误信息,相信各方面品质都会比第一次印刷更好。
非常感谢各位读者热心积极的反馈以及肯定,感谢各位朋友的支持,感谢博文视点出版社的大力帮助,谢谢大家了。

, , ,