从需求出发来看关系模型与非关系模型–时代的变革1
于是,破坏与重构就成为了新时代的主音。
对互联网应用而言,最急需的需求,就是处理大量用户输入的海量数据,进行一些逻辑处理后再将结果返回给用户。因此,对于在线数据处理来说,可水平扩展的容量指标,可无限增长的写入tps和读取qps,是互联网企业的最大,最急需的需求。
相比较而言,为了追求性能和容量的尽可能最大化,其他的指标则被迫的推到了后面。这也非常容易理解,性能不够,容量不够,直接面临的是不能提供服务,作为互联网应用,如果不能为用户带来服务,其核心价值就受到了最大的挑战。因此,互联网应用的关键需求就是,高可用,高可扩展,高性能,其他则是额外的追求。因此,综合来看,互联网在线处理的需求排序列表基本上可以认为是: 数据的扩展性>请求的响应时间尽可能短>down机时间尽可能短>成本尽可能低>可自动快速恢复>数据的读取一致性>程序开发者的方便与快速响应需求。
但历史的演进也是渐进式的发展的,必须考虑到前人们的经验。因为关系模型的流行,关系数据库也自然而然的是当时人们能够找到的最安全合理的扩展目标,也正因为如此,传统数据库的水平切分,是第一个尝试解决这个问题的方案。
在这类方案中,用户一般会被要求使用某一个简单的切分条件将数据均匀的分散到几台甚至几百台数据库中,从而可以做到无论多少数据,都可以通过水平加机器的方式来做到能力的提升,从而使用数据库就可以满足 “数据的扩展性” , “请求的响应时间” ,“down机时间短” ,这几个指标了,但,有好就有坏,使用这种切分的方案后,原来可以运行的SQL或事务却不得不做出必要的限制了,虽然不爽,但与开发成本相比,满足核心需求是第一位的,所以,这个方案是基本符合要求的。
从上世纪80年代到本世纪,大部分应用使用水平切分的方式满足了业务的实际需要。自然而然的,人们开始要求更多,希望能够更简单的解决问题。自然的,会有人提出来:关系数据库我们用着很好,关系模型表达也非常清楚和明确,大家都熟悉,你们为什么不做个中间层,从而实现对上层完全透明,并且与关系数据库完全兼容的数据访问层出来呢? 这样我们就可以既不用修改我们的业务逻辑,又可以享受到近乎无限的水平扩展能力了不是么?
想法很好,于是就有非常多的人开始往这个方向努力,他们在开始设计之初拿到的需求列表里也是这么写的: 可以实现对应用完全透明的数据库访问,用户不需要关心下层是什么数据,只需要按照关系模型写业务逻辑,其他东西都应该能够自动做好。
然而开始着手去满足这个需求的时候,就发现了几个必须要解决的问题。
1. 多机事务怎么做? 2. 多机join怎么做才能非常高效? 3. 分布式索引怎么做?
嗯 ,其实这些问题一直困扰人们到现在都没有得到解决,为什么呢?因为硬件碰到了天花板。
下面我们来做个简单分析:
计算机是个分型的系统,从cpu设计开始,直到分布式存储,所有的操作处理其实都在做类似的事情。 在cpu架构设计里面,最核心的问题就是,一个数据要被多个处理器访问,到底是共享这个数据呢呢?还是每次访问都复制一份呢?
也因此才会有CPU的三种标准处理方式,A方案:全局共享(smp)。B方案:全局不共享。以及C方案:部分共享部分不共享(numa)的折中方案。
在分布式存储领域也是一样的,想要水平的扩展,势必需要尽可能的减少竞争的数据。而如果碰到所有机器都需要读写的数据时,只有共享才能做到最好的性能。数据库sharding明显的属于mpp架构,因此碰到需要多机器都需要读写的数据时,只能依靠机器与机器之间的通信来完成数据读写的协调性工作。
这种协调,在单机的时候会使用cpu之间的消息队列,或者数据总线。而在分布式领域,协调就必须依托网络来进行了。而网络就是个硬件天花板。
既然要谈到天花板,我们就需要对网络来进行一个简要的分析,这样才能更容易的理解这天花板在哪里:作为一种通信的媒介,我们把它抽象为以下几个关键的指标: 延迟,吞吐量,安全性。
为了比较方便,我们以cpu到内存的数据传输通道作为对比:
延迟 网络:30 ms 内存:21ns
吞吐量 网络 :100mb/s 内存:800ms/s
安全性 网络 :有不可达问题 内存:无不可达问题
明显能够看到,延迟增加非常多,吞吐量则有明显的降低。又因为网络不够安全,所以需要更多次的网络交互才能做到更高的安全性。在这几个属性的中,最麻烦的是延迟,因为延迟与距离相关,当距离变远的时候,延迟就会无法控制。我们在后面还会更深入的来讨论网络在分布式领域中造成的影响。
因此,就算是算法十分完善,我们也无法降低在分布式领域内针对同一个数据的延迟。而这直接导致原来可能能够进行的关系代数或事务过程,延迟直接变大一百倍。以至于业务无法接受!
关系代数模型也有类似的问题,因为查询共享的数据需要与多台机器交互,延迟比使用内存增加很多,因此延迟 也被迫的增加了很多。
于是,我们就悲剧的发现,想做到与单机数据库一样的事务或一致性体验,在分布式存储领域则不再能够体验的到了。
因为这件事没办法得到很好的解决,所以这里的解决方案就发生了分化:
我们在这里不会去评价一种思路的好坏,不过一切思路和想法的最终判断标准是他能够解决多少实际的问题。
一部分人从自己的实际场景出发,发现自己在一部分场景中(比如存储业务日志)只是在使用简单的接口,而基于分布式环境实现关系代数模型的难度又是这么的令人沮丧。那么,自然而然的会产生一种推论,抛弃关系代数模型不就好了?!
于是一个概念产生了: nosql。不要sql,扩展的广一点就是不要关系代数模型和一致性模型。这一派的核心思路比较激进:既然关系代数模型性能那么低,干脆丢弃它而选择更简单的层次模型不就解决问题了?因为实现一个层次模型的 key val数据库实现相对的容易,于是根据nosql这一理念,在很短时间内就出现了一大批nosql的产品。这类产品的基本特征就是,只实现了简单的key value接口,主要关注于数据的自动运维,以及利用新的存储引擎实现来达到写的优化,从而能够降低成本。比较有特色的nosql系统是cassandra,hbase,mongodb等。
我本身觉得这个想法挺不错的,可惜有一批nosql的开发者为了自己的利益,把nosql宣传成了无所不能的开发神器,完全无视其导致的开发成本上升的负面作用,这就比较无语了。 大部分情况下,开发效率比自动的数据运维重要的多,在这种情况下盲目的使用原始的层次模型接口来完成功能,可能会极大的降低生产效率,还望各位读者小心。
另外的一些人认为关系代数模型与扩展性无关,希望能够用新的方式来支持分布式关系代数模型,这种尝试目前有个统一的称呼:newsql 。 他们的主要思路就是只做适当的权衡,并努力将关系代数模型在分布式环境下进行重构。
在这个领域内的一些比较有特色的想法是基于内存的数据库实现,他们假定未来的数据库应主要依托更大的内存和网络来进行构建,这样,数据库就成功的规避了慢速磁盘设备对系统造成的影响,让延迟下降到可以接受的程度。比较具有代表性的是 voltdb, mysql cluster等
在另外的一些尝试中,人们假定事务冲突的概率很小,而事务的数量则很大,依托这个假定,人们使用传统意义上的读写锁来实现数据的读写一致性,从而能够支持数据库的查询。 这类实现中最出名的就是google的megastore 和spanner
而传统的数据库阵营也在逐渐的被互联网的需求所引导,逐渐的将自己历史的包袱逐渐丢下,以更轻盈的体态来面对互联网应用的需求了。
而针对不同读取场景进行优化的实现就更如皓月繁星那样多了。。
在我们快速的浏览了这么多针对现在问题的尝试思路之后,让我们针对目前的人们针对在线海量数据库的需求做一个简单的总结吧:
从目前来看,原教旨的nosql运动已经遇到了瓶颈,虽然在实际的应用场景中,人们可以在开始将自己的用户模型使用经过精心设计的key val引擎进行实现。不过随着新业务需求被不断的提出,用户会逐渐的发现自己的大部分的开发内容是 :将原有的数据,按照另外一个key进行组织,然后提供给用户进行查询。这个过程则正是关系数据库主要能够解决的问题。
在满足了基本需求以后,用户对于方便性的需求会逐渐的变为矛盾的主要方面,因此,借鉴传统的关系数据库的优秀经验,结合互联网应用的实际需求进行适当的改进和裁剪,是目前所有存储领域从业人员共同努力的方向。