Redis存储原理与数据模型

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: Redis存储原理与数据模型

Redis存储结构

存储转换

  • redis-value编码
  • string
  • int:字符串长度小于等于20切能转成整数
  • raw:字符串长度大于44
  • embstr:字符串长度小于等于44
  • list
  • quicklist(双向链表)
  • ziplist(压缩链表)
  • hash
  • dict(字典):节点数量大于512或者字符串长度大于64
  • ziplist(压缩链表):节点数量小于等于512且字符串长度小于等于64
  • set
  • intset(整数数组):元素都为整数且节点数量小于等于512
  • dict(字典):元素有一个不是整数或者数量大于512
  • zset
  • skiplist(跳表):数量大于128或者有一个字符串长度大于64
  • ziplist(压缩列表):子节点数量小于等于128且字符串长度小于等于64

字典实现

redis中的KV组织是通过字典实现的;hash结构当节点超过512个或者单个字符串长度大于64时,hash结构采用字典实现。

数据结构

typedef struct dictEntry {
  void *key;
  union {
    void *val;
    uint64_t u64;
    int64_t s64;
    double d;
  } v;
  struct dictEntry *next;
} dictEntry;
typedef struct dictht {
  dictEntry **table;
  unsigned long size; // 数组长度
  unsigned long sizemask; // size - 1
  unsigned long used; // 当前数组中包含的元素
} dictht;
typedef struct dict {
    dictType *type;
    void *privdata;
    dictht ht[2];
    long rehashidx; /* rehashing not in progress if rehashidx == -1 */
int16_t pauserehash; /* If >0 rehashing is paused (<0 indicates coding error) 用于安全遍历*/ 
} dict;
  • 字符串经过hash函数运算得到64位整数;
  • 相同字符串多次通过hash函数得到相同的64位整数;
  • 整数对2^n取余可以转化为位运算;
  • 抽屉原理 n+1个苹果放在 n 个抽屉中,苹果最多的那个抽屉至少有 2 个苹果;64位整数远大于数组的长度,比如数组长 度为 4,那么 1、5、9、1+4n 都是映射到1号位数组;所以 大概率会发生冲突;

冲突

  • 负载因子:负载因子=used/sizeused是数字元素个数,size是数组长度;负载因子越小,冲突越小;负载因子越大,冲突越大;redis的负载因子是1

扩容

  • 如果负载因子>1,则会发生扩容;扩容的规则是翻倍;
  • 如果正在fork(在rdb、aof复写以及rdb-aof混用的情况下)时,会阻止扩容;但是此时若负载因子>5,索引效率会大大下降,则马上扩容;这里涉及到写时复制原理

缩容

  • 如果负载因子 < 0.1,则会发生缩容;缩容的规则是恰好包含 used 的 ;
  • 恰好的理解:假如此时数组存储元素个数为 9,恰好包含该元素 的就是 ,也就是 16;

渐进式rehash

当hashtable中的元素过多的时候,不能一次性rehash到th[1];这样会长期占用redis,其他命令得不到相应;所以需要使用渐进式rehash;

rehash步骤

ht[0]中的元素重新hash成64位整数,再对ht[1]长度进行取余,从而映射到ht[1];

渐进式规则

  1. 分治的思想,将rehash分到之后的每步增删改查的操作当中;
  2. 再定时器中,最大执行一毫秒rehash;每次步长100个数组槽位;
  3. rehash阶段,不会发生扩容和缩容。

scan

scan cursor [MATCH pattern] [COUNT count] [TYPE type]

  • 采用高位进位加法的遍历顺序,rehash 后的槽位在遍历顺序上 是相邻的;
  • 遍历目标是:不重复,不遗漏 ;
  • 会出现一种重复的情况:在 scan 过程当中,发生两次缩容的时候,会发生数据重复;

expire机制

expire key seconds
pexpire key milliseconds
ttl key
pttl key

惰性删除

分布在每一个命令操作时检查key是否过期;若过期删除key,再进行命令操作;

定时删除

定时器中检查库中指定个数(25)个key;

#define ACTIVE_EXPIRE_CYCLE_KEYS_PER_LOOP 20 /* Keys for each DB loop.
/* Keys for each DB loop. */
    
/*The default effort is 1, and the maximum configurable effort is 10. */
config_keys_per_loop = 
ACTIVE_EXPIRE_CYCLE_KEYS_LOOP + ACTIVE_EXPIRE_CYCLE_KEYS_LOOP/4*effort,
int activeExpireCycleTryExpire(redisDb *db, dictEntry *de, long long now);

