NoSQL数据库笔谈
序
日前国内没有一套比较完整的NoSQL数据库资料,有不少先驱整理发表了不少,但不是很系统。不材尝试着将各家的资料整合一下,并书写了一些本身的看法。
本书写了一些目前的NoSql的一些主要技术,算法和思想。同时列举了大量的现有的数据库实例。读彻底篇,相信读者会对NoSQL数据库了解个大概。
另外我还准备开发一个开源内存数据库galaxydb.本书也是为这个数据库提供一些架构资料。php
思想篇
CAP,BASE和最终一致性是NoSQL数据库存在的三大基石。而五分钟法则是内存数据存储了理论依据。这个是一切的源头。
CAP
- C: Consistency 一致性
- A: Availability 可用性(指的是快速获取数据)
- P: Tolerance of network Partition 分区容忍性(分布式)
10年前,Eric Brewer教授指出了著名的CAP理论,后来Seth Gilbert 和 Nancy lynch两人证实了CAP理论的正确性。CAP理论告诉咱们,一个分布式系统不可能知足一致性,可用性和分区容错性这三个需求,最多只能同时知足两个。
熊掌与鱼不可兼得也。关注的是一致性,那么您就须要处理由于系统不可用而致使的写操做失败的状况,而若是您关注的是可用性,那么您应该知道系统的read操做可能不能精确的读取到write操做写入的最新值。所以系统的关注点不一样,相应的采用的策略也是不同的,只有真正的理解了系统的需求,才有可能利用好CAP理论。
做为架构师,通常有两个方向来利用CAP理论
- key-value存储,如Amaze Dynamo等,可根据CAP三原则灵活选择不一样倾向的数据库产品。
- 领域模型 + 分布式缓存 + 存储 (Qi4j和NoSql运动),可根据CAP三原则结合本身项目定制灵活的分布式方案,难度高。
我准备提供第三种方案:实现能够配置CAP的数据库,动态调配CAP。
- CA:传统关系数据库
- AP:key-value数据库
而对大型网站,可用性与分区容忍性优先级要高于数据一致性,通常会尽可能朝着 A、P 的方向设计,而后经过其它手段保证对于一致性的商务需求。架构设计师不要精力浪费在如何设计能知足三者的完美分布式系统,而是应该进行取舍。
不一样数据对于一致性的要求是不一样的。举例来说,用户评论对不一致是不敏感的,能够容忍相对较长时间的不一致,这种不一致并不会影响交易和用户体验。而产品价格数据则是很是敏感的,一般不能容忍超过10秒的价格不一致。
最终一致性
一言以蔽之:过程松,结果紧,最终结果必须保持一致性
为了更好的描述客户端一致性,咱们经过如下的场景来进行,这个场景中包括三个组成部分:
存储系统能够理解为一个黑盒子,它为咱们提供了可用性和持久性的保证。
ProcessA主要实现从存储系统write和read操做
ProcessB和C是独立于A,而且B和C也相互独立的,它们同时也实现对存储系统的write和read操做。
下面以上面的场景来描述下不一样程度的一致性:
html
强一致性(即时一致性) 假如A先写入了一个值到存储系统,存储系统保证后续A,B,C的读取操做都将返回最新值
假如A先写入了一个值到存储系统,存储系统不能保证后续A,B,C的读取操做能读取到最新值。此种状况下有一个“不一致性窗口”的概念,它特指从A写入值,到后续操做A,B,C读取到最新值这一段时间。
最终一致性是弱一致性的一种特例。假如A首先write了一个值到存储系统,存储系统保证若是在A,B,C后续读取以前没有其它写操做更新一样的值的话,最终全部的读取操做都会读取到最A写入的最新值。此种状况下,若是没有失败发生的话,“不一致性窗口”的大小依赖于如下的几个因素:交互延迟,系统的负载,以及复制技术中replica的个数(这个能够理解为master/salve模式中,salve的个数),最终一致性方面最出名的系统能够说是DNS系统,当更新一个域名的IP之后,根据配置策略以及缓存控制策略的不一样,最终全部的客户都会看到最新的值。
变体
- Causal consistency(因果一致性)
若是Process A通知Process B它已经更新了数据,那么Process B的后续读取操做则读取A写入的最新值,而与A没有因果关系的C则能够最终一致性。
- Read-your-writes consistency
若是Process A写入了最新的值,那么Process A的后续操做都会读取到最新值。可是其它用户可能要过一会才能够看到。
此种一致性要求客户端和存储系统交互的整个会话阶段保证Read-your-writes consistency.Hibernate的session提供的一致性保证就属于此种一致性。
- Monotonic read consistency
此种一致性要求若是Process A已经读取了对象的某个值,那么后续操做将不会读取到更早的值。
- Monotonic write consistency
此种一致性保证系统会序列化执行一个Process中的全部写操做。
BASE
提及来颇有趣,BASE的英文意义是碱,而ACID是酸。真的是水火不容啊。
前端
- Basically Availble --基本可用
- Soft-state --软状态/柔性事务
"Soft state" 能够理解为"无链接"的, 而 "Hard state" 是"面向链接"的
- Eventual Consistency --最终一致性
最终一致性, 也是是 ACID 的最终目的。
BASE模型反ACID模型,彻底不一样ACID模型,牺牲高一致性,得到可用性或可靠性: Basically Available基本可用。支持分区失败(e.g. sharding碎片划分数据库) Soft state软状态 状态能够有一段时间不一样步,异步。 Eventually consistent最终一致,最终数据是一致的就能够了,而不是时时一致。
BASE思想的主要实现有
1.按功能划分数据库
2.sharding碎片
BASE思想主要强调基本的可用性,若是你须要高可用性,也就是纯粹的高性能,那么就要以一致性或容错性为牺牲,BASE思想的方案在性能上仍是有潜力可挖的。
其余
I/O的五分钟法则
在 1987 年,
Jim Gray 与 Gianfranco Putzolu 发表了这个"五分钟法则"的观点,简而言之,若是一条记录频繁被访问,就应该放到内存里,不然的话就应该待在硬盘上按须要再访问。这个临界点就是五分钟。 看上去像一条经验性的法则,实际上五分钟的评估标准是根据投入成本判断的,根据当时的硬件发展水准,在内存中保持 1KB 的数据成本至关于硬盘中存据 400 秒的开销(接近五分钟)。这个法则在 1997 年左右的时候进行过一次回顾,证明了五分钟法则依然有效(硬盘、内存实际上没有质的飞跃),而此次的回顾则是针对 SSD 这个"新的旧硬件"可能带来的影响。
随着闪存时代的来临,五分钟法则一分为二:是把 SSD 当成较慢的内存(extended buffer pool )使用仍是当成较快的硬盘(extended disk)使用。小内存页在内存和闪存之间的移动对比大内存页在闪存和磁盘之间的移动。在这个法则首次提出的 20 年以后,在闪存时代,5 分钟法则依然有效,只不过适合更大的内存页(适合 64KB 的页,这个页大小的变化偏偏体现了计算机硬件工艺的发展,以及带宽、延时)。
不要删除数据
Oren Eini(又名Ayende Rahien)建议开发者尽可能避免数据库的软删除操做,读者可能所以认为硬删除是合理的选择。做为对Ayende文章的回应,Udi Dahan强烈建议彻底避免数据删除。
所谓软删除主张在表中增长一个IsDeleted列以保持数据完整。若是某一行设置了IsDeleted标志列,那么这一行就被认为是已删除的。Ayende以为这种方法“简单、容易理解、容易实现、容易沟通”,但“每每是错的”。问题在于:
删除一行或一个实体几乎总不是简单的事件。它不只影响模型中的数据,还会影响模型的外观。因此咱们才要有外键去确保不会出现“订单行”没有对应的父“订单”的状况。而这个例子只能算是最简单的状况。……
当采用软删除的时候,无论咱们是否情愿,都很容易出现数据受损,好比谁都不在乎的一个小调整,就可能使“客户”的“最新订单”指向一条已经软删除的订单。
若是开发者接到的要求就是从数据库中删除数据,要是不建议用软删除,那就只能硬删除了。为了保证数据一致性,开发者除了删除直接有关的数据行,还应该级联地删除相关数据。可Udi Dahan提醒读者注意,真实的世界并非级联的:
假设市场部决定从商品目录中删除同样商品,那是否是说全部包含了该商品的旧订单都要一并消失?再级联下去,这些订单对应的全部发票是否是也该删除?这么一步步删下去,咱们公司的损益报表是否是应该重作了?
没天理了。
问题彷佛出在对“删除”这词的解读上。Dahan给出了这样的例子:
我说的“删除”实际上是指这产品“停售”了。咱们之后再也不卖这种产品,清掉库存之后再也不进货。之后顾客搜索商品或者翻阅目录的时候不会再看见这种商品,但管仓库的人暂时还得继续管理它们。“删除”是个贪方便的说法。
他接着举了一些站在用户角度的正确解读:
订单不是被删除的,是被“取消”的。订单取消得太晚,还会产生花费。
员工不是被删除的,是被“解雇”的(也多是退休了)。还有相应的补偿金要处理。
职位不是被删除的,是被“填补”的(或者招聘申请被撤回)。
在上面这些例子中,咱们的着眼点应该放在用户但愿完成的任务上,而非发生在某个
实体身上的技术动做。几乎在全部的状况下,须要考虑的实体总不止一个。
为了代替IsDeleted标志,Dahan建议用一个表明相关数据状态的字段:有效、停用、取消、弃置等等。用户能够借助这样一个状态字段回顾过去的数据,做为决策的依据。
删除数据除了破坏数据一致性,还有其它负面的后果。Dahan建议把全部数据都留在数据库里:“别删除。就是别
删除。”
RAM是硬盘,硬盘是磁带
Jim Gray在过去40年中对技术发展有过巨大的贡献,“内存是新的硬盘,硬盘是新的磁带”是他的名言。“实时”Web应用不断涌现,达到海量规模的系统愈来愈多,这种后浪推前浪的发展模式对软硬件又有何影响?
Tim Bray早在网格计算成为热门话题以前,就
讨论过以RAM和网络为中心的硬件结构的优点,能够用这种硬件创建比磁盘集群速度更快的RAM集群。
对于数据的随机访问,内存的速度比硬盘高几个数量级(即便是最高端的磁盘存储系统也只是勉强达到1,000次寻道/秒)。其次, 随着数据中心的网络速度提升,访问内存的成本更进一步下降。经过网络访问另外一台机器的内存比访问磁盘成本更低。就在我写下这段话的时候,Sun的 Infiniband产品线中有一款具有9个全互联非阻塞端口交换机,每一个端口的速度能够达到30Gbit/sec!Voltaire产品的端口甚至更多;简直不敢想象。(若是你想了解这类超高性能网络的最新进展,请关注Andreas Bechtolsheim在Standford开设的课程。)
各类操做的时间,以2001年夏季,典型配置的 1GHz 我的计算机为标准:java
执行单一指令 |
1 纳秒 |
从L1 高速缓存取一个字 |
2 纳秒 |
从内存取一个字 |
10 纳秒 |
从磁盘取连续存放的一个字 |
200 纳秒 |
磁盘寻址并取字 |
8 毫秒 |
以太网 |
2GB/s |
Tim还指出Jim Gray的
名言中后半句所阐述的真理:“对于随机访问,硬盘慢得不可忍受;但若是你把硬盘当成磁带来用,它吞吐连续数据的速率使人震惊;它天生适合用来给以RAM为主的应用作日志(logging and journaling)。”
时间闪到几年以后的今天,咱们发现硬件的发展趋势在RAM和网络领域势头不减,而在硬盘领域则止步不前。Bill McColl提到用于并行计算的
海量内存系统已经出现:
内存是新的硬盘!硬盘速度提升缓慢,内存芯片容量指数上升,in-memory软件架构有望给各种数据密集的应用带来数量级的性能提高。小型机架服务器(1U、2U)很快就会具有T字节、甚至更大量的内存,这将会改变服务器架构中内存和硬盘之间的平衡。硬盘将成为新的磁带,像磁带同样做为顺序存储介质使用(硬盘的顺序访问至关快速),而再也不是随机存储介质(很是慢)。这里面有着大量的机会,新产品的性能有望提升10倍、100倍。
Dare Obsanjo指出
若是不把这句真言当回事,会带来什么样的恶劣后果—— 也就是Twitter正面临的麻烦。论及Twitter的内容管理,Obsanjo说,“若是一个设计只是简单地反映了问题描述,你去实现它就会落入磁盘 I/O的地狱。无论你用Ruby on Rails、Cobol on Cogs、C++仍是手写汇编都同样,读写负载照样会害死你。”换言之,应该把随机操做推给RAM,只给硬盘留下顺序操做。
Tom White是
Hadoop Core项目的提交者,也是Hadoop项目管理委员会的成员。他对Gray的真言中“硬盘是新的磁带”部分做了更深刻地探讨。White在讨论MapReduce编程模型的时候指出,为什么对于Hadloop这类工具来讲,
硬盘仍然是可行的应用程序数据存储介质:
本质上,在MapReduce的工做方式中,数据流式地读出和写入硬盘,MapReduce是以硬盘的传输速率不断地对这些数据进行排序和合并。 与之相比,访问关系数据库中的数据,其速率则是硬盘的寻道速率(寻道指移动磁头到盘面上的指定位置读取或写入数据的过程)。为何要强调这一点?请看看寻道时间和磁盘传输率的发展曲线。寻道时间每一年大约提升5%,而数据传输率每一年大约提升20%。寻道时间的进步比数据传输率慢——所以采用由数据传输率决定性能的模型是有利的。MapReduce正是如此。
虽然固态硬盘(SSD)可否改变寻道时间/传输率的对比还有待观察,
White文章的跟贴中,不少人都认为
SSD会成为RAM/硬盘之争中的平衡因素。
Nati Shalom对
内存和硬盘在数据库部署和使用中的角色做了一番有理有据的评述。 Shalom着重指出用数据库集群和分区来解决性能和可伸缩性的局限。他说,“数据库复制和数据库分区都存在相同的基本问题,它们都依赖于文件系统/硬盘 的性能,创建数据库集群也很是复杂”。他提议的方案是转向In-Memory Data Grid(IMDG),用Hibernate二级缓存或者GigaSpaces Spring DAO之类的技术做支撑,将持久化做为服务(Persistence as a Service)提供给应用程序。Shalom解释说,IMDG
提供在内存中的基于对象的数据库能力,支持核心的数据库功能,诸如高级索引和查询、事务语义和锁。IMDG还从应用程序的代码中抽象出了数据的拓扑。经过这样的方式,数据库不会彻底消失,只是挪到了“正确的”位置。
IMDG相比直接RDBMS访问的优点列举以下:
- 位于内存中,速度和并发能力都比文件系统优越得多
- 数据可经过引用访问
- 直接对内存中的对象执行数据操做
- 减小数据的争用
- 并行的聚合查询
- 进程内(In-process)的局部缓存
- 免除了对象-关系映射(ORM)
你是否须要改变对应用和硬件的思惟方式,最终取决于你要用它们完成的工做。但彷佛公论认为,开发者解决性能和可伸缩性的思路已经到了该变一变的时候。 node
Amdahl定律和Gustafson定律
这里,咱们都以S(n)表示n核系统对具体程序的加速比,K表示串行部分计算时间比例。
Amdahl 定律的加速比:S(n) = 使用1个处理器的串行计算时间 / 使用n个处理器的并行计算时间python
S(n) = 1/(K+(1-K)/n) = n/(1+(n-1)K)mysql
Gustafson定律的加速比:S(n) = 使用n个处理器的并行计算量 / 使用1个处理器的串行计算量c++
S(n) = K+(1-K)n
有点冷是否是?
通俗的讲,Amdahl 定律将工做量看做1,有n核也只能分担1-K的工做量;而Gustafson定律则将单核工做量看做1,有n核,就能够增长n(1-K)的工做量。
这里没有考虑引进分布式带来的开销,好比网络和加锁。成本仍是要仔细核算的,不是越分布越好。
控制算法的复杂性在常数范围以内。
git
万兆以太网
手段篇
一致性哈希
要求分布式架构的发展提及。
第一阶段
考虑到单服务器不能承载,所以使用了分布式架构,最初的算法为 hash() mod n, hash()一般取用户ID,n为节点数。此方法容易实现且可以知足运营要求。缺点是当单点发生故障时,系统没法自动恢复。
第二阶段
为了解决单点故障,使用 hash() mod (n/2), 这样任意一个用户都有2个服务器备选,可由client随机选取。因为不一样服务器之间的用户须要彼此交互,因此全部的服务器须要确切的知道用户所在的位置。所以用户位置被保存到memcached中。
当一台发生故障,client能够自动切换到对应backup,因为切换前另外1台没有用户的session,所以须要client自行从新登陆。github
这个阶段的设计存在如下问题
负载不均衡,尤为是单台发生故障后剩下一台会压力过大。
不能动态增删节点
节点发生故障时须要client从新登陆
第三阶段
打算去掉硬编码的hash() mod n 算法,改用一致性哈希(consistent hashing)分布
假如采用Dynamo中的strategy 1
咱们把每台server分红v个虚拟节点,再把全部虚拟节点(n*v)随机分配到一致性哈希的圆环上,这样全部的用户从本身圆环上的位置顺时针往下取到第一个vnode就是本身所属节点。当此节点存在故障时,再顺时针取下一个做为替代节点。
优势:发生单点故障时负载会均衡分散到其余全部节点,程序实现也比较优雅。
亚马逊的现状
aw2.0公司的Alan Williamson撰写了一篇报道,主要是关于他在Amazon EC2上的体验的,他抱怨说,Amazon是公司惟一使用的云提供商,看起来它在开始时可以适应得很好,可是有一个临界点:
在开始的日子里Amazon的表现很是棒。实例在几分钟内启动,几乎没有遇到任何问题,即使是他们的
小实例(SMALL INSTANCE)也很健壮,足以支持适当使用的MySQL数据库。在20个月内,Amazon云系统一切运转良好,不须要任何的关心和抱怨。
……
然而,在最后的八个月左右,他们“盔甲”内的漏洞开始呈现出来了。第一个弱点前兆是,新加入的Amazon SMALL实例的性能出现了问题。根据咱们的监控,在服务器场中新添加的机器,与原先的那些相比性能有所降低。开始咱们认为这是天然出现的怪现象,只是碰 巧发生在“吵闹的邻居”(Noisy Neighbors)旁边。根据随机法则,一次快速的停机和从新启动常常就会让咱们回到“安静的邻居”旁边,那样咱们能够达到目的。
…… 然而,在最后的一两个月中,咱们发现,甚至是这些“使用高级CPU的中等实例”也遭受了与小实例相同的命运,其中,新的实例无论处于什么位置,看起来彷佛都表现得同样。通过调查,咱们还发现了一个新问题,它已经悄悄渗透到到Amazon的世界中,那就是内部网络延迟。
算法的选择
不一样的哈希算法能够致使数据分布的不一样位置,若是十分均匀,那么一次MapReduce就涉及节点较多,但热点均匀,方便管理。反之,热点不均,会大体机器效率发挥不彻底。
Quorum NRW
- N: 复制的节点数量
- R: 成功读操做的最小节点数
- W: 成功写操做的最小节点数
只需W + R > N,就能够保证强一致性。
第一个关键参数是 N,这个 N 指的是数据对象将被复制到 N 台主机上,N 在实例级别配置,协调器将负责把数据复制到 N-1 个节点上。N 的典型值设置为 3.
复 制中的一致性,采用相似于 Quorum 系统的一致性协议实现。这个协议有两个关键值:R 与 W。R 表明一次成功的读取操做中最小参与节点数量,W 表明一次成功的写操做中最小参与节点数量。R + W>N ,则会产生相似 quorum 的效果。该模型中的读(写)延迟由最慢的 R(W)复制决定,为获得比较小的延迟,R 和 W 有的时候的和又设置比 N 小。
若是N中的1台发生故障,Dynamo当即写入到preference list中下一台,确保永远可写入
如 果W+R>N,那么分布式系统就会提供强一致性的保证,由于读取数据的节点和被同步写入的节点是有重叠的。在一个RDBMS的复制模型中 (Master/salve),假如N=2,那么W=2,R=1此时是一种强一致性,可是这样形成的问题就是可用性的减低,由于要想写操做成功,必需要等 2个节点都完成之后才能够。
在分布式系统中,通常都要有容错性,所以通常N都是大于3的,此时根据CAP理论,一致性,可用性和分区容错 性最多只能知足两个,那么咱们就须要在一致性和分区容错性之间作一平衡,若是要高的一致性,那么就配置N=W,R=1,这个时候可用性就会大大下降。若是 想要高的可用性,那么此时就须要放松一致性的要求,此时能够配置W=1,这样使得写操做延迟最低,同时经过异步的机制更新剩余的N-W个节点。
当存储系统保证最终一致性时,存储系统的配置通常是W+R<=N,此时读取和写入操做是不重叠的,不一致性的窗口就依赖于存储系统的异步实现方式,不一致性的窗口大小也就等于从更新开始到全部的节点都异步更新完成之间的时间。
(N,R,W) 的值典型设置为 (3, 2 ,2),兼顾性能与可用性。R 和 W 直接影响性能、扩展性、一致性,若是 W 设置 为 1,则一个实例中只要有一个节点可用,也不会影响写操做,若是 R 设置为 1 ,只要有一个节点可用,也不会影响读请求,R 和 W 值太小则影响一致性,过大也很差,这两个值要平衡。对于这套系统的典型的 SLA 要求 99.9% 的读写操做在 300ms 内完成。
无 论是Read-your-writes-consistency,Session consistency,Monotonic read consistency,它们都经过黏贴(stickiness)客户端到执行分布式请求的服务器端来实现的,这种方式简单是简单,可是它使得负载均衡以 及分区容错变的更加难于管理,有时候也能够经过客户端来实现Read-your-writes-consistency和Monotonic read consistency,此时须要对写的操做的数据加版本号,这样客户端就能够遗弃版本号小于最近看到的版本号的数据。
在系统开发过程 中,根据CAP理论,可用性和一致性在一个大型分区容错的系统中只能知足一个,所以为了高可用性,咱们必须放低一致性的要求,可是不一样的系统保证的一致性 仍是有差异的,这就要求开发者要清楚本身用的系统提供什么样子的最终一致性的保证,一个很是流行的例子就是web应用系统,在大多数的web应用系统中都 有“用户可感知一致性”的概念,这也就是说最终一致性中的“一致性窗口"大小要小于用户下一次的请求,在下次读取操做来以前,数据能够在存储的各个节点之 间复制。还好比假如存储系统提供了
read-your-write-consistency一致性,那么当一个用户写操做完成之后能够立马看到本身的更 新,可是其它的用户要过一会才能够看到更新。
几种特殊状况:
W = 1, R = N,对写操做要求高性能高可用。
R = 1, W = N , 对读操做要求高性能高可用,好比相似cache之类业务。
W = Q, R = Q where Q = N / 2 + 1 通常应用适用,读写性能之间取得平衡。如N=3,W=2,R=2
Vector clock
vector clock算法。能够把这个vector clock想象成每一个节点都记录本身的版本信息,而一个数据,包含全部这些版本信息。来看一个例子:假设一个写请求,第一次被节点A处理了。节点A会增长一个版本信息(A,1)。咱们把这个时候的数据记作D1(A,1)。 而后另一个对一样key(这一段讨论都是针对一样的key的)的请求仍是被A处理了因而有D2(A,2)。
这个时候,D2是能够覆盖D1的,不会有冲突产生。如今咱们假设D2传播到了全部节点(B和C),B和C收到的数据不是从客户产生的,而是别人复制给他们的,因此他们不产生新的版本信息,因此如今B和C都持有数据D2(A,2)。好,继续,又一个请求,被B处理了,生成数据D3(A,2;B,1),由于这是一个新版本的数据,被B处理,因此要增长B的版本信息。
假设D3没有传播到C的时候又一个请求被C处理记作D4(A,2;C,1)。假设在这些版本没有传播开来之前,有一个读取操做,咱们要记得,咱们的W=1 那么R=N=3,因此R会从全部三个节点上读,在这个例子中将读到三个版本。A上的D2(A,2);B上的D3(A,2;B,1);C上的D4(A,2;C,1)这个时候能够判断出,D2已是旧版本,能够舍弃,可是D3和D4都是新版本,须要应用本身去合并。
若是须要高可写性,就要处理这种合并问题。好假设应用完成了冲入解决,这里就是合并D3和D4版本,而后从新作了写入,假设是B处理这个请求,因而有D5(A,2;B,2;C,1);这个版本将能够覆盖掉D1-D4那四个版本。这个例子只举了一个客户的请求在被不一样节点处理时候的状况, 并且每次写更新都是可接受的,你们能够本身更深刻的演算一下几个并发客户的状况,以及用一个旧版本作更新的状况。
上面问题看似好像能够经过在三个节点里选择一个主节点来解决,全部的读取和写入都从主节点来进行。可是这样就违背了W=1这个约定,实际上仍是退化到W=N的状况了。因此若是系统不须要很大的弹性,W=N为全部应用都接受,那么系统的设计上能够获得很大的简化。Dynamo 为了给出充分的弹性而被设计成彻底的对等集群(peer to peer),网络中的任何一个节点都不是特殊的。
Virtual node
虚拟节点,未完成
gossip
Gossip协议是一个Gossip思想的P2P实现。现代的分布式系统常用这个协议,他每每是惟一的手段。由于底层的结构很是复杂,并且Gossip也颇有效。
Gossip协议也被戏称为病毒式传播,由于他的行为生物界的病毒很类似。
Gossip (State Transfer Model)
在状态转移到模式下,每一个重复节点都保持的一个Vector clock和一个state version tree。每一个节点的状态都是相同的(based on vector clock comparison),换句话说,state version tree包含有所有的冲突updates.
At query time, the client will attach its vector clock and the replica will send back a subset of the state tree which precedes the client's vector clock (this will provide monotonic read consistency). The client will then advance its vector clock by merging all the versions. This means the client is responsible to resolve the conflict of all these versions because when the client sends the update later, its vector clock will precede all these versions.
At update, the client will send its vector clock and the replica will check whether the client state precedes any of its existing version, if so, it will throw away the client's update.
Replicas also gossip among each other in the background and try to merge their version tree together.
Gossip (Operation Transfer Model)
In an operation transfer approach, the sequence of applying the operations is very important. At the minimum causal order need to be maintained. Because of the ordering issue, each replica has to defer executing the operation until all the preceding operations has been executed. Therefore replicas save the operation request to a log file and exchange the log among each other and consolidate these operation logs to figure out the right sequence to apply the operations to their local store in an appropriate order.
"Causal order" means every replica will apply changes to the "causes" before apply changes to the "effect". "Total order" requires that every replica applies the operation in the same sequence.
In this model, each replica keeps a list of vector clock, Vi is the vector clock the replica itself and Vj is the vector clock when replica i receive replica j's gossip message. There is also a V-state that represent the vector clock of the last updated state.
When a query is submitted by the client, it will also send along its vector clock which reflect the client's view of the world. The replica will check if it has a view of the state that is later than the client's view.
When an update operation is received, the replica will buffer the update operation until it can be applied to the local state. Every submitted operation will be tag with 2 timestamp, V-client indicates the client's view when he is making the update request. V-@receive is the replica's view when it receives the submission.
This update operation request will be sitting in the queue until the replica has received all the other updates that this one depends on. This condition is reflected in the vector clock Vi when it is larger than V-client
On the background, different replicas exchange their log for the queued updates and update each other's vector clock. After the log exchange, each replica will check whether certain operation can be applied (when all the dependent operation has been received) and apply them accordingly. Notice that it is possible that multiple operations are ready for applying at the same time, the replica will sort these operation in causal order (by using the Vector clock comparison) and apply them in the right order.
The concurrent update problem at different replica can also happen. Which means there can be multiple valid sequences of operation. In order for different replica to apply concurrent update in the same order, we need a total ordering mechanism.
One approach is whoever do the update first acquire a monotonic sequence number and late comers follow the sequence. On the other hand, if the operation itself is commutative, then the order to apply the operations doesn't matter
After applying the update, the update operation cannot be immediately removed from the queue because the update may not be fully exchange to every replica yet. We continuously check the Vector clock of each replicas after log exchange and after we confirm than everyone has receive this update, then we'll remove it from the queue.
Merkle tree
有数据存储成树状结构,每一个节点的Hash是其全部子节点的Hash的Hash,叶子节点的Hash是其内容的Hash。这样一旦某个节点发生变化,其Hash的变化会迅速传播到根节点。须要同步的系统只须要不断查询跟节点的hash,一旦有变化,顺着树状结构就可以在logN级别的时间找到发生变化的内容,立刻同步。
Paxos
paxos是一种处理一致性的手段,能够理解为事务吧。
其余的手段不要Google GFS使用的Chubby的Lock service。我不大喜欢那种重型的设计就不费笔墨了。
背景
当规模愈来愈大的时候。
1、Master/slave
这个是多机房数据访问最经常使用的方案,通常的需求用此方案便可。所以你们也常常提到“premature optimization is the root of all evil”。
优势:利用mysql replication便可实现,成熟稳定。
缺点:写操做存在单点故障,master坏掉以后slave不能写。另外slave的延迟也是个困扰人的小问题。
2、Multi-master
Multi-master指一个系统存在多个master, 每一个master都具备read-write能力,需根据时间戳或业务逻辑合并版本。好比分布式版本管理系统git能够理解成multi-master模式。具有最终一致性。多版本数据修改能够借鉴Dynamo的vector clock等方法。
优势:解决了单点故障。
缺点:不易实现一致性,合并版本的逻辑复杂。
3、Two-phase commit(2PC)
Two-phase commit是一个比较简单的一致性算法。因为一致性算法一般用神话(如Paxos的The Part-Time Parliament论文)来比喻容易理解,下面也举个相似神话的例子。
某班要组织一个同窗聚会,前提条件是全部参与者赞成则活动举行,任意一人拒绝则活动取消。用2PC算法来执行过程以下
Phase 1
Prepare: 组织者(coordinator)打电话给全部参与者(participant) ,同时告知参与者列表。
Proposal: 提出周六2pm-5pm举办活动。
Vote: participant需vote结果给coordinator:accept or reject。
Block: 若是accept, participant锁住周六2pm-5pm的时间,再也不接受其余请求。
Phase 2
Commit: 若是全部参与者都赞成,组织者coodinator通知全部参与者commit, 不然通知abort,participant解除锁定。
Failure 典型失败状况分析
Participant failure:
任一参与者无响应,coordinator直接执行abort
Coordinator failure:
Takeover: 若是participant一段时间没收到cooridnator确认(commit/abort),则认为coordinator不在了。这时候可自动成为Coordinator备份(watchdog)
Query: watchdog根据phase 1接收的participant列表发起query
Vote: 全部participant回复vote结果给watchdog, accept or reject
Commit: 若是全部都赞成,则commit, 不然abort。
优势:实现简单。
缺点:全部参与者须要阻塞(block),throughput低;无容错机制,一节点失败则整个事务失败。
4、Three-phase commit (3PC)
Three-phase commit是一个2PC的改进版。2PC有一些很明显的缺点,好比在coordinator作出commit决策并开始发送commit以后,某个participant忽然crash,这时候无法abort transaction, 这时候集群内实际上就存在不一致的状况,crash恢复后的节点跟其余节点数据是不一样的。所以3PC将2PC的commit的过程1分为2,分红preCommit及commit, 如图。
(图片来源:http://en.wikipedia.org/wiki/File:Three-phase_commit_diagram.png)
从图来看,cohorts(participant)收到preCommit以后,若是没收到commit, 默认也执行commit, 即图上的timeout cause commit。
若是coodinator发送了一半preCommit crash, watchdog接管以后经过query, 若是有任一节点收到commit, 或者所有节点收到preCommit, 则可继续commit, 不然abort。
优势:容许发生单点故障后继续达成一致。
缺点:网络分离问题,好比preCommit消息发送后忽然两个机房断开,这时候coodinator所在机房会abort, 另外剩余replicas机房会commit。
Google Chubby的做者Mike Burrows说过, “there is only one consensus protocol, and that’s Paxos” – all other approaches are just broken versions of Paxos. 意即“世上只有一种一致性算法,那就是Paxos”,全部其余一致性算法都是Paxos算法的不完整版。相比2PC/3PC, Paxos算法的改进
P1a. 每次Paxos实例执行都分配一个编号,编号须要递增,每一个replica不接受比当前最大编号小的提案
P2. 一旦一个 value v 被replica经过,那么以后任何再批准的 value 必须是 v,即没有拜占庭将军(Byzantine)问题。拿上面请客的比喻来讲,就是一个参与者一旦accept周六2pm-5pm的proposal, 就不能改变主意。之后无论谁来问都是accept这个value。
一个proposal只须要多数派赞成便可经过。所以比2PC/3PC更灵活,在一个2f+1个节点的集群中,容许有f个节点不可用。
另外Paxos还有不少约束的细节,特别是Google的chubby从工程实现的角度将Paxos的细节补充得很是完整。好比如何避免Byzantine问题,因为节点的持久存储可能会发生故障,Byzantine问题会致使Paxos算法P2约束失效。
以上几种方式原理比较以下
DHT
Distributed hash table
Map Reduce Execution
Map Reduce已经烂大街了,不过仍是要提一下。
参见:http://zh.wikipedia.org/wiki/MapReduce
Handling Deletes
但咱们执行删除操做的时候必须很是谨慎,以防丢失掉相应的版本信息。
一般咱们给一个Object标注上"已删除"的标签。在足够的时间以后,咱们在确保版本一致的状况下能够将它完全删除。回收他的空间。
存储实现
One strategy is to use make the storage implementation pluggable. e.g. A local MySQL DB, Berkeley DB, Filesystem or even a in memory Hashtable can be used as a storage mechanism.
Another strategy is to implement the storage in a highly scalable way. Here are some techniques that I learn from CouchDB and Google BigTable.
CouchDB has a MVCC model that uses a copy-on-modified approach. Any update will cause a private copy being made which in turn cause the index also need to be modified and causing the a private copy of the index as well, all the way up to the root pointer.
Notice that the update happens in an append-only mode where the modified data is appended to the file and the old data becomes garbage. Periodic garbage collection is done to compact the data. Here is how the model is implemented in memory and disks
In Google BigTable model, the data is broken down into multiple generations and the memory is use to hold the newest generation. Any query will search the mem data as well as all the data sets on disks and merge all the return results. Fast detection of whether a generation contains a key can be done by checking a bloom filter.
When update happens, both the mem data and the commit log will be written so that if the
节点变化
Notice that virtual nodes can join and leave the network at any time without impacting the operation of the ring.
When a new node joins the network
- 新加入的节点宣告本身的存在(广播或者其余手段)
- 他的邻居节点要调整Key的分配和复制关系。这个操做一般是同步的
- 这个新加入的节点异步的拷贝数据
- 这个节点变化的操做被发布到其余节点
Notice that other nodes may not have their membership view updated yet so they may still forward the request to the old nodes. But since these old nodes (which is the neighbor of the new joined node) has been updated (in step 2), so they will forward the request to the new joined node.
On the other hand, the new joined node may still in the process of downloading the data and not ready to serve yet. We use the vector clock (described below) to determine whether the new joined node is ready to serve the request and if not, the client can contact another replica.
When an existing node leaves the network (e.g. crash)
- The crashed node no longer respond to gossip message so its neighbors knows about it.崩溃的节点再也不发送Gossip Message的回应,因此他的邻居都知道他是了
- The neighbor will update the membership changes and copy data asynchronously,他的邻居处理后事,将他的活分给别人干,同时调整节点关系。
We haven't talked about how the virtual nodes is mapped into the physical nodes. Many schemes are possible with the main goal that Virtual Node replicas should not be sitting on the same physical node. One simple scheme is to assigned Virtual node to Physical node in a random manner but check to make sure that a physical node doesn't contain replicas of the same key ranges.
Notice that since machine crashes happen at the physical node level, which has many virtual nodes runs on it. So when a single Physical node crashes, the workload (of its multiple virtual node) is scattered across many physical machines. Therefore the increased workload due to physical node crashes is evenly balanced.
列存
描述
数据库以行、列的二维表的形式存储数据,可是却以一维字符串的方式存储,例如如下的一个表:
EmpId |
Lastname |
Firstname |
Salary |
1 |
Smith |
Joe |
40000 |
2 |
Jones |
Mary |
50000 |
3 |
Johnson |
Cathy |
44000 |
这个简单的表包括员工代码(EmpId), 姓名字段(Lastname and Firstname)及工资(Salary).
这个表存储在电脑的内存(RAM)和存储(硬盘)中。虽然内存和硬盘在机制上不一样,电脑的操做系统是以一样的方式存储的。数据库必须把这个二维表存储在一系列一维的“字节”中,又操做系统写到内存或硬盘中。
行式数据库把一行中的数据值串在一块儿存储起来,而后再存储下一行的数据,以此类推。1,Smith,Joe,40000;2,Jones,Mary,50000;3,Johnson,Cathy,44000;
列式数据库把一列中的数据值串在一块儿存储起来,而后再存储下一列的数据,以此类推。1,2,3;Smith,Jones,Johnson;Joe,Mary,Cathy;40000,50000,44000;
特色
- 良好的压缩比。因为大多数数据库设计都有冗余,如此一来,压缩比很是高,把40多M的数据导入infobright,没想到数据文件只有1M多
- 列上的计算很是的快。
- 方便MapReduce和Key-value模型的融合
- 读取整行的数据较慢,但部分数据较快
简单分析含源码
软件篇
亚数据库
我发明的新概念,就是称不上数据库但有一些数据库的特征。能够指缓存。
MemCached
Memcached是danga.com(运营LiveJournal的技术团队)开发的一套分布式内存对象缓存系统,用于在动态系统中减小数据库 负载,提高性能。
特色
- 协议简单
- 基于libevent的事件处理
- 内置内存存储方式
- memcached不互相通讯的分布式
Memcached处理的原子是每个(key,value)对(如下简称kv对),key会经过一个hash算法转化成hash-key,便于查找、对比以及作到尽量的散列。同时,memcached用的是一个二级散列,经过一张大hash表来维护。
Memcached有两个核心组件组成:服务端(ms)和客户端(mc),在一个memcached的查询中,mc先经过计算key的hash值来 肯定kv对所处在的ms位置。当ms肯定后,客户端就会发送一个查询请求给对应的ms,让它来查找确切的数据。由于这之间没有交互以及多播协议,因此 memcached交互带给网络的影响是最小化的。
内存分配
默认状况下,ms是用一个内置的叫“块分配器”的组件来分配内存的。舍弃c++标准的malloc/free的内存分配,而采用块分配器的主要目的 是为了不内存碎片,不然操做系统要花费更多时间来查找这些逻辑上连续的内存块(其实是断开的)。用了块分配器,ms会轮流的对内存进行大块的分配,并 不断重用。固然因为块的大小各不相同,当数据大小和块大小不太相符的状况下,仍是有可能致使内存的浪费。
同时,ms对key和data都有相应的限制,key的长度不能超过250字节,data也不能超过块大小的限制 --- 1MB。
由于mc所使用的hash算法,并不会考虑到每一个ms的内存大小。理论上mc会分配几率上等量的kv对给每一个ms,这样若是每一个ms的内存都不太同样,那 可能会致使内存使用率的下降。因此一种替代的解决方案是,根据每一个ms的内存大小,找出他们的最大公约数,而后在每一个ms上开n个容量=最大公约数的 instance,这样就等于拥有了多个容量大小同样的子ms,从而提供总体的内存使用率。
缓存策略
当ms的hash表满了以后,新的插入数据会替代老的数据,更新的策略是LRU(最近最少使用),以及每一个kv对的有效时限。Kv对存储有效时限是在mc端由app设置并做为参数传给ms的。
同时ms采用是偷懒替代法,ms不会开额外的进程来实时监测过期的kv对并删除,而是当且仅当,新来一个插入的数据,而此时又没有多余的空间放了,才会进行清除动做。
缓存数据库查询
如今memcached最流行的一种使用方式是缓存数据库查询,下面举一个简单例子说明:
App须要获得userid=xxx的用户信息,对应的查询语句相似:
“SELECT * FROM users WHERE userid = xxx”
App先去问cache,有没有“user:userid”(key定义可预先定义约束好)的数据,若是有,返回数据;若是没有,App会从数据库中读取数据,并调用cache的add函数,把数据加入cache中。
当取的数据须要更新,app会调用cache的update函数,来保持数据库与cache的数据同步。
从上面的例子咱们也能够发现,一旦数据库的数据发现变化,咱们必定要及时更新cache中的数据,来保证app读到的是同步的正确数据。固然咱们可 以经过定时器方式记录下cache中数据的失效时间,时间一过就会激发事件对cache进行更新,但这之间总会有时间上的延迟,致使app可能从 cache读到脏数据,这也被称为狗洞问题。(之后我会专门描述研究这个问题)
数据冗余与故障预防
从设计角度上,memcached是没有数据冗余环节的,它自己就是一个大规模的高性能cache层,加入数据冗余所能带来的只有设计的复杂性和提升系统的开支。
当一个ms上丢失了数据以后,app仍是能够从数据库中取得数据。不过更谨慎的作法是在某些ms不能正常工做时,提供额外的ms来支持cache,这样就不会由于app从cache中取不到数据而一会儿给数据库带来过大的负载。
同时为了减小某台ms故障所带来的影响,能够使用“热备份”方案,就是用一台新的ms来取代有问题的ms,固然新的ms仍是要用原来ms的IP地址,大不了数据从新装载一遍。
另一种方式,就是提升你ms的节点数,而后mc会实时侦查每一个节点的状态,若是发现某个节点长时间没有响应,就会从mc的可用server列表里 删除,并对server节点进行从新hash定位。固然这样也会形成的问题是,本来key存储在B上,变成存储在C上了。因此此方案自己也有其弱点,最好 能和“热备份”方案结合使用,就能够使故障形成的影响最小化。
Memcached客户端(mc)
Memcached客户端有各类语言的版本供你们使用,包括java,c,php,.net等等,具体可参见memcached api page [2]。
你们能够根据本身项目的须要,选择合适的客户端来集成。
缓存式的Web应用程序架构
有了缓存的支持,咱们能够在传统的app层和db层之间加入cache层,每一个app服务器均可以绑定一个mc,每次数据的读取均可以从ms中取得,若是 没有,再从db层读取。而当数据要进行更新时,除了要发送update的sql给db层,同时也要将更新的数据发给mc,让mc去更新ms中的数据。
性能测试
Memcached 写速度
平均速度: 16222 次/秒
最大速度 18799 次/秒
Memcached 读速度
平均速度: 20971 次/秒
最大速度 22497 次/秒
Memcachedb 写速度
平均速度: 8958 次/秒
最大速度 10480 次/秒
Memcachedb 读速度
平均速度: 6871 次/秒
最大速度 12542 次/秒
源代码级别的分析
很是好的剖析文章
dbcached
● dbcached 是一款基于 Memcached 和 NMDB 的分布式 key-value 数据库内存缓存系统。
● dbcached = Memcached + 持久化存储管理器 + NMDB 客户端接口
● Memcached 是一款高性能的,分布式的内存对象缓存系统,用于在动态应用中减小数据库负载,提高访问速度。
● NMDB 是一款多协议网络数据库(dbm类)管理器,它由内存缓存和磁盘存储两部分构成,使用 QDBM 或 Berkeley DB 做为后端数据库。
● QDBM 是一个管理数据库的例程库,它参照 GDBM 为了下述三点而被开发:更高的处理速度,更小的数据库文件大小,和更简单的API。QDBM 读写速度比 Berkeley DB 要快,详细速度比较见《
Report of Benchmark Test》。
Memcached 和 dbcached 在功能上同样吗?
● 兼容:Memcached 能作的,dbcached 都能作。除此以外,dbcached 还将“Memcached、持久化存储管理器、NMDB 客户端接口”在一个程序中结合起来,对任何原有 Memcached 客户端来说,dbcached 仍旧是个 Memcached 内存对象缓存系统,可是,它的数据能够持久存储到本机或其它服务器上的 QDBM 或 Berkeley DB 数据库中。
● 性能:前端 dbcached 的并发处理能力跟 Memcached 相同;后端 NMDB 跟 Memcached 同样,采用了libevent 进行网络IO处理,拥有本身的内存缓存机制,性能不相上下。
● 写入:当“dbcached 的 Memcached 部分”接收到一个 set(add/replace/...) 请求并储存 key-value 数据到内存中后,“dbcached 持久化存储管理器”可以将 key-value 数据经过“NMDB 客户端接口”保存到 QDBM 或 Berkeley DB 数据库中。
● 速度:若是加上“-z”参数,采用 UDP 协议“只发送不接收”模式将 set(add/replace/...) 命令写入的数据传递给 NMDB 服务器端,对 Memcache 客户端写速度的影响几乎能够忽略不计。在千兆网卡、同一交换机下服务器之间的 UDP 传输丢包率微乎其微。在命中的状况下,读取数据的速度跟普通的 Memcached 无差异,速度同样快。
● 读取:当“dbcached 的 Memcached 部分”接收到一个 get(incr/decr/...) 请求后,若是“dbcached 的 Memcached 部分”查询自身的内存缓存未命中,则“dbcached 持久化存储管理器”会经过“NMDB 客户端接口”从 QDBM 或 Berkeley DB 数据库中取出数据,返回给用户,而后储存到 Memcached 内存中。若是有用户再次请求这个 key,则会直接从 Memcached 内存中返回 Value 值。
● 持久:使用 dbcached,不用担忧 Memcached 服务器死机、重启而致使数据丢失。
● 变动:使用 dbcached,即便由于故障转移,添加、减小 Memcached 服务器节点而破坏了“key 信息”与对应“Memcached 服务器”的映射关系也不怕。
● 分布:dbcached 和 NMDB 既能够安装在同一台服务器上,也能够安装在不一样的服务器上,多台 dbcached 服务器能够对应一台 NMDB 服务器。
● 特长:dbcached 对于“读”大于“写”的应用尤为适用。
● 其余:《
dbcached 的故障转移支持、设计方向以及与 Memcachedb 的不一样之处》
列存系列
Hadoop之Hbase
Hadoop / HBase: API: Java / any writer, Protocol: any write call, Query Method: MapReduce Java / any exec, Replication: HDFS Replication, Written in: Java, Concurrency: ?, Misc: Links: 3 Books [
1, 2, 3]
耶鲁大学之HadoopDB
GreenPlum
FaceBook之Cassandra
Cassandra: API: many Thrift » languages, Protocol: ?, Query Method: MapReduce, Replicaton: , Written in: Java, Concurrency: eventually consistent , Misc: like "Big-Table on Amazon Dynamo alike", initiated by Facebook, Slides » , Clients »
Cassandra是facebook开源出来的一个版本,能够认为是BigTable的一个开源版本,目前twitter和digg.com在使用。
Cassandra特色
- 灵活的schema,不须要象数据库同样预先设计schema,增长或者删除字段很是方便(on the fly)。
- 支持range查询:能够对Key进行范围查询。
- 高可用,可扩展:单点故障不影响集群服务,可线性扩展。
Cassandra的主要特色就是它不是一个数据库,而是由一堆数据库节点共同构成的一个分布式网络服务,对Cassandra的一个写操做,会 被复制到其余节点上去,对Cassandra的读操做,也会被路由到某个节点上面去读取。对于一个Cassandra群集来讲,扩展性能是比较简单的事 情,只管在群集里面添加节点就能够了。我看到有文章说Facebook的Cassandra群集有超过100台服务器构成的数据库群集。
Cassandra也支持比较丰富的数据结构和功能强大的查询语言,和MongoDB比较相似,查询功能比MongoDB稍弱一些,twitter的平台架构部门领导Evan Weaver写了一篇文章介绍Cassandra:
http://blog.evanweaver.com/articles/2009/07/06/up-and-running-with-cassandra/,有很是详细的介绍。
Cassandra以单个节点来衡量,其节点的并发读写性能不是特别好,有文章说评测下来Cassandra每秒大约不到1万次读写请求,我也看 到一些对这个问题进行质疑的评论,可是评价Cassandra单个节点的性能是没有意义的,真实的分布式数据库访问系统必然是n多个节点构成的系统,其并 发性能取决于整个系统的节点数量,路由效率,而不只仅是单节点的并发负载能力。
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都有其应用场景,咱们要作的就是为本身找到合适的架构。
Hypertable
Hypertable
:
(can you help?) Open-Source Google BigTable alike.
它是搜索引擎公司Zvents根据Google的9位研究人员在2006年发表的一篇论文《
Bigtable:结构化数据的分布存储系统》 开发的一款开源分布式数据储存系统。Hypertable是按照1000节点比例设计,以 C++撰写,可架在 HDFS 和 KFS 上。尽管还在初期阶段,但已有不错的效能:写入 28M 列的资料,各节点写入速率可达7MB/s,读取速率可达 1M cells/s。Hypertable目前一直没有太多高负载和大存储的应用实例,可是最近,Hypertable项目获得了
百度的赞助支持,相信其会有更好的发展。
Google之BigTable
研究Google的产品老是感激Google给了本身那么多方便,真心喜欢之。
Google AppEngine Datastore 是在BigTable之上建造出来的,是Google的内部存储系统,用于处理结构化数据。AppEngine Datastore其自身及其内部都不是直接访问BigTable的实现机制,可被视为BigTable之上的一个简单接口。
AppEngine Datastore所支持的项目的数据类型要比SimpleDB丰富得多,也包括了包含在一个项目内的数据集合的列表型。
若是你打算在Google AppEngine以内建造应用的话,几乎能够确定要用到这个数据存储。然而,不像SimpleDB,使用谷歌网络服务平台以外的应用,你并不能并发地与AppEngine Datastore进行接口 (或经过BigTable)。
Yahoo之PNUTS
Yahoo!的PNUTS是一个分布式的数据存储平台,它是Yahoo!云计算平台重要的一部分。它的上层产品一般也称为Sherpa。按照官方的 描述,”PNUTS, a massively parallel and geographically distributed database system for Yahoo!’s web applications.” PNUTS显然就深谙CAP之道,考虑到大部分web应用对一致性并不要求很是严格,在设计上放弃了对强一致性的追求。代替的是追求更高的 availability,容错,更快速的响应调用请求等。
特色
- 地理分布式,分布在全球多个数据中心。因为大部分Web应用都对响应时间要求高,所以最好服务器部署在离用户最近的本地机房。
- 可扩展,记录数可支持从几万条到几亿条。数据容量增长不会影响性能。
- schema-free,即非固定表结构。实际使用key/value存储的,一条记录的多个字段实际是用json方式合并存在value中。所以delete和update必须指定primary key。但也支持批量查询。
- 高可用性及容错。从单个存储节点到整个数据中心不可用都不会影响前端Web访问。
- 适合存相对小型的记录,不适合存储大文件,流媒体等。
- 弱一致性保证。
PNUTS实现
Record-level mastering 记录级别主节点
每一条记录都有一个主记录。好比一个印度的用户保存的记录master在印度机房,一般修改都会调用印度。其余地方如美国用户看这个用户的资料调用 的是美国数据中心的资料,有可能取到的是旧版的数据。非master机房也可对记录进行修改,但须要master来统一管理。每行数据都有本身的版本控 制,以下图所示。
PNUTS的结构
每一个数据中心的PNUTS结构由四部分构成
Storage Units (SU) 存储单元
物理的存储服务器,每一个存储服务器上面含有多个tablets,tablets是PNUTS上的基本存储单元。一 个tablets是一个yahoo内部格式的hash table的文件(hash table)或是一个MySQL innodb表(ordered table)。一个Tablet一般为几百M。一个SU上一般会存在几百个tablets。
Routers
每一个tablets在哪一个SU上是经过查询router得到。一个数据中心内router一般可由两台双机备份的单元提供。
Tablet Controller
router的位置只是个内存快照,实际的位置由Tablet Controller单元决定。
Message Broker
与远程数据的同步是由YMB提供,它是一个pub/sub的异步消息订阅系统。
Tablets寻址与切分
存储分hash和ordered data store。
以hash为例介绍,先对全部的tablets按hash值分片,好比1-10,000属于tablets 1, 10,000到20,000属于tablets 2,依此类推分配完全部的hash范围。一个大型的IDC一般会存在100万如下的tablets, 1,000台左右的SU。tablets属于哪一个SU由routers所有加载到内存里面,所以router访问速度极快,一般不会成为瓶颈。按照官方的 说法,系统的瓶颈只存在磁盘文件hash file访问上。
当某个SU访问量过大,则可将SU中部分tablets移到相对空闲的SU,并修改tablet controller的偏移记录。router定位tablet失效以后会自动经过tablet controller从新加载到内存。因此切分也相对容易实现。
Tim也曾经用MySQL实现过相似大规模存储的系统,当时的作法是把每条记录的key属于哪一个SU的信息保存到 一个字典里面,好处是切分能够得到更大的灵活性,能够动态增长新的tablets,而不须要切分旧的tablets。但缺点就是字典无法像router这 样,能够高效的所有加载到内存中。因此比较而言,在实际的应用中,按段分片会更简单,且已经足够使用。
Write调用示意图
PNUTS感悟
2006年Greg Linden就说I want a big, virtual database
What I want is a robust, high performance virtual relational database that runs transparently over a cluster, nodes dropping in an out of service at will, read-write replication and data migration all done automatically.
I want to be able to install a database on a server cloud and use it like it was all running on one machine.
详细资料:
http://timyang.net/architecture/yahoo-pnuts/
微软之SQL数据服务
SQL数据服务 是微软 Azure 网 络服务平台的一部分。该SDS服务也是处于测试阶段,所以也是免费的,但对数据库大小有限制。 SQL数据服务其自身其实是一项处在许多SQL服务器之上的应用,这些SQL服务器组成了SDS平台底层的数据存储。你不须要访问到它们,虽然底层的数 据库多是关系式的;SDS是一个键/值型仓储,正如咱们迄今所讨论过的其它平台同样。
微软看起来不一样于前三个供应商,由于虽然键/值存储对于可扩性���言很是棒,相对于RDBMS,在数据管理上却很困难。微软的方案彷佛是入木三分,在实现可扩性和分布机制的同时,随着时间的推移,不断增长特性,在键/值存储和关系数据库平台的鸿沟之间搭起一座桥梁。
非云服务竞争者
在云以外,也有一些能够独立安装的键/值数据库软件产品。大部分都还很年轻,不是alpha版就是beta版,但大都是开源的;经过看看它的代码,比起在非开源供应商那里,你也许更能意识到潜在的问题和限制。
文档存储
CouchDB
CouchDB: API: JSON, Protocol: REST, Query Method: MapReduceR of JavaScript Funcs, Replication: Master Master, Written in: Erlang, Concurrency: MVCC, Misc:
Links: 3 CouchDB books », Couch Lounge » (partitioning / clusering), ...
它是Apache社区基于 Erlang/OTP 构建的高性能、分布式容错非关系型数据库系统(NRDBMS)。它充分利用 Erlang 自己所提供的高并发、分布式容错基础平台,而且参考 Lotus Notes 数据库实现,采用简单的文档数据类型(document-oriented)。在其内部,文档数据均以 JSON 格式存储。对外,则经过基于 HTTP 的 REST 协议实现接口,能够用十几种语言进行自由操做。
CouchDB一种半结构化面向文档的分布式,高容错的数据库系统,其提供RESTFul HTTP/JSON接口。其拥有MVCC特性,用户能够经过自定义Map/Reduce函数生成对应的View。
在CouchDB中,数据是以JSON字符的方式存储在文件中。
特性
- RESTFul API:HTTP GET/PUT/POST/DELETE + JSON
- 基于文档存储,数据之间没有关系范式要求
- 每一个数据库对应单个个文件(以JSON保存),Hot backup
- MVCC(Multi-Version-Concurrency-Control),读写均不锁定数据库
- 用户自定义View
- 内建备份机制
- 支持附件
- 使用Erlang开发(更多的特性)
应用场景 在咱们的生活中,有不少document,好比信件,帐单,笔记等,他们只是简单的信息,没有关系的需求,咱们可能仅仅须要存储这些数据。 这样的状况下,CouchDB应该是很好的选择。固然其余使用关系型数据库的环境,也能够使用CouchDB来解决。
根据CouchDB的特性,在某些偶 尔链接网络的应用中,咱们能够用CouchDB暂存数据,随后进行同步。也能够在Cloud环境中,做为分布式的数据存储。CouchDB提供给予 HTTP的API,这样全部的常见语言均可以使用CouchDB。
使用CouchDB,意味着咱们不须要在像使用RMDBS同样,在设计应用前首先设计负责数据Table。咱们的开发更加快速,灵活。
详细参见:
http://www.javaeye.com/topic/319839
Riak
Riak: API: JSON, Protocol: REST, Query Method: MapReduce term matching , Scaling:Multiple Masters; Written in: Erlang, Concurrency: eventually consistent (stronger then MVCC via Vector Clocks), Misc: ... Links: talk »,
MongoDB
MongoDB: API: BSON, Protocol: lots of langs, Query Method: dynamic object-based language, Replication: Master Slave, Written in: C++,Concurrency: Update in Place.Misc: ... Links: Talk »,
MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。他支持的数据结构很是松散,是 相似json的bjson格式,所以能够存储比较复杂的数据类型。Mongo最大的特色是他支持的查询语言很是强大,其语法有点相似于面向对象的查询语 言,几乎能够实现相似关系数据库单表查询的绝大部分功能,并且还支持对数据创建索引。
Mongo主要解决的是海量数据的访问效率问题,根据官方的文档,当数据量达到50GB以上的时候,Mongo的数据库访问速度是MySQL的 10倍以上。Mongo的并发读写效率不是特别出色,根据官方提供的性能测试代表,大约每秒能够处理0.5万-1.5次读写请求。对于Mongo的并发读 写性能,我(robbin)也打算有空的时候好好测试一下。
由于Mongo主要是支持海量数据存储的,因此Mongo还自带了一个出色的分布式文件系统GridFS,能够支持海量的数据存储,但我也看到有些评论认为GridFS性能不佳,这一点仍是有待亲自作点测试来验证了。
最后因为Mongo能够支持复杂的数据结构,并且带有强大的数据查询功能,所以很是受到欢迎,不少项目都考虑用MongoDB来替代MySQL来实现不是特别复杂的Web应用,比方说why we migrated from MySQL to MongoDB就是一个真实的从MySQL迁移到MongoDB的案例,因为数据量实在太大,因此迁移到了Mongo上面,数据查询的速度获得了很是显著的提高。
MongoDB也有一个ruby的项目MongoMapper,是模仿Merb的DataMapper编写的MongoDB的接口,使用起来很是简单,几乎和DataMapper如出一辙,功能很是强大易用。
Terrastore
Terrastore: API: Java & http, Protocol: http, Language: Java, Querying: Range queries, Predicates, Replication: Partitioned with consistent hashing, Consistency: Per-record strict consistency, Misc: Based on Terracotta
ThruDB
ThruDB: (please help provide more facts!) Uses Apache Thrift to integrate multiple backend databases as BerkeleyDB, Disk, MySQL, S3.
Key Value / Tuple 存储
Amazon之SimpleDB
Amazon SimpleDB: Misc: not open source, Book »
SimpleDB 是一个亚马逊网络服务平台的一个面向属性的键/值数据库。SimpleDB仍处于公众测试阶段;当前,用户能在线注册其“免费”版 --免费的意思是说直到超出使用限制为止。
SimpleDB有几方面的限制。首先,一次查询最多只能执行5秒钟。其次,除了字符串类型,别无其它数据类型。一切都以字符串形式被存储、获取和 比较,所以除非你把全部日期都转为ISO8601,不然日期比较将不起做用。第三,任何字符串长度都不能超过1024字节,这限制了你在一个属性中能存储 的文本的大小(好比说产品描述等)。不过,因为该模式动态灵活,你能够经过追加“产品描述1”、“产品描述2”等来绕过这类限制。一个项目最多能够有 256个属性。因为处在测试阶段,SimpleDB的域不能大于10GB,整个库容量则不能超过1TB。
SimpleDB的一项关键特性是它使用一种最终一致性模型。 这个一致性模型对并发性颇有好处,但意味着在你改变了项目属性以后,那些改变有可能不能当即反映到随后的读操做上。尽管这种状况实际发生的概率很低,你也 得有所考虑。好比说,在你的演出订票系统里,你不会想把最后一张音乐会门票卖给5我的,由于在售出时你的数据是不一致的。
Chordless
Chordless: API: Java & simple RPC to vals, Protocol: internal, Query Method: M/R inside value objects, Scaling: every node is master for its slice of namespace, Written in:Java, Concurrency: serializable transaction isolation, Links:
Redis
Redis : (please help provide more facts!) API: Tons of languages, Written in: C, Concurrency: in memory and saves asynchronous disk after a defined time. Append only mode available. Different kinds of fsync policies. Replication: Master / Slave,
Redis是一个很新的项目,刚刚发布了1.0版本。Redis本质上是一个Key-Value类型的内存数据库,很像memcached,整个数据库统 统加载在内存当中进行操做,按期经过异步操做把数据库数据flush到硬盘上进行保存。由于是纯内存操做,Redis的性能很是出色,每秒能够处理超过 10万次读写操做,是我知道的性能最快的Key-Value DB。
Redis的出色之处不只仅是性能,Redis最大的魅力是支持保存List链表和Set集合的数据结构,并且还支持对List进行各类操做,例 如从List两端push和pop数据,取List区间,排序等等,对Set支持各类集合的并集交集操做,此外单个value的最大限制是1GB,不像 memcached只能保存1MB的数据,所以Redis能够用来实现不少有用的功能,比方说用他的List来作FIFO双向链表,实现一个轻量级的高性 能消息队列服务,用他的Set能够作高性能的tag系统等等。另外Redis也能够对存入的Key-Value设置expire时间,所以也能够被看成一 个功能增强版的memcached来用。
Redis的主要缺点是数据库容量受到物理内存的限制,不能用做海量数据的高性能读写,而且它没有原生的可扩展机制,不具备scale(可扩展) 能力,要依赖客户端来实现分布式读写,所以Redis适合的场景主要局限在较小数据量的高性能操做和运算上。目前使用Redis的网站有 github,Engine Yard。
Scalaris
Scalaris: (please help provide more facts!) Written in: Erlang, Replication: Strong consistency over replicas, Concurrency: non blocking Paxos.
Tokyo cabinet / Tyrant
Tokyo Cabinet / Tyrant: Links: nice talk », slides », Misc: Kyoto Cabinet »
它是日本最大的SNS社交网站mixi.jp开发的 Tokyo Cabinet key-value数据库网络接口。它拥有Memcached兼容协议,也能够经过HTTP协议进行数据交换。对任何原有Memcached客户端来说, 能够将Tokyo Tyrant当作是一个Memcached,可是,它的数据是能够持久存储的。Tokyo Tyrant 具备故障转移、日志文件体积小、大数据量下表现出色等优点,详见:http://blog.s135.com/post/362.htm
Tokyo Cabinet 2009年1月18日发布的新版本(Version 1.4.0)已经实现 Table Database,将key-value数据库又扩展了一步,有了MySQL等关系型数据库的表和字段的概念,相信不久的未来,Tokyo Tyrant 也将支持这一功能。值得期待。
TC除了支持Key-Value存储以外,还支持保存Hashtable数据类型,所以很像一个简单的数据库表,而且还支持基于column的条 件查询,分页查询和排序功能,基本上至关于支持单表的基础查询功能了,因此能够简单的替代关系数据库的不少操做,这也是TC受到你们欢迎的主要缘由之一, 有一个Ruby的项目
miyazakiresistance将TT的hashtable的操做封装成和ActiveRecord同样的操做,用起来很是爽。
TC/TT在mixi的实际应用当中,存储了2000万条以上的数据,同时支撑了上万个并发链接,是一个久经考验的项目。TC在保证了极高的并发 读写性能的同时,具备可靠的数据持久化机制,同时还支持相似关系数据库表结构的hashtable以及简单的条件,分页和排序操做,是一个很棒的 NoSQL数据库。
TC的主要缺点是在数据量达到上亿级别之后,并发写数据性能会大幅度降低,
NoSQL: If Only It Was That Easy提到,他们发如今TC里面插入1.6亿条2-20KB数据的时候,写入性能开始急剧降低。看来是当数据量上亿条的时候,TC性能开始大幅度降低,从TC做者本身提供的mixi数据来看,至少上千万条数据量的时候尚未遇到这么明显的写入性能瓶颈。
这个是Tim Yang作的一个
Memcached,Redis和Tokyo Tyrant的简单的性能评测,仅供参考
CT.M
GT.M: API: M, C, Python, Perl, Protocol: native, inprocess C, Misc: Wrappers: M/DB for SimpleDB compatible HTTP », MDB:X for XML », PIP for mapping to tables for SQL », Features: Small footprint (17MB), Terabyte Scalability, Unicode support, Database encryption, Secure, ACID transactions (single node), eventual consistency (replication), License: AGPL v3 on x86 GNU/Linux, Links: Slides »,
Scalien
Scalien: API / Protocol: http (text, html, JSON), C, C++, Python, Concurrency: Paxos.
Berkley DB
Berkley DB: API: Many languages, Written in: C, Replication: Master / Slave, Concurrency: MVCC, License: Sleepycat, BerkleyDB Java Edition: API: Java, Written in:Java, Replication: Master / Slave, Concurrency: serializable transaction isolation, License: Sleepycat
MemcacheDB
MemcacheDB: API: Memcache protocol (get, set, add, replace, etc.), Written in: C, Data Model: Blob, Misc: Is Memcached writing to BerkleyDB.
它是新浪互动社区事业部为在Memcached基础上,增长Berkeley DB存储层而开发一款支持高并发的分布式持久存储系统,对任何原有Memcached客户端来说,它仍旧是个Memcached,可是,它的数据是能够持久存储的。
Mnesia
Mnesia: (ErlangDB »)
LightCloud
LightCloud: (based on Tokyo Tyrant)
HamsterDB
HamsterDB: (embedded solution) ACID Compliance, Lock Free Architecture (transactions fail on conflict rather than block), Transaction logging & fail recovery (redo logs), In Memory support – can be used as a non-persisted cache, B+ Trees – supported [Source: Tony Bain »]
Flare
TC是日本第一大SNS网站mixi开发的,而Flare是日本第二大SNS网站green.jp开发的,有意思吧。Flare简单的说就是给 TC添加了scale功能。他替换掉了TT部分,本身另外给TC写了网络服务器,Flare的主要特色就是支持scale能力,他在网络服务端以前添加了 一个node server,来管理后端的多个服务器节点,所以能够动态添加数据库服务节点,删除服务器节点,也支持failover。若是你的使用场景必需要让TC可 以scale,那么能够考虑flare。
flare惟一的缺点就是他只支持memcached协议,所以当你使用flare的时候,就不能使用TC的table数据结构了,只能使用TC的key-value数据结构存储。
最终一致性Key Value存储
Amazon之Dynamo
Amazon Dynamo: Misc: not open source (see KAI below)
功能特点
架构特点
- 彻底的分布式
- 去中心化(人工管理工做很小)
- Key 惟一表明一个数据对象,对该数据对象的读写操经过 Key 来完成.
- 一般是一台自带硬盘的主机。每一个节点有三个 Java 写的组件:请求协调器(request coordination)、成员与失败检测、本地持久引擎(local persistence engine)
- 数据分区并用改进的一致性哈希(consistent hashing)方式进行复制,利用数据对象的版本化实现一致性。复制时由于更新产生的一致性问题的维护采起相似 quorum 的机制以及去中心化的复制同步协议。
- 每一个实例由一组节点组成,从应用的角度看,实例提供 IO 能力。一个实例上的节点可能位于不一样的数据中心内, 这样一个数据中心出问题也不会致使数据丢失。
BeansDB
简介
BeansDB 是一个主要针对大数据量、高可用性的分布式KeyValue存储系统,采用HashTree和简化的版本号来快速同步保证最终一致性(弱),一个简化版的Dynamo。
它采用相似memcached的去中心化结构,在客户端实现数据路由。目前只提供了Python版本的客户端,其它语言的客户端能够由memcached的客户端稍加改造获得。
Google Group: http://groups.google.com/group/beandb/
更新
2009.12.29 第一个公开版本 0.3
特性
- 高可用:经过多个可读写的用于备份实现高可用
- 最终一致性:经过哈希树实现快速完整数据同步(短期内数据可能不一致)
- 容易扩展:能够在不中断服务的状况下进行容量扩展。
- 高性能:异步IO和高性能的KeyValue数据TokyoCabinet 可配置的
- 可用性和一致性:经过N,W,R进行配置 简单协议:Memcache兼容协议,大量可用客户端
性能
在小数据集上,它跟memcached同样快: # memstorm -s localhost:7900 -n 1000
Num of Records : 10000
Non-Blocking IO : 0
TCP No-Delay : 0
Successful [SET] : 10000
Failed [SET] : 0
Total Time [SET] : 0.45493s
Average Time [SET] : 0.00005s
Successful [GET] : 10000
Failed [GET] : 0
Total Time [GET] : 0.28609s
Average Time [GET] : 0.00003s
实际部署状况下的性能(客户端测量): 􀂄 服务器 请求数 评价时间(ms) 中位数(ms) 99%(ms) 99.9%(ms)
􀂄 get A:7900 n=151398, avg=8.89, med=5.94, 99%=115.5, 99.9%=310.2
􀂄 get B:7900 n=100054, avg=6.84, med=0.40, 99%=138.5, 99.9%=483.0
􀂄 get C:7900 n=151250, avg=7.42, med=5.34, 99%=55.2, 99.9%=156.7
􀂄 get D:7900 n=150677, avg=7.63, med=5.09, 99%=97.7, 99.9%=284.7
􀂄 get E:7900 n=3822, avg=3.07, med=0.18, 99%=44.3, 99.9%=170.0
􀂄 get F:7900 n=249973, avg=8.29, med=6.36, 99%=46.8, 99.9%=241.5
􀂄 set A:7900 n=10177, avg=18.53, med=12.78,99%=189.3, 99.9%=513.6
􀂄 set B:7900 n=10431, avg=12.85, med=1.19, 99%=206.1, 99.9%=796.8
􀂄 set C:7900 n=10556, avg=17.29, med=12.97,99%=132.2, 99.9%=322.9
􀂄 set D:7900 n=10164, avg=7.34,