1. 项目概述为什么要系统学习Redis而不是零散看教程1.1 核心需求解析从面试题到生产环境Redis到底卡住了多少人先说个直白的现象。我见过不少同学Redis命令背得滚瓜烂熟SET、GET、HSET随口就来但一聊到“你的缓存是怎么设计的”“缓存和数据库的一致性怎么保证”“为什么缓存会穿透”立刻卡壳。这其实就是典型的学习断层——把Redis当成一个“能存数据的字典”却不知道它真正的价值在于数据结构、内存模型和应用场景的深度结合。我最初系统梳理Redis起因其实很实际。项目上线前压测QPS一高数据库连接池直接被打满接口响应从50ms飙到2000ms。当时临时把热点数据塞进了Redis问题瞬间缓解。但随后一连串问题来了缓存雪崩、缓存穿透、数据不一致一个接一个踩坑。等到真正把Redis从“会用”变成“懂用”才发现市面上90%的教程都停留在命令层面没人告诉你生产环境下到底该怎么做。所以这篇笔记的定位很明确把Redis从源代码级到业务级拆开来讲。适合三类人——刚接触Redis想建立完整知识框架的新手用过Redis但没系统梳理过的初中级开发者以及准备面试、需要把“会用”升级为“懂原理”的同学。核心不是背命令而是搞清楚Redis为什么快、数据怎么存、怎么设计才能发挥它的价值。1.2 学习路线设计先把“内存数据库”这个心智模型建立起来学习任何技术第一步是建立正确的心智模型。Redis最核心的心智模型就一句话它是一个跑在内存里的单线程事件循环服务器所有的数据操作都在内存中完成通过IO多路复用机制监听和分发网络事件。这句话拆开有三层含义。第一数据在内存里所以读写速度是微秒级这是它能扛高并发的物理基础。第二单线程模型意味着没有锁竞争、没有上下文切换所有命令按顺序执行避免了多线程环境下令人头疼的并发问题。第三IO多路复用让一个线程能同时处理成千上万个客户端连接而不是为每个连接开一个线程。理解了这个模型很多表面现象就能解释了。为什么Redis的LPOP不会出现并发弹错数据因为单线程串行执行。为什么KEYS命令在生产环境绝对不能乱用因为它遍历全部键单线程下会让整个服务卡顿。为什么Redis的持久化会有性能损耗因为RDB快照是fork子进程生成AOF是追加写文件都要落盘。2. Redis核心数据结构不只是Key-Value是五种数据模型2.1 String类型缓存、计数器、分布式锁的基础载体String是Redis最基础也最常用的数据类型底层是SDS简单动态字符串相比C语言的原生字符串它记录了长度信息从而支持O(1)复杂度的长度查询空间预分配和惰性空间释放减少了内存重分配次数。在实际开发中String的典型场景有三个缓存对象、计数器、分布式锁。缓存对象最常见。把数据库查出来的用户信息序列化成JSON字符串存入Rediskey设计成user:info:1001这样的格式读取时先查缓存命中直接返回未命中再查数据库回填。计数器则是利用INCR和DECR的原子性实现点赞数、访问数、库存扣减这类高频操作。这里有个细节值得注意INCR的原子性不只是线程安全它是Redis单线程模型下天然保证的不需要额外加锁。分布式锁是String比较有技术含量的应用。核心命令是SET lock:order:1001 random_value NX EX 10这句话的含义是只有key不存在时才设置成功NX设置的值是随机字符串同时指定10秒过期时间EX。为什么用随机值因为释放锁时要先比较value是否一致防止误删别人的锁。用Lua脚本保证“比较删除”的原子性if redis.call(get,KEYS[1]) ARGV[1] then return redis.call(del,KEYS[1]) else return 0 end2.2 Hash类型对象存储的天然选择与内存优化细节Hash类型适合存储对象比如用户信息、商品信息。它底层有两种编码方式ziplist压缩列表和hashtable。当字段数量少且值比较短时用ziplist节省内存字段增多或某个值变大才会转换为hashtable。这里有个很实用的小技巧想查看某个key当前用了什么编码用OBJECT ENCODING key命令。我当初排查内存问题时发现一个存储商品信息的Hash有上万个字段但内存占用却异常高一查编码发现已经转成了hashtable但实际很多字段频繁更新、过期。后来把大Hash拆成了多个小Hash每个Hash的字段控制在100个以内内存直接降了40%。Hash的另一个价值在于支持针对字段的原子操作。比如HINCRBY可以只对Hash中某个字段做累加这在设计“商品库存商品详情”这类复合数据结构时太方便了——不需要把整个对象都塞进一个String再反序列化、修改、重新写入直接操作字段就行。2.3 List、Set、ZSet顺序、去重、排序三种业务形态List类型底层是quicklist结构支持双向阻塞队列典型场景是消息队列、最新列表。LPUSH BRPOP组合实现了一个可靠的消息队列BRPOP会阻塞等待新消息避免空轮询浪费CPU。如果有多个消费者BRPOP会从多个key中按顺序弹出实现了简单的负载均衡。Set类型的关键特性是无序、去重、支持集合运算。用来做标签系统、好友关系、抽奖去重都很好用SINTER可以求两个集合的交集比如“同时关注了A和B的用户”数据库里写SQL要JOIN半天Redis一条命令解决。ZSet有序集合是Redis中最有含金量的数据结构之一。它底层是跳表skip list 哈希表的复合结构每个成员关联一个score分数按分数排序。排行榜、延迟队列、限流器都能用它实现。拿排行榜举例ZADD leaderboard:game1 100 user_001ZREVRANGE leaderboard:game1 0 9 WITHSCORES取出前10名ZSCORE查某个人当前分数全程毫秒级响应。延时队列用ZSet实现也很巧妙把任务的执行时间戳作为score消费者用ZRANGEBYSCORE取出score小于当前时间的任务去执行执行完删除。相比用定时任务扫描数据库这种方案轻量得多而且天然支持多消费者并发拉取。2.4 底层编码机制一个Key的内存占用是怎么算出来的看一个Redis同学的进阶水平只要问一个问题一个10个字段的Hash和10个独立的String谁更省内存答案是Hash更省。Hash在字段少、值小的场景下使用ziplist编码这是一块连续的内存区域没有指针开销。而10个独立的String每个都有独立的SDS结构、dictEntry节点、内存碎片和RedisObject头开销巨大。这引出了Redis的一个核心优化思想尽可能用内嵌类型减少键的数量。我在实际项目中做过一个对比测试存储100万条用户简要信息方案A用user:1001这样的String内存约220MB方案B用Hash分片比如user:hash:100存储100个用户的字段映射内存约110MB节省了一半。Redis还有个专门的命令MEMORY USAGE key可以查看某个Key占用多少字节。通过它你能直观地看到不同数据类型、不同编码方式带来的内存差异。我建议排查内存问题时先用INFO memory看总量再用redis-cli --bigkeys找大Key最后用MEMORY USAGE对嫌疑对象精确定位三步走。3. Redis持久化机制数据安全与性能的博弈3.1 RDB快照fork子进程的COW机制到底做了什么RDB持久化就是把内存中的数据生成快照写入磁盘文件。表面上看很简单但真正有价值的是它底层的**写时复制Copy-On-Write**机制。触发BGSAVE的时候Redis会fork一个子进程。fork的瞬间子进程和父进程共享同一份内存页表。父进程继续处理请求当某个内存页要被修改时内核会先复制一份原页面父进程在副本上改子进程看到的还是原始数据这样快照就不受写入操作的影响。这里面有个隐性坑如果fork期间父进程有大量写入内存会被瞬间翻倍。我记得有一次线上机器内存16GRedis数据量8G触发RDB后机器内存飙升到15G差点OOM。后来排查发现是某个业务在半夜跑批量任务大量写入触发了COW复制。解决方案是把stop-writes-on-bgsave-error设为yes错误时停止写入同时把RDB的触发策略调整成只在低峰期手动执行。3.2 AOF重写与fsync策略掉数据的分寸该怎么拿捏AOFAppend Only File记录的是每一条写命令通过重放命令来恢复数据。它的优势是数据安全性更高可以做到每秒甚至每条命令都刷盘最多丢失1秒数据。AOF有三个刷盘策略always每条命令都fsync、everysec每秒fsync、no交给系统。很多初学者直接选always觉得最安全但实际上每条命令都fsync会导致写性能下降好几个数量级。生产环境最常用的是everysec它能保证最多丢失1秒数据性能损耗可以接受。AOF有个有意思的机制叫AOF重写。随着写入越来越多AOF文件会无限膨胀。比如一个计数器INCR执行了一万次AOF里会有一万条INCR命令但其实重写后只需要一条SET key 10000。重写的过程是fork子进程把当前内存中的数据生成对应的写命令写入临时文件完成后替换旧文件。新生成了AOF文件之后主进程的写命令会同时写进旧AOF和AOF重写缓冲区保证不丢数据。3.3 混合持久化与选型建议不是所有业务都需要AOFRedis 4.0之后引入了混合持久化RDB文件作为基础快照AOF记录RDB之后的增量写操作。这样重启恢复时加载RDB快同时用AOF补齐增量兼顾恢复速度和数据完整性。我给出的选型建议是对数据安全要求极高如支付、交易的用AOF everysec对恢复速度要求高且能接受少量丢失的用RDB既可以组合使用也可以根据场景单独使用。实际生产中我常用混合持久化同时设置合理的自动触发策略比如save 900 1900秒内至少有1次修改就保存、save 300 10300秒内至少有10次修改就保存。需要注意的是持久化和主从复制是两回事。之前有个同事把持久化关了以为有了主从就万事大吉结果主库宕机后从库晋升为主库但后来主库恢复了数据同步混乱最终丢了大量数据。主从复制不能替代持久化这是底线。4. 缓存设计实战穿透、击穿、雪崩的完整解法4.1 缓存穿透查询不存在的数据把数据库打穿了缓存穿透指查询一个一定不存在的数据缓存里没有数据库里也没有每次请求都直接打到数据库。恶意的并发攻击可以轻松让数据库挂掉。三种解法我按推荐程度排一下。第一种缓存空值。查询数据库结果为null时也往Redis写一个keyvalue设为空字符串或特殊占位符过期时间设短一点比如60秒。这样后续同样的查询击穿到Redis就停了。第二种布隆过滤器。把所有可能存在的数据的key提前存入布隆过滤器查询前先判断key是否可能存在不存在直接返回。布隆过滤器有个特点判断不存在一定正确判断存在可能误判。误判会导致某些不存在的key仍能穿透到数据库但概率很低。用Redisson的RBloomFilter实现很方便或者用bitmap自己做一个。第三种参数校验。在入口层直接拦截明显非法的参数比如id小于0、包含特殊字符直接返回错误。这是成本最低的一层防护。4.2 缓存击穿热点key过期瞬间请求全部打到数据库缓存击穿和穿透的区别在于击穿的key是真实存在的高热度数据只是缓存过期的那一瞬间大量并发请求同时发现没缓存一起涌向数据库。经典解法是互斥锁。在重建缓存之前让线程先尝试获取分布式锁只有拿到锁的线程才能去查数据库并回填缓存其他线程等待缓存回填后直接读取。我用Redisson的RLock实现过代码逻辑大致是String cacheValue redisTemplate.opsForValue().get(cacheKey); if (cacheValue null) { RLock lock redissonClient.getLock(cacheKey :lock); try { if (lock.tryLock(3, TimeUnit.SECONDS)) { // 双重检查也许其他线程刚回填完 cacheValue redisTemplate.opsForValue().get(cacheKey); if (cacheValue null) { cacheValue dao.findById(id); redisTemplate.opsForValue().set(cacheKey, cacheValue, 30, TimeUnit.MINUTES); } } } finally { lock.unlock(); } }这里有两个细节要注意一是锁的粒度必须是锁某一个具体的key而不是全局锁否则一个热点key过期会阻塞所有缓存操作二是一定要做二次检查否则第一个线程还在查数据库的间隙另一个线程已经回填了第二个线程又会重复查一次数据库。另一个解法是逻辑过期。不设置物理过期时间而是在value里存一个逻辑过期时间戳查询时发现逻辑过期了返回旧值的同时异步启动一个线程重建缓存。这种方案能保证请求永远不会被阻塞但会短暂读到过期数据适合对一致性要求不高的场景。4.3 缓存雪崩大量key同时过期Redis瞬间失去作用雪崩的成因是大批量key在同一个时间过期或者Redis节点挂了导致所有请求都落到数据库。解决思路从三个层面展开。第一层过期时间加随机值。缓存设置过期时间时在基础值上加一个随机秒数比如30分钟 random(0~300秒)让key的过期时间分散开。这个方案简单到令人发指但对业务的冲击最小我一般把它作为默认策略。第二层多级缓存。在应用层加一个本地缓存Caffeine或GuavaRedis之上再做一层挡板。Redis挂了或者大量过期本地缓存还能扛一部分热点请求。这其实是用空间换时间但收益非常明显——我曾经用Caffeine做热点商品缓存Redis故障期间接口可用性从80%提升到了99.5%。第三层Redis高可用。主从复制加哨兵模式Redis挂了自动从从库提升一个主库客户端通过哨兵发现新主库并重连。集群模式下用Cluster分片数据分布到多个节点避免单点故障。4.4 缓存与数据库一致性先更新数据库还是先删缓存这个问题面试必问网上的答案足够多但真正动手做的时候还是容易踩坑。先说结论推荐先更新数据库再删除缓存的方案配合延迟双删。剩下的一个关键点是为什么不是先删缓存再更新数据库因为并发场景下删完缓存之后、更新数据库之前另一个线程读到旧值回填了缓存之后就再也不会更新了数据一致性被破坏。那先更新数据库再删缓存的问题是什么如果删缓存这个操作失败了缓存里还是旧值下一次请求读到的还是旧数据。解法有两种一是延迟双删——先删缓存、再更新数据库、再延时删一次缓存保证即使在更新数据库期间有旧值回填延时删除也能覆盖掉二是通过消息队列异步重试删除缓存删失败后反复尝试。时间窗口的分析也要说清楚。更新数据库和删除缓存之间是有时间差的理论上这个窗口期内读到的还是旧数据。但相比先删后更新这个窗口要小得多而且业务上通常可以容忍。如果是强一致场景就不要用缓存了或者借助数据库binlog订阅来精确删除对应缓存。5. Redis高可用架构主从复制、哨兵与集群5.1 主从复制从库为什么不能写复制延迟怎么解决主从复制的核心价值是读写分离和故障转移的数据备份。主库负责写从库负责读主库将写操作同步给从库。同步过程有三个阶段全量同步、增量同步、命令传播。全量同步发生在从库刚连接或者连接断开重连时主库生成RDB快照发送给从库从库加载快照。增量同步和命令传播则是主库把写命令实时推送给从库。有一个复制积压缓冲区repl-backlog的概念如果从库断开时间较短主库可以在重连时把断线期间的命令补发给它避免全量同步。这里最常见的问题是主从复制延迟即从库的数据永远比主库旧一点。网络波动、从库负载过高、大key传输都可能导致延迟。对一致性要求高的场景就不要走从库读取对基于数据时效性的业务比如排行榜、推荐列表从库读完全没问题。5.2 哨兵模式自动故障转移的监听机制哨兵Sentinel是一个独立运行的进程它监控所有Redis主从节点的状态。当主库失联时哨兵会发起投票选举一个从库晋升为新主库并把其他从库的主节点指向它同时通知客户端新的主库地址。多个哨兵之间互相通信避免单点误判——只有多个哨兵都认为主库挂了客观下线才会触发故障转移。我在部署哨兵时踩过一个坑哨兵至少需要三个实例且部署在不同的物理机器上否则当机器宕机时哨兵和Redis一起挂哨兵就失去了意义。另外sentinel monitor配置里的quorum法定人数和选举票数的关系要搞清楚quorum是判定主库下线所需的最小同意数failover真正执行需要获得多数哨兵的授权所以哨兵进程数以2n1为最佳。5.3 Redis Cluster数据分片与节点间的路由机制Redis Cluster是官方推荐的分布式方案。它把数据按**哈希槽hash slot**来分布总共16384个槽位多个节点各负责一部分槽位区间。写入数据时集群先计算key的CRC16并模16384找到对应的槽和节点客户端可以直接路由到正确的节点如果相连的是错误的节点服务端会返回MOVED命令重定向客户端再重新发起请求。Cluster模式解决的是数据量超过单机和QPS持续走高时的扩容问题。它自身就包含主从复制每个主节点有从节点也天然具备高可用。但要注意Cluster的MGET这种多key操作要求所有key在同一个槽上所以设计key时要考虑使用哈希标签hash tag比如{user:1001}:orders和{user:1001}:cart花括号部分参与哈希计算确保同用户的key落到同一个槽。6. Redis性能优化与监控从上手的简单操作到压测调优心得6.1 性能监控的核心指标慢查询、内存碎片和命中率我日常排查Redis问题最常用的三个指标是慢查询日志、内存碎片率和命中率。慢查询日志通过SLOWLOG GET查看它记录的是超过阈值的命令。阈值由slowlog-log-slower-than配置单位是微秒。发现慢命令后要重点检查是不是用了KEYS、HGETALL、SMEMBERS这类O(N)命令或者命令带了太多数据、在遍历大集合。优化方向是改成SCAN这种方式或者把大集合拆分成多个小集合。内存碎片率用INFO memory里的mem_fragmentation_ratio查看。碎片率大于1.5说明内存分配频繁导致碎片过多可以采用jemalloc的优化分配策略或者适当增大内存页。碎片率过小则说明实际使用内存远超申请内存可能存在大key或内存泄漏。命中率则是用INFO stats里的keyspace_hits和keyspace_misses之比来算。命中率太低说明缓存基本没起作用需要排查缓存过期策略或者key设计是否合理。6.2 日常踩坑记录大Key、热Key与Key的TTL设计我把实操中比较多发的坑列成表大家可以直接对照自查场景典型表现解决方案大Key内存占用高、删除阻塞、迁移超时redis-cli --bigkeys扫描超过10KB的key拆分为多个小keyHash大key分散为多个字段组热Key单个key访问QPS极高单节点CPU打满本地缓存前置key加随机后缀分发到多个节点读多写少的用副本Key过期集中缓存雪崩过期时间加随机值多级缓存前置Key命名混乱运维排查困难统一的业务:模块:实体:ID命名规范便于前缀搜索TTL设置不合理要么缓存过早失效要么内存持续膨胀高变动数据10-30分钟低变动数据1-24小时永不过期的key做专门标记这里特别说一下大Key删除的坑。Redis删除一个大Key比如一个几MB的String或者上百万成员的Hash命令执行期间会阻塞主线程导致其他命令排队等待接口大面积超时。正确姿势是分批删除如果是Hash用HSCAN分批取一部分字段、分批HDEL如果是List用LTRIM逐步裁剪。6.3 压测实测单线程Redis的极限与瓶颈在哪里我用redis-benchmark跑过一次本机压测简单记录一下结果。环境是4核8G的虚拟机Redis 7.0版本默认配置。redis-benchmark -t set,get -n 1000000 -c 100意思是100万次读写请求100个并发连接SET和GET的表现都在10万QPS上下。这个数字已经很能说明Redis的性能水平。但QPS高不代表没有瓶颈。我观察到的瓶颈通常是三个方向一是网络带宽如果单次写入的数据量很大甘特CPU表现再好网络也会成为瓶颈二是fork子进程的阻塞RDB持久化时fork会在瞬间阻塞主线程耗时几十毫秒甚至更长三是内存分配器在大量写入和删除的场景下jemalloc的内存分配效率会直接体现到CPU消耗上。从调优角度我的经验排序是优先保证命令的复杂度是O(1)或O(log N)其次注意持久化策略对性能的影响最后考虑操作系统的网络参数优化。代码层面的优化往往比硬件堆配置更有效。7. 实操过程与核心细节从安装到二次开发调试的完整记录7.1 环境准备与安装Windows本机开发和Linux生产部署Windows上官方没有原生版本我一般用两种方案一是WSL2跑Linux发行版二是在Windows下用Memurai或编译好的Redis发行包。但生产环境强烈建议用Linux部署。Linux上安装最省事的是用包管理器比如Ubuntu执行apt install redis-serverCentOS/RHEL上执行yum install redis。也可以直接编译源码下载stable版本后make make install。编译的优势是可以手动开启DEBUG开关对后续调试比较方便。启动后立刻验证三件事redis-cli ping返回PONGredis-cli info看role是否为masterredis-cli config get maxmemory确认内存限制配置了没有。大部分生产事故都始于maxmemory没配内存被打满后Redis开始被动淘汰或者直接拒绝写入。7.2 常用运维指令与配置参数速查这里我从实践出发整理了一份高频配置与命令速查配置参数方面maxmemory限制最大内存maxmemory-policy设定淘汰策略常用的有allkeys-lru、volatile-lru、noevictionappendonly yes开启AOFsave设置RDB触发条件requirepass设置连接密码。运维命令方面redis-cli --bigkeys扫描大keyredis-cli --scan --pattern user:*按前缀遍历所有keyredis-cli --stat实时查看QPS和内存变化redis-cli -3批量发送命令redis-cli -x set key从标准输入读入数据避免输入特殊字符被终端解释。排查问题时我用得最顺手的套路是先INFO看内存、命令统计、持久化状态再SLOWLOG查慢命令再MONITOR实时追踪一段时间内所有请求。MONITOR在生产环境不要长时间开启它会拖慢Redis适合短时间定位问题。7.3 二次开发调试技巧如何读懂慢命令和执行链路遇到疑难问题时光靠命令不够需要结合源码或者调试工具。比如之前线上出现过一次偶发的连接卡顿用SLOWLOG看不出来因为不是命令本身慢而是服务端处理连接的事件循环被什么东西卡住了。最后是开启DEBUG JMAPRedis 7的调试命令和redis-cli --latency工具定位到是AOF刷盘的fsync阻塞了主线程。还有一个小技巧是使用COMMAND INFO查看命令的时间复杂度和参数说明COMMAND COUNT统计命令总数。Redis 6以后有了ACL访问控制列表可以给不同的账号配置精细的权限这个在生产环境多人共用一套Redis时非常有用别再搞一个requirepass所有人共用。8. 学习路径与面试加分点从会用到懂原理的飞跃8.1 系统的学习路径命令、源码、项目实践三线并行如果想把Redis学透我的建议是三条线同时推进而不是一条路走到黑。第一线是命令与数据结构核心是把五种基础类型加三种特殊类型HyperLogLog、Geo、Bitmap都实际操作一遍尤其是ZSet和Hash它们是解决实际问题的利器。第二线是底层原理《Redis设计与实现》这本书值得精读重点是SDS、跳跃表、字典、ziplist、事件处理器和持久化。第三线是项目实践每个人都要在真实项目中至少踩过两个坑才算入门比如缓存穿透、缓存击穿、大Key阻塞、主从延迟。我个人的体会是源码阅读不要一开始就上先把行为摸透了再倒推Why效率高很多。比如你已经用LPUSH做了一个消息队列意识到BRPOP会阻塞再去看阻塞队列的实现就非常顺畅。直接看源码容易迷失在细节里。8.2 面试高频问题与答题框架Redis相关的面试问题我总结了一套高频题和对应答题思路。“Redis为什么快”要答三个层次内存存储、IO多路复用、高效的数据结构。加分点是补充单线程模型避免了上下文切换和锁竞争。“缓存穿透和缓存击穿的区别”要答场景差异和解法差异穿透是查不存在的数据击穿是热点Key过期瞬间。两者不能用同一种解法穿透要防空值或布隆过滤器击穿要锁或逻辑过期。“Redis持久化方式怎么选”要答RDB和AOF的优缺点RDB恢复快但可能丢失多AOF丢失少但文件膨胀然后引到混合持久化。“分布式锁怎么实现”要答SET NX EX加随机值Lua脚本释放锁然后引到Redission的看门狗机制。“ZSet底层为什么用跳表”要答跳表查询O(logN)实现简单相比平衡树更适合范围查询和顺序遍历。9. 扩展思考与经验总结Redis的边界与未来方向9.1 什么场景不适合用RedisRedis不是银弹有些场景真的不合适。数据量远大于内存的场景就不合适——虽然Redis有集群可以横向扩容但内存成本摆在那里海量数据存储还是数据库或对象存储更合适。强一致性的交易场景也要谨慎Redis的主从复制是异步复制主库挂了可能丢数据AOF再稳妥也有刷盘窗口金融级场景还是要数据库事务兜底。还有一个容易被忽视的问题Redis不适合存过期后还有历史价值的冷数据。你可能临时为了性能把某些报表缓存了结果业务结束后忘了清理内存被持续占用得不偿失。运维上要对缓存数据做定期的资产盘点。9.2 后续可扩展的方向从缓存到实时计算与向量检索Redis的非K-V用法越来越丰富。Redis Stream支持消费者组和ack机制可以担纲轻量级消息队列。Bitmaps能实现亿级用户在线状态追踪。Geo数据类型支持附近的人查询底层是跳跃表加有序集合的复合应用。更值得关注的是Redis 8引入了向量检索模块可以存储向量并进行相似度搜索。在AIGC应用里它能把Embedding向量和业务数据存放在同一个Redis实例中对于中小规模项目往往比专门架设一个向量数据库更务实。借写这篇Redis笔记的机会我重新梳理了一遍从底层存储到上层应用的完整脉络。Redis之所以难学在于它不是只有一条主线而是“数据结构、持久化、缓存设计、高可用、性能优化”五条线交织在一起。每一线单独拿出来都不复杂但一旦实际业务场景叠加交互关系就变多了。我自己的经验是——至少在真实产品里完整跑完一个“从缓存设计到性能优化”的闭环比看十篇理论文章都有用。