首页 > 数据库 >Redis存储原理与数据模型

Redis存储原理与数据模型

时间:2024-07-13 22:01:22浏览次数:16  
标签:rehash 存储 hash redis Redis key 字符串 长度 数据模型

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

标签:rehash,存储,hash,redis,Redis,key,字符串,长度,数据模型
From: https://blog.csdn.net/H520xcodenodev/article/details/140280056

相关文章

  • [Redis]字符串详解
    Redis中的字符串是可以修改的字符串,在内存中它是以字节数组的形式存在的。我们知道C语言里面的字符串标准形式是以NULL(即0x\0)作为结束符,但是在Redis里面,字符串不是这么表示的。因为要获取以NULL结尾的字符串的长度使用的是strlen标准库函数,这个函数的算法复杂度是0(n......
  • 【java登录锁定功能】redis实现登录失败锁定账号
    登录失败(账号密码<5次时不提示),>=5次时,锁定时间5min,最高密码错误次数为10,第十次密码输入错误后,提醒,“账号已停用,请联系管理员开通”,次日0时,重新计算错误次数代码实现publicstaticStringLOGIN_FAIL_LOCK="login:error:count:";publicstaticStringLOGIN......
  • 8-队列的链式存储结构的操作
    顺序队列的操作#include<stdio.h>#include<stdlib.h>#include<stdbool.h>typedefintElemType;/*链式队列的节点*/typedefstructLinkNode{/*数据域*/ElemTypedata;/*指针域,指向下一个节点*/structLinkNode*next;}LinkNode;/*链式队列*/......
  • Docker部署Redis
    查看可用的redis版本dockersearchredis拉取redis最新镜像dockerpullredis:latest查看本地镜像dockerimages创建挂在文件点击查看代码mkdir-pv/test1/docker_volume/redis/datamkdir-pv/test1/docker_volume/redis/confcd/test1/docker_volume/re......
  • Redis实战篇之商户查询缓存(基于黑马程序员Redis讲解视频总结)
    1.什么是缓存举个例子:越野车,山地自行车,都拥有"避震器",防止车体加速后因惯性,在酷似"U"字母的地形上飞跃,硬着陆导致的损害,像个弹簧一样;同样,实际开发中,系统也需要"避震器",防止过高的数据访问猛冲系统,导致其操作线程无法及时处理信息而瘫痪;这在实际开发中对企业......
  • 实验9 存储过程与函数的创建管理实验
    一、实验目的:理解存储过程和函数的概念。掌握创建存储过程和函数的方法。掌握执行存储过程和函数的方法。掌握游标的定义、使用方法。二、实验内容1.某超市的食品管理的数据库的Food表,Food表的定义如表所示,Food表的定义各列有如下数据:‘QQ饼干’,‘QQ饼干厂’,2.5,‘2......
  • 我的MYSQL学习心得, 自定义存储过程和函数
    转载:https://www.cnblogs.com/lyhabc/p/3793524.html我的MYSQL学习心得(一)简单语法我的MYSQL学习心得(二)数据类型宽度我的MYSQL学习心得(三)查看字段长度我的MYSQL学习心得(四)数据类型我的MYSQL学习心得(五)运算符我的MYSQL学习心得(六)函数我的MYSQL学习心得(七)查询我的MYSQ......
  • PostgreSQL 中如何处理数据的存储压缩和查询性能的平衡?
    文章目录PostgreSQL中数据存储压缩与查询性能的平衡之道PostgreSQL中数据存储压缩与查询性能的平衡之道在数据库管理的广袤领域中,PostgreSQL犹如一位稳重可靠的智者,为我们提供了丰富的功能和强大的性能。然而,当面对数据存储压缩和查询性能这对“欢喜冤家”时,如......
  • Redis的哨兵和集群实现高可用
    一个典型的高可用Redis集群示例配置1个主服务器2-3个从服务器3-5个哨兵哨兵和集群就是为了高可用哨兵哨兵的功能:监听和故障转移(1)客户端可以从哨兵获得集群的状态。(2)当主服务器断开,哨兵可以进行选举主服务器。哨兵的工作流程在配置中,设置master的ip和端口创建maste......
  • Java-Redis缓存穿透、缓存击穿及缓存雪崩(配解决方案及代码示例)
    前言在现代高并发的互联网应用中,缓存技术已成为提升系统响应速度与减轻后端数据库压力的关键手段。Redis,以其卓越的性能和丰富的数据结构,成为众多开发者构建缓存层的首选。然而,随着业务复杂度的增加,Redis缓存层也可能遭遇“缓存穿透”、“缓存击穿”以及“缓存雪崩”等现......