大KEY

在 redis 实例中形成了很大的对象,比如一个很大的 hash 或很 大的 zset,这样的对象在扩容的时候,会一次性申请更大的一块 内存,这会导致卡顿;如果这个大 key 被删除,内存会一次性 回收,卡顿现象会再次产生;

如果观察到redis内存大起大落,极有可能是大key导致的;

# 每隔0.1秒,执行100条scan命令
redis-cli -h 127.0.0.1 --bigkeys -i 0.1
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
1月前
|
NoSQL Redis
Redis的数据淘汰策略有哪些 ?
Redis 提供了 8 种数据淘汰策略,分为淘汰易失数据和淘汰全库数据两大类。易失数据淘汰策略包括:volatile-lru、volatile-lfu、volatile-ttl 和 volatile-random;全库数据淘汰策略包括:allkeys-lru、allkeys-lfu 和 allkeys-random。此外,还有 no-eviction 策略,禁止驱逐数据,当内存不足时新写入操作会报错。
127 16
|
2月前
|
监控 NoSQL Java
场景题:百万数据插入Redis有哪些实现方案?
场景题:百万数据插入Redis有哪些实现方案?
46 1
场景题:百万数据插入Redis有哪些实现方案?
|
2月前
|
消息中间件 缓存 NoSQL
Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。
【10月更文挑战第4天】Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。随着数据增长,有时需要将 Redis 数据导出以进行分析、备份或迁移。本文详细介绍几种导出方法:1)使用 Redis 命令与重定向;2)利用 Redis 的 RDB 和 AOF 持久化功能;3)借助第三方工具如 `redis-dump`。每种方法均附有示例代码,帮助你轻松完成数据导出任务。无论数据量大小,总有一款适合你。
84 6
|
11天前
|
存储 消息中间件 监控
Redis Stream:实时数据流的处理与存储
通过上述分析和具体操作示例,您可以更好地理解和应用 Redis Stream,满足各种实时数据处理需求。
46 14
|
7天前
|
缓存 NoSQL Redis
Redis经典问题:数据并发竞争
数据并发竞争是大流量系统(如火车票系统、微博平台)中常见的问题,可能导致用户体验下降甚至系统崩溃。本文介绍了两种解决方案:1) 加写回操作加互斥锁,查询失败快速返回默认值;2) 保持多个缓存备份,减少并发竞争概率。通过实践案例展示,成功提高了系统的稳定性和性能。
|
7天前
|
缓存 监控 NoSQL
Redis经典问题:数据不一致
在使用Redis时,缓存与数据库数据不一致会导致应用异常。主要原因包括缓存更新失败、Rehash异常等。解决方案有:重试机制、缩短缓存时间、优化写入策略、建立监控报警、定期验证一致性、采用缓存分层及数据回滚恢复机制。这些措施可确保数据最终一致性,提升应用稳定性和性能。
|
1月前
|
缓存 NoSQL 关系型数据库
Redis和Mysql如何保证数据⼀致?
在项目中,为了解决Redis与Mysql的数据一致性问题,我们采用了多种策略:对于低一致性要求的数据,不做特别处理;时效性数据通过设置缓存过期时间来减少不一致风险;高一致性但时效性要求不高的数据,利用MQ异步同步确保最终一致性;而对一致性和时效性都有高要求的数据,则采用分布式事务(如Seata TCC模式)来保障。
70 14
|
1月前
|
缓存 NoSQL PHP
Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出
本文深入探讨了Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出。文章还介绍了Redis在页面缓存、数据缓存和会话缓存等应用场景中的使用,并强调了缓存数据一致性、过期时间设置、容量控制和安全问题的重要性。
44 5
|
1月前
|
存储 NoSQL 算法
Redis分片集群中数据是怎么存储和读取的 ?
Redis集群采用哈希槽分区算法,共有16384个哈希槽,每个槽分配到不同的Redis节点上。数据操作时,通过CRC16算法对key计算并取模,确定其所属的槽和对应的节点,从而实现高效的数据存取。
52 13
|
1月前
|
存储 NoSQL Redis
Redis的数据过期策略有哪些 ?
Redis 采用两种过期键删除策略:惰性删除和定期删除。惰性删除在读取键时检查是否过期并删除,对 CPU 友好但可能积压大量过期键。定期删除则定时抽样检查并删除过期键,对内存更友好。默认每秒扫描 10 次,每次检查 20 个键,若超过 25% 过期则继续检查,单次最大执行时间 25ms。两者结合使用以平衡性能和资源占用。
51 11