Redis的设计感悟

编码,类型和指令

Redis有5大基础类型(ROBJ),string,list,hash,set和zset。此外,底层实现有一些基本的数据结构(编码),linkedlist,ziplist,string,hashtable,skiplist。在上层,就是指令,也是和用户交互的指令。用户可以只关心这些指令,而完全不知道数据类型(ROBJ)以及编码(基础结构)的存在。

先看下,类型和编码的关系

一个类型往往可以对应对一种以上的编码形式(数据结构)。需要对应多种数据结构一般有2种理由。第一,数据结构类型的存储可以套用特化的形式,比如string,如果是纯字符串的string,就用整数来存储,否则才使用编码的string。第二,一些需要支持快速索引的结构(HASH),如果数据较少时底层就使用压缩链表(ziplist),用遍历来进行查找,数据多了还是老老实实hash表或跳表。

一般一套类型支持一套指令,比如HASH相关的是H开头,HSET,HDEL;ZSET相关的就是Z开头,ZADD,ZRANK。这里,系统需要做一次指令的适配,同一条指令,需要为底层的各种编码方式做适配支持。这种支持,对于一种编码可能只需要简单的调用一个对应的函数,对于另一个编码可以就需要依次调用几个函数才能完成任务。

总结一下,指令集和类型的关系,是一对一的关系;而类型与编码是一对多的实现关系。

REdis的数据结构除了在数据编码时对应用到,在系统的一些地方可以看到。比如redis中的所有KEY都是SYSSTR类型,redis的KEY-V树(键空间)本身是一个hashtable。这给人的感觉是,这些定义的基础类型构成了自己,同时服务于上层,既优雅又高效。

键空间

键空间存储着所有的KEY-VALUE数据。下图包含2个字典的数据结构。第一个是dict,这是一个必须的数据结构,记录了所有的键空间数据。这边重点要说的是第二个dcit-----expires,这个字典的key和dict的key是相同的,而val是超时时间。

到底是扩展现有的数据结构类型(比如扩展类型,加一个超时字段),还是像redis做的一样,我们为新的功能再加一个新的dict。这样的问题,在我们的日常设计中也是经常需要面对的问题。在我看来,使用前者来做类型扩展是比较简单快速,也是偷懒的扩展方式。这种方式对现有的工作模式影响很小,咋看下来,一切都很和谐,工作的很好,但其实也有一些缺点。

  • 产生胖对象,减少了一个内存页可以缓存的对象数量。
  • 存储了大量默认值,比较稀疏的字段,会造成大量的内存浪费,比如上图的expire。

那么,我个人一般是采用redis方式来做对象属性设计的,主要的属性,放到主对象中,次要属性(可选属性)放到二级对象的封装中。这种主次要关系可能是第一次系统实现时无法很好设计到的,所以需要重构时来完成设计。然后,如果对接口使用者而言,通过封装完成对底层实现方式的隐藏,方案就会更完美。也就是对外的封装保证外围使用者不知道底层是存储了一个对象,还是2个对象,是一个字典,还是2个字典。

文件事件和时间事件

对于一个网络服务器,需要面对各种各样的事件,比如客户端会提交请求,服务器会产出定时的任务等等。redis给出了一种比较优雅的任务调度形式。所有的工作都需要先创建为一种事件(redis只支持时间和文件两种事件类型)。通过派发文件事件(来自socket网络)和定时事件给不同的事件处理里,来完成任务的调度。

硬限制和软限制

redis的网络客户端限制,兼具硬限制和软限制两种限制的手段。硬限制一般我们都会在平时的工作中想的,比如客户端出现3次异常,就断开它等等。软限制的存在可以使我们的控制手段更加灵活。这么做的一个好处是,如果出现一次偶然或低频的异常,那么我们可以容许它的发生。我觉得,这可以扩展为一种普适的判定模式。

subscribe的全模式和匹配模式

下面2个图分别展示了全字符串的匹配模式和通配符的匹配模式。

对用户来说,订阅全字符的通道和订阅通配符的通道并没有什么差别。但实际上我们可以看到,如果是全字符匹配,我们可以通过字典查找绑定的频道,O(logn)的开销;而如果是部分字符匹配,只能通过遍历整个订阅数组来完成匹配,O(n)的开销。而在实际运用中,大部分情况下,我们都会使用全字符的匹配模式,部分匹配通道中对象的数量并不会很多。所以,尽管部分匹配的性能看上去比较差,但在实际的工作中并不会成为性能的瓶颈。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值