CAP理论与分布式数据库

5 10th, 2010 | Posted by jacky | Filed under 大话技术

根据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应用更容易做到分布式扩展。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与传统数据库的对比,可以看到VoltDB即支持传统数据库的ACID模型,又提供了类似NoSQL产品很高的扩展能力。

这个产品,让我想到了MySQL cluster,同样是shared-nothing架构,NDB存储引擎也要求将数据存放在内存中,数据根据PK被分布到多个不同的节点上,同一份数据可以保存多个副本,防止单点故障。

MySQL cluster目前的主要问题是性能不佳,但是我认为MySQL cluster的架构是分布式数据库未来的趋势,Oracle收购MySQL后,很多人对MySQL的前途表示担忧,而我作为一个用户,除了可能会收费这件事以外,我一点也不担心MySQL的前景,反而有所期待,因为在数据库领域没有任何一个公司比Oracle更懂数据库,而Oracle也正在大力发展MySQL cluster,MySQL cluster一定会成为分布式数据库领域内最好的解决方案之一。

–EOF–

标签: , , ,

Oracle or MySQL ?

4 27th, 2010 | Posted by jacky | Filed under 大话技术

本篇文章不得以任何形式转载或发表。

这不是一篇关于Oracle和MySQL技术比较的文章,而是我对Oracle和MySQL甚至 NoSQL产品选择上的一些想法。

我们过去和现在使用了大量的Oracle数据库,几乎我们所有的数据都存放在Oracle数据库里面,我们有高端的小型机,大型存储和全国最牛的DBA团队。这些都让我们引以为傲。

随着业务不断增长,数据量和计算量越来越庞大,我们发现小型机都无法满足我们的需求,除了Oracle我们别无选择,我们被“绑架”了,被IBM,EMC,Oracle绑架了,我们辛辛苦苦赚的血汗钱都交给他们了。

2009年开始,我们引入了MySQL数据库,采用sharding技术,利用PC服务器搭建高可用的数据库集群,极大的降低了我们的成本,并提供了充足的扩展能力,让业务有更大的发展空间。

最近,我们遇到了一些困惑:应用如何选择Oracle还是MySQL?从Oracle迁移到MySQL的意义是什么?Oracle收购SUN之后,MySQL何去何从?

我们的目标不是要用MySQL数据库替代所有的Oracle,事实上,这不现实也不是我们的目标,目前很多应用都依赖于Oracle数据库的特性,相当长的一段时间内,Oracle依然是我们的首选。但是,这并不意味着Oracle是我们唯一的选择,我们选择MySQL和PC服务器来搭建大规模数据库集群,最终的目标是要证明我们具备更换数据库的能力,具备用廉价设备替换小型机的能力,能够用我们自己的软件搭建高可用可扩展的架构。所以说,MySQL只是一个数据库而已,如果某天Oracle将MySQL收费,我们可以换成其他的数据库(比如 PostgreSQL)。我们正在做的事,其中的价值并不能简单的用节省 Oracle license的费用来评估。

阿里巴巴正在研发云计算系统,同样要证明阿里巴巴具备这种能力,这是每一个伟大的公司都要具备的能力。我相信,未来的数据存储肯定不仅仅局限于数据库,数据库和其他NoSQL产品一定会百花齐放。

我们做了大量的努力和尝试,包括Sharding和功能分区,SSD的尝试,MySQL高可用架构,数据同步工具等等,都是为了一个目标:证明的是我们能够设计出一种架构,可以做到用PC server和开源数据库(不仅仅局限于MySQL)来替换高端设备和Oracle,不被设备厂家和Oracle所绑架,将主动权掌握在自己手中。所以,我们不要过分纠结于Oracle和MySQL 在具体性能上的差异,作为一个数据库产品,MySQL无法和Oracle相比,单个PC server的可用性更是无法同小型机相比,但是我们用架构去弥补,整体上达到更高的可用性。

所以,我们不应该单纯用MySQL和Oracle本身的优劣,来评估技术方案,更不能用pc server的可用性和小型机去相比。关键是我们的技术架构能否用廉价的东西搭建出高可用可扩展的系统,这才是我们真正引以为傲的地方。

–EOF–

标签: ,

NoSQL漫谈

4 16th, 2010 | Posted by jacky | Filed under 大话技术

什么是NoSQL?wiki上的定义是“NoSQL is a movement promoting a loosely defined class of non-relational data stores that break with a long history of relational databases”。其实并不存在一个叫NoSQL的产品,它是一类non-relational data stores的集合。NoSQL的重点是non-relational,而传统的数据库是relational。

我们都知道,传统关系型数据库的最大缺陷是扩展性,虽然各个数据库厂家都有cluster的解决方案,但是不管是share storage还是share nothing的解决方案,扩展性都十分有限。目前解决数据库扩展性的思路主要有两个:第一是数据分片(sharding)或者功能分区,虽然说可以很好的解决数据库扩展性的问题,但是在实际使用过程中,一旦采用数据分片或者功能分区,必然会导致牺牲“关系型”数据库的最大优势-join,对业务局限性非常大,而数据库也退化成为一个简单的存储系统。另外一个思路是通过maser-slave复制的方式,通过读写分离技术在某种程度上解决扩展性的问题,但这种方案中,由于每个数据库节点必须保存所有的数据,这样每个存储的IO subsystem必然成为扩展的瓶颈,而且masert节点也是一个瓶颈。总的来说,传统关系型数据库的扩展能力十分有限。

