Redis 数据类型

Redis 数据类型

一:redis 定位和特性

在大部分时候,我们优先考虑使用关系型数据库还存储业务数据,比如:Mysql
关系型数据库特点:

  • 1、基于行存储数据,二维的模式

  • 2、存储结构化的数据,数据存储有固定的模式(schema)

  • 3、表与表之间存在关联(Relationship)

  • 4、大都支持SQL(结构化查询语言)的操作,支持复杂的关联查询

  • 5、通过支持事务ACID来提供严格或者实时的数据一致性

但是关系型数据库页存在一些限制:

  • 1、要实现扩容的话,只能向上(垂直)扩展,不支持动态的扩缩容
  • 2、表结构修改困难,因此存储的数据格式也受到限制
  • 3、高并发情况下,基于磁盘的读写压力比较大

为了规避这一系列问题,所以就有了非关系型数据库(non-relational)。
非关系型数据库特点:

  • 1、存储非结构化的数据,比如文本、图片、音频、视频
  • 2、表与表之间没有关联,可扩展性强
  • 3、保证数据的最终一致性,遵循BASE 理论
  • 4、支持海量数据的存储和高并发的高效读写
  • 5、支持分布式,能够对数据进行分片存储,扩缩容简单

对于不同的存储类型,就有了各种各样的非关系型数据库:

  • 1、KV存储:Redis和Memcached
  • 2、文档存储:MongoDB
  • 3、列存储:HBase
  • 4、图存储:Neo4j
  • 5、对象存储:Oss

Redis基本特点

为什么把数据放入内存中?

  • 内存访问的速度快,10w qps
  • 减少计算时间,减轻数据库压力

Redis基本特点:

  • 速度快

  • 支持多种数据类型

  • 支持多种编程语言

  • 持久化、内存淘汰

  • 功能丰富:事务、发布订阅、pipeline、lua

  • 集群、分布式

二:redis 基本数据类型

2.1、String-存储类型

String可以储存:

  • 1、INT 整型
  • 2、Float 单精度浮点型
  • 3、String 字符串

底层:C语言中没有字符串类型,String用char[]数组表示,源码中用SDS(simple dynamic string)封装char[],这是是Redis存储的最小单元,一个SDS最大可以存储512M信息。

struct sdshdr{
  unsigned int len; // 标记char[]的长度
  unsigned int free; //标记char[]中未使用的元素个数
  char buf[]; // 存放元素的坑
}

为什么Redis要用SDS实现字符串?

  • 1、内存空间预先分配
  • 2、获取字符长度的时间复杂度O(n)
  • 3、长度变更引起内存重新分 配
  • 4、用’\0’判断字符串结束
  • 5、惰性释放空间,

Redis对SDS再次封装生成了RedisObject,实际上五种常用的数据类型的任何一种的value,都是通过RedisObject来存储的。
当你执行set hello world的时候,其实Redis会创建两个RedisObject对象,键的RedisObject 和 值的RedisOjbect 其中它们type = REDIS_STRING,而SDS分别存储的就是 hello 跟 world字符串。

虽然对外都是String,用的也是String命令,但是会出现三种不同的编码:

  • 1、int ,储存8个字节的长整型(2^63-1)
  • 2、embstr,存储小于44个字节的字符串
  • 3、raw,长度超过了44个字节

转换:

  • 1、int 数据不再是整数——raw
  • 2、int大小超过了 long 的范围(2^63-1)——embstr
  • 3、embstr长度超过了44个字节——raw

编码转换在 Redis 写入数据时完成,且转换过程不可逆, 只能从小内存编码向大内存编码转换(不包括重新set)

String应用场景

1、缓存,key-value存储
2、分布式Session (这种很少,目前都是JWT)
3、分布式锁 set NX EX
4、分布式全局ID incr
5、计数器 incr
6、限流 incr
7、位操作

2.2、Hash 哈希

存储多个无序的键值对,最大存储数量2^32-1(40亿左右)。
Hash的value只能是字符串,不能嵌套其他的类型,比如hash、list。

String与Hash的区别或者Hash的特点

  • 1、节省内存空间
  • 2、减少key冲突
  • 3、取值减少性能消耗

Hash不适合的场景:

  • 1、Field不能单独设置过期时间
  • 2、需要考虑数据量分布的问题

redis的Hash本身也是K-V的结构,底层是使用了两种存储数据结构实现的

  • ziplist:OBJ_ENCODING_ZIPLIST(压缩列表)
  • hashtable:OBJ_ENCODING_HT(哈希表)

ziplist是一个经过特殊编码的,由连续内存块组成的双向链表。 它不存储指向上一个链表节点和指向下一个链表节点的指针,而是存 储上一个节点长度和当前节点长度。

