ledisDB底层实现——本质上就是用leveldb这样的底层存储,和ssdb一样,meta里存的是hash、list等的元数据

Hash

hash可以算是一种两级kv,首先通过key找到一个hash对象,然后再通过field找到或者设置相应的值。 在ledisdb里面,我们需要将key跟field关联成一个key,用来存放或者获取对应的值,也就是key:field这种格式。 这样我们就将两级的kv获取转换成了一次kv操作。 另外,对于hash来说,(后面的list以及zset也一样),我们需要快速的知道它的size,所以我们需要在leveldb里面用另一个key来实时的记录该hash的size。 hash还必须提供keys,values等遍历操作,因为leveldb里面的key默认是按照内存字节升序进行排列的,所以我们只需要找到该hash在leveldb里面的最小key以及最大key,就可以轻松的遍历出来。在前面我们看到,我们采用的是key:field的方式来存入leveldb的,那么对于该hash来说,它的最小key就是"key:",而最大key则是"key;",所以该hash的field一定在"(key:, key;)"这个区间范围。至于为什么是“;”,因为它比":"大1。所以"key:field"一定小于"key;"。后续zset的遍历也采用的是该种方式,就不在说明了。

List

list只支持从两端push,pop数据,而不支持中间的insert,这样主要是为了简单。我们使用key:sequence的方式来存放list实际的值。 sequence是一个int整形,一个list最多存放1<<31 - 2000条数据,至于为啥是1000,我说随便定得你信不? 对于一个list来说,我们会记录head seq以及tail seq,用来获取当前list开头和结尾的数据。 当第一次push一个list的时候,我们将head seq以及tail seq都设置为listInitialSeq。当lpush一个value的时候,我们会获取当前的head seq,然后将其减1,新得到的head seq存放对应的value。而对于rpush,则是tail seq + 1。 当lpop的时候,我们会获取当前的head seq,然后将其加1,同时删除以前head seq对应的值。而对于rpop,则是tail seq - 1。 我们在list里面一个meta key来存放该list对应的head seq,tail seq以及size信息。

ZSet

zset可以算是最为复杂的,我们需要使用三套key来实现。需要用一个key来存储zset的size,需要用一个key:member来存储对应的score,需要用一个key:score:member来实现按照score的排序。

这里重点说一下score,在redis里面,score是一个double类型的,但是我们决定在ledisdb里面只使用int64类型,原因一是double还是有浮点精度问题,在不同机器上面可能会有误差(没准是我想多了),另一个则是我不确定double的8字节memcmp是不是也跟实际比较结果一样(没准也是我想多了),其实更可能的原因在于我们觉得int64就够用了,实际上我们项目也只使用了int的score。 因为score是int64的,我们需要将其转成大端序存储(好吧,我假设大家都是小端序的机器),这样通过memcmp比较才会有正确的结果。同时int64有正负的区别,负数最高位为1,所以如果只是单纯的进行binary比较,那么负数一定比正数大,这个我们通过在构建key的时候负数前面加"<",而正数(包括0)加"="来解决。所以我们score这套key的格式就是这样: key<score:member //<0key=score:member //>=0 对于zset的range处理,其实就是确定某一个区间之后通过leveldb iterator进行遍历获取,这里我们需要明确知道的事情是leveldb的iterator正向遍历的速度和逆向遍历的速度完全不在一个数量级上面,正向遍历快太多了,所以最好别去使用zset里面带有rev前缀的函数。

总结

总的来说,用leveldb来实现redis那些高级的数据结构还算是比较简单的,同时根据我们的压力测试,发现性能还能接受,除了zset的rev相关函数,其余的都能够跟redis保持在同一个数量级上面,具体可以参考ledisdb里面的性能测试报告以及运行ledis-benchmark自己测试。 后续ledisdb还会持续进行性能优化,同时提供expire以及replication功能的支持,预计6月份我们就会实现。 ledisdb的代码在这里https://github.com/siddontang/ledisdb,希望感兴趣的童鞋共同参与。

摘自:http://www.itkeyword.com/doc/0652992288452803948

时间: 2024-11-10 01:14:09

ledisDB底层实现——本质上就是用leveldb这样的底层存储,和ssdb一样,meta里存的是hash、list等的元数据的相关文章

parquet文件格式——本质上是将多个rows作为一个chunk,同一个chunk里每一个单独的column使用列存储格式,这样获取某一row数据时候不需要跨机器获取

Parquet是Twitter贡献给开源社区的一个列数据存储格式,采用和Dremel相同的文件存储算法,支持树形结构存储和基于列的访问.Cloudera Impala也将使用Parquet作为底层的存储格式.在很多大数据的应用场景下面,比如电信行业,具有一定规则的数据,字段很多,但是每次查询仅仅针对其中少数的几个字段,这个时候列式存储是极佳的选择.优势: 使用列式存储,一列的值都是同质的,从而带来了更高的压缩比:对于在hadoop集群上的大数据量来说,使用parquet可以节省大量空间:可以提高

HTTP中GET与POST的区别 (本质上是一样一样的TCP链接)

