redis 数据类型和对象类型

1 数据类型

这些数据结构我们并不会用到,他是redis底层的数据结构.

我们能够用到的是对象

1.1 简单动态字符串

redis中的字符串使用的是

struct sdshdr
{
  int len; //已用长度
  int free; //未用长度
  char buf[]; // buf 的大小为len+free+1
}

  最后依然兼容c的字符串,最后一个字节使用‘\0‘,因此最终的总长度为len+free+1

相比较c的字符串优点在于:

  1. o(1)内获得字符串长度
  2. 避免了缓冲区溢出
  3. 减少了修改字符串带来的内存充分配次数
  4. 二进制安全,使用len记录长度,而不是\0

    因此字符串中可以出现‘\0‘

空间与分配

小于1M时,分配:需要长度×2+1?,因此最终len和free相同

大于1M是,多分配1M长度.也就是?1024*1024

且在字符串缩短的时候不会释放重新分配.

1.2 链表

使用的是一个双向链表.存储的是指针void*

typedef struct listNode
{
  struct listNode *prev;
  struct listNode *next;
  void *value;
}listNode;

  

然后,再次封装了上面的链表结构,可以实现多态.

typedef struct list
{
  listNode *head; //指向链表头
  listNode *tail; //指向链表尾
  unsigned long len; //链表总长
  void *(*dup)(void* ptr); //复制节点的函数
  void *(free)(void* ptr); //释放节点的函数
  int (*match)(void* ptr,void* key); //比较节点与一个值的函数
};

  

  1. 链表是双向的
  2. 无环
  3. 记录了头尾指针
  4. 记录了链表长度
  5. 多态

1.3 字典hash

distht结构存储一个哈希表,记录了哈希表总大小,掩码,已有节点数量

typedef struct dictht {
    dictEntry **table;      //哈希表数组
    unsigned long size;     //哈希表大小
    unsigned long sizemask; //用于计算索引值,
                            //总是等于 size - 1
    unsigned long used;     //哈希表已有节点数量
}  dictht;

  每个节点结构内部记录了,键,值.值使用联合体,是一个8字节大小的,因此可以存储一个指针.同时还有一个指向下一个节点的指针.

typedef struct dictEntry {
    void *key;          //键
    union {             //值
        void *val;
        uint_64 u64;
        int64_t s64;
    } v;
    sturct dictEntry *next; //指向下个哈希表节点,形成链表
} dictEntry;

  

字典使用链表法解决冲突

dict结构进一步封装字典,能够主要是记录类型和方便rehash

typedef struct dict {
    dictType *type;     //类型特定函数
    void *privdata;     //私有数据
    dictht ht[2];       //哈希表,rehash的时候使用另一个
    int rehashdx;      //rehash 索引,当 rehash 不在进行时,值为-1
} dict;

  dictType用于实现多态

typedef struct dictType {
    unsigned int (*hashFunction)(const void *key);// 含key的hash函数
    void *(*keyDup)(void *privdata, const void *key);// key的拷贝函数
    void *(*valDup)(void *privdata, const void *obj);// value的拷贝函数
    int (*keyCompare)(void *privdata, const void *key1, const void *key2);  // 对key的compare函数
    void (*keyDestructor)(void *privdata, void *key);// key析构
    void (*valDestructor)(void *privdata, void *obj);// value析构
} dictType;

  

因此存储过程是

int index = dict->type->hashFunction(key) & dict->ht[x].sizemask;

  

redis的哈希算法使用的murmurhash

使用了链表发解决冲突

rehash过程

  1. 如果没有执行bgsave,也就是rdb持久化,那么负载银子大于等于1时执行
  2. 在执行bgsave,那么负载因子大于等于5时执行.
  3. 负载因子小于0.1时开始收缩

扩展的大小为上次使用的大小的2倍.然后取2^n,收缩的则是取已使用取2^n.都是取的最近接的一个2^n.

使用的是ht[2]里面的两个表相互对调的方式.然后再讲ht[2]两个互换,也就是最终,都是ht[0]中存储哈希表

渐进式rehash

  1. ht[1]分配空间
  2. rehashidx设置为0,表示rehash开始
  3. 随后的在增删改查过程,都会将对应的hash值的ht[0]中的数据,rehash到ht[1]
  4. 直到最后一个ht[0]中的节点被rehash

渐进式rehash的查增删改查会在两个表中依次进行一次.也就是ht[0]一直在减少.

1.4 跳跃表

使用跳跃表,.代替红黑树和平衡树来实现set.其实就是c++中的map,是一个有序键值对的集合

只在有序集合和集群节点时使用.

1.5 整数集合

就是个扩展的数组.

存储了数组中每个元素所占位数和长度,然后紧跟这一个数组.

数组中每个元素所占位数称为编码.

整数集合中的元素可以由低编码,转换为高编码,但是不能反过来转换,也就是从16位到32可以,反过来不可以.

