Redis基础1(五种类型结构)

本文深入解析Redis五种主要数据类型:字符串、列表、哈希、集合及有序集合的特点与应用场景,探讨其内部存储结构,适合对Redis感兴趣的开发者阅读。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文章最前: 我是Octopus,这个名字来源于我的中文名--章鱼;我热爱编程、热爱算法、热爱开源。所有源码在我的个人github ;这博客是记录我学习的点点滴滴,如果您对 Python、Java、AI、算法有兴趣,可以关注我的动态,一起学习,共同进步。

 相关文章:

  1. Redis基础1(五种类型结构)
  2. Redis基础2(过期,发布,持久化,Lua脚本)
  3. Redis基础3(集群,备份,哨兵机制)
  4. Redis基础4(分布式锁,客户端源码分析)

缓存大致可以分为两类,一种是应用类缓存,比如Map(简单的数据结构),以及EH Cache(Java第三方库),另一种就是缓存组件,比如Memached,Redis;Redis(remote dictionary server)是一个基于key-value的高性能的存储系统,通过提供多种键值数据类型来适应不同场景下的缓存与存储需求。

存储结构
     大家一定对字典类型的数据结构非常熟悉,比如map ,通过key value的方式存储的结构。 redis的全称是remote dictionary server(远程字典服务器),它以字典结构存储数据,并允许其他应用通过TCP协议读写字典中的内容。数据结构如下:

                      

Redis的安装
      Redis约定次版本号(第一个小数点后的数字)为偶数版本是稳定版,如2.8、3.0, 奇数版本为非稳定版,生产环境需要使用稳定版;目前最新版本为Redis4.0.9。

安装配置

1. 下载redis的安装包
2. tar -zxvf 解压
3. cd 到解压后的目录
4. 执行make 完成编译
5. make test 测试编译状态
6. make install {PREFIX=/path}
启动停止Redis
        安装完redis后的下一步就是怎么去启动和访问,我们首先先了解一下Redis包含哪些可执行文件:

Redis-serverRedis服务器
Redis-cliRedis命令行客户端
Redis-benchmarkRedis性能测试工具
Redis-check-aofAof文件修复工具
Redis-check-dumpRdb文件检查工具
Redis-sentinelSentinel服务器(2.8以后)

 常用的命令是redis-server和redis-cli:

1. 直接启动
      redis-server ../redis.conf
      服务器启动后默认使用的是6379的端口 ,通过--port可以自定义端口 ; 6379在手机键盘上MERZ对应,MERZ是一名意大利歌女的名字
     Redis-server --port 6380
    以守护进程的方式启动,需要修改redis.conf配置文件中daemonize yes
2. 停止redis
      redis-cli SHUTDOWN
      考虑到redis有可能正在将内存的数据同步到硬盘中,强行终止redis进程可能会导致数据丢失,正确停止redis的方式应该是向Redis发送SHUTDOW命令
当redis收到SHUTDOWN命令后,会先断开所有客户端连接,然后根据配置执行持久化,最终完成退出。
数据类型
1)字符串数据类型(String)

        字符串类型是redis中最基本的数据类型,它能存储任何形式的字符串,包括二进制数据。你可以用它存储用户的邮箱、json化的对象甚至是图片,一个字符类型键允许存储的最大容量是512M。
内部数据结构
        在Redis内部,String类型通过 int、SDS(simple dynamic string)作为结构存储,int用来存放整型数据,sds存放字节/字符串和浮点型数据。在C的标准字符串结构下进行了封装,用来提升基本操作的性能,同时也充分利用已有的C的标准库,简化实现逻辑。我们可以在redis的源码中【sds.h】中看到sds的结构:typedef char *sds;
        Redis3.2分支引入了五种sdshdr类型,目的是为了满足不同长度字符串可以使用不同大小的Header,从而节省内存,每次在创建一个sds时根据sds的实际长度判断应该选择什么类型的sdshdr,不同类型的sdshdr占用的内存空间不同。这样细分一下可以省去很多不必要的内存开销,下面是3.2的sdshdr定义:

struct __attribute__ ((__packed__)) sdshdr8 { 8表示字符串最大长度是2^8-1 (长度为255)
sdshdr8的内存布局:(根据大小选择不同的大小选择不同的sdshdr)

                                                  

使用场景:

1.ip限制 2.短信验证 3.分布式session存储

2)列表list类型(list)

       列表类型(list)可以存储一个有序的字符串列表,常用的操作是向列表两端添加元素或者获得列表的某一个片段。列表类型内部使用双向链表实现,所以向列表两端添加元素的时间复杂度为O(1), 获取越接近两端的元素速度就越快。这意味着即使是一个有几千万个元素的列表,获取头部或尾部的10条记录也是很快。

                                                    

