可扩展的分布式数据库架构
本文发表在《程序员》杂志2010年第6期
引 言
数据库的可用性和扩展性一直是数据库厂商和用户最关注的问题。过去我们采用高端的设备,比如使用小型机和大型存储来保证数据库的可用 性。而扩展性主要采用向上扩展(Scale up)的方式,通过增加CPU,内存,磁盘等方式提高处理能力。这种集中式数据库的架构,使得数据库成为了整个系统的瓶颈,已经越来越不适应海量数据对计 算能力的巨大需求。近些年来,分布式系统成为了一种趋势,我们希望用廉价的设备堆叠出具备高可用性和高扩展性的计算集群,从而摆脱对大型设备的依赖。数据 库作为系统架构中的重要组成部分,如何做到即提供高可用性,又具备向外扩展(Scale out)的能力,数据库厂商和用户都做了很多的探索。
Oracle RAC
几乎每个数据库产品都有集群解决方案,Oracle RAC是业界最流行的产品。其架构的最大特点是共享存储架构(Shared-disk),整个RAC集群是建立在一个共享的存储设备之上的,节点之间采用 高速网络互连。Oracle RAC提供了非常好的高可用特性,比如负载均衡和应用透明切换(TAF),其最大优势在于对应用完全透明,应用无需修改便可以切换到RAC集群。但 是,RAC的扩展能力有限,首先因为整个集群都依赖于底层的共享存储,所以共享存储的IO能力和可用性决定了整个集群的可以提供的能力,其依然无法摆脱对 大型存储设备的依赖。Oracle显然也意识到了这个问题,在Oracle的MAA(Maximum Availability Architecture)架构中,采用ASM来整合多个存储设备的能力,使得RAC底层的共享存储也具备线性扩展的能力,整个集群不再依赖于大型存储的 处理能力和可用性。
RAC的另外一个问题是,随着节点数的不断增加,节点间通信的成本也会随之增加,当到达某个限度时,增加节点可能不会 再带来性能上的提高,甚至可能造成性能下降。这个问题的主要原因是Oracle RAC对应用透明,应用可以连接集群中的任意节点进行处理,当不同节点上的应用争用资源时,RAC节点间的通信开销会严重影响集群的处理能力。所以使用 Oracle RAC有两个建议:1.节点间通信使用高速互联网络;2.尽可能将不同的应用分布在不同的节点上。基于这个原因,Oracle RAC通常在DSS环境中可以做到很好的扩展性,因为DSS环境很容易将不同的任务分布在不同的计算节点上,而对于OLTP应用,Oracle RAC更多情况下是用来提高可用性,而不是为了提高扩展性。
MySQL Cluster
MySQL cluster和Oracle RAC完全不同,它采用Shared-nothing架构。整个集群由管理节点(ndb_mgmd),处理节点(mysqld)和存储节点(ndbd)组 成,不存在一个共享的存储设备。MySQL cluster主要利用了NDB存储引擎来实现,NDB存储引擎是一个内存式存储引擎,要求数据必须全部加载到内存之中。数据被自动分布在集群中的不同存 储节点上,每个存储节点只保存完整数据的一个分片(fragment)。同时,用户可以设置同一份数据保存在多个不同的存储节点上,以保证单点故障不会造 成数据丢失。
MySQL cluster的优点在于其是一个分布式的数据库集群,处理节点和存储节点都可以线性增加,整个集群没有单点故障,可用性和扩展性都可以做到很高,更适合 OLTP应用。但是它的问题在于:1.NDB存储引擎必须要求数据全部加载到内存之中,限制比较大,但是目前NDB新版本对此做了改进,允许只在内存中加 载索引数据,数据可以保存在磁盘上。2.目前的MySQL cluster的性能还不理想,因为数据是按照主键hash分布到不同的存储节点上,如果应用不是通过主键去获取数据的话,必须在所有的存储节点上扫描, 返回结果到处理节点上去处理。而且,写操作需要同时写多份数据到不同的存储节点上,对节点间的网络要求很高。
虽然MySQL cluster目前性能还不理想,但是share nothing的架构一定是未来的趋势,Oracle接手MySQL之后,也在大力发展MySQL cluster,我对MySQL cluster的前景抱有很大的期待。
分布式数据库架构目前,除了数据库厂商的 集群产品以外,解决数据库扩展能力的方法主要有两个:数据分片和读写分离。数据分片(Sharding)的原理就是将数据做水平切分,类似于hash分区 的原理,通过应用架构解决访问路由和数据合并的问题。Sharding架构的优势在于,集群扩展能力很强,几乎可以做到线性扩展,而且整个集群的可用性也 很高,部分节点故障,不会影响其他节点提供服务。Sharding原理简单,容易实现,是一种非常好的解决数据库扩展性的方案。但是Sharding对应 用场景的要求很高,因为一旦使用数据分片架构,如果需要跨不同的节点做join,或者统计类型的操作,将会变得非常困难,应该尽量避免。所以说 Sharding架构会损失部分关系型数据库的特性,比如join,从而使数据库退化为Key-Value store类型的存储。所以,并不是所有的应用都适合做Sharding,它可能会造成应用架构复杂或者限制系统的功能,这也是它的缺陷所在。
Sharding架构图
读写分离架构利用了数据库的复制技术,将读和 写分布在不同的处理节点上,从而达到提高可用性和扩展性的目的。最通常的做法是利用MySQL Replication技术,Master DB承担写操作,将数据变化复制到多台Slave DB上,并承担读的操作。这种架构适合read-intensive类型的应用,通过增加Slave DB的数量,读的性能可以线性增长。为了避免Master DB的单点故障,集群一般都会采用两台Master DB做双机热备,所以整个集群的读和写的可用性都非常高。除了MySQL,Oracle从11g开始提供Active Standby的功能,也具备了实现读写分离架构的基础。读写分离架构的缺陷在于,不管是Master还是Slave,每个节点都必须保存完整的数据,如 果在数据量很大的情况下,集群的扩展能力还是受限于单个节点的存储能力,而且对于Write-intensive类型的应用,读写分离架构并不适合。
读写分离架构图
读写分离架构应用非常广泛,很多网站都采用cache+DB的读写分离架构,通 过cache层来承载大量的读访问。Memcached是一种广泛使用的Key-Value cache,它不具备持久化存储的功能,所以它通常和数据库一起组成读写分离的架构,由数据库承载数据持久化存储的功能,而Memcached则用来承载 大量的并发访问。通常的做法是:应用的读请求会首先访问Memcached,如果命中则返回,如果没有命中,则会去数据库中读取,并将数据加载到 Memcached中。关于新增,修改和删除操作,一般采用lazy load的策略,即新增时只写入数据库,并不会马上更新Memcached,而是等到再次读取时才会加载到Memcached中,修改和删除操作也是更新 数据库,然后将Memcached中的数据标记为失效,等待下次读取时再加载。Memcached支持数据分区,利用hash算法将数据分布到不同的服务 器,组成一个分布式的cache集群。
MySQL+Memcached读写分离架构
数据库与CAP理论
根据 CAP理论,一致性(C),可用性(A),分区容错性(P),三者不可兼得,必须有所取舍。而传统数据库保证了强一致性(ACID模型)和高可用性,所以 要想实现一个分布式数据库集群非常困难,这也解释了为什么数据库的扩展能力十分有限。而近年来不断发展壮大的NoSQL运动,就是通过牺牲强一致性,采用 BASE模型,用最终一致性的思想来设计分布式系统,从而使得系统可以达到很高的可用性和扩展性。
但是,对于CAP理论也有一些不同的声 音,数据库大师Michael Stonebraker就撰文《Errors in Database Systems, Eventual Consistency, and the CAP Theorem》,表示为了P而牺牲C是不可取的。事实上,数据库系统最大的优势就对一致性的保证,如果我们放弃了一致性,也许NoSQL比数据库更有优 势。那么,有没有可能实现一套分布式数据库集群,即保证可用性和一致性,又可以提供很好的扩展能力呢?
目前,已经有很多分布式数据库的产 品,但是绝大部分是面向DSS类型的应用,因为相比较OLTP应用,DSS应用更容易做到分布式扩展,比如基于PostgreSQL发展的 Greenplum,就很好的解决了可用性和扩展性的问题,并且提供了很强大的并行计算能力。对于OLTP应用,业务特点决定其要求:高可用性,一致性, 响应时间短,支持事务和join等等。Michael Stonebraker提到了一种新的数据库产品VoltDB,它的定义是Next-Generation SQL Database for Fast-Scaling OLTP Applications。虽然产品还没有问世,但是从技术资料上来看,它有几个特点:
1.采用Share nothing架构,将物理服务器划分为以CPU core为单位的Virtual node,采用Sharding技术,将数据自动分布到不同的Virtual node,最大限度的利用机器的计算资源;
2.采用内存数据访问技 术,类似于内存数据库(In-memory database),区别于传统的数据库(Disk-based database),消除了传统数据库内存管理的开销,而且响应速度非常快;
3.每个Virtual node上的操作是自治的,利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销(比如Latch和Lock);
4.数据同步写 多个副本,不存在单点故障,而且消除了传统数据库需要记录redo log的开销。
VoltDB不仅支持传统数据库的ACID模型和 SQL接口,而且提供类似NoSQL产品的高可用性和很强的扩展能力,可谓鱼肉熊掌兼得。CAP理论并不是神话,相信未来类似的数据库产品会不断涌现。
数 据库和NoSQL
当越来越多的NoSQL产品涌现出来,它们具备很多关系型数据库所不具备的特性,在可用性和扩展性方面都可以做到很好。 那么,未来传统的关系型数据库还有优势吗?NoSQL会取代数据库吗?我个人认为关系型数据库至少在相当长的一段时间内,依然是主流,而且还有很大的发展 空间。
第一,NoSQL的应用场景非常局限,某个类型的NoSQL仅仅针对特定类型的应用场景而设计。而关系型数据库则要通用的多,使用 NoSQL必须搞清楚自己的应用场景是否适合,所以说NoSQL对于很多人来说是“汝之蜜糖,彼之砒&霜”。
第二,利用关系型数据库配合应用架构, 比如Sharding和读写分离技术,同样可以搭建出具备高可用和扩展性的分布式数据库集群。
第三,关系型数据库厂商依然很强大,全世界有大量的 用户,需求必然会推动新的产品问世。
第四,硬件的发展日新月异,比如闪存的技术的不断成熟,未来闪存可以作为磁盘与内存之间的cache,或者完 全替代磁盘。而内存价格越来越低,容量越来越大,In-memory cache或database的应用越来越广泛,可以给应用带来数量级的性能提升。数据库面临的IO问题将被极大改善,数据库也将随着这些新技术而焕发第 二春。
我并不担心关系型数据库的未来,但我们也不能忽视NoSQL的巨大力量。未来,各种产品和技术一定是百花齐放,关系型数据库依然有 很强的生命力,各种NoSQL产品也会层出不穷,所以完全不用担心谁将会替代谁,我们要做的就是找到最佳的解决方案。有人将NoSQL解释成为Not only SQL,我想也是这个原因吧。
结论
前面探讨了关于数据库可用性和扩展性方面的问题,我们看到每种产品和 架构都是有缺陷的,其实架构就是有所取舍的过程,目标是用最小的代价去解决问题。所以找到适合自己的产品和架构,这才是最重要的