这个过程称为升级,当天家一个多位的元素是,整个集合都需要升级.

过程为:

  1. 计算空间,并分配
  2. 从后向前一次搬运

1.6 压缩列表

是一个嗯...自定义的数组结构,用来存储整数和短字符串.

也就是说一个压缩列表里可以同时存储两种类型的数据.

压缩列表就是一个连续内存区域,头部记录

  1. 整个内存区域总长度4字节
  2. 最后一个节点到头部的距离.4字节
  3. 节点数量

后面根一个个的节点,最后一个特殊值表示结尾

每个节点的格式为:前一个节点的长度(采用1字节或是5字节来揭露),本节点的编码,编码为本节点的数据类型和长度.数据

连锁更新

值得是节点的前一节点长度字段的连锁更新.

当压缩列表中的所有节点都是250~254左右,也就是一个字节能够记录.然后头部插入一个大于254长度的节点,因此后一个节点本来长度字段使用1字节,因此变为5字节,连锁的后面的节点的长度字段都需要跟着更新,成为连锁更新.

最坏复杂度o(n^2)

2 对象类型

编码和对象

redis使用对象来表示数据库中的键和值.当在数据库中创建一个键值对的时候,至少就创建了两个对象:一个键,一个值

  1. 字符串对象

    整数值实现实现 int

    embstr的简单动态字符串embstr

    简单动态字符串实现raw

  2. 列表对象

    压缩列表实现

    双端链表实现linkedlist

  3. 哈希对象

    字典实现hashtable

    压缩列表实现ziplist

  4. 集合对象

    整数集合实现intset

    字典实现

  5. 有序集合对象

    压缩列表实现

    跳跃表和字典实现skiplist

2.1 字符串对象

浮点数被保存为字符串,计算的时候会先转为浮点数然后在计算,计算完了在以字符串的形式保存.

只有整数会被保存为int,

  1. set 新建

    整数被保存为int,其他被保存为字符串

  2. get 获取

    都转化为raw也就是简单动态字符串,然后返回字符串

    没有则nil

  3. append

    转换为raw.raw调用sdscatlen

    没有则直接新建

  4. incrbyfloat 基础上加一个浮点数

    只有int类型,可以其他两种报错

    没有则新建.

  5. incrby 整数假发

    同上

  6. decrby

    同上

  7. strlen

    转换为字符串,返回长度

  8. setrange name index value

    转换为字符串,改变指定位置上的值

  9. getrange name start end

    转换为字符串,返回给定两个索引作为起始坐标的字符串

2.2 列表对象

ziplist和linkedlist

ziplist的使用条件为

  1. 每个字符串元素长度小于64
  2. 元素个数小于512

否则会被转化.redis自动转化

  1. lpush

    压入链表头

  2. rpush

    尾部添加

  3. lpop

    头删除

  4. rpop

    尾删除

  5. lindex name index

    返回指定index的元素

  6. llen

    链表长

  7. linsert name BEFORE/AFTER 已存在值 要加入的值

    指定位置插入,指定的已存在的值,而不是index

  8. lrem

    不懂

  9. lset name index value

    替换,指定的index

2.3 哈希对象

ziplish或是hashtable

转换条件同上

操作

命令 作用
hset obj key value 插入值
hget obj key 获取值,不存在返回nil
hexosts obj key 是否存在,不存在返回0
hdel obj key 删除键值对
hlen obj 获取元素个数
hgetall obj
获取所有

2.4 集合对象

intset或是hashtable

转换条件

  1. 存在元素不是整数值
  2. 保存元素超过512
命令 描述
sadd obj ... 添加元素
scard obj 返回元素数量
sismember obj value 是否存在,没有返回0
srandmember obj 随机返回一个数
spop obj 随机返回并删除
srem obj value 删除给顶元素
   

2.5 有序集合

ziplist和skiplish

有序集合使用字典和跳跃表实现的时候,是为了增加性能.集合了两种性能.同事保存,也就是保存了两份数据,一份用哈希表一份用跳跃表

转换条件:

  1. 元素长度大于64
  2. 元素个数大于128
命令 描述
zadd obj number value 插入,key只能是数值,float
zcard obj 返回数量
zcount obj value1 value2 给定value 范围内的数量,value只能是数值,float
zrange obj index1 index2 返回范围内的所有的值
zrevramge 反向饭饭
zrank obj value 返回value所对应key的排名
zrevrank 反向,同上
zrem value 删除执行
score obj value
返回对应的key

内存回收

redis实现了引用计数的内存回收.

共享对象

服务器初始化穿件了0~9999的一万个字符串,共享这些对象.

使用

OBJECT REFCOUNT name查看计数,一般只是上面的10000个整数共享了.

对象空转时长

也就是记录从上次访问到现在经过的时间.单位秒

OBJECT IDELTIME name

原文地址:https://www.cnblogs.com/perfy576/p/8605918.html

时间: 2024-08-01 22:47:44