Hash-什么时候用ziplist?

  • 1、一个hash对象保存的field数量<512个
  • 2、一个hash对象中所有的field和value的字符串长度都<64byte

HashTable(dict)

从自底层到最高层 dictEntry —>dictht—>dict,它是 一个数组+链表的结构 。

Hash应用场景

  • 1、String能做的,Hash都可以做
  • 2、存储对象类型的数据
  • 3、非常适用于将一些相关的数据存储在一起,比如用户的购物车。该类型在日常用途还是挺多的。

2.3、List

  • 存储有序的字符串(从左到右),元素可以重复

  • 最大存储数量2^32-1(40亿左右)

List目前统一使用quicklist来存储,底层就是个数组+链表的结构 ,常用就这几个组合。

lpush + lpop = stack 先进后出的栈 
lpush + rpop = queue 先进先出的队列 
lpush + ltrim = capped collection 有限集合
lpush + brpop = message queue 消息队列

list-应用场景

  • 列表: 消息列表 文章列表 评论列表 活动列表
  • 简单的消息队列

2.4、set集合

  • Set存储String类型的无序集合。
  • 最大存储数量2^32-1(40亿左右)。

redis set-存储结构

  • 1、intset
  • 2、hashtable

如果是整数类型是用intset存储,不是整数类型就用hashtable(数组+链表),如果元素个数超过512个也会用hashtable

set-应用场景

  • 1、抽奖:spop myset
  • 2、点赞、签到、打卡(用户记录)
  • 3、商品标签、用户画像(人口属性、信用属性、社交、兴趣爱好…)
  • 4、用户关注、推荐模型(相互关注? 我关注的人也关注了他? 可能认识的人?)

2.5、zset 有序集合

在这里插入图片描述
zset-存储结构

  • ziplist(元素数量<128,所有元素长度小于64bytes)
  • skiplist + dict

skiplist跳表就是多层链表的结合体,跳表分为许多层(level),每一层都可以看作是数据的索引,这些索引的意义就是加快跳表查找数据速度

在这里插入图片描述
zset-应用场景

  • 积分排行榜
  • 时间排序新闻
  • 延时队列(jesque)

2.6、Bitmap:

是用一个比特位来映射某个元素的状态。由于一个比特位只能表示 0 和 1 两种状态,所以 BitMap 能映射的状态有限,但是使用比特位的优势是能大量的节省内存空间。

Bitmap-应用场景

  • 用户签到

  • 统计活跃用户

2.7、Geospatial:

核心思想就是将地球近似为球体来看待,然后 GEO利用 GeoHash 将二维的经纬度转换成字符串,来实现位置的划分跟指定距离的查询
应用场景:经纬度来实现位置的划分跟指定距离的查询

2.8、Hyperloglogs
是一种概率数据结构,它使用概率算法来统计集合的近似基数。
应用场景:误差允许范围内做基数统计 (基数就是指一个集合中不同值的个数) 的时候非常有用,每个HyperLogLog的键可以计算接近2^64不同元素的基数,而大小只需要12KB。错误率大概在0.81%。所以如果用做 UV 统计很合适。

2.9、streams
redis 5.0 推出的数据类型,支持多播的可持久化队列,用于实现发布订阅功能,借鉴了kafka 的设计

2.10、Bloom Filter

当一个元素被加入集合时,通过K个散列函数将这个元素映射成一个位数组中的K个点(有效降低冲突概率),把它们置为1。检索时,我们只要看看这些点是不是都是1就知道集合中有没有它了:如果这些点有任何一个为0,则被检元素一定不在;如果都是1,则被检元素很可能在。这就是布隆过滤器的基本思想。
在这里插入图片描述
以上图为例,假设集合里面有3个元素{x, y, z},哈希函数的个数为3。首先将位数组进行初始化,将里面每个位都设置位0。对于集合里面的每一个元素,将元素依次通过3个哈希函数进行映射,每次映射都会产生一个哈希值,这个值对应位数组上面的一个点,然后将位数组对应的位置标记为1。查询W元素是否存在集合中的时候,同样的方法将W通过哈希映射到位数组上的3个点。如果3个点的其中有一个点不为1,则可以判断该元素一定不存在集合中。反之,如果3个点都为1,则该元素可能存在集合中。注意:此处不能判断该元素是否一定存在集合中,可能存在一定的误判率。可以从图中可以看到:假设某个元素通过映射对应下标为4,5,6这3个点。虽然这3个点都为1,但是很明显这3个点是不同元素经过哈希得到的位置,因此这种情况说明元素虽然不在集合中,也可能对应的都是1,这是误判率存在的原因。

使用布隆过滤器得到的判断结果:不存在的一定不存在,存在的不一定存在。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值