抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

什么是Redis?

Remote dictionary Server,基于内存的高性能键值(Key-Value)存储系统,常被用作缓存中间件。

常见数据结构

概览

类型 用途 底层实现
String(字符串)

可存储字符串、整数或浮点数
计数器

分布式锁

存储序列化对象
int(如果存的全数字)

SDS 简单动态字符串
Hash(哈希)

可存储多个键值对
缓存对象 ZipList 压缩列表 (连续占用内存,因此存储的元素不能太多)

一旦元素存储太多,会转为 Dict 哈希表

Redis 7.0 引入了 listpack 取代 ZipList 压缩列表
List(列表)

可重复、(插入和取出)有序
朋友圈点赞/评论列表 QuickList 快速列表:一种双向链表,每个节点是一个压缩列表

结合了压缩列表和双向链表的优点
Set(集合)

不可重复,无序,求交集、差集等
求共同关注

去重
若集合中的元素都是整数且元素个数小于 512 : IntSet 整数集合

否则:Dict 哈希表(Set是单列集合,Dict的每个节点是存键值对

的,那么其实是只用了键来存元素,值都设为null)
ZSet(有序集合)

不可重复,每个元素都关联一个分数

自动按照分数排序元素
排行榜 当元素数量小于128,每个元素小于64字节:ZipList 压缩列表

否则:Dict + SkipList,存储两份数据,Dict 和 SkipList 各一份

为什么要存储两份数据?因为这是它的特性需求

- 利用Dict去键值查询:根据元素查分数
- 利用SkipList范围查询 (快速跳过大量无关节点,定位范围的起始点):

- 获取指定分数区间的元素
- 获取排名在指定区间的元素

Redis 7.0 引入了 listpack 取代 ZipList 压缩列表
BitMap(位图)

存储二进制位
布隆过滤器

用户签到记录
HyperLogLog(基数估算)

基数统计
网页UV计数统计
Geo

可存储地理位置信息(如经纬度)
附近的人/地点查询

地理位置范围查询
Stream(流) 消息队列

String

  • 用途:存储整数、字符串和浮点数
  • 本质:二进制安全的动态字符串
  • 底层实现:SDS

Simple Dynamic String

Redis并没有使用C语言的char *, 而是自己设计了一个结构。

1
2
3
4
5
6
struct sdshdr {
int len; // 已使用字节数
int alloc; // 分配的总字节数
char flags; // 类型标识
char buf[]; // 实际字符数组
};

SDS的优势

  • O(1)时间获取长度
  • 杜绝缓冲区溢出
  • 二进制安全:不依赖 \0 结尾,可以存任意字节

二进制安全:一个系统或函数能够正确处理任意字节序列(包括 \0 字符),而不会因为遇到特殊字节(如空字符)而提前截断或出错

Hash

  • 缓存键值对
  • 用途:存储对象
  • 底层实现:当存储元素比较少时,使用ZipList;元素较多时,使用Hashtable

Zip List

压缩链表:是Redis为节省内存而设计的一种连续内存、紧凑存储的双向链表结构
压缩 == 去指针 + 连续存储
(原文包含外部图片引用,未转换为博客资源)

  • bytes:总字节数
  • tail:最后一个实体的offset
  • len:实体的个数
  • end:固定值 0xFF 表示结尾

List

  • 用途:联系人点赞
  • 元素是String
  • 有序
  • 可重复
  • 底层实现:双向链表(quick list)

Quick List

外层是双向链表,每个节点是一个压缩列表

Set

  • 用途:去重
  • O(1)时间判断存在性
  • 底层实现:元素个数小于512,intSet;大于512,HashTable;

Dict 哈希表

1
2
3
4
5
6
7
typedef struct dict {
dictType *type; // 类型函数指针(如 hash 函数、key 比较等)
void *privdata; // 私有数据
dictht ht[2]; // 两个哈希表(用于渐进式 rehash)
long rehashidx; // rehash 索引,-1 表示未 rehash
int16_t pauserehash; // 是否暂停 rehash
} dict;

Set中的每个元素存储到Dict的键上,value为null。
rehash
Dict会收缩或扩容,此时需要重新计算key的位置;redis采用的是一种渐进式rehash的过程:
不一次性迁移完所有数据,而是每次(增删改查)中,顺带迁移。

  • 新增操作:直接在ht[1](新哈希表)中新增
  • 删除、查找、修改:在ht[1] 和 ht[2]中依次进行

Zset

1
2
3
4
typedef struct zset {
dict *dict; // member → score 的映射(O(1) 查分数)
zskiplist *zsl; // 按 score 排序的跳跃表(O(log N) 范围查询)
} zset;
  • 每个元素关联一个分数
  • 用途:排行榜
  • 当元素数量小于128,每个元素小于64字节:ZipList 压缩列表;否则:Dict + SkipList,存储两份数据,Dict 和 SkipList 各一份

SkipList

(原文包含外部图片引用,未转换为博客资源)
跳表:一种多层链表

HyperLogLog

HyperLogLog(HLL) 是 Redis 中一种用于高性能、低内存消耗的基数统计(Cardinality Estimation)的概率数据结构。它能以极小的内存(通常 12KB 左右)估算集合中不重复元素的数量(即 UV,Unique Visitor)
核心思想:通过观察哈希值的“稀有程度”来反推总体数量

评论