redis常见数据结构

1、String

  • 缓存对象(直接缓存整个对象的JSON、采用将key进行分离为user:ID)、常规计数(原子性)、分布式锁、共享session信息
  • SDS(简单动态字符串),SDS不仅可以保存文本数据还可以保存二进制数据,拼接字符串不会造成缓冲区溢出,空间不够会自动扩容

2、List

  • 消息队列(但是有两个问题:1. 生产者需要自行实现全局唯一 ID;2. 不能以消费组形式消费数据)
  • 之前是由双向链表或压缩列表实现,列表元素个数小于512个且列表每个元素值都小于64字节时用压缩列表,否则用双向列表;后来3.2版本后redis用快表实现

快表

压缩列表的不足:虽然通过紧凑型内存布局节省了内存开销,但如果保存的元素数量增加或者元素变大了,压缩列表会有「连锁更新」风险,一旦发生会造成性能下降。快表通过控制每个链表节点中的压缩列表的大小或者元素个数,来规避连锁更新的问题。因为压缩列表元素越少或越小,连锁更新带来的影响就越小,从而提供了更好的访问性能

3、Hash

  • 缓存对象、购物车
  • 列表元素个数小于512个且列表每个元素值都小于64字节时用压缩列表,否则用哈希表;后面用listpack

4、Set

  • 聚合计算(并集、交集、差集)场景:点赞、共同关注、抽奖活动
  • 元素都是整数且元素个数小于512则用整数集合,否则用哈希表

5、Zset

相比于 Set 类型多了一个排序属性 score

  • 排序场景:排行榜、电话和姓名排序
  • 列表元素个数小于512个且列表每个元素值都小于64字节时用压缩列表,不满足就用跳表。后面用listpack

跳表

跳表(O(logN))是在链表(O(N))基础上改进过来的,实现了一种多层的有序链表。

B+Tree VS 跳表

  • B+树存储2千万数据树的高度仅为3,适合IO读取,即落盘存储;B+树是一种平衡树,频繁写入和删除会造成额外性能开销从而性能降低,适合读多写少场景
  • 跳表实现简单,无需平衡数据结构,但存储量大的时候跳表的深度也随之大
  • 写入时由于B+Tree需要分裂合并索引数据页,以及调整二叉树,维持平衡; 而跳表是独立插入,且根据随机函数确定层数,没有旋转和维持平衡的开销。因此跳表写入性能会比B+树好

Mysql为什么用B+树而不是跳表

mysql数据库是持久化数据库,也就是存到磁盘上的,因此查询时要求更少磁盘IO。而且mysql读多写少的场景较多,显然B+树更适合mysql。

redis的zset为什么用跳表而不是B+树

redis是内存存储,不存在io瓶颈,所以跳表层数的耗时可以忽略不计,而且插入数据时不需要开销以平衡数据结构(写多)。