在说NoSQL之前,首先得说两个重要的概念,一个是CAP理论,另一个是BASE模型。

CAP

Consistency(一致性),数据一致更新,所有数据变动都是同步的
Availability(可用性),好的响应性能
Partition tolerance(分区容错性) 可靠性

CAP原理告诉我们,这三个因素最多只能满足两个,不可能三者兼顾。对于分布式系统来说,分区容错是基本要求,所以必然要放弃一致性。对于大型网站来说,分区容错和可用性的要求更高,所以一般都会选择适当放弃一致性。对应CAP理论,NoSQL追求的是AP,而传统数据库追求的是CA,这也可以解释为什么传统数据库的扩展能力有限的原因。

BASE

Basically Availble:基本可用
Soft-state: 软状态/柔性事务
Eventual Consistency:最终一致性

BASE模型是传统ACID模型的反面,不同与ACID,BASE强调牺牲高一致性,从而获得可用性。基本可用是指通过sharding,允许部分分区失败。软状态是指异步,允许数据在一段时间内的不一致,只要保证最终一致就可以了。最终一致性是整个NoSQL中的一个核心理念,很多NoSQL产品就是基于最终一致性而设计的,包括Amazon的Dynamo.

NoSQL产品简介

NoSQL是很多non-relational data stores的集合,总体来说,他们基本都是基于Key-value形式的一种分布式存储,但是每一种NoSQL产品都面向一个特定的应用场景,根据这些应用场景,我们可以把NoSQL分为以下类型(参考了wiki上的定义,只列举了我们比较熟悉的产品):

KV cache:Memcached
KV store:Tokyo Tyrand/Cabinet,Memcachedb,Berkley DB
Eventually consistent KV store:dynamo,voldemort,Cassandra
Wide columnar store:BigTable,Cassandra,Hbase
document store:MongoDB

KV Cache类型不具有持久化存储的功能,其中的memcached被我们广泛使用,用来缓解数据库的压力,至于数据持久化存储的功能则由数据库来替代了。

KV store具备了持久化存储的功能,其中的memcachedb是新浪在memcached的基础上,采用Berkley DB作为存储层开发的分布式KV store。Tokyo Tyrand/Cabinet是日本最大的SNS社交网站mixi.jp开发的KV store,其中TC是一个NoSQL的数据库,用来做持久化数据存储,TT则是TC的网络接口(兼容memcached协议)。至于Berkley DB则是一个嵌入式数据库,现在掌握在Oracle手中。

Eventually consistent KV store是以最终一致性原理设计的一类KV store,包括Amazon的Dynamo,Lindedin的voldemort以及Facebook的Cassandra,Dynamo的主要特点是:分布式(去中心化),高可用,可扩展,永远可写等等。Dynamo的设计思想是分布式系统中最重要的理论之一,另外一个是Bigtable。

Wide columnar store包括Bigtable,Cassandra和Hbase,这种类型是用来处理结构化数据的,它有几个特点:具备大规模扩展能力,有类似数据库中column的概念,非常灵活的schema,采用memtable/sstable的存储机制,并基于列存储。Cassandra采用了Dynamo最终一致性的理念,并借鉴了Bigtable的数据模型和实现方式,所以很多人把他看作是开源版本的Bigtable+Dynamo,这种类型的KV store是我们关注的重点。

document store是基于文档的KV store,这种类型主要面向海量数据处理,其中MongoDB的特点是支持非常复杂的数据类型,而且查询语言非常强大,有些类似于关系型数据库。但它并不适合大规模并发读写的应用。

下面介绍几个分布式系统的概念:consistent hashing,virtual node,quorum,vector clock:

consistent hashing

我们通常使用的hash算法是hash() mod n,但是如果发生某个节点失效时,无法快速切换到其他节点。为了解决单点故障的问题,我们为每个节点都增加一个备用节点,当某个节点失效时,就自动切换到备用节点上,类似于数据库的master和slave。但是依然无法解决增加或删除节点后,需要做hash重分布的问题,也就是无法动态增删节点。这时就引入了一致性hash的概念 ,将所有的节点分布到一个hash环上,每个请求都落在这个hash环上的某个位置,只需要按照顺时针方向找到的第一个节点,就是自己需要的服务节点。当某个节点发生故障时,只需要在环上找到下一个可用节点即可。一致性hash解决了增删节点后需要hash重分布的问题,是分布式系统的基础。

virtual node

虚拟节点是在一致性hash的基础上,把一台物理节点虚拟成多个虚拟节点,并映射到hash环的不同位置上。这样的好处是可以根据机器硬件的性能,灵活的定义虚拟节点的个数。这里所说的虚拟节点不是用虚拟机技术实现的,而是把一个物理节点映射为多个虚拟节点。

quorum NRW

N: 复制的节点数,即一份数据被保存的份数。
R: 成功读操作的最小节点数,即每次读取成功需要的份数。
W: 成功写操作的最小节点数 ,即每次写成功需要的份数。