redis 数据类型和对象类型的相关文章

【Javascript 拾遗之六】深入Javascript数据类型和对象类型

通过前几章的讲解,我们已经摸清楚Javascript的几个重要特征,具有类概念的函数,“函数”实例化的后得到对象, 原型链, 函数的定义等等.作为高级脚本语言的Javascript同样是面向对象的语言,但是Javascript中的数据类型不像JAVA中的“万物皆对象”,本文我们就来深入学习一下Javascript中的几种数据类型及其判断.Let's start learning, move it! 深入Javascript数据类型 1.5种基本数据类型和1种复杂数据类型 5种基本数据类型包括 :

Redis 的数据类型 - Hash 对象类型

#Hash更容易存储对象,比如在设置用户姓名,年龄,邮箱等属性时,用string需要分别来进行设置存储,通过Hash就可以把属性放到对象中,然后再存储对象,因此相对于string类型,Hash类型存储对象可以占用更少的字节# 在配置文件中可以通过配置 hash-max-ziplist-entries 512 #存储值得最大字节512字节# hash-max-ziplist-value 64 #字段数目,默认64# HSET:将 Hash 表 key 中域 field 设置成指定的 value H

Redis数据类型之SORTEDSET类型

Web程序猿博客:http://blog.csdn.net/thinkercode sorted set类型-特点 sorted set 是 set 的一个升级版本,它在 set 的基础上增加了一个顺序属性,这一属性在添加修改元素的时候可以指定,每次指定后,zset 会自动重新按新的值调整顺序.可以理解为有两列的 mysql 表,一列存 value,一列存顺序.操作中 key 理解为 zset 的名字. 和 set 一样 sorted set 也是 string 类型元素的集合,不同的是每个元素

Redis数据类型之LIST类型

Web程序猿博客:http://blog.csdn.net/thinkercode list类型-特点 list 是一个链表结构,主要功能是 push.pop.获取一个范围的所有值等等,操作中 key理解为链表的名字. Redis 的 list类型其实就是一个每个子元素都是 string 类型的双向链表.链表的最大长度是(2的 32 次方).我们可以通过 push,pop 操作从链表的头部或者尾部添加删除元素.这使得 list既可以用作栈,也可以用作队列. 有意思的是 list 的 pop 操作

Redis数据类型之HASH类型

Web程序猿博客:http://blog.csdn.net/thinkercode HASH类型-特点 Redis hash 是一个 string 类型的 field 和 value 的映射表.它的添加. 删除操作都是 O(1) (平均) . hash 特别适合用于存储对象. 相较于将对象的每个字段存成单个 string 类型. 将一个对象存储在 hash 类型中会占用更少的内存,并且可以更方便的存取整个对象.省内存的原因是新建一个 hash 对象时开始是用 zipmap(又称为 small h

Redis数据类型之strings类型

Web程序猿博客:http://blog.csdn.net/thinkercode string类型-特点 string 是最简单的类型,你可以理解成与 Memcached 是一模一样的类型,一个 key对应一个value,其上支持的操作与 Memcached 的操作类似.但它的功能更丰富. string 类型是二进制安全的.意思是redis的string可以包含任何数据,比如jpg图片或者序列化的对象:从内部实现来看其实string可以看作byte数组,最大上限是1G字节. 另外string类

小蚂蚁学习Redis笔记(3)——Redis数据类型之string类型

昨天安装完毕,今天终于可以进入正题了. Redis中string类型的常用命令: string是最简单的类型,一个key对应一个value,string类型是二进制安全的类型,Redis的string可以包含任何数据,比如:图片或者序列化的对象. 1.    set    设置一对键值 格式:set    键    值        例如:set     name    "allen" 含义:添加一个键值对. 值得注意的是,这个命令在设置重复的key时,value是会覆盖的.它的作用是

小蚂蚁学习Redis笔记(5)——Redis数据类型之list类型

Redis之lists类型以及操作 list是一个链表结构,主要功能是push.pop,获取一个范围的所有值等等.操作中key理解为链表的名字.Redis的list类型其实就是一个每个子元素都是string类型的双向链表.可以通过push.pop操作从链表的头部或者尾部添加删除元素,这样list既可以作为栈,也可以作为队列. 栈和队列的特性    栈:先进后出:队列:先进先出. 1.    lpush    为链表的头部添加字符串元素 格式:    lpush    mylist1    "al

Redis数据类型之SET类型

Web程序猿博客:http://blog.csdn.net/thinkercode set类型-特点 set 是集合,和我们数学中的集合概念相似,对集合的操作有添加删除元素,有对多个集合求交并差等操作,操作中 key 理解为集合的名字. Redis 的 set 是 string 类型的无序集合.set 元素最大可以包含(2 的 32 次方)个元素. set 的是通过 hash table 实现的,所以添加.删除和查找的复杂度都是 O(1).hash table 会随着添加或者删除自动的调整大小.