通用对象模型
typedef struct redisObject {
unsigned type:4; // 数据类型(String、Hash、List等)
unsigned encoding:4; // 实际编码方式
unsigned lru:24; // 最近访问时间,用于LRU淘汰
int refcount; // 引用计数,用于内存回收
void *ptr; // 指向实际数据结构的指针
} robj;c
Redis的每个键值不是直接保存的而是使用一个redisObject结构体封装保存的。
数据类型
string
-
适用场景: 用户信息,计数,商品数据等缓存
-
设计原理:
-
string有三种编码方式
- int => 整数 不额外分配内存,
- embstr => <=44b 单次内存分配 redisOBJ & SDS连续存储
- raw => 大于44b 两次内存分配 Obj & SDS分开存储
-
SDS (动态字符) : 内存预分配:扩容策略(小于1MB时翻倍,大于1MB时每次加1MB)
-
-
特性:
-
原子性操作: Redis中,由于单线程模型,每个命令都是原子执行的。单线程模型保证每个命令执行不被中断 (decrby,incr操作都是原子性,计数与库存扣减等场景都必须要保证其原子性)
-
分布式锁 SetNx :
# 如果lock:order不存在,则设置值为1,返回1(成功) # 如果lock:order已存在,则不设置,返回0(失败) SETNX lock:order 1; def acquire(self, lock_key, expire_time=30): """ 获取分布式锁 :param lock_key: 锁的键名 :param expire_time: 锁的过期时间(秒) :return: 是否获取成功 """ # 使用SET with NX和EX参数,保证原子性 result = self.redis.set( lock_key, "locked", nx=True, ex=expire_time ) return result is not None def release(self, lock_key): """释放锁""" self.redis.delete(lock_key)
-
Hash
-
适用场景: 用户信息,商品详情等具有多属性的实体(购物车之类)
-
设计原理 :
- 底层为两种编码方式:ziplist(压缩列表,适合小数据量,默认val长度不超过64字节,field数量不超过512),HashTable(哈希表,当不满足ziplist会自动转化为hashtable,扩展或收缩时需要rehash来完成操作)
-
特性:优化结构化数据的存储与访问 ,可以单独对属性进行读写,减少序列化操作整个对象
List
- 适用场景:文章列表,热点推文等
- 设计原理: redis3.2+版本后list默认的底层实现为QuickList(ziplist和linkedlist结合实现,平衡内存效率和查询性能)。
- 特性:基于双向有序列表 可重复的集合两端操作速度快 (O(1))
Set
-
适用场景:好友关系(共同好友) ,投票抽奖类的业务
-
设计原理:
- 两种编码方式:intSet (整数集合,元素都为整数,数量不超过默认的512),HashTable(当不满足intSet时,使用hashtable,value为null,只存key元素)
-
特性: 无序唯一的集合,可以提供搞笑的集合运算(交集,差集,并集)
Sorted Set
-
适用场景: 排行榜之类 延迟队列实现(执行时间作为score)
-
设计原理:
- 两种编码方式:zipList(元素为数量小于默认128,长度小于默认64字节)SkipLIst + Dict (跳跃表&字典混合结构,跳跃表将数据顺序用纵向的层级关系,高层指针跨越节点提升查找效率 O(log n),dict提供O(1)的Zscore操作)
-
特性: 唯一且有序的集合,每个元素关联一个score作为排序依据。
BitMap
- 适用场景:签到,大数据量的统计(活跃用户)
- 设计原理:本质时string,使用sds存储位数据,使用RAW编码,自动补0扩展,提供位级操作接口
- 特性: 在字符基础上进行位操作节省内存空间
HyperLogLog
- 适用场景:大规模去重统计(网站统计UV PV等)
- 设计原理:基于12kb的固定大小寄存器数组,使用14bit的寄存器(可计算2的14次方 16384),对输入值进行hash,利用前导0的数量进行估计基数,使用调和平均数提高准确性,标准误差0.81%
- 特性:用于基数估计,用极小的且固定的内存空间(约12kb)统计海量数据,结果有一定误差。