这三个因素决定了可用性,一致性和分区容错性。对于一个分布式系统来说,N通常都大于3,也就说同一份数据需要保存在三个以上不同的节点上,以防止单点故障。W是成功写操作的最小节点数,这里的写成功可以理解为“同步”写,比如N=3,W=1,那么只要写成功一个节点就可以了,另外的两份数据是通过异步的方式复制的。R是成功读操作的最小节点数,读操作为什么要读多份数据呢?在分布式系统中,数据在不同的节点上可能存在着不一致的情况,我们可以选择读取多个节点上的不同版本,来达到增强一致性的目的。下面我们分析几个典型的场景:

N=W,R=1,这种情况是最强一致性的,每个节点都被同步写入,读取任意节点即可,所以读取的性能最高,但是可用性是最差的,因为必须保证每个节点都必须成功写人。

R+W>N,这种情况也是可以保证一致性的,因为读取数据的节点和同步写入的节点至少有一个重叠,比如N=3,W=2,R=2,每份数据有三个复本,每次同步写成功两份数据,每次读取至少两份数据,则说明读取的数据至少有一份是同步写人的最新数据,所以一致性可以得到保证,N=3,W=2,R=2是可用性和性能的一个平衡。

N=R,W=1,这种情况最大程度保证了写的性能,数据只写一份即成功,而读取时则需要所有的数据复本,以此来达到保证一致性的目的,但是同样牺牲了可用性。

W+R<=N,这种情况是不保证一致性的,因为读取和写入的节点可能存在不重叠的情况,在数据同步到其他节点的这段时间窗口内,可能会出现数据不一致的情况。

总体来说,CAP原理决定了鱼肉熊掌不可兼得,必须有所取舍。数据库ACID模型保证了强一致性,但是对于大部分网站类型的应用,并不需要如此强的一致性,保证用户感知一致性就可以了,即在用户下次访问之前保证数据最终一致。还有一些应用要求Read your writes consistency,即用户对自己所做的修改即时可见,而对别人的数据则允许出现一定时间的延迟。

vector clock

vector clock相当于在数据上增加了一个版本控制。wiki上的解释:“Vector clocks is an algorithm  for generating a partial ordering of events in a distributed system and detecting causality violations.”

有Sx,Sy,Sz三个节点,N=3,W=1,R=3,数据分别初始为(Sx:0),(Sy:0),(Sz:0),数据在Sx节点发生变更,变成了D1(Sx:1),然后又被更新变为D2(Sx:2),此时D2(Sx:2)可以覆盖D1(Sx:1),假设数据已经被同步到另外两个节点,这时有两个请求分别在Sy和Sz节点上更新数据,产生了新的版本D3(Sx:2,Sy:1)和D4(Sx:2,Sz:1)。此时,如果发生读操作,从三个节点上读取到不同的版本,发现D1版本不是最新的数据,而D3和D4版本都是最新的数据,这时就需要应用自己去进行合并,并由Sx节点产生了新的版本D5(Sx:3,Sy:1,Sz:1)。

存储实现

NoSQL的存储实现非常多,个人觉得比较有代表性的有:Memcachedb采用Berkley DB,TC底层采用Hash table和B-tree的结构,Bigtable和Cassandra采用的Memtable和SStable存储机制。

我想说一下Cassandra的存储机制,和数据库类似,每次写操作之前,必须首先记录到日志中,Cassandra的日志称为commitlog。Memtable是一个按照key排序的内存结构,当Memtable写满后,会刷新到磁盘上存储起来,称为SStable,SStable一旦写入,就不能修改,只能读取和追加。这种方式的优势在于将随机IO变成了顺序IO,大大提高了系统的IO能力。当读取数据时,可能需要将Memtable和SStable的数据进行合并,Cassandra使用bloom filter来快速判定一个key是否落在某个SStable中。而一旦出现Memtable中的数据丢失,则可以通过commitlog来恢复,这点很象传统的数据库。

数据库和NoSQL

能否用数据库实现NoSQL类似的应用?事实上就有人这样做,Friendfeed就用MySQL数据库来实现的。但是用关系型数据库来实现,存在几个问题:1.性能问题;2.schema无法灵活定义;3.扩展性的问题。

首先是性能问题,所有的数据库都基于存储优化,而不是基于内存优化的,也就是说数据库的最佳应用场景是具有少量内存,而具有大量外部IO的情况。就算你有足够大的cache,把所有的数据都cache到内存中,与专门设计的内存数据库或者Key-Value cache相比,依然要慢几个数量级。这是数据库内部的算法决定的,所以不要指望把数据库当cache来用,当然专门的内存数据库除外,比如Oracle timesten.

第二个问题是schema不够灵活,关系型数据库中schema是无法灵活定义的,而Cassandra这类NoSQL数据库,You can add and remove arbitrary fields on the fly。其中最根本的原因是数据库是关系型的,新增或删除列都必须影响到每个表中的每一行。而NoSQL则不需要,每一行的column都可以不同,可以说根本就不存在schema的概念。根据Bigtable的定义:A Bigtable is a sparse, distributed, persistent multidimensional sorted map。相对于Bigtable“稀疏”的概念,我们认为关系型数据库中的表是“密集”的,也可以把Bigtable理解为一张满是空洞的table。

