
Redis作为一款高性能的内存数据库其强大的灵活性和高效性核心源于它支持的八大核心数据类型。不同于传统关系型数据库的固定表结构Redis的每一种数据类型都有其独特的底层实现、适用场景和操作命令掌握这些数据类型是用好Redis、避开生产坑的关键。本文将逐一拆解Redis八大核心数据类型——String字符串、Hash哈希、List列表、Set集合、ZSet有序集合、Bitmap位图、HyperLogLog基数统计、GEO地理空间从底层实现原理、核心操作命令到实际业务落地场景全方位讲透让你既能理解“是什么”也能明白“怎么用”“为什么这么用”。一、String字符串Redis最基础的“万能类型”String是Redis最基础、最常用的数据类型也是所有数据类型的“基础载体”——Redis中所有的Key本质上都是String类型而Value既可以是字符串、数字也可以是二进制数据如图片、视频片段是Redis中最灵活的类型。1. 底层实现Redis的String并非C语言原生的char*字符串固定长度、二进制不安全而是自定义的简单动态字符串SDSSimple Dynamic String核心结构由3部分组成len当前字符串的实际长度字节数无需遍历即可获取时间复杂度O(1)free当前字符串的空闲空间字节数用于预分配空间减少内存分配次数buf字节数组存储字符串内容末尾会自动添加\0作为结束标识不计算在len内。示例存储字符串“redis”的SDSlen5free0buf[r,e,d,i,s,\0]。SDS的核心优势的是“动态扩容”和“二进制安全”动态扩容修改字符串时若空间不足会自动扩容小于1MB时翻倍扩容大于1MB时每次增加1MB二进制安全通过len标识长度不依赖\0结束可存储图片、音频等二进制数据避免被截断。2. 核心操作命令高频必记SET key value [EX seconds] [PX milliseconds]设置键值对可指定过期时间EX秒级PX毫秒级GET key获取指定key的value若key不存在返回nilAPPEND key value在指定key的value末尾追加字符串返回追加后的总长度STRLEN key获取key对应的value长度时间复杂度O(1)INCR key将value为数字的key自增1仅支持整数若key不存在则初始化为0后自增DECR key将value为数字的key自减1用法同INCRINCRBY key increment自增指定数值如INCRBY num 5自增5SETNX key value仅当key不存在时设置值原子操作常用于分布式锁。3. 实战场景缓存热点数据如首页banner、热门商品基本信息keyproduct:info:1001valueJSON字符串计数器如文章阅读量、商品销量INCR read:count:1001分布式锁基于SETNX实现简单分布式锁后续缓存章节详细讲解存储二进制数据如用户头像将图片转为二进制用SET存储GET获取后还原。二、Hash哈希适合存储“对象型数据”的高效类型Hash类型是Redis中用于存储“键值对集合”的数据类型本质上是一个“Hash表”适合存储对象型数据如用户信息、商品详情——可以单独操作对象的某个字段无需修改整个对象比String存储对象更节省内存、更高效。1. 底层实现自适应结构Hash的底层实现会根据数据量自动切换兼顾内存占用和操作效率压缩列表ziplist当Hash的字段数量少、字段值小时默认配置hash-max-ziplist-entries512hash-max-ziplist-value64使用ziplist存储。ziplist是一种紧凑的连续内存结构将所有字段field和值value按顺序存储在一块连续内存中减少内存碎片查询效率高。字典dict当Hash的字段数量或字段值超过上述阈值时自动切换为dict存储。dict类似Java的HashMap采用“数组链表”的结构哈希冲突时用链表解决支持O(1)的增删改查操作。dict的扩容机制当哈希表的负载因子used/size超过1时翻倍扩容负载因子低于0.1时减半缩容确保操作效率。2. 核心操作命令HSET key field value给指定key的Hash表设置字段和值若字段已存在则覆盖HGET key field获取指定key的Hash表中某个字段的值HGETALL key获取指定key的Hash表中所有字段和值注意字段过多时会阻塞Redis建议用HSCAN渐进式遍历HDEL key field [field ...]删除指定key的Hash表中一个或多个字段HLEN key获取指定key的Hash表中字段的数量HKEYS key获取指定key的Hash表中所有字段名HVALS key获取指定key的Hash表中所有字段值HEXISTS key field判断指定key的Hash表中是否存在某个字段存在返回1不存在返回0。3. 实战场景存储用户信息keyuser:info:1001fieldname/age/gendervalue对应具体值修改年龄时只需执行HSET user:info:1001 age 25存储商品详情keyproduct:detail:1001fieldprice/stock/category无需存储完整JSON灵活修改单个字段缓存小对象集合如购物车keycart:user:1001fieldproductIdvalue数量。三、List列表有序、可重复的“双向链表”List类型是Redis中用于存储“有序、可重复”元素的线性结构本质上是一个双向链表Redis 3.2后优化为quicklist支持从两端插入、删除元素查询两端元素速度极快O(1)查询中间元素速度较慢O(n)适合场景化的顺序存储需求。1. 底层实现Redis 3.2之前小数据量时用压缩列表ziplist大数据量时用双端链表adlistRedis 3.2之后统一改为quicklist快速列表本质是“双端链表压缩列表”的组合——将List拆分为多个ziplist每个ziplist作为一个节点用双端链表连接既保留ziplist的内存紧凑性又解决双端链表内存碎片多的问题。quicklist的核心优势两端操作快内存占用比纯双端链表少性能比纯ziplist更稳定。2. 核心操作命令LPUSH key value [value ...]从列表左侧插入一个或多个元素返回插入后的列表长度RPUSH key value [value ...]从列表右侧插入一个或多个元素用法同LPUSHLPOP key从列表左侧弹出一个元素删除并返回RPOP key从列表右侧弹出一个元素用法同LPOPLRANGE key start stop获取列表中从start到stop的元素start0stop-1表示获取所有元素LLEN key获取列表的长度LREM key count value删除列表中count个值为value的元素count0从左删count0从右删count0删除所有BLPOP key [key ...] timeout阻塞式从左侧弹出元素若列表为空等待timeout秒后返回nil常用于消息队列。3. 实战场景消息队列基于LPUSHBRPOP实现简单的消息队列生产者LPUSH发送消息消费者BRPOP阻塞接收消息最新消息列表如用户消息通知LPUSH添加消息LRANGE获取最新10条消息栈/队列实现LPUSHLPOP实现栈先进后出LPUSHRPOP实现队列先进先出。四、Set集合无序、不可重复的“哈希集合”Set类型是Redis中用于存储“无序、不可重复”元素的集合本质上是一个基于dict实现的哈希集合key是集合元素value为null支持交集、并集、差集等集合操作适合需要去重、统计交集/并集的场景。1. 底层实现自适应结构整数集合intset当Set中的所有元素都是整数且数量不超过阈值默认配置set-max-intset-entries512时使用intset存储。intset是紧凑的整数数组按升序排列支持二分查找O(log n)内存占用极低。字典dict当Set中存在非整数元素或元素数量超过阈值时使用dict存储利用dict的O(1)增删改查特性保证高效操作。2. 核心操作命令SADD key member [member ...]向集合中添加一个或多个元素重复元素会自动去重返回添加成功的元素个数SMEMBERS key获取集合中所有元素元素过多时阻塞Redis建议用SSCAN渐进式遍历SREM key member [member ...]从集合中删除一个或多个元素返回删除成功的个数SISMEMBER key member判断元素是否在集合中存在返回1不存在返回0SCARD key获取集合的元素个数SINTER key1 key2求两个集合的交集共同元素SUNION key1 key2求两个集合的并集所有元素去重SDIFF key1 key2求两个集合的差集key1中有、key2中没有的元素。3. 实战场景用户标签keyuser:tag:1001member篮球/音乐/旅行用于用户画像、个性化推荐去重统计如网站UV统计SADD uv:20240329 192.168.1.1SCARD获取UV数好友关系keyuser:friend:1001member好友IDSINTER求两个用户的共同好友。五、ZSet有序集合有序、不可重复的“排序集合”ZSetSorted Set有序集合是Redis中最复杂的数据类型之一兼具Set的“不可重复”特性和List的“有序”特性每个元素都会关联一个“分数score”Redis通过分数对元素进行排序升序/降序支持范围查询适合排行榜、优先级队列等场景。1. 底层实现跳跃表字典ZSet的底层采用“跳跃表skiplist 字典dict”的组合两者协同工作兼顾排序和查询效率跳跃表skiplist核心用于排序和范围查询。跳跃表是一种有序数据结构通过“多层索引”实现快速查找——每一层都是一个有序链表上层链表是下层链表的“索引”可快速跳过大量元素查询效率接近O(log n)。Redis的跳跃表最多支持64层层数越高查询速度越快。字典dict核心用于快速获取元素的分数scorekey是ZSet的元素value是对应的分数支持O(1)的分数查询和修改。优势跳跃表的插入、删除、范围查询效率高字典的单点查询效率高两者结合完美适配“排序快速查询”的需求。2. 核心操作命令ZADD key score member [score member ...]向有序集合中添加元素指定分数若元素已存在则更新分数返回添加/更新的元素个数ZRANGE key start stop [WITHSCORES]按分数升序获取从start到stop的元素加上WITHSCORES可同时返回分数ZREVRANGE key start stop [WITHSCORES]按分数降序获取元素用法同ZRANGEZSCORE key member获取指定元素的分数ZREM key member [member ...]从有序集合中删除一个或多个元素返回删除成功的个数ZCOUNT key min max统计分数在min到max之间的元素个数ZRANK key member获取元素按分数升序的排名排名从0开始ZREVRANK key member获取元素按分数降序的排名用法同ZRANK。3. 实战场景排行榜如商品销量排行榜keyproduct:rank:salesscore销量member商品IDZREVRANGE获取top10优先级队列如任务调度keytask:queuescore优先级member任务IDZRANGE获取优先级最高的任务分数统计如学生成绩排名keystudent:rank:scorescore成绩member学生ID。六、Bitmap位图高效存储“布尔值”的紧凑类型Bitmap位图是Redis中用于存储“布尔值true/false”的紧凑数据类型本质上是一个二进制数组每个bit位对应一个布尔值0表示false1表示true内存占用极低——1MB内存可存储800多万个布尔值适合大量布尔型数据的存储和统计。1. 底层实现Bitmap的底层基于String类型实现String本质是字节数组每个字节包含8个bit位Redis通过对字节数组的bit位进行操作实现布尔值的存储和查询核心是“bit位级别的操作”效率极高。2. 核心操作命令SETBIT key offset value设置指定偏移量offset的bit位值0或1offset从0开始返回该bit位原来的值GETBIT key offset获取指定偏移量的bit位值0或1若offset超出范围返回0BITCOUNT key [start end]统计key对应的位图中值为1的bit位个数start和end指字节偏移量默认统计所有BITOP operation destkey key [key ...]对多个位图执行位运算AND/OR/XOR/NOT结果存储到destkey中BITPOS key value [start end]查找位图中第一个值为value0或1的bit位偏移量。3. 实战场景签到统计keyuser:sign:1001:202403offset日期1-31SETBIT user:sign:1001:202403 5 1表示5号签到BITCOUNT统计月签到天数在线状态keyuser:onlineoffset用户IDSETBIT user:online 1001 1表示用户1001在线GETBIT查询在线状态权限控制keyrole:perm:adminoffset权限IDbit位为1表示拥有该权限BITOP实现权限交集/并集。七、HyperLogLog基数统计海量数据的“去重统计神器”HyperLogLog简称HLL是Redis中用于“基数统计”的高级数据类型核心作用是统计一个集合中“不重复元素的个数”基数无需存储所有元素仅通过少量内存即可实现海量数据的统计——12KB内存可统计千万级数据误差率仅为0.81%适合UV、PV等无需精确统计的场景。1. 底层实现HyperLogLog基于“概率算法”实现核心原理是通过统计“元素哈希值的前导零个数”估算集合的基数无需存储元素本身仅存储统计所需的中间数据因此内存占用极低。注意HyperLogLog是“估算值”不是精确值误差率固定为0.81%但对于UV等场景这个误差完全可接受换来的是内存的极大节省。2. 核心操作命令PFADD key element [element ...]向HyperLogLog中添加一个或多个元素返回1表示基数发生变化0表示基数未变化PFCOUNT key [key ...]统计一个或多个HyperLogLog的基数不重复元素个数PFMERGE destkey key [key ...]将多个HyperLogLog合并合并后的基数是所有集合的并集基数结果存储到destkey中。3. 实战场景网站UV统计keyuv:website:20240329PFADD添加访问用户IPPFCOUNT获取当日UV商品浏览去重统计keyproduct:view:1001PFADD添加浏览用户ID统计不重复浏览人数海量数据去重如日志中的用户ID去重统计无需存储所有ID仅用12KB内存即可完成千万级统计。八、GEO地理空间专门处理“地理位置”的类型GEOGeospatial是Redis 3.2版本新增的地理空间数据类型专门用于存储和操作地理位置信息经纬度支持根据经纬度计算距离、查找附近的地点等操作适合地图、外卖、打车等需要地理位置服务的场景。1. 底层实现GEO的底层基于ZSet实现将经纬度转换为一个“geohash值”通过特定算法将二维经纬度映射为一维整数作为ZSet的score地理位置名称作为member利用ZSet的排序特性实现地理位置的快速查询和距离计算。2. 核心操作命令GEOADD key longitude latitude member [longitude latitude member ...]向指定key中添加地理位置经度、纬度、名称返回添加成功的个数GEOPOS key member [member ...]获取指定地理位置的经纬度GEODIST key member1 member2 [unit]计算两个地理位置之间的距离unit可选m米km千米mi英里ft英尺默认米GEORADIUS key longitude latitude radius unit [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]根据指定经纬度和半径查找该范围内的地理位置COUNT指定返回个数GEORADIUSBYMEMBER key member radius unit [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]根据指定地理位置查找其周围radius范围内的地点用法同GEORADIUSGEODEL key member [member ...]删除指定的地理位置。3. 实战场景外卖商家定位keytakeout:merchant存储商家经纬度GEORADIUS查找用户附近的商家打车平台附近车辆keytaxi:car存储车辆经纬度GEORADIUSBYMEMBER查找用户周围的车辆地理位置距离计算如计算用户与景点的距离用于推荐附近景点。九、总结八大数据类型核心对比与选型建议Redis八大核心数据类型各有其底层实现和适用场景选择正确的类型能大幅提升Redis的性能和内存利用率避免不必要的性能瓶颈。以下是核心对比和选型建议方便大家快速选型数据类型核心特性底层实现核心场景String万能、灵活可存字符串/数字/二进制SDS简单动态字符串缓存热点数据、计数器、分布式锁Hash对象型存储可单独操作字段ziplist dict存储用户/商品信息、小对象集合List有序、可重复两端操作快quicklist双端链表ziplist消息队列、最新消息列表、栈/队列Set无序、不可重复支持集合运算intset dict用户标签、去重统计、好友关系ZSet有序、不可重复按分数排序skiplist dict排行榜、优先级队列、分数统计Bitmap紧凑存储布尔值bit位操作String字节数组签到统计、在线状态、权限控制HyperLogLog海量数据基数统计内存占用低概率算法UV统计、海量数据去重GEO地理位置存储与距离计算ZSetgeohash映射地图服务、附近地点查询最后提醒Redis的选型核心是“贴合业务场景”——无需追求复杂类型简单场景用String对象场景用Hash排序场景用ZSet海量去重用HyperLogLog根据业务需求选择最合适的类型才能发挥Redis的最大价值。