(转自微信公众号WebTechGarden) GET和POST是HTTP请求的两种基本方法,要说它们的区别,接触过WEB开发的人都能说出一二. 最直观的区别就是GET把参数包含在URL中,POST通过request body传递参数. 你可能自己写过无数个GET和POST请求,或者已经看过很多权威网站总结出的他们的区别,你非常清楚知道什么时候该用什么. 当你在面试中被问到这个问题,你的内心充满了自信和喜悦. 你轻轻松松的给出了一个"标准答案": GET在浏览器回退时是无害的,而POST

C++学习笔记----2.4 C++引用在本质上是什么,它和指针到底有什么区别

从概念上讲.指针从本质上讲就是存放变量地址的一个变量,在逻辑上是独立的,它可以被改变,包括其所指向的地址的改变和其指向的地址中所存放的数据的改变. 而引用是一个别名,它在逻辑上不是独立的,它的存在具有依附性,所以引用必须在一开始就被初始化,而且其引用的对象在其整个生命周期中是不能被改变的(自始至终只能依附于同一个变量). 在C++中,指针和引用经常用于函数的参数传递,然而,指针传递参数和引用传递参数是有本质上的不同的: 指针传递参数本质上是值传递的方式,它所传递的是一个地址值.值传递过程中,被调

活动图本质上就是流程图

活动图(activity diagram,动态图)是阐明了业务用例实现的工作流程.业务工作流程说明了业务为向所服务的业务主角提供其所需的价值而必须完成的工作. 在 UML 中, 活动图本质上就是流程图. 它用于描述系统的活动, 判定点和分支等. 活动图是UML用于对系统的动态行为建模的另一种常用工具,它描述活动的顺序,展现从一个活动到另一个活动的控制流.活动图在本质上是一种流程图. 它是UML中用于对系统动态活动建模的图形,反映系统中一个活动到另一个活动的流程,常常用于描述业务过程和并行处理过程

大数据DDos检测——DDos攻击本质上是时间序列数据,t+1时刻的数据特点和t时刻强相关,因此用HMM或者CRF来做检测是必然! 和一个句子的分词算法CRF没有区别!

DDos攻击本质上是时间序列数据,t+1时刻的数据特点和t时刻强相关,因此用HMM或者CRF来做检测是必然!--和一个句子的分词算法CRF没有区别!注:传统DDos检测直接基于IP数据发送流量来识别,通过硬件防火墙搞定.大数据方案是针对慢速DDos攻击来搞定.难点:在进行攻击的时候,攻击数据包都是经过伪装的,在源IP 地址上也是进行伪造的,这样就很难对攻击进行地址的确定,在查找方面也是很难的.这样就导致了分布式拒绝服务攻击在检验方法上是很难做到的.领域知识见:http://blog.csdn.n

jQuery的$.ajax方法响应数据类型有哪几种?本质上原生ajax响应数据格式有哪几种,分别对应哪个属性?

jQuery的$.ajax方法响应数据类型有:xml.html.script.json.jsonp.text 本质上原生ajax响应数据格式只有2种:xml和text,分别对应xhr.responseText和xhr.responseXML 理论上来说这道题目是应该非常简单的,但是我看到题目的时候,有点想复杂了,还是对ajax了解的不是非常清楚,需要不断的努力去学习

人工智能对我们有什么本质上的影响

人工智能对我们有什么本质上的影响 比力量,人类连个挖掘机都不如.上个世纪五六十年代有了计算机,有了网络之后,机器在计算和记忆方面也已经超越人类了.而这一次的"机器学习",机器将会在感知和认知两个层次上超越人类. 首先要认清楚一点,AI在认知和感知方面迟早是会超过人类的.现在AI已经在感知方面有局部超越人类了,认知方面虽然现在还不行,但也在一个突发猛进的高速发展中.从ALphaGo就可以看出,ALphaGo就已经是战胜了人类.人类原来只在那些需要用明确的数学公式进行表达的领域不如AI,譬

与传统餐饮相比网红餐饮有什么本质上的不同?

近年来关于网红餐饮的话题见诸于各大媒体的报道,也引发了不少相关的关注.这些网红餐饮如Luckin Coffee.喜茶们与当年的西少爷.黄太吉们,到底有什么不同呢?他们和传统上的餐饮又有什么区别?今天我们就来就这个话题简短聊聊. 黄太吉的成功被称为"微博营销经典案例",它一度是创业者们的的谈资,是口中的行业颠覆者.而目前,黄太吉已经化身为接地气小吃的连锁公司.黄太吉充分利用了互联网营销的优势,老板开奔驰送煎饼.美女老板娘等热点事件都有着较高的吸睛度. 而西少爷被称为是中国互联网餐饮第一品

PCA算法详解——本质上就是投影后使得数据尽可能分散(方差最大),PCA可以被定义为数据在低维线性空间上的正交投影,这个线性空间被称为主?空间(principal subspace),使得投影数据的?差被最?化(Hotelling, 1933),即最大方差理论。

PCA PCA(Principal Component Analysis,主成分分析)是一种常用的数据分析方法.PCA通过线性变换将原始数据变换为一组各维度线性无关的表示,可用于提取数据的主要特征分量,常用于高维数据的降维.网上关于PCA的文章有很多,但是大多数只描述了PCA的分析过程,而没有讲述其中的原理.这篇文章的目的是介绍PCA的基本数学原理,帮助读者了解PCA的工作机制是什么. 当然我并不打算把文章写成纯数学文章,而是希望用直观和易懂的方式叙述PCA的数学原理,所以整个文章不会引入严格的