第三扩展性问题,数据库基于ACID模型设计,保证了强一致性,必然牺牲了扩展性,虽然可以用sharding或功能分区做横向扩展,但是也让数据库退化成为一个简单的key value store。

NoSQL会取代数据库吗?

未来NoSQL会取代数据库吗?传统的关系型数据库还有优势吗?我个人认为关系型数据库至少在相当长的一段时间内,依然是主流,而且还有很大的发展空间。

首先,NoSQL的应用场景非常局限,某个类型的NoSQL仅仅针对特定类型的应用场景而设计,Cassandra在facebook用来承担inbox的搜索功能,而关系型数据库则要通用的多,也就是说NoSQL很难拿来就用,首先你必须搞清楚自己的应用场景,所以说NoSQL对于很多人来说是此之蜜糖,彼之砒霜

第二,利用关系型数据库一样可以搭建出可以灵活扩展的架构,根据CAP原理,只要有所取舍,利用关系型数据库同样可以做到。

第三,关系型数据库厂家依然很强大,全世界有大量的用户。同时,硬件的发展更是日新月异,比如SSD的出现,就可以作为内存和磁盘之间的一层cache,甚至在不远的将来,完全替换磁盘。随着IO能力的巨大提升,数据库的性能也随着得到了更大的提升,很多现在面临的IO问题都不再是问题。而且,针对数据库的扩展性,厂家也提出了很多解决的方案,在一定程度上说,关系型数据库依然是最好的解决方案之一。

作为一名DBA,我并不担心数据库的未来,但我也不忽视NoSQL的巨大力量。有人将NoSQL解释成为Not only SQL,我想就是这个原因吧。

没有一种解决方案是完美的,架构就是有所取舍,世界也因为多样才美丽。

–EOF–

这篇文章是我根据网络上各种粗枝末节的信息,结合我对NoSQL的一些粗浅理解整理出来的,肯定有不正确的地方,希望大家批评指正。

标签:

招聘Application DBA

3 22nd, 2010 | Posted by jacky | Filed under IT江湖

阿里B2B招聘应用DBA一名,要求:

1.热爱数据库,精通Oracle原理;

2.精通SQL优化,数据库性能优化;

3.良好的沟通能力和抗压能力;

4.具备开发经验者优先考虑。

有意者发送邮件至:freezr@gmail.com

由于简历数量比较多,恕不能一一回复,请见谅。对该职位不了解的,可以看看以前的招聘帖子

–EOF–

标签:

我的珠海之旅

3 22nd, 2010 | Posted by jacky | Filed under 一地鸡毛, 边走边拍

今年在珠海休了一个长假,我参加了妹妹的婚礼,老婆去了香港和澳门大采购,老妈与久别多年的姐妹们重逢,儿子更是玩的乐不思蜀。

来杭州前,我曾经在珠海呆了五年,对这个地方还是挺有感情的,环境我很喜欢,就是发展机会少了些。这次见到了以前在L+G的老同事,大家都在感概光阴荏苒,岁月如梭。

儿子看起来比我更喜欢这个地方,因为有小狗,小朋友还有沙滩,一片看起来很普通的小沙滩,他就可以一个下午玩得不亦乐乎。他的内心比我单纯,要求很低,只要这么一小片沙滩,他就心满意足。而我,总是想要更多更好,欲望总是让我不自觉的陷入痛苦之中。我要努力找寻属于自己的那片小沙滩,在我的心灵深处,那里阳光明媚,有柔软的沙滩和各色的贝壳,我别无所求。

海滨公园 香港维港 澳门葡京赌场

–EOF–

Cassandra数据模型

2 10th, 2010 | Posted by jacky | Filed under 大话技术

提起NoSQL这个话题,仿佛不应该是DBA要关注的事,而是架构师应该关心的。但是作为一名DBA,在使用传统的关系型思想建模时,应该有必要了解NoSQL的建模方法。

各种NoSQL数据库有很多,我最关注的还是BigTable类型,因为它是一个高可用可扩展的分布式计算平台,用来处理海量的结构化数据,而数据库同样也是处理结构化数据,所以除了没有SQL,在数据模型方面有相似之处。Cassandra是facebook开源出来的一个版本,可以认为是BigTable的一个开源版本,目前twitter和digg.com在使用。我们尝试从DBA的角度出发去理解Cassandra的数据模型。

NoSQL并不能简单的理解为No SQL,其本质应该是No Relational,也就是说它不是基于关系型的理论基础,而我们所有传统的数据库都是基于这套理论而发展起来的,所以SQL并不是问题的关键所在,比如有些NoSQL数据库可以提供SQL类型的接口,允许你通过类SQL的语法去访问数据。而Friendfeed则是反其道而行之,利用关系型数据库MySQL,采用了去关系化的设计方法,去实现自己的KeyValue存储。所以NoSQL的本质是No Relational.

Cassandra特点:

1.灵活的schema,不需要象数据库一样预先设计schema,增加或者删除字段非常方便(on the fly)。

