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
ledisDB底层实现——本质上就是用leveldb这样的底层存储,和ssdb一样,meta里存的是hash、list等的元数据的更多相关文章
- parquet文件格式——本质上是将多个rows作为一个chunk,同一个chunk里每一个单独的column使用列存储格式,这样获取某一row数据时候不需要跨机器获取
Parquet是Twitter贡献给开源社区的一个列数据存储格式,采用和Dremel相同的文件存储算法,支持树形结构存储和基于列的访问.Cloudera Impala也将使用Parquet作为底层的存 ...
- ES transport client底层是netty实现,netty本质上是异步方式,但是netty自身可以使用sync或者await(future超时机制)来实现类似同步调用!因此,ES transport client可以同步调用也可以异步(不过底层的socket必然是异步实现)
ES transport client底层是netty实现,netty本质上是异步方式,但是netty自身可以使用sync或者await(future超时机制)来实现类似同步调用! 因此,ES tra ...
- GET和POST本质上有什么区别,这才是标准答案
不知道各位读者在面试的时候,有没有被问过这个问题:"请说一下GET和POST两者的本质区别".基本上做过WEB开发的,对这个问题,都可以回答出一堆的区别. 比如: 最直接的区别,G ...
- ReactiveCocoa 中 RACSignal 所有变换操作底层实现分析(上)
前言 在上篇文章中,详细分析了RACSignal是创建和订阅的详细过程.看到底层源码实现后,就能发现,ReactiveCocoa这个FRP的库,实现响应式(RP)是用Block闭包来实现的,而并不是用 ...
- Jsp与servlet本质上的区别
1.jsp经编译后就变成了Servlet.(JSP的本质就是Servlet,JVM只能识别java的类,不能识别JSP的代码,Web容器将JSP的代码编译成JVM能够识别的java类)2.jsp更擅长 ...
- jQuery的$.ajax方法响应数据类型有哪几种?本质上原生ajax响应数据格式有哪几种,分别对应哪个属性?
jQuery的$.ajax方法响应数据类型有:xml.html.script.json.jsonp.text 本质上原生ajax响应数据格式只有2种:xml和text,分别对应xhr.response ...
- 使用深度学习检测TOR流量——本质上是在利用报文的时序信息、传输速率建模
from:https://www.jiqizhixin.com/articles/2018-08-11-11 可以通过分析流量包来检测TOR流量.这项分析可以在TOR 节点上进行,也可以在客户端和入口 ...
- 利用CNN进行流量识别 本质上就是将流量视作一个图像
from:https://netsec2018.files.wordpress.com/2017/12/e6b7b1e5baa6e5ada6e4b9a0e59ca8e7bd91e7bb9ce5ae89 ...
- QTime的本质上是一个int,QDateTime本质上是一个qint64
研究这个问题的起因发现使用<=比较时间的不准确,所以怀疑是一个浮点数(Delphi里的time就是一个浮点数).结果却发现是一个int class Q_CORE_EXPORT QTime { e ...
随机推荐
- ibatis知识点
1:ibatis是apache的一个开源的项目,是一个O/R mapping解决方案,优点,小巧,灵活.2:搭建环境:导入ibatis相关jar包,jdbc驱动包等3:配置文件: jdbc连接的属性文 ...
- C# textbox 获得焦点
this.ActiveControl = txt_core;
- 关于 实体类中 时间字段 为string 类型和 datatime类型 比较
经发现, 数据库中保存时间格式数据 可以正常 排序, 数据中保存时间格式字符串 排序出现问题 /// <summary> /// 修改时间 /// </summary> pu ...
- 写一个 sum方法,在使用下面任一语法调用时,都可以正常工作
console.log(sum(2,3)); // Outputs 5 console.log(sum(2)(3)); // Outputs 5 (至少)有两种方法可以做到: 方法1: functio ...
- HDU-1864&&HDU-2602(01背包问题)
DP-01背包问题例题 输入处理有点恶心人,不过处理完后就是简单的DP了 从头开始dp[i]表示从0开始到i的最优结果,最后从都边里dp数组,求得最大的报销额. 对于每个i都要从头维护最优结果.(二刷 ...
- [luogu3155 CQOI2009] 叶子的染色(树形dp)
传送门 Solution 十分简单的树形dpQwQ,转移关系:父亲染了儿子不用染 只需要确定根就是简单树形dp,而其实根可以随便取一个非叶子节点 可以分情况讨论发现答案并不会改变 Code //By ...
- vs2015 配置 cplex
首先设置模式为Release, 根据软件选择x86或x64 附加库目录(链接器 - 常规) C:\Program Files\IBM\ILOG\CPLEX_Studio128\cplex\lib\x6 ...
- 第一节:numpy之ndarray对象数据类型及属性
- CVE-2014-6271 漏洞告警
原理:BASH除了可以将shell变量导出为环境变量,还可以将shell函数导出为环境变量!当前版本的bash通过以函数名作为环境变量名,以“(){”开头的字串作为环境变量的值来将函数定义导出为环境变 ...
- 剖析Spark-Shell
打开spark-shell,我们可以看到 function main() { if $cygwin; then stty -icanon min 1 -echo > /dev/null 2> ...