Redis数据类型

string

使用

这是最基本的类型了,没啥可说的,就是普通的set和get,做简单的kv缓存

应用场景

  • redis锁
  • 字符串记录

原理

存储数据三种类型:

  • int: 长度 1 num类型。
    set int_key "111"
    输入:object encoding int_key
    输出:int
  • embstr: 小于4字节
  • raw:大于44字节

SDS:是一个简单动态字符串

struct sdshdr{
  int len;
  int free;
  int buff[];
}
  • len 记录buf数组中已经使用字节的数量,也就是SDS类型所保存的字符串的长度。
  • free 记录了buf数组中未使用的字节数量。
  • buf 是存储字节的数组,用于保存字符串。

优点

  • 体现了用空间换时间的算法思想。牺牲了一些空间,来换取更快的查询效率。比如说结构体中len的值5表示这个SDS保存了一个五个字节长的字符串,O(1)的时间复杂度就可以查询出结果
  • 空间预分配:在申请空间的时候预先分配好一定长度的空间。当空间不够用的时候,通过SDS提供的API可以重新申请一片更大的空间。
  • 惰性释放空间:当申请的空间不再被使用的时候,不是立刻释放空间,而是在SDS中的free属性将这些字节的数量记录下来,等待将来使用。

hash

使用

这个是类似map的一种结构,这个一般就是可以将结构化的数据,比如一个对象(前提是这个对象没嵌套其他的对象)给缓存在redis里,然后每次读写缓存的时候,可以就操作hash里的某个字段。

key=150
value={
“id”: 150,
“name”: “zhangsan”,
“age”: 20
}

hash类的数据结构,主要是用来存放一些对象,把一些简单的对象给缓存起来,后续操作的时候,你可以直接仅仅修改这个对象中的某个字段的值

value={
  “id”: 150,
  “name”: “zhangsan”,
  “age”: 21
}

应用场景

  • 登录信息
  • 对象信息

原理

哈希对象的编码可以是 ziplist 或者 hashtable。

hset profile name "Tom"
hset profile age 25
hset profile career "Programmer"
  • ziplist储存
  1. 所有的键值对的键和值小于等于64byte。
  2. 哈希对象保存的键值数量小于512个

image

  • hasTable 储存

image

list

使用

存储有序的字符串,(从左到右),这个是可以玩儿出很多花样的

比如可以通过lrange命令,就是从某个元素开始读取多少个元素,可以基于list实现分页查询,这个很棒的一个功能,基于redis实现简单的高性能分页,可以做类似微博那种下拉不断分页的东西,性能高,就一页一页走

push : lpush name val
pop : lpop name

应用场景

  1. 比如可以搞个简单的消息队列,从list头怼进去,从list尾巴那里弄出来
  2. 文章列表
  3. 评论列表
  4. 微博,某个大v的粉丝,就可以以list的格式放在redis里去缓存 key=某大v
    value=[zhangsan, lisi, wangwu]

原理

列表对象的编码可以是 ziplist(压缩列表) 和 **linkedlist(双端链表)**。 关于链表和压缩列表的特性

ziplist如图 hash

linkedlist存储

image

set

使用

//向k中添加2,3,4,5
//结果为:k={2,3,4,5}
sadd k 2 3 4 5

无序集合,自动去重。直接基于set将系统里需要去重的数据扔进去,自动就给去重了,如果你需要对一些数据进行快速的全局去重,你当然也可以基于jvm内存里的HashSet进行去重,但是如果你的某个系统部署在多台机器上呢?

得基于redis进行全局的set去重

应用

可以基于set玩儿交集、并集、差集的操作,比如交集吧,可以把两个人的粉丝列表整一个交集,看看俩人的共同好友是谁?对吧

把两个大v的粉丝都放在两个set中,对两个set做交集

原理

集合对象的编码可以是 intset 或者 hashtable。

intset存储:

image

hashTable 如hash类型存储

sorted set

使用

排序的set,去重但是可以排序,写进去的时候给一个分数,自动根据分数排序,这个可以玩儿很多的花样,最大的特点是有个分数可以自定义排序规则

比如说你要是想根据时间对数据排序,那么可以写入进去的时候用某个时间作为分数,人家自动给你按照时间排序了

应用

排行榜:将每个用户以及其对应的什么分数写入进去,zadd board score username,接着zrevrange board 0 99,就可以获取排名前100的用户;zrank board username,可以看到用户在排行榜里的排名

原理

跳表
链表,相信大家都不陌生,维护一个有序的链表是一件非常简单的事情,我们都知道,在一个有序的链表里面,查询跟插入的算法复杂度都是O(n)。

image

我们能不能进行优化呢,比如我们一次比较两个呢?那样不就可以把时间缩小一半?如果我们4个4个比,那不就更快了?
image

跳表就是这样的一种数据结构,结点是跳过一部分的,从而加快了查询的速度。跳表跟红黑树又有什么差别呢?既然两者的算法复杂度差不多,

为什么Redis要使用跳表而不使用红黑树呢?

跳表相对于红黑树,主要有这几个优点:

  1. 代码相对简单,手写个跳表还有可能,手写个红黑树试试?
  2. 如果我们要查询一个区间里面的值,用平衡树可能会麻烦。这里的麻烦指的是实现和理解上,平衡二叉树查询一段区间也是可以做到的。
  3. 删除一段区间,这个如果是平衡二叉树,就会相当困难,毕竟设计到树的平衡问题,而跳表则没有这种烦恼。好了,相信你对跳表已经有一些认识了。

实现原理

有序集合的编码可以是 ziplist 或者 skiplist。


文章作者: 凌云
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 凌云 !
  目录