2.支持range查询:可以对Key进行范围查询。

3.高可用,可扩展:单点故障不影响集群服务,可线性扩展。

Keyspace

Cassandra中的最大组织单元,里面包含了一系列Column family,Keyspace一般是应用程序的名称。你可以把它理解为Oracle里面的一个schema,包含了一系列的对象。

Column family(CF)

CF是某个特定Key的数据集合,每个CF物理上被存放在单独的文件中。从概念上看,CF有点象数据库中的Table.

Key

数据必须通过Key来访问,Cassandra允许范围查询,例如:start => '10050', :finish => '10070'

Column

在Cassandra中字段是最小的数据单元,column和value构成一个对,比如:name:“jacky”,column是name,value是jacky,每个column:value后都有一个时间戳:timestamp。

和数据库不同的是,Cassandra的一行中可以有任意多个column,而且每行的column可以是不同的。从数据库设计的角度,你可以理解为表上有两个字段,第一个是Key,第二个是长文本类型,用来存放很多的column。这也是为什么说Cassandra具备非常灵活schema的原因。

Super column

Super column是一种特殊的column,里面可以存放任意多个普通的column。而且一个CF中同样可以有任意多个Super column,一个CF只能定义使用Column或者Super column,不能混用。下面是Super column的一个例子,homeAddress这个Super column有三个字段:分别是street,city和zip:

homeAddress: {street: "binjiang road",city: "hangzhou",zip: "310052",}

Sorting

不同于数据库可以通过Order by定义排序规则,Cassandra取出的数据顺序是总是一定的,数据保存时已经按照定义的规则存放,所以取出来的顺序已经确定了,这是一个巨大的性能优势。有意思的是,Cassandra按照column name而不是column value来进行排序,它定义了以下几种选项:BytesType, UTF8Type, LexicalUUIDType, TimeUUIDType, AsciiType,  和LongType,用来定义如何按照column name来排序。实际上,就是把column name识别成为不同的类型,以此来达到灵活排序的目的。UTF8Type是把column name转换为UTF8编码来进行排序,LongType转换成为64位long型,TimeUUIDType是按照基于时间的UUID来排序。例如:

Column name按照LongType排序:

{name: 3, value: "jacky"},
{name: 123, value: "hellodba"},
{name: 976, value: "Cassandra"},
{name: 832416, value: "bigtable"}

Column name按照UTF8Type排序:

{name: 123, value: "hellodba"},
{name: 3, value: "jacky"},
{name: 832416, value: "bigtable"}
{name: 976, value: "Cassandra"}

下面我们看twitter的Schema:

<Keyspace Name="Twitter">
  <ColumnFamily CompareWith="UTF8Type" Name="Statuses" />
  <ColumnFamily CompareWith="UTF8Type" Name="StatusAudits" />
  <ColumnFamily CompareWith="UTF8Type" Name="StatusRelationships"
    CompareSubcolumnsWith="TimeUUIDType" ColumnType="Super" />
  <ColumnFamily CompareWith="UTF8Type" Name="Users" />
  <ColumnFamily CompareWith="UTF8Type" Name="UserRelationships"
    CompareSubcolumnsWith="TimeUUIDType" ColumnType="Super" />
</Keyspace>

我们看到一个叫Twitter的keyspace,包含若干个CF,其中StatusRelationships和UserRelationships被定义为包含Super column的CF,CompareWith定义了column的排序规则,CompareSubcolumnsWith定义了subcolumn的排序规则,这里使用了两种:TimeUUIDType和UTF8Type。我们没有看到任何有关column的定义,这意味着column是可以灵活变更的。

为了方便大家理解,我会尝试着用关系型数据库的建模方法去描述Twitter的Schema,但千万不要误认为这就是Cassandra的数据模型,对于Cassandra来说,每一行的colunn都可以是任意的,而不是象数据库一样需要在建表时就创建好。

Users CF记录用户的信息,Statuses CF记录tweets的内容,StatusRelationships CF记录用户看到的tweets,UserRelationships CF记录用户看到的followers。我们注意到排序方式是TimeUUIDType,这个类型是按照时间进行排序的UUID字段,column name是用UUID函数产生(这个函数返回了一个UUID,这个UUID反映了当前的时间,可以根据这个UUID来排序,有点类似于timestamp一样),所以得到结果是按照时间来排序的。使用过twitter的人都知道,你总是可以看到自己最新的tweets或者最新的friends.

存储

Cassandra是基于列存储的(Bigtable也是一样),这个和基于列的数据库是一个道理。

API

下面是数据库,Bigtable和Cassandra API的对比:

Relational			SELECT `column` FROM `database`.`table` WHERE `id` = key;
BigTable			table.get(key, "column_family:column")
Cassandra: standard model	keyspace.get("column_family", key, "column")
Cassandra: super column model	keyspace.get("column_family", key, "super_column", "column")

我对Cassandra数据模型的理解:

1.column name存放真正的值,而value是空。因为Cassandra是按照column name排序,而且是按列存储的,所以往往利用column name存放真正的值,而value部分则是空。例如:“jacky”:“null”,“fenng”:”null”

