
我第一次用Redis是在一个流量不大的后台系统里。当时的需求很简单——“把数据库查询结果缓存起来少一点压力”所以我的用法就是set get后来为了省事所有key的过期时间都统一设成一小时。直到有一次活动页面流量上来缓存大面积同时失效数据库连接瞬间被打满我盯着监控面板看错误率往上飙才第一次意识到Redis学习这件事如果只停留在“会几个命令”的层面基本等于在给未来的线上事故埋雷。这篇文章把我从入门到踩坑的完整路线整理出来覆盖安装下载、数据类型、底层机制、常见故障和项目落地。无论你是刚接触Redis的学生还是工作中被迫接手Redis运维的开发者都能在这里找到一条相对完整的参考路径。我不打算写成一堆命令的堆砌而是想把“为什么这么设计”“为什么这个坑容易踩”也讲清楚。1. 安装Redis之前先把版本和下载方式想清楚很多人一上来就apt install redis-server装完能用就行。但Redis的版本差异其实挺大的不同版本之间的特性、配置项、甚至部分命令行为都不一样。先把版本选明白后面能少踩很多坑。1.1 现在装哪个版本比较合适Redis官方这几年的迭代明显加快。6.x引入了ACL权限控制、客户端缓存、I/O多线程7.0把ziplist相关结构替换成了listpack新增了Functions、Sharded Pub/Sub7.2是相对成熟稳定的长支持版本2025年发布的8.0则带来了多线程命令执行和内存与闪存混合存储属于比较大的架构变化。我的建议很简单生产环境的新项目优先选7.2.x稳定性和新特性平衡得最好。老项目如果还在用6.x短期不用焦虑但尽量不要停留在5.x以下5到7的差距已经很大了。8.0可以装一套测试环境玩别一上来直接上生产刚发布的版本总会需要一点观察期。推荐版本号的同时要连带考虑发行方式。Linux上先用redis-server --version看一下现有版本再决定怎么升级。1.2 各平台的下载安装方式官方源码包在download.redis.io这个地址下各版本的tar.gz都有。Linux服务器最稳妥的方式是编译安装wget https://download.redis.io/releases/redis-7.2.5.tar.gz tar xzf redis-7.2.5.tar.gz cd redis-7.2.5 make -j4 make install PREFIX/usr/local/redis编译完redis-server和redis-cli会被放到/usr/local/redis/bin下建议把这两个二进制加到PATH里。make test也可以跑一遍验证当前环境没问题。Ubuntu/Debian上直接用apt装会方便很多apt update apt install redis-server systemctl enable redis-server systemctl start redis-servermacOS用户一条brew install redis就搞定适合本机学习调试。Windows官方一直不支持原生安装别再折腾什么Windows移植版了直接用WSL2或者Docker跑干净利落docker run -d --name redis \ -p 6379:6379 \ -v /myredis/data:/data \ redis:7.2 \ redis-server --appendonly yes我第一次在Windows上踩过坑装了个第三方编译的Redis后来发现很多配置行为和官方版本不一致。从此学到一条经验Redis相关的环境问题先确认是不是安装来源不正规而不是先怀疑自己的配置。1.3 首次启动需要改的配置用默认配置直接redis-server启动很容易遇到两个问题一是前台运行ssh一断开服务就没了二是protected-mode yes模式下的网络限制让外部客户端连不上。学习阶段我习惯改这几个配置项daemonize yes logfile /usr/local/redis/redis.log dir /usr/local/redis/data appendonly yesdaemonize yes让Redis以后台守护进程方式运行logfile指定日志路径排查问题全靠它。appendonly yes是开启AOF持久化这个后面讲数据安全会细说学习阶段建议直接开不然redis一重启就发现数据全没了心态容易崩。启动之后用redis-cli验证一下redis-cli ping能看到PONG返回说明服务正常了。再看一眼redis-cli info server里的版本号和运行模式确认你启动的确实是那个编译好的Redis而不是系统自带的旧版本。2. 别再只当它是个缓存Redis的本质是内存数据结构服务器市面上讲Redis的文章十个有八个开头都是“Redis是一个开源的高性能键值数据库”。这句话没错但很容易让人产生误解以为它就是个put/get的缓存工具。事实远不止如此。2.1 从“键值存储”到“数据结构服务器”的认知转变Redis和传统键值存储最大的区别在于value不只是一个字符串它可以是String、List、Hash、Set、ZSet、Bitmap、HyperLogLog、Geo、Stream等多种数据结构。这意味着很多业务逻辑可以直接在Redis里完成而不必把数据拉到应用层处理。举个例子排行榜功能用ZSet实现Redis内部已经把排序逻辑做好了应用只需要ZADD往里加分数查询时ZREVRANGE按分数倒序取前N名十几行代码搞定。如果用MySQL实现就是一个带ORDER BY score DESC LIMIT的查询数据库压力一大就会成为性能瓶颈。我在做社区功能的时候很长一段时间把点赞数、评论数、热度分都放在MySQL里算后来迁移到Redis的Hash和ZSet后响应时间从几十毫秒降到了个位数毫秒。这种提升不是服务器变强了而是数据结构和业务模型更匹配了。2.2 单线程模型为什么还能这么快这是个老生常谈但必须搞清楚的问题。Redis在处理命令时是单线程的所有命令在一个主线程里依次执行天然没有并发竞争和锁的消耗。那它为什么快首先数据在内存里内存访问本身是纳秒级的比磁盘快几个数量级。其次Redis的事件驱动模型基于I/O多路复用通过epollLinux/kqueuemacOS在一个线程里去监听大量客户端连接每次只在有socket事件真正发生时去处理避免了阻塞等待。这里有个大坑要提醒单线程意味着任何一条命令执行过慢后面所有命令都要排队等。所以KEYS *这种遍历全库的命令在线上环境是绝对禁止的。我亲眼见过有人因为执行KEYS *导致Redis阻塞了几秒钟那一瞬间整个业务的缓存全部超时。后面会专门讲慢查询和BigKey的处理方法。Redis 6.0引入了多线程I/O把网络读写拆分到了额外的线程池但命令执行仍是主线程单线程。Redis 8.0开始支持命令执行多线程算是一个架构上的大变化有兴趣可以在测试环境研究。2.3 数据都在内存里持久化是最后的兜底Redis数据放内存所以快。但机器重启、进程崩溃的时候内存数据会全部消失。这是学习Redis必须接受的第一性原理没有开启持久化Redis就是一个带高级数据结构的内存缓存。持久化方案有RDB、AOF和二者的混合模式细节放到后面专门讲。这里只想建立一个观念使用Redis之前先问自己一个问题——“如果这个Redis实例重启了数据丢了能接受吗”纯缓存场景业务数据都在数据库里丢了缓存无非是重新回源加载可以接受。库存、订单、分布式锁等关键数据一旦丢了就是事故必须开启AOF甚至要做高可用。想清楚这个问题你才知道该往redis.conf里写什么。3. 五大基础数据类型逐一说透命令、场景与底层结构Redis学习绕不开的核心就是五大基础数据类型。光记住命令没有用得知道每种结构面对什么业务场景、底层怎么实现、坑在哪。3.1 String最基础也最容易滥用String是Redis最简单的结构value最大能到512MB。常用命令包括SET、GET、SETNX、INCR、DECR、EXPIRE、TTL。这里有几个典型场景缓存直接把数据库查询结果的JSON序列化后存入String。计数器INCR自增天然线程安全做点赞数、播放量、PV统计非常顺手。分布式锁SET key value NX PX 30000这个后面实战章节会展开。分布式IDINCRBY key 1000生成一批ID再在应用层分配。底层实现上String用的是一种叫SDSSimple Dynamic String的结构相比C语言的字符串它记录了长度信息取长度是O(1)的而且因为存储了len二进制安全。Redis会根据value的长度和内容选择编码方式短整数用int编码短字符串用embstr超过一定阈值则用raw。大量新手会踩的坑是把一个特别大的对象直接SET进Redis比如把用户的完整订单列表JSON序列化后塞进去。String本身能放下但后续每次对这个key做操作都可能触发大key问题传输慢、阻塞高还容易把网络带宽打满。后面会专门讲BigKey的危害与排查。3.2 Hash对象模型的最佳搭档Hash是一个field-value映射集合适合表示对象。比如用户信息HSET user:1001 name 张三 age 28 city 北京 HGET user:1001 name HGETALL user:1001和把整个对象序列化成String相比Hash最大的优势是可以单独更新某个字段。用户改了头像只需要HSET user:1001 avatar new.jpg不用把整个对象读出来改完再写回去。这在并发场景下能减少很多数据竞争问题。Hash内部编码有两种field数量少且值小的时候用listpack7.0之前是ziplist省内存field多或者某个value大时自动转为hashtable。学习中可以用OBJECT ENCODING user:1001查看当前key用的编码这是个很好的理解底层的方式。购物车是Hash的经典应用HSET cart:1001 sku_001 2加购就是HINCRBY查询HGETALL删除HDEL。字段是商品ID值是数量语义非常清晰。3.3 List顺序列表与阻塞队列List是双向链表结构支持从头部和尾部操作。常用命令LPUSH、RPUSH、LPOP、RPOP、LRANGE、LLEN、BRPOP。最经典的场景有两个最新消息列表LPUSH新内容LRANGE list 0 9取最新10条。微博/朋友圈feed流这种时间线场景用List做分页非常合适。简单工作队列LPUSH任务消费者BRPOP阻塞弹出。BRPOP key 0的含义是如果列表为空就阻塞等待直到有新元素进来。这个命令让Redis能在不引入消息中间件的情况下实现一个轻量级队列。底层实现上List用的是quicklist结构本质是“链表压缩节点”的组合。7.0以后每个节点用listpack存储多个元素既保证了两端操作的高效又控制了内存占用。缺点是List做队列没有消息确认机制消费者LPOP拿到任务后如果处理失败消息就丢了。真要追求可靠消息要么引入Stream下面会讲要么直接用专业的消息队列。3.4 Set去重与关系运算Set是唯一元素的无序集合。常用命令SADD、SREM、SMEMBERS、SISMEMBER、SCARD以及集合运算SINTER交集、SUNION并集、SDIFF差集。直接说场景标签系统一篇博客打多个标签每个标签是一个Set集合里存文章ID。SINTER可以找到同时包含多个标签的文章。共同好友两个用户各自的好友集合求交集。抽奖去重SADD pool user_001抽奖时SPOP随机弹出。点赞/收藏SADD post:123:liked user_001判断SISMEMBER。Set底层在元素都是整数且数量不多时用intset编码极端省内存当元素不是整数或数量变大时转为hashtable。所以不要把大对象塞进Set当集合用那会把hashtable弄得很大。3.5 ZSet排行榜的实现神器ZSet也就是有序集合每个member关联一个score按照score排序。命令包括ZADD、ZINCRBY、ZRANGE、ZREVRANGE、ZSCORE、ZRANGEBYSCORE、ZREM。排行榜是ZSet最完美的应用场景。比如积分榜ZADD rank 100 user_001分数变化时ZINCRBY rank 5 user_001查前10名ZREVRANGE rank 0 9 WITHSCORES。整个过程全部在Redis内完成性能极高。ZSet还能做延迟队列把时间戳作为scoreZADD delay_queue task_001 1691234567消费者用ZRANGEBYSCORE delay_queue 0 now LIMIT 0 1取出到期任务处理完ZREM删除。比List队列更灵活因为你能看到“还有多久到期”的元素。底层实现是跳表skip list加哈希表。跳表是个多层级链表查询复杂度O(logN)代码实现比红黑树简单但表现接近。如果你想深入Redis跳表值得花时间研究一下很多面试也从这里出题。4. 扩展数据类型从Bitmap到Stream每个都能解决一类实际问题五大基础类型是入门但实际业务里经常需要更“专”的结构。Redis提供的几个扩展数据类型用好了能省大量存储和代码。4.1 BitMap用一个bit统计一个用户Bitmap不是独立的数据结构本质上是String类型上的一组位操作。命令包括SETBIT、GETBIT、BITCOUNT、BITPOS。最典型的场景是用户签到。一年365天每天给用户分配一个bit位0表示未签到1表示已签到。SETBIT user:sign:2025 100 1表示第101天签到了BITCOUNT user:sign:2025统计全年签到天数。1亿用户做一年签到统计大概只需要1亿×365/8字节也就是几个GB级别相比存365个Hash字段省得多。还有一个经典用法是统计在线用户。用户上线时SETBIT online 1001 1定时BITCOUNT online就是当前在线人数下线SETBIT online 1001 0。4.2 HyperLogLog用极小的空间统计UV如果只需要知道“去重后的数量”不关心具体是哪些用户HyperLogLog是最合适的选择。命令只有三个PFADD、PFCOUNT、PFMERGE。它的原理是基于概率统计每个key固定占用约12KB内存却能统计2^64级别的去重数。代价是有0.81%左右的标准误差。对于UV统计这种精度需求不算苛刻的场景完全够用。我做过一个埋点统计系统用PFADD uv:2025-08-01 user_001记录每日访客PFCOUNT uv:2025-08-01出报表。换MySQL的方案需要一张天量的明细表换Redis Set方案内存会膨胀HyperLogLog是性价比最高的。4.3 Geo附近的人与门店Redis 3.2引入的Geo类型底层基于ZSet把经纬度编码成score。命令有GEOADD、GEOSEARCH、GEODIST。做“附近的门店”功能时把门店坐标GEOADD shop:location 116.40 39.90 store_001查询时GEOSEARCH shop:location FROMLONLAT 116.35 39.85 BYRADIUS 5 km ASC就能按距离从近到远返回门店列表。底层的geohash编码把二维坐标转成一维字符串相邻位置的前缀也相近所以能高效做范围检索。这个功能如果自己实现得引入一个空间索引库复杂度不低。Redis内置Geo以后小规模场景直接就能用。4.4 StreamRedis原生消息队列Stream是Redis 5.0引入的日志型消息结构解决了List做消息队列时“消息没有确认机制、无法多消费者组”的痛点。命令有XADD、XREAD、XGROUP CREATE、XREADGROUP、XACK。Stream和Pub/Sub最大的区别是Pub/Sub的消息是即发即焚消费者不在线消息直接没了Stream则把消息持久化在Redis里消费者可以按需读取读取后通过XACK确认处理成功。它天然支持消费者组一条消息可以被组内多个消费者分担处理也可以通过XREADGROUP GROUP指定消费。如果一个项目里不想引入Kafka/RabbitMQ业务量又不算大Stream完全可以充当一个可靠的消息队列。但要认识到它仍是单机Redis的能力做分布式的消息集群不是一个简单的话题。4.5 模块生态布隆过滤器等“外挂”Redis的模块机制让它能扩展更多数据结构最常用的就是RedisBloom提供的布隆过滤器。命令是BF.ADD、BF.EXISTS。布隆过滤器解决的问题是快速判断一个key“一定不存在”还是“可能存在”。它用多个哈希函数对元素映射到bit数组查询时只要有一个bit为0就说明肯定不存在全部为1只能说可能存在。用在缓存穿透场景下可以在请求Redis之前先查布隆过滤器拦截掉那些肯定不存在于数据库中的非法key。使用模块的方式是下载并加载loadmodule /path/to/redisbloom.so。Redis Stack版本则直接集成了BloomFilter、Search、JSON、TimeSeries等模块开发环境用起来非常方便。5. 数据不丢的三道防线过期删除、内存淘汰与持久化Redis的运维属性和工程属性都在这一章。不理解过期和淘汰机制内存被写爆了都不一定知道原因不理解持久化重启丢数据只会一脸懵。5.1 过期删除为什么内存还是居高不下EXPIRE key seconds设置过期时间TTL key查看剩余秒数。很多人以为设置了过期时间数据到点就会被立刻清掉但Redis默认采用惰性删除 定期删除的组合策略。惰性删除是当key被访问时发现已过期就直接删除并返回空定期删除是每隔一段时间抽样一部分带过期时间的key把到期了的删除。这样做是为了避免“每秒遍历所有key”带来的CPU开销但也导致一个现象过期的key不会立刻从内存消失内存占用在过期高峰后会滞后下降。理解这个机制后就能解释很多问题为什么设置了TTLused_memory还是只涨不跌为什么明明没多少有效数据内存却一直很高。应对办法是如果系统对内存回收有硬性要求可以考虑主动SCAN遍历并删除过期key或者直接调低淘汰策略的触发水位下面讲。5.2 内存淘汰写满之后会发生什么Redis配置里maxmemory限制最大可用内存maxmemory-policy决定内存写满后怎么办。默认策略是noeviction意思是不再接受写请求直接返回OOM错误。这在不允许误删数据的场景是对的但缓存场景根本没法用——缓存全堆满了写不进去等于服务雪崩。常用策略allkeys-lru从所有key中淘汰最久没被访问的key适合纯缓存场景。volatile-lru只从设置了过期时间的key里淘汰最久没被访问的适合“一部分数据要长期保留一部分允许淘汰”的混合场景。allkeys-lfu按访问频率淘汰比LRU更精准能防住“偶发热点刷掉老热点”的问题。volatile-ttl优先淘汰剩余过期时间最短的key。我自己的实践是缓存实例通常设maxmemory-policy allkeys-lfu因为缓存本来就是允许丢失的LFU比LRU更能准确反映真实热门程度。5.3 持久化RDB、AOF和混合模式怎么选RDB是周期性生成数据快照执行BGSAVE后由fork出的子进程把全量数据写入磁盘文件。优点是文件紧凑、恢复速度快缺点是快照之间丢数据。触发条件由save配置控制比如默认的save 900 1表示900秒内有1次写操作就保存一次。RDB在fork子进程时如果内存数据量非常大主进程创建子进程的一瞬间会有短暂的阻塞这是运维层需要关注的点。AOF是把每次写命令追加到日志文件重启时回放日志恢复数据。appendfsync有三个级别always每个命令都刷盘最安全但慢everysec每秒刷一次盘是性能和安全的平衡点no交给操作系统决定刷盘时机最快但丢数据可能性最大。AOF文件会无限增长所以需要BGREWRITEAOF重写压缩重写时会生成当前数据的最小命令集。混合持久化是Redis 4.0之后的方案aof-use-rdb-preamble yes开启后AOF重写产生的文件开头是RDB格式的全量快照后面追加增量命令。好处是恢复快、文件体积小、丢数据窗口小。也是我目前的默认选择。部署时的建议很简单要么不开架构允许要么开混合持久化加appendfsync everysec。既不要盲目把所有写都刷盘性能下降明显也不要完全不持久化数据丢失无兜底。6. 从踩坑到防坑BigKey、慢查询与三大缓存故障这一节是我最想写给初学者的。Redis学习到一定阶段命令和数据类型的知识都好掌握真正区分水平的是线上问题的排查和预防能力。6.1 BigKey和HotKey到底怎么搞BigKey指单个key对应的value过大比如一个String超过10KB或者一个Hash/List/ZSet里的元素超过几千个。危害有两个操作慢网络传输就需要大量时间单线程下会阻塞其他命令。内存不均Redis集群分片时按key分配某个大key会落到某个节点导致节点内存和CPU都成为瓶颈。发现BigKey最快的方式是用redis-cli --bigkeys它会用SCAN遍历并统计各类结构最大的key。更精确的方式是写脚本遍历key对String执行STRLEN对集合类型执行HLEN/LLEN/SCARD/ZCARD把超大key揪出来。处理思路也是三板斧拆把一个Hash大key按业务维度拆成多个小key压把大JSON用压缩算法或者按字段精简删删除大key时用UNLINK而不是DELUNLINK是异步释放内存不会阻塞主线程。HotKey则是指某个key被高频访问。比如一个热门活动的配置。单点到同一个实例后这台机器打满其他机器很闲。解决方式在应用层加一层本地缓存比如Caffeine兜住大部分热点请求或者把同样的数据复制成多份keyproduct:399散列成product:399:0到product:399:9把请求分散到不同分片。6.2 慢查询日志怎么配置和阅读Redis提供了一套慢查询日志机制CONFIG SET slowlog-log-slower-than 10000 CONFIG SET slowlog-max-len 128 SLOWLOG GET 10slowlog-log-slower-than单位是微秒10000就是10毫秒。执行时间超过10毫秒的命令会被记录。slowlog-max-len是保存条数。出现慢查询后SLOWLOG GET能看到是哪条命令、哪个客户端、什么时间执行的。实际线上Redis慢查询九成来自三类KEYS、SMEMBERS/HGETALL大集合全量读取、以及BigKey上的大量写操作。KEYS必须替换成SCANSMEMBERS改成分页取这些都是基本操作。6.3 缓存穿透、击穿、雪崩的成因与应对这三个词是Redis面试必问也是线上事故重灾区。我不念定义直接讲成因和方案。穿透是查一个必定不存在的key缓存没有数据库也没有每次请求都直达数据库相当于缓存被绕过。恶意攻击尤其喜欢用不存在的ID打穿缓存。解法有两个层次第一层用布隆过滤器在缓存之前拦住不存在的key第二层把“查不到”也缓存一份短时间数据比如SET empty:user:999 null EX 60避免持续打数据库。击穿是某个热点key恰好到点过期大量请求同时发现缓存为空全部回源数据库。必须靠并发控制比如热点key加一个互斥锁只有一个请求允许去数据库加载并回写缓存其他请求等待或者用旧值兜底。或者让热点数据“逻辑不过期”后台线程定期刷新缓存里只有极短的逻辑过期时间。雪崩是大量key同时过期或者Redis直接宕机。大量key同时过期的解法很简单过期时间加一个随机抖动。比如基础TTL是3600秒实际设置成3600 random(0, 600)把集中失效打散。Redis宕机这个层面的方案是主从加哨兵、Cluster集群和高可用架构这是运维层面的事但应用层也要做好降级和限流不然数据库会被瞬间打垮。7. 落到项目里缓存一致性、分布式锁与秒杀库存学Redis的最终目的是写进业务。我从自己做过的高并发项目里挑三个高频场景讲讲正确写法和容易翻车的地方。7.1 缓存与数据库的双写一致性最常见的缓存模式是Cache Aside读时先查缓存miss了读数据库再把数据写进缓存更新时先更新数据库再删除缓存。这里关键是为什么“删缓存”而不是“更新缓存”。更新缓存的问题是如果两个并发请求同时更新数据后写数据库的请求可能先写缓存或者先写缓存的请求被后写数据库的数据覆盖最终缓存里留下过期数据。删除缓存则不同下次读请求会拉取最新数据重建缓存即使并发也只会多一次数据库查询。但“先更新数据库再删缓存”也会有一个经典窗口线程A读缓存miss去数据库读旧值线程B更新数据库并删缓存线程A再把旧值写回缓存。解决思路之一是延迟双删更新数据库后删除缓存再等几百毫秒比如500ms删除一次。第二次删除的目的就是清掉那个被旧值写回的缓存。实际项目中还可以用消息队列异步删缓存或订阅MySQL binlog同步删除都能做到更严格的最终一致。7.2 分布式锁的正确姿势Redis分布式锁是用了最多次也最容易写错的。正确加锁方式一条命令SET lock:order uuid-123 NX PX 30000NX保证只有key不存在时才能设置成功PX设置过期时间防止持锁进程崩溃导致死锁value必须是唯一标识比如UUID用于释放时确认是自己持有的锁。释放锁必须用Lua脚本if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end用Lua的原因很简单GET判断和DEL必须原子执行。如果先GET再DEL中间可能被别人的锁覆盖。value里的UUID就是为了防止误删A的锁过期了B拿到了锁A执行DEL把B的锁删掉了。开源客户端Redisson把加锁、续期、释放都封装好了还带了“看门狗”机制默认每10秒自动续期到30秒避免业务没执行完锁就过期。自己写分布式锁要很谨慎能用成熟库就不要重复造轮子。7.3 秒杀库存Lua脚本保证原子扣减秒杀场景下的库存扣减要求并发环境下不能超卖。Redis单线程执行命令的特性让原子扣减变得很优雅。先把库存预热到RedisSET stock:1001 100扣减库存使用Lua脚本local stock tonumber(redis.call(get, KEYS[1])) if not stock then return -1 end if stock 0 then return 0 end redis.call(decrby, KEYS[1], 1) return 1因为Lua脚本在Redis中是原子执行的多个线程同时执行这个脚本时Redis会挨个执行不存在同时读到相同库存的情况。脚本返回1表示扣减成功返回0表示库存不足返回-1表示key不存在。我自己做秒杀时会把库存扣减和资格写入分开。扣减成功后把用户ID写入一个Set占位再发消息给下游做订单创建。整个过程在Redis层就完成了高并发控制数据库只接收最终已经扣减成功的订单请求压力小很多。8. 一条实用的Redis学习路径和工具清单最后分享一点学习路线层面的建议。Redis入门门槛低但深入需要花费的时间不少。如果你是从零开始我的建议顺序是这样。第一阶段先把基础命令过一遍彻底理解String、Hash、List、Set、ZSet的使用场景。不要死记命令每学一个类型就想一个业务问题能用它解决。我给自己的练习方式是拿朋友圈功能练手用户时间线用List用户资料用Hash点赞关系用Set热度排行用ZSet。第二阶段去研究底层实现。SDS为什么比C字符串安全ziplist和listpack有什么差别跳表是怎么做到O(logN)的字典的rehash过程是怎样的。这些知识短期看起来不影响写代码但排查性能和内存问题的时候非常有用。第三阶段理解持久化、过期、淘汰、主从复制、哨兵、集群。不需要亲手搭一个生产级集群但至少要在本地用docker compose把一主二从三哨兵跑起来看看主从切换时发生什么。第四阶段就是实战和故障演练。往Redis里灌数据人为制造BigKey观察慢查询设置极端小的maxmemory看淘汰策略表现敲DEBUG SEGFAULT模拟崩溃检查持久化恢复。工具方面官方RedisInsight是必装的图形客户端看key结构、时长曲线、慢查询都很直观。命令行工具iredis支持命令补全和语法高亮写脚本调试时比redis-cli好用。排查RDB文件可以用redis-rdb-tools。压测就老老实实用redis-benchmark它自带了一些常用场景的基准测试模板能看到机器上的真实吞吐。我自己的体会是Redis学习性价比很高它把非常多经过实践验证的系统设计思路浓缩在了一个简单的结构里。不要停留在“会用”多问几个“为什么”多模拟几次故障等你真正理解了它为什么快、为什么数据不会丢、为什么某些操作会阻塞线上遇到的绝大多数问题就都能自己推导出答案了。