内部数据结构
       Redis3.2之前,List类型的value对象内部以linkedlist或者ziplist来实现, 当list的元素个数和单个元素的长度比较小的时候,Redis会采用ziplist(压缩列表)来实现来减少内存占用,否则就会采用linkedlist(双向链表)结构。
      Redis3.2之后,采用的一种叫quicklist的数据结构来存储list,列表的底层都由quicklist实现。这两种存储方式都有优缺点,双向链表在链表两端进行push和pop操作,在插入节点上复杂度比较低,但是内存开销比较大; ziplist存储在一段连续的内存上,所以存储效率很高,但是插入和删除都需要频繁申请和释放内存;quicklist仍然是一个双向链表,只是列表的每个节点都是一个ziplist,其实就是linkedlist和ziplist的结合,quicklist中每个节点ziplist都能够存储多个数据元素,在源码中的文件【quicklist.c】,在源码第一行中有解释为:Adoubly linked list of ziplists意思为一个由ziplist组成的双向链表:(redis的list存储结构图)

                       

应用场景:

1.可以做消息队列   2.可以做栈   3.可以做堆

3)hash类型(hash)
   Hash整体看作一个对象,每个field-value相当于对象的属性和属性值;

                                             
数据结构
        map提供两种结构来存储,一种是hashtable、另一种是前面讲的ziplist,数据量小的时候用ziplist. 在redis中,哈希表分为三层,源码(参见hashmap)

4) 集合类型(set)

        集合类型中,每个元素都是不同的,也就是不能有重复数据,同时集合类型中的数据是无序的。一个集合类型键可以存储至多232-1个 。集合类型和列表类型的最大的区别是有序性和唯一性集合类型的常用操作是向集合中加入或删除元素、判断某个元素是否存在。由于集合类型在redis内部是使用的值为空的散列表(hash table),所以这些操作的时间复杂度都是O(1)。
                                 

数据结构
      Set在的底层数据结构以intset或者hashtable来存储。当set中只包含整数型的元素时,采用intset来存储,否则,采用hashtable存储,但是对于set来说,该hashtable的value值用于为NULL。通过key来存储元素
5) 有序集合     
                                                           

       有序集合类型,顾名思义,和前面讲的集合类型的区别就是多了有序的功能;
       在集合类型的基础上,有序集合类型为集合中的每个元素都关联了一个分数,这使得我们不仅可以完成插入、删除和判断元素是否存在等集合类型支持的操作,还能获得分数最高(或最低)的前N个元素、获得指定分数范围内的元素等与分数有关的操作。虽然集合中每个元素都是不同的,但是他们的分数却可以相同。
数据结构

       zset类型的数据结构就比较复杂一点,内部是以ziplist或者skiplist+hashtable来实现,这里面最核心的一个结构就是skiplist,也就是跳跃表。

                                    

Redis 提供了五种基础数据类型:String(字符串)、Hash(哈希)、List(列表)、Set(集合)和 ZSet(有序集合)。每种数据类型在底层都有多种实现方式,以兼顾性能与内存效率。 ### String(字符串) String 是 Redis 中最基本的数据类型,一个 key 对应一个 value。它支持存储文本、数字、二进制数据等,最大可存储 512MB 的数据。String 类型的底层实现主要有以下几种: - **int**:用于存储整数,使用 long 类型表示。 - **embstr**:用于存储短字符串,内部使用简单动态字符串(SDS)结构,但分配和释放效率更高。 - **raw**:用于存储较长的字符串,同样基于 SDS 实现,但与 embstr 相比,raw 更适合处理大字符串。 ### Hash(哈希) Hash 是一个值对集合,适用于存储对象。它的底层实现主要依赖于以下结构: - **ziplist**:当哈希中的值对数量较少且值内容较小时,Redis 使用 ziplist 作为底层实现,以节省内存[^4]。 - **hashtable**:当值对数量增加或值内容变大时,Redis 会自动切换到 hashtable 实现,以提升访问效率[^3]。 ### List(列表) List 是一个有序的字符串集合,支持双向操作。它的底层实现主要包括: - **ziplist**:当列表中的元素数量较少且每个元素内容较小时,使用 ziplist 存储。 - **linkedlist**:当列表元素较多或单个元素较大时,切换为双端链表实现[^3]。 ### Set(集合) Set 是一个无序的字符串集合,不允许重复元素。其底层实现包括: - **intset**:当集合中所有元素都是整数且数量较少时,使用 intset 存储,节省内存且效率高。 - **hashtable**:当集合包含非整数元素或元素数量较多时,使用字典实现[^3]。 ### ZSet(有序集合) ZSet 是一个有序的集合,每个元素都关联一个分数(score),用于排序。它的底层实现较为复杂,主要包括: - **ziplist**:当有序集合中的元素数量较少且每个元素内容较小时,使用 ziplist 实现。 - **skiplist + hashtable**:当元素数量较多或内容较大时,Redis 使用跳跃表(skiplist)和字典结合的方式实现。跳跃表用于高效排序,字典用于快速查找元素。 ### 总结 Redis 的每种基础数据类型都有多种底层实现,具体选择哪种结构取决于数据的大小、数量以及操作需求。这种灵活的设计使得 Redis 在不同场景下都能保持较高的性能与存储效率。 ```python # 示例代码:Redis 常见数据类型及其底层结构的映射 data_types = { "String": ["int", "embstr", "raw"], "Hash": ["ziplist", "hashtable"], "List": ["ziplist", "linkedlist"], "Set": ["intset", "hashtable"], "ZSet": ["ziplist", "skiplist + hashtable"] } for data_type, encodings in data_types.items(): print(f"{data_type} 的底层实现包括:{', '.join(encodings)}") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值