2.Super column可以看作是一个索引,有点象关系型数据库中的外键,利用super column可以实现快速定位,因为它可以返回一堆column,而且是排好序的。

3.排序在定义时就确定了,取出的数据肯定是按照确定的顺序排列的,这是一个巨大的性能优势。

4. 非常灵活的schema,column可以灵活定义。实际上,colume name在很多情况下,就是value(是不是有点绕)。

5.每个column后面的timestamp,我并没有找到明确的说明,我猜测可能是数据多版本,或者是底层清理数据时需要的信息。

最后说说架构,我认为架构的核心就是有所取舍,不管是CAP还是BASE,讲的都是这个原则。架构之美在于没有任何一种架构可以完美的解决各种问题,数据库和NoSQL都有其应用场景,我们要做的就是为自己找到合适的架构。

–EOF–

这篇文章,我参考了up and running with cassandra,除此以外,我还参考了twitter提供的API,它帮助我理解twitter的schema设计。这篇文章,肯定有很多理解不正确的地方,希望朋友们指正。

标签: ,

Oracle Exadata技术浅析

2 1st, 2010 | Posted by jacky | Filed under 大话技术

自从Oracle和HP推出Exadata之后,我就很关注这个产品,之前也写了一篇Oracle database machine介绍它。去年,Oracle和SUN合并后,推出了Oracle Exadata V2,相比较上一代产品有几个变化:第一,使用SUN的硬件;第二,宣称支持OLTP应用;第三,Oracle 11g R2提供了更多的新特性。

Exadata Smart Flash Cache

Exadata V2整体架构并没有太多改变,换用了SUN的硬件,除了采用intel最新的nehalem CPU以外,每台storage cell更是配置了384GB的flash,这也是为什么V2可以支持OLTP应用的关键。

Flash cache完全是自动管理,Oracle会根据数据的访问情况,决定哪些数据放在flash cache中。所有的数据都是先被写到普通磁盘上,再根据访问情况读入flash cache的,所以如果flash card发生故障,数据不会丢失。当然,Oracle提供了方式,可以让用户手动将表或者索引pin在flash cache中。

在自动管理的方式之外,Oracle还允许用户人工创建flash disks,和普通磁盘一样,这些flash disks通过ASM输出给数据库使用,用户可以把一些访问非常频繁的数据文件放在上面。这些flash disks不仅仅是cache了,所以ASM会在cell和cell之间做镜像。如果某块卡发生故障,那么整个storage cell上的flash disks会offline,保证数据不会丢失。

Smart scan

Smart scan是Exadata最重要的一个功能,它的作用就是把SQL放在每个cell上去运行,然后每个cell只返回符合条件的数据给数据库,这样就极大的降低了数据库服务器的负载和网络流量,并充分利用了cell的计算资源和IO资源。

传统方式:所有的数据都需要返回给数据库服务器,网络带宽要求高,所有的计算在数据库服务器上完成。

Smart scan:只返回符合条件的数据,减少网络带宽,并充分利用了cell上的计算和IO资源。

这里有一点要注意,在使用smart scan时,每个cell返回给DB server的是结果集,而不再是传统的block,DB server完成结果集的处理,并返回给客户端。

Smart scan如何处理join?是我一直想要搞清楚的问题。事实上,smart scan只能处理join filtering,而真正join的工作必须在DB Server上完成,而且smart scan仅适合于处理DSS环境的复杂join,对于OLTP类型的简单join,smart scan并不能发挥其优势。设想下面的查询:

select e.ename,d.dname from emp e, dept d where and e.ename=’Jacky’ and e.deptno=d.deptno;

假设采用nested loops join,smart scan只能完成e.ename=’Jacky’这个条件的过滤,然后将符合条件的emp表的数据返回到DB server,然后由DB Server完成join的工作,逐条查询dept表(e.deptno=d.deptno)的数据。所以smart scan并不适合nested loop join(我认为smart scan只有在适合的条件下才会启用),只有DSS环境的大数据量复杂join才会发挥出优势。而且smart scan只能完成filtering的工作,而不能真正完成join的工作,这个与Greenplum数据库是不同的(有兴趣可以看我的文章,Greenplum技术浅析)。设想下面的查询(emp和dept都是大表):

select e.ename,d.dname from emp e, dept d where e.deptno=d.deptno;

假设采用hash join,由于没有任何过滤条件,smart scan只能把两个表的数据全部返回到DB Server上进行join操作,不过smart scan也不是一点用都没有,至少还可以进行column的过滤,只返回需要的字段就可以了。

Oracle的文档中,曾经提到对于一个大表和小表join时,smart scan会采用bloom filter来快速定位(可以看我以前的文章,有趣的bloom filter)。方法是把小表build成为bloom filter,然后在每个storage cell上对大表做scan,利用bloom filter快速定位符合条件的结果,并返回给DB Server作join。

Storage index

存储索引,顾名思义是在存储级别建立的索引,简单的说就是为表中的每一列数据建立一个索引,每个index entry记录一段数据区间的最大值,最小值以及它们的物理位置,文档上说1MB数据对应一条index entry,见下图:

如果我们查询B<2,或者B>8的数据,根据存储索引,我们就可以跳过这些不在min和max之间的数据块,极大的提高了扫描的速度,这就是存储索引的意义。

