你了解redis如何组织数据高效运行的吗?
大家好,我是热心的大肚皮,皮哥。
之前我们聊过string、list、hash、set、zset,并且自实现了动态字符串、双端链表、hash字典、压缩链表、跳跃链表等结构。那么redis是怎么组织这些数据结构高效的运行呢?
redis如何新增一个kv
redis的键值都是redisObject对象,在创建时会生成redisDb中一个键名和一个键值的redisObject对象。其中redisDb对象构成了redis的键空间。
键空间
redis是一个键值对(key-value pair)数据库服务器,服务器中的每个数据库都由一个redisDb结构表示,redisDb结构中dict字典保存了数据库中的所有键值对,我们将这个字典称为键空间(key space)。
typedef struct redisDb {
// 保存着数据库以整数表示的号码
int id;
// 保存着数据库中的所有键值对数据
// 这个属性也被称为键空间(key space)
dict *dict;
// 保存着键的过期信息
dict *expires;
// 实现列表阻塞原语,如 BLPOP
dict *blocking_keys;
dict *ready_keys;
// 用于实现 WATCH 命令
dict *watched_keys;
} redisDb;
redisObject
每一个redis中key的value都是下面的结构。
typedef struct redisObject {
// 类型
unsigned type:4;
// 编码
unsigned encoding:4;
// 指向数据的指针
void *ptr;
// 记录对象最后一次被程序访问时间,用于计算空转时长(当前时间-lru)
unsigned lru:22; /* lru time (relative to server.lruclock) */
// 引用计数,用于内存回收
int refcount;
} robj;
如图所示:
大家看到这里应该明白了吧,具体的添加如下图。
- 在键空间中根据hash算法查询新增加的key是否存在。
- 不存在则进行新增。
修改与删除区别不大,就不过多阐述了。
redis如何过期一个kv
过期字典
在键空间中,不单单有dict字典,还有个expires属性,这个expires字典记录着当前数据库的全部过期时间,也叫做过期字典:
- 过期字典的键是一个指针,指向某个对象。
- 过期字典的值是一个long类型的整数。
其中过期字典与正常的键都指向同一个对象,所以不存在空间浪费。
过期策略
我们推断一下过期策略可能有三种。
- 定时过期:在设置key时,同时创建一个定时器,在key过期的时候,执行key的删除操作。
- 惰性过期:在每次查询时,判断是否过期,过期则进行删除。
- 定期过期:每隔一段时间,对数据库进行检查,删除其中的过期key。
定时过期,在redis中创建大量的定时器,太消耗性能,而惰性过期,如果key不被访问,那么会浪费大量的内存,定期过期则会造成过期的数据也被访问到。为了解决上面的问题,redis采用惰性过期与定期过期一起使用。
惰性过期具体流程如下。
而定期过期由activeExpireCycle函数实现,每当serverCron函数执行时,activeExpireCycle函数会在规定时间内分多次遍历各个数据库,在过期字典里随机检查一部分key的过期时间并删除,
- 默认是每个库随机检查20个key,扫描时间上限25ms。
- 删除这个20个过期的key。
- 如果过期的比例超过4分之1,则重复删除。
工作小技巧
假设一个大型的redis集群中,大量的key同时过期了,会出现什么样的结果呢?之前皮哥接手了一个电商某模块的C端系统后,通过性能监控发现每天一个固定的时间,用到的redis的接口都会出现性能抖动,可用率降低。
经过分析发现,是在同一时间有大量的key过期,从而导致性能波动,那么为什么会出现这种原因呢?原因有二。
- redis在过期key的时候,会多次扫描过期字典,直到过期key变得稀疏后,才会停止。
- 内存管理器需要频繁回收内存页,会产生cpu消耗。
如果在过期时客户端请求过来,而客户端的超时时间设置的比较短,那么会出现大量的链接超时断开,业务会出现很多异常。所以一定要注意,解起来也比较简单,可以在过期时间上加个随机数来避免,这样也能让你的TL对你刮目相看呦。
相关文章
- 在Redis中如何保存时间序列数据详解
- 快速清空Redis中的数据(redis清空命令)
- /客户端模式实现快速数据存取利用Redis实现快速服务器/客户端数据访问(redis以服务器)
- 实战推荐:Redis集群稳定部署方案分享(redis集群部署方案)
- 如何解决Redis内存满的问题(怎么看redis内存满了)
- 结合Redis提升数据存储速度(怎么整合redis)
- 深入浅出查看Redis集群数据(查看redis集群数据)
- 使用Redis存储集合提高数据存储性能(用redis存集合)
- Redis TPS查询最佳优化实践(查redis tps)
- 分布式Redis事务队列实现数据共享(事务队列redis共享)
- 上海Redis设置失控,急需解决(上海redis设置异常)
- Redis数据存储的优秀秘书(topic redis)
- 重视安全如何确保安全地删除Redis记录(删除redis的记录)
- 如何连接外部Redis步骤指南(如何连接外部redis)
- 开启Redis自动上电启动若何达成(如何redis开机自启动)
- 任务Redis定时任务及应用细节(使用redis实现定时)
- Redis一种广泛应用的分布式数据存储技术(什么是redis技术)
- 细心构建Redis集群如何轻松实现(redis集群建立过程)
- 红色不可再等Redis邮箱注册快速体验(redis邮箱注册)
- 利用Redis连接远程服务器(redis连接远程服务端)
- 使用Redis跳表和二叉树提高数据查询性能(redis跳表与二叉树)
- 控制掌握Redis连接数大小的控制方法(redis连接数大小如何)
- 数据Redis实现指定条数数据的返回(redis 返回指定条数)
- 复制玩转Redis负载均衡与主从复制实战(redis负载均衡 主从)