Redis数据类型

Redis所有key都是字符串,存储值有5种基本数据结构:string,list,hash,set和zset(有序集合),3种特殊数据结构:HyperLogLogs(基数统计),Bitmaps(位图)和Geospatial(地理位置),Redis 5.0中还增加了Stream类型,借鉴了kafka的设计,是一个强大的支持多播的可持久化消息队列。

5种基础数据类型

结构类型 结构存储的值 结构的读写能力
String字符串 可以是字符串、整数或浮点数 对整个字符串或字符串的一部分进行操作;对整数或浮点数进行自增或自减操作;
List列表 一个链表,链表上的每个节点都包含一个字符串 对链表的两端进行push和pop操作,读取单个或多个元素;根据值查找或删除元素;
Set集合 包含字符串的无序集合 字符串的集合,包含基础的方法有看是否存在添加、获取、删除;还包含计算交集、并集、差集等
Hash散列 包含键值对的无序散列表 包含方法有添加、获取、删除单个元素
Zset有序集合 和散列一样,用于存储键值对 字符串成员与浮点数分数之间的有序映射;元素的排列顺序由分数的大小决定;包含方法有添加、获取、删除单个元素以及根据分值范围或成员来获取元素

String字符串

Redis的字符串是动态字符串,采用预分配冗余空间的方式来减少内存的频繁分配(即当前字符串实际分配空间一般高于字符串实际长度)。

  • 常用命令:get,set,del,strlen,getrange(获取子串),setrange(覆盖子串),append(追加子串),incr(键值加1),decr(键值减1),incrby(键值增加指定整数),decrby(键值减去指定整数)

    注:字符串类型没有提供子串插入方法和子串删除方法。后面四种改变键值方法是将字符串当做计数器使用,其值的上下限分别为Long.Max和Long.Min

  • 底层原理:不是使用C语言的字符串,而是自己构建的SDS抽象类型。

  • 应用场景:缓存(常用信息、图片、视频等)、计数器、session

List列表

Redis中的List其实就是一个双向列表,可以用于实现消息队列等功能。

  • 常用命令:rpush,lpush,rpop,lpop,lrange(返回指定范围所有值),lindex(指定索引下的值,-1表示最后一个元素),llen(返回链表长度),lset(指定位置修改元素),linsert(指定位置插入元素,不是通过下标,而是通过具体值指定,并通过参数before和after指定前置或后置插入),lrem(删除元素,也不是通过位置删除,需要指定删除最大个数和元素的值),ltrim(指定起始下标start和结束下标end,删除范围之外的所有元素)。
  • 底层原理:List在数据量较少时使用的时ZipList,即压缩列表,分配一块连续内存,所有元素紧挨着存储。在数据量较大时,List底层采用的QuickList。因为普通链表需要附加空间指针太大,比较浪费时间,所以Redis中的QuickList是将若干个ZipList用指针连起来。这样既满足快速的插入性能,又不会出现太大的空间冗余。
  • 应用场景:消息队列,展示最新列表信息等。

Set集合

Redis中Set是String类型的无序集合,通过哈希表实现,所有value都指向同一内部值,添加、删除、查找的复杂度都是O(1)。

  • 常用命令:sadd,scard,smember(返回集合所有成员),sismember(集合是否存在某元素)。
  • 应用场景:标签(给用户加标签或者用户给消息添加标签)、点赞、收藏等。

Zset有序集合

Zset和set基本类似,区别在于集合中每个元素会关联一个分数,redis正是通过这个分数来为集合中成员进行从小到大的排序。

  • 常用命令:zadd key score value(将一个带有给定分值的成员添加到集合),zrange,zrem key value(从集合中移除value),zcard(获取集合元素个数),zrem(删除1个或多个元素),zincrby(计数器),zscore(分数),zrank(排名),zrange(获取范围内所有元素,携带withscores可一并获取元素权重),zrangebyscore(分数范围获取元素,±inf表示正负无穷),zremrangebyrank(通过rank范围移除元素),zremrangebyscore(通过score范围移除元素)
  • 底层原理:redis有序集合底层通过跳跃列表来实现的,比较复杂,感兴趣的可以自行了解。
  • 应用:排行榜。

Hash散列

Hash是一种string类型key和value的映射表,适合用于存储对象。

  • 常用命令:hset,hmset(增加多个键值对),hget,hmget(获取多个key对应的value),hkeys,hvalues,hdel(删除指定的1个或多个key),hexists,hincrby(计数器)。

  • 底层原理:Redis中hash底层结构类似java中的hashmap或python中的dict,通过一个二维结构来实现。第一维是数组,第二维是链表,hash的key和value分别存放于数组和链表中。通过key查找元素时,先计算key的hashcode,然后用hashcode对链表长度取模定位到链表表头,再对链表进行遍历获取到相应的value值, 链表的作用就是用来将产生了「hash碰撞」的元素串起来 。

    image-20220305221525703

    • 扩容:hash碰撞频繁发生时需要进行扩容。扩容时需要申请新的两倍大小数组,然后将所有key-value键值对进行rehash存储,之一过程对于单线程redis来说有点压力过大。Redis采用的是渐进式rehash方案,同时保留两个新旧hash结构,在后续定时任务以及hash结构的读写指令中逐渐将旧hash迁移到新hash中。
    • 缩容:原理和扩容类似,新数组大小是旧数组的一半。

3种特殊类型

HyperLogLogs(基数统计)

HyperLogLogs用于基数统计(即一个集合中不重复的元素数量),比如 注册 IP 数、每日访问 IP 数、页面实时UV、在线用户数,共同好友数等,它允许容错。

  • 特点:每个键占用12K空间,不管什么值都可以可以存储近2642^{64}个值。需要注意的是它估算出来的基数并不一定准确, 是一个带有 0.81% 标准错误的近似值 。(其背后的HyperLogLog算法,感兴趣可以自行了解。)
  • 常用命令:pfadd,pfcount,pfmerge
  • 应用场景:计算日活、统计网站日UV、注册IP数、访问IP数等等。

Bitmap(位图)

bitmap通过操作bit来进行记录,只有0和1两个状态,可以大幅节省存储空间。

  • 常用命令:setbit,getbit,bitcount(值为1的bit数量)
  • 应用场景:用户行为分析、保存状态信息(是否签到、是否登录等)、活跃用户、用户在线状态等。

Geospatial(地理位置)

Redis的Geo用于存储位置信息,可以通过地理位置(经纬度),推算两地之间距离、附近的人等。

  • 常用命令:geoadd(geoadd key longitude latitude member [longitude latitude member …]),geodist(geodist key member1 member2 [unit] unit可以指定长度单位:m,km,ft等 默认为m),geohash(geohash key member [member …],返回位置元素的hash表示),geopos(geopos key member [member …]),georadius( georadiuskey longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count],半径内所有元素),georadiusbymember(和georadius类似,不过中心点不是经纬度,而是已添加的某个位置)。
  • 底层:其底层为zset,因此可以使用zset命令来操作geo,比如zrange key 0 -1 withscores。

参考链接

  1. https://pdai.tech/md/db/nosql-redis/db-redis-data-types.html
  2. https://juejin.cn/post/6844903644798664712
打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2021-2022 Yin Peng
  • 引擎: Hexo   |  主题:修改自 Ayer
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信