Hybrid Columnar Compressed

首先我们要搞清楚,什么是行压缩,什么叫列压缩。我们熟悉的数据库,如Oracle,MySQL等都是基于行的数据库,就是行的不同字段物理上存放在一起,还有一种是基于列的数据库,就是每个字段的不同行物理上存放在一起。他们的优缺点同样突出:

基于行的数据库,访问一行非常方便,但是由于同一列的数据是分开存放的,如果要针对某一列进行查询时,几乎要扫描整个表才能得到结果。基于行数据库的压缩,称为行压缩。

基于列的数据库,因为同一列的数据物理上放在一起,所以访问一列非常方便,也就是说如果针对某一列进行查询时,不需要扫描整个表,只需要扫描这一列的数据就可以了,但是访问一行的全部字段非常不方便(又是废话)。基于列数据库的压缩,称为列压缩。

Oracle通常说的compress功能(包括11g R2的Advanced compress),都是行压缩,因为Oracle是个基于行的数据库。大概的方法就是在block头部存放一个symbol table,然后将相同的值放在那里,每行上相同的数据指向symbol table,以此来达到压缩的目的。行压缩的效果通常不好,因为我们知道行与行之间,其实相同的数据并不多。但是列压缩则不同,因为相同列的数据类型相同,很容易达到很好的压缩效果。

行压缩和列压缩都有其优缺点,而Oracle的混合列压缩技术,实际上是融合了列压缩的高压缩比和行数据库的访问特性,将两者的优点结合起来。Oracle提出了CU的概念(compress unit),在一个CU内,是一个基于列的存储方式,采用列压缩,但是一个CU内保存了行的所有字段信息,所以在CU与CU之间,Oracle还是一个基于行的数据库,访问某一行,总是只在一个CU内。每个CU由一些连续的block组成,CU header中记录了每一行的各个列在CU中的分布情况,在混合列压缩模式下,一行通常是跨多个block的。

所以说混合列压缩,结合了列压缩和行访问的特点,即可以提供非常高的压缩率,又很好的保证了基于行类型的访问。

Exadata的另一个重要功能是IO resource management,如果我们在一个Exadata上部署了很多个数据库,可以用它来管理IO资源,这里就不作阐述了。

目前,我还没有了解到在国内有Exadata的应用,而且资料也是比较少的。希望有机会可以真实的测试一下它的性能,我不怀疑他在DSS环境下的表现,但是对于OLTP类型的应用,是否真的象Oracle说的那么强劲,还有待于验证。

–EOF–

标签: ,

如何控制SQL执行计划之9i篇

1 28th, 2010 | Posted by jacky | Filed under 大话技术

对于一个高并发的OLTP系统,SQL执行计划的改变往往意味着灾难。很多因素都可能导致执行计划发生不可预期的改变,比如表结构,索引,统计信息等变化,甚至我们发生过一个小小的grant操作,导致执行计划失效,重新解析后生成了一个不正确的执行计,让整个系统Crash的案例。最近,我们对一个分区表增加分区后,导致了执行计划发生改变,故障再次重演。

如何控制SQL的执行计划就成为了一个课题,之前我曾经写过一篇关于调整SQL执行计划的文章,但是内容比较粗略。因为Oracle提供了很多手段去控制执行计划,所以我打算为每个版本都整理一个最佳实践。

我们设想一个场景,一个SQL本来应该走nested loop join,但是由于某种原因,突然变成了hash join,调整统计信息无效,数据库load不断升高,只留给你很少的时间,怎么办?最直接有效的方法是在SQL上加hints,但是需要程序发布,或者程序根本无法修改。

9i为我们提供了Stored outline,大家都非常熟悉,但是对于上面的场景,还是需要点技巧。方法是:生成两个stored outline,一条是错误的,一条是正确的(加hints),两个然后将其执行计划交换。看下面的步骤:

1.创建两个public stroed outline,第一个是目前运行的,第二个是加了hints.

create or replace outline OUTLN1 on select e.ename from emp e, dept d where e.deptno=d.deptno;
create or replace outline OUTLN2 on select /*+ use_nl(e d)*/ e.ename from emp e, dept d
where e.deptno=d.deptno;

拷贝成为private outline

create or replace private outline PRIV_OUTLN1 from OUTLN1;
create or replace private outline PRIV_OUTLN2 from OUTLN2;

交换两个stored outline的执行计划

update ol$ set ol_name=decode(ol_name,'PRIV_OUTLN1','PRIV_OUTLN2','PRIV_OUTLN2','PRIV_OUTLN1')
where ol_name in ('PRIV_OUTLN1','PRIV_OUTLN2');

设置本session生效,并测试结果

alter session set use_private_outlines=true;

刷新

execute dbms_outln_edit.refresh_private_outline('PRIV_OUTLN1');
execute dbms_outln_edit.refresh_private_outline('PRIV_OUTLN2');

发布到public outline

create or replace outline OUTLN1 from private PRIV_OUTLN1;
create or replace outline OUTLN2 from private PRIV_OUTLN2;

设置使用,调整完毕

alter system set use_stored_outlines=true;

这样操作的原因是因为stroed outline必须依赖SQL的文本匹配,所以,我们利用加hints之后的SQL产生正确的执行计划,并通过交换的方式,让SQL的执行计划变成我们想要的结果。当然,如果你愿意,也可以直接修改ol$hints表的内容,同样可以达到改变执行计划的目的。

–EOF–

online rebuild发生的问题

1 26th, 2010 | Posted by jacky | Filed under 大话技术

朋友遇到一个问题,当建立一个包含varchar2(4000)的索引时,直接创建没有问题,但是如果加上online子句,则报错:

ORA-00604: error occurred at recursive SQL level 1
ORA-01450: maximum key length (3215) exceeded

这里实际上包含了两个问题:

1.索引的key到底可以有多大?因为索引的key是不可以跨越block的,所以最直接的决定因素是block size,Oracle的文档给出了一个计算公式:

DB_BLOCK_SIZE:                  Maximum Index Key Length:
==============                  =========================

2K  (2048)                       758  Bytes
4K  (4096)                       1578 Bytes
8K  (8192)                       3218 Bytes
16K (16384)                      6498 Bytes

文档中说:每个index leaf block至少有两行记录,考虑block header,PCTFREE,INITRANS等因素,每个index key最大可以为block size的40%。但是我测试了一下(8K block size),发现并不是如此。

create table test(id varchar2(4000),id2 varchar2(3000));
create index test_ind on test(id,id2);
ORA-01450: maximum key length (6398) exceeded

最大的长度是6398,而不是文档中提到的3218,后来我把block dump出来,发现每个index leaf block中只有一行,而不是文档中所说的至少有两行,这样index key的最大值就自然变大了,大约为block size的80%。为什么与文档上不一致,应该是版本的问题,文档描述的是在9i之前的情况,而9i之后Oracle作了改进(没有8i的环境,没法证实)。

2.为什么online无法创建,而直接创建没有问题呢?

因为online创建的过程中会生成一个中间表,用来记录创建过程中的变化,而这个表是IOT表。经过测试,发现IOT表的限制比较严格,8k的block size,最大长度只能有3215,所以普通创建可以成功,而online创建则不行,关键还在背后的IOT表上。

怎么解决这个问题,Oracle的官方说法是加大block size,但是对于IOT表,我们发现加大block size并没有太大作用,最大长度也只有3800。看来,对于INDEX每个block可以只存放一条,而IOT比较特殊,每个block需要至少存放两条记录。简单点说,IOT的限制比普通INDEX更严格一些,至于为什么,我想也许没什么特别的原因吧,也许只是版本改进过程中的代码问题。

我很奇怪,怎么会在varchar2(4000)的字段上建索引呢?一问才知道,原来这个字段实际内容并不长,但是当时设计时,可能是为了方便,直接设计成最大值了,才导致现在的问题。现在只能想办法,重新建一个适当长度的字段,把内容拷贝过去,然后再建立索引。

–EOF–

标签:

我这五年

1 26th, 2010 | Posted by jacky | Filed under 一地鸡毛

不知不觉,来杭州已经五年了。翻看了以前的blog,里面记录了我这五年的心路历程。

2004年12月27日,《新的征程》

“上帝关上了一扇门,总会打开一扇窗。所以,别担心。”

2005年3月19日,《杭州两个月》

“说说工作吧,刚来的时候,我感觉到很大的压力,毕竟我和周围的同事相比,水平还差很多。但是发现 BITI,RUDOLF,GRASSBELL,FENNG,WANGHAI,CHENYP,CHENJP,都对我非常的好。虽然我的水平很差,但是有什么 问题,都耐心的给我讲,让我很感动,尤其是BITI,能在这样的环境中工作,我感觉很满足。”

2005年7月28日,《一致读的实现》

第一次有点技术含量的文章,现在看起来依然很优雅,短短几句话,就将一致读的原理解释的清清楚楚:)

2007年3月4日,《细节决定成败》

做DBA的第一次犯错。

2007年5月19日,《IBM P570+DMX3》

第一次跟着老大做项目,学到了很多东西,现在仍然受益匪浅。

2008年1月1日,《我的2007》

2007年,终于实现了梦寐以求的目标,正式当上了DBA。比当DBA更重要的是,当上了别人的爹。

2008年3月6日,《我有压力 未解决》

“工作是挣扎滴,前途是渺茫滴
压力是很大滴,解决是没有滴
抱怨是没用滴,开心是重要滴
未来是光明滴,什么都会有滴

五年时光,很快就过去了,虽然没成就什么大事业,不过也算是小有成就,感谢家人和朋友的支持,真是挺不容易的。

一直一来,我的梦想是成为象BITI那样的技术大牛,也一直为了这个目标而努力,但是今年情况可能发生了变化,我从技术岗位调整为管理岗位,这本不是我的意愿和初衷,但是我也欣然接受。未来我将把更多的心思放在团队身上,努力让每个人都能从团队发展的过程中受益。

我不会放弃自己的梦想,大师说过:只有自己坚信,才会有人同路。我坚信现在的工作是有价值的,我坚信所有的痛都是暂时的,我坚信付出总有一天会有回报的,我坚信……

–EOF–