恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

Redis从入门到实战:数据结构、分布式锁与高可用部署

  • 首页
  • 资讯中心
  • /
  • Redis从入门到实战:数据结构、分布式锁与高可用部署

相关资讯

NocoBase RunJS 深度解析:ctx.collection 数据表实例的元数据访问、主键操作与字段联动实践 2026/9/17 13:04:46
WinUI 代码库指针体系完全指南:从 ctl::ComPtr 到 TrackerPtr 的选型与实践 2026/9/17 13:04:46
Swift Package Manager 从入门到进阶:配置、构建与排错实战 2026/9/17 13:04:46

最新资讯

Security-101 课程精讲:以身份为边界,用 IAM 构建零信任架构
CMSIS-4:Cortex-M嵌入式开发的确定性软件契约
Java高校社团招新系统设计与实现:数据库、状态机与权限
radix-vue Separator 分割线组件完全指南:属性、无障碍与实战用法
数据中心机房建设指南:GB 50174、UPS容量与冷通道落地
聚合平台订单撮合系统:订单路由、分佣结算与合规监控

今日推荐

每日热评|13% 的 Agent 技能带严重漏洞,这个注册表想用“验证+签名”解决信任危机
即梦AI保姆级教程:从生图到数字人,一站式搞定AI视频创作
BERT+LLM混合架构:突破NER长尾实体抽取瓶颈的工程实践

本周热门

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验
Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化
Flutter应用改名全指南:从Android到iOS的配置与工具实践

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

Redis从入门到实战:数据结构、分布式锁与高可用部署

发布时间:2026/9/17 13:09:46
Redis从入门到实战:数据结构、分布式锁与高可用部署 要说这几年后端开发里最绕不开的技术组件Redis绝对排前三。不管你是写Java、Go还是Python面试要问缓存设计项目要撑高并发流量最后多半都会落到Redis头上。但说句实在话很多人对Redis的理解只是停留在“缓存数据库”这五个字真要动手去解决问题的时候总是差那么口气。这篇文章不打算从官网配置开始逐条罗列而是从一个实际干活的角度把Redis是什么、能干什么、怎么用好这几个事讲清楚。无论你是刚入行的新人还是已经被Redis坑过几次的老开发都应该能从里面找到点有用的东西。尤其是那些在热搜词里出现的场景比如redis数据类型、redis分布式锁、docker安装redis主从、redis哨兵模式、redis缓存治理之类的内容我都会结合真实项目经验展开聊。1. Redis到底是什么——先把它从“缓存”的刻板印象里解放出来1.1 一句话说清楚Redis的定位Redis的全称叫Remote Dictionary Server直译过来是“远程字典服务器”。这个名字其实已经把它最核心的定位说清楚了一个基于内存的、以键值对形式存储数据的服务。但“键值对存储”这个说法在今天看来已经远远不够了因为Redis支持的不仅仅是简单的String字符串还有Hash、List、Set、ZSet有序集合等等每一种数据结构都有自己的专属应用场景。官方的形容是“数据结构服务器”。这比“缓存数据库”要准确得多。你把它当缓存用它是一个高性能的缓存系统你把它当队列用它的List和Stream也能顶一阵子你把它当数据库用它能持久化到磁盘并在重启后恢复数据。所以不要把Redis想象成只能放临时数据的“内存仓库”它更像是一把多功能的瑞士军刀关键看你拿它来切什么。我在实际项目里见过不少刚接触Redis的同事第一反应都是“这不就是查一下再存一下的事吗”。其实这种看法低估了Redis的工程价值。一个真正用好的Redis能在架构里扮演缓存、消息中间件、分布式锁服务、排行榜引擎、计数统计中心等多个角色它的边界远比“缓存”这两个字要宽。1.2 为什么Redis能这么快很多人第一次接触Redis都会问为什么它这么快一个单线程的程序怎么就能扛住每秒几十万的读取量先说最核心的一点Redis的数据在内存里。内存本身的读写速度是纳秒级别的这跟磁盘那种动不动就要做随机IO的存储完全不同。缓存的意义就是把热点数据放到离CPU更近、访问更快的地方Redis正是干这件事的。其次Redis经典版本采用的是单线程事件循环模型。这里有个误区有人一听“单线程”就觉得这一定是性能瓶颈但实际上单线程在Redis的场景里有它独特的优势没有多线程之间的锁竞争没有线程上下文切换的开销也不需要考虑共享数据一致性的问题。加上Redis内部用IO多路复用技术处理网络连接一个线程就能同时管理成千上万个客户端连接把等待IO的空闲时间都利用起来了。说到底Redis的性能瓶颈几乎只可能出现在网络带宽或者内存大小上CPU通常不是你需要操心的问题。这也是它能做为“缓存层”站在数据库前面替数据库挡掉大量重复读请求的原因。我测过一台普通的4核8G云服务器单机Redis可以轻松扛住8万以上的QPS这个性能在大多数业务场景下完全够用了。1.3 Redis和Memcached到底差在哪聊Redis不对比一下Memcached似乎不太完整。尽管现在主流新项目基本都直接用Redis了但如果你去翻老项目的代码还是能看到Memcached的影子。两者最大的区别在于数据结构的丰富程度。Memcached基本只能存简单的String类型追加删除操作都很原始而Redis从诞生起就带着丰富的数据结构清单这让它能应对各种复杂业务逻辑而不只是“存一段文本”。其次是持久化能力Memcached挂了就是数据也没了重启之后只能冷启动重新缓存Redis则支持RDB快照和AOF日志两种持久化方式重启之后能把数据恢复回来。还有一个很重要的点高可用方案。Memcached在分布式场景下需要客户端自己做一致性哈希来分片维护成本不低。Redis则原生提供了主从复制、哨兵模式、Cluster集群模式这些机制能让Redis在节点故障时自动转移流量保证服务可用性。单凭这一点Redis在生产环境里的地位就没办法被Memcached替代。2. 数据结构是Redis的第一生产力2.1 String最基础但也最容易被低估String是Redis里最基础的数据结构存一个字符串、数字、JSON序列化后的对象都是用它。但很多人只把它当成一个简单的键值对在用却不知道String类型里藏着很多高效的原子操作。比如INCR、DECR、INCRBY这些命令能在内存里直接对数字做自增自减不需要先GET回来改完再SET整套操作是原子的天然线程安全。这个特性在做计数器场景时非常有用比如文章的浏览量、商品的库存扣减、用户积分增减都能直接用几条命令搞定连分布式锁都不需要加。另外String类型有个容易被忽略的用法SET key value EX seconds可以把设置值和过期时间放在一条命令里原子执行这在不希望因为两步操作之间出间隙导致问题的场景下特别有用。后面讲分布式锁还会提到它。我在项目里用String存过用户登录令牌、短信验证码、接口返回数据的临时副本、灰度开关配置基本覆盖了大多数业务需求。如果连String都还没用熟练不建议急着研究高级功能。2.2 HashJava开发者的对象存储利器Hash在Redis里是一个field-value对集合通俗点说就是一个“里层还有键值对”的结构非常适合存储一个对象的多个属性。举个最常见的例子用户信息。如果直接用String存你得把整个用户对象序列化成JSON要么整存整取要么拆成多个key分别存。用Hash就方便多了每个用户对应一个Redis key用户ID下面再挂用户名、头像、积分、等级这些filed。想更新某个字段时一条HSET命令就能完成不用把整个对象读出来再反序列化改写再存回去。这种结构的读取效率也很高HGETALL能一次拿到整个对象HGET只需取某一个字段。在缓存数据库表记录时我一般优先考虑Hash因为在字段多的场景下它的内存占用和维护成本都比多个String要划算。有一个实际经验可以分享用Hash缓存数据库行时可以在每个字段前面加上查询时需要单独使用的索引字段形成一个“字段级别的缓存单元”。这样部分更新时不会影响其他字段并发修改同一个对象的不同字段也不会互相覆盖。2.3 List消息列表和轻量队列的底子List是一个双向链表结构支持在头部和尾部进行push/pop操作。正因为这种特性它可以用两个命令的组合实现一个非常轻量的消息队列生产者用LPUSH往列表左侧写入消息消费者用BRPOP从右侧阻塞式读取。这里的B代表block就是说如果没有数据消费者会一直等着不会白白轮询浪费CPU。List的另一类典型场景是“最新消息列表”比如新闻资讯的最近动态、用户的操作日志每次有新增内容就往列表头部推一条再用LRANGE key 0 9取出前10条效率非常高。比起去数据库里查ORDER BY create_time DESC LIMIT 10这种方式的响应时间要低一个数量级。但也要说清楚边界List适合做轻量级队列业务量特别大、需要消息确认、需要延迟消息、需要消息回溯的场景还是老实交给专业的消息队列中间件比如RabbitMQ、Kafka去处理。拿Redis硬扛复杂队列场景迟早会被各种边界问题折磨。2.4 Set去重、交集与随机抽奖Set是一个无序的、元素不可重复的字符串集合它最大的价值是“天然去重”和“集合运算”。最常见的应用场景是标签系统。比如一个用户的兴趣标签可以存成一个Set一篇博客的所属分类标签也能是Set。用户之间共同关注了哪些账号直接SINTER一次就能算出交集不用写一层层循环去数据库里比对。要做“你可能认识的人”这种功能时这种集合运算能让代码简洁很多。Set还支持SPOP和SRANDMEMBER命令能随机返回集合中的元素。用这个特性就能轻松实现一个抽奖功能把所有参与用户ID加入一个Set然后用SPOP弹出一个用户作为中奖者弹出后TA就自动从集合中移除了天然保证一个人不会被重复抽中。我记得有个项目里做“好友共同关注提醒”原来用SQL查了两层才算出共同关注数接口耗时稳定在300毫秒左右。后来改成把关注关系同步到Redis Set里用SINTERCARD直接数交集数量耗时降到10毫秒以内。这个对比让团队里不少人都对Redis的数据结构有了新的认识。2.5 ZSet排行榜场景的终极答案ZSet又叫有序集合和Set一样不允许重复元素区别在于每个元素还关联了一个score分数。Redis按照score从小到大为集合中的元素排序这就让排行榜类需求变得非常简单。做“热榜”、销售排行、积分排行核心逻辑就一条命令ZADD key score member往集合里加元素并带上分数要查询前N名ZREVRANGE key 0 N-1 WITHSCORES倒序取出前N个元素和分数。更新分数时用ZINCRBY能在原分数基础上增加不用先查出来再写回去是原子的天然能处理并发加分的问题。ZSet还可以做延时队列。score存任务的执行时间戳定时任务每隔几秒用ZRANGEBYSCORE key -inf now取所有到期的任务取出来处理后删除。这个模式在实现订单超时关闭、定时提醒等场景时都很顺手比用轮询数据库要高效得多。实际项目中我做得最多的还是排行榜从一套通用的排行榜服务起步接入了社区积分排行、商城热销排行、视频热门排行多个业务底层都是ZSet。写一套代码所有排行榜类需求都能复用。2.6 容易被忽略的三种高级结构除了五大基础结构Redis还提供了几种针对性很强的数据类型平时讨论得不如String、Hash多但在特定场景下能解决的问题会让你眼前一亮。Bitmap位图本质上不是一个独立类型它是String类型的一种位运算视角但用SETBIT、GETBIT可以对一个字符串的每个二进制位进行操作。签到场景特别适合用Bitmap一年365天记住365天每天签到置为1统计时用BITCOUNT数一下有多少个1整年签到的存储空间只需要不到50个字节比存365个key要省无数倍。在线状态也可以用同样的思路来做用户量上亿时这种极致的内存节省显得很值钱。HyperLogLog是专门用于基数统计的结构。什么叫基数就是集合里不重复元素的个数。做UV统计时访问量再大每个用户ID只需要很少的内存就能完成去重统计标准误差在0.81%左右对于绝大多数数据分析场景这个误差完全在可接受范围内。当然如果业务要求精确去重就不适合用HyperLogLog了得回到Set或者引入其他方案。Geo是地理位置类型用GEOADD把经纬度存进去用GEOSEARCH能查出某个坐标附近的元素并按距离排序。“附近的人”“附近的店”这类功能用Geo做会非常简洁底层也是ZSet实现的所以能支持范围查询和排序。这些数据类型不是让你全部背下来而是要让自己的工具箱里有这些东西。等业务场景出现时适合用什么结构一目了然而不是什么都往String里塞。3. 生产环境里Redis最常见的几种玩法3.1 缓存加速用好缓存不是把数据塞进去就行Redis在项目里最核心的任务就是做缓存。但有太多项目“接入缓存”等于“把要读的数据全部塞进Redis”没有思考哪些数据该缓存、缓存多久、数据变了怎么更新。结果往往是缓存命中率很低缓存没起到挡流量的作用反而因为多了一层网络访问让接口变慢了。一个合格的缓存方案至少要回答这几个问题哪些数据适合缓存通常是读多写少、访问频繁、实时性要求不高的数据。缓存多久设置过期时间能避免数据永久占用内存但过期时间的设置需要一个权衡太短会频繁回源数据库太长会导致数据不能及时更新。数据更新时缓存怎么处理是主动删除缓存让下次读取时回填还是在数据库更新后同步更新缓存或者干脆删了让后面再建。最简单的做法是Cache Aside模式读的时候先查缓存缓存没有再去查数据库拿到结果后回填Redis并设置过期时间写的时候更新数据库后删除对应缓存。这个模式是很多团队的基础缓存策略它的好处是逻辑清晰不容易出现数据库和缓存长时间不一致的情况。但是这里也有个小坑删除缓存的时机要在数据库事务真正提交之后。如果先删缓存再更新数据库中间来一个读请求就很容易把旧数据回填进去新数据反而被“压住”了。我现在通常是数据库更新成功后直接把对应key删掉。如果担心删缓存失败造成脏数据可以考虑延时双删也就是删完之后下沉一个延迟任务再过几百毫秒删一次双保险。3.2 分布式锁看似简单实则坑多做微服务、多实例部署后本地锁synchronized就不够用了因为不同实例的JVM锁是互相不可见的。这时候需要用分布式锁来保证同一时刻只有一个实例能执行关键代码比如库存扣减、订单支付回写、定时任务抢单执行。用Redis做分布式锁是大家最熟悉的方式但里面藏着不少坑。很多年前大家习惯的做法是SETNX key value加锁然后EXPIRE key seconds单独设置过期时间。这两个操作合在一起不是原子的一旦在设置过期时间前程序挂了这个锁就永远不释放后面的请求全被堵死。现在的正确姿势是用一条SET key value NX EX seconds命令让加锁和设置过期时间在原子操作中完成。但设置过期时间本身又引入另一个问题如果一个线程加锁后业务执行时间超过了锁的过期时间锁被自动释放了另一个线程乘虚而入拿到锁这时前一个线程执行完后又去释放锁结果把别人的锁给释放了。这个问题的标准解法是给value设置一个唯一标识释放前先比较value是否是自己设置的那个比较和删除的过程需要用Lua脚本来保证原子性。后来有了Redisson这个客户端库它实现了“看门狗”机制加锁成功后后台会有一个定时任务不断给锁续期只要业务没执行完锁就不会被过期逻辑上规避了“业务时间超过锁过期时间”的困境。这也是我现在做分布式锁的默认选择除非是一些特别简单的场景不想引入额外依赖才会手写原生命令。另外要提醒一下分布式锁只能保证互斥不能保证业务一定能成功。拿到锁之后执行的操作本身还是要做幂等设计锁只是帮你挡住了并发真正的数据一致性还是得靠业务逻辑自己兜底。3.3 会话保持与登录态共享传统单机项目里用户登录状态通常存在服务器本地的Session里。做了负载均衡请求被分发到A机器时登录状态在A机器第二次请求被分发到B机器B机器上找不到Session用户就变成“未登录”了。解决这类问题有三种常见思路一是做“会话粘滞”让同一IP的请求都固定发给同一台机器但这在机器宕机时依然会出问题二是用Session集群同步但同步本身有性能损耗第三种就是把登录态挪到Redis里所有人共用同一个Session存储。Spring Session框架最擅长的就是这个事它能把原本存在Tomcat里的Session序列化到Redis对业务代码近乎透明。实现“强制下线”之类功能时只要从Redis里把对应用户的Session删掉就行非常方便。另外Token也是一样的思路把Token作为key登录用户信息、有效期作为value存在Redis里接口鉴权时只查Redis就能拿到完整用户上下文不用每次去数据库查用户表。这种设计既能支撑大规模并发访问又方便用户体系从单系统扩展到多应用间的SSO登录。3.4 排行榜与限流计数排行榜在2.5节已经详细讲过ZSet方案这里想补充说明的是Redis在高并发计数场景下的应用远不止排行榜一个。比如接口限流最简单的固定窗口限流可以用INCR配合过期时间来实现以当前分钟为key每次请求执行INCR第一次执行的时候顺手设置一下过期时间为60秒如果在同一个key上的计数超过阈值就拒绝请求。更平滑的滑动窗口限流可以结合ZSet每次请求把当前时间戳插入ZSet然后用ZREMRANGEBYSCORE清理旧数据ZCARD查看窗口内的请求量。不过如果服务规模比较大还是建议用专门的限流组件Redis适合做业务级的轻量限流不适合硬扛所有基础设施层的限流逻辑。还有一个运用极其广泛的场景是“点赞/收藏统计”。传统的做法是每次点赞都写数据库一旦出现热点内容数据库的压力会非常大。用Redis做前置计数层点赞数、收藏数、浏览数全部先在内存里自增后台定时把数值回写到数据库。这样前台用户看到的数字是实时的数据库也不至于被打穿。但这里要留意Redis里的计数如果丢了后台和前台会不一致所以回写频率要做合适的权衡同时即便Redis重启也应该能从数据库恢复出比较接近真实值的数。3.5 消息队列Redis能行但要认清边界上一节讲过基于List可以实现一个简单的消息队列。这里继续把这个话题展开因为实际项目中真的会遇到“不想为一个小功能专门引入Kafka”的纠结时刻。List做队列最大的优势就是简单生产端LPUSH消费端BRPOP不再需要额外部署任何中间件。对于并发量不高、消息总量不大、允许少量消息丢失的场景这个方案完全够用。我在一些内部系统里用它传过异步通知任务、数据导出任务跑了一年多也没有出过岔子。但Redis 5.0版本以后官方自己也觉得List做队列不够专业所以推出了Stream类型。Stream支持消费者组、消息确认、消息回溯等这些专业消息队列才有的特性某种程度上Redis已经具备了成为一个轻量消息队列管理系统的能力。如果你在选型时需要“Redis已有但不想引入新组件”这个理由Stream是个不错的折中方案。但我还是想泼一盆冷水消息队列最怕的不只是吞吐量更重要的是可靠性。Redis的关键数据毕竟常驻内存即便开启AOF持久化也可能存在刷盘延迟造成的少量消息丢失风险。一旦你的业务场景要求“每条消息都必须处理成功不能丢不能重复”就老老实实用Kafka、RabbitMQ这类具备完善消费确认机制和高可用设计的专业消息中间件Redis只适合处理“丢了也不会出大事”的消息。4. 部署与运维单机不是终点主从哨兵集群要拎清楚4.1 从单机到主从数据要有备份很多小项目把Redis部署在一台单机上用着也挺好。但单机部署有个致命问题这台机器挂了Redis里的缓存数据全部无法访问数据库直接被所有请求打穿更严重的是如果Redis里存了未持久化的重要数据数据直接就丢了。Redis支持主从复制Master-Slave从节点会不断从主节点拉取数据变更保持与主节点基本一致。这样即使主节点挂了可以把从节点提升为新的主节点服务不至于中断。同时从节点也可以分担一部分读流量让主节点专心写。搭建主从复制很简单在从节点的配置文件里加一行replicaof 主节点IP 端口即可。但生产环境里通常不手写配置而是用Docker或者编排工具管理。很多团队会选择用Docker的network把主从节点串起来。我提供一个最基本的docker-compose主从示例你可以在此基础上扩展version: 3 services: redis-master: image: redis:7.0 container_name: redis-master command: [redis-server, --appendonly, yes] ports: - 6379:6379 redis-replica: image: redis:7.0 container_name: redis-replica command: [redis-server, --slaveof, redis-master, 6379, --appendonly, yes] depends_on: - redis-master ports: - 6380:6379主从复制有一个要注意的地方全量复制阶段主节点会把整个数据集生成RDB快照发给从节点这个过程中主节点会产生一定的磁盘IO和网络压力。如果数据量很大建议低峰期搭建从节点并且考虑在互联网络质量好的环境内部署。4.2 哨兵模式让故障转移自动发生主从复制能解决数据备份和读扩展的问题但它不能自动做主节点切换。主节点挂了之后应用依然连接的是原来的主节点地址从节点虽然拥有全量数据却不会自动接管写入流量。这时候就需要哨兵Sentinel登场了。哨兵是Redis的高可用方案它的主要工作有监控主节点和从节点的在线状态当主节点宕机时自动从从节点中选举出新的主节点通知客户端新的主节点地址让应用可以重新连接哨兵本身通常也要部署成奇数个节点满足过半机制。在主从基础上配置哨兵模式后Redis的可用性会提升一个量级一两个节点宕机对业务无感服务不会中断。部署哨兵时有一个常见问题就是“启动后没生成known节点”。这通常是因为哨兵的配置文件里没有正确指定sentinel monitor的配置项或者网络端口没放通哨兵发现不了主节点的存在。排查时可以先手动跑redis-cli -p 26379 info sentinel看输出如果显示master0:namemymaster,statusodown说明哨兵认为主节点挂了要检查网络连接和配置文件里的地址是否正确。还有一个容易疏忽的点哨兵配置里的IP地址、端口必须能被其他哨兵节点和客户端真实访问到如果用Docker部署哨兵而映射端口不一致也会出现类似的问题。4.3 Cluster真正意义上的水平扩展当数据量或者读写流量大到单机无法承载时主从模式也没辙了这时要考虑Redis Cluster集群模式。Redis Cluster采用数据分片的思路把整个键空间分成16384个槽位slot每个节点负责其中一部分槽位。客户端通过CRC16(key) % 16384计算出某个key应该落在哪个槽位上再由槽位找到对应的节点。这样整个集群可以水平扩展数据量增长时往集群里加新节点把部分槽位迁移过去就行。集群模式下每个主节点还建议配一个从节点形成“主从分片”的结构。这样既解决了单机容量瓶颈又保证了高可用。有一点特别需要提醒使用Redis Cluster时客户端要使用支持集群模式的库。比如Java生态里的JedisCluster或者LettuceClusterConnection命令行则用redis-cli -c开启集群模式。如果普通客户端连上集群后执行跨节点的multi-key操作会得到CROSSSLOT Keys in request dont hash to the same slot的错误。要解决这个限制可以使用HashTag把需要一起操作的key放在同一个大括号里比如{user:123}:profile和{user:123}:posts会落在同一个槽位上就可以做原子操作了。对绝大多数中小团队来说我的建议是数据量没到单机瓶颈之前别急着上集群。一个4主4从的集群运维复杂度远高于单机加哨兵日常监控、数据备份、槽位迁移都要额外关注。过早引入集群架构反而可能让自己深陷运维泥潭。4.4 Docker部署Redis生产环境的注意点热词里出现“redis docker compose 生产环境部署”说明很多人都在用容器化方式管理Redis。Docker确实能极大简化部署流程但生产环境里用Docker跑Redis有几个坑得提前知道。数据卷必须挂载且建议使用Bind Mount而非Docker Volume。如果你不在启动参数里加-v挂载宿主机目录Redis的数据只存在容器内部容器一删数据全没了。正确的做法是挂载一个宿主机路径比如/data/redis:/data并且设置--appendonly yes这样AOF文件和RDB文件都会写到宿主机磁盘上。内存限制要设置。Redis主要吃内存如果容器内某个应用把数据塞爆了内存系统可能会触发OOM杀掉容器这会让你在排查问题时一头雾水。建议在容器层面设置mem_limit同时给Redis自身配置maxmemory再配合合理的过期策略和内存淘汰策略避免内存完全耗尽。还有网络模式的选择。默认的bridge网络在容器重启后IP可能变化如果客户端配置的是容器IP下次重启后可能就链接不上了。最好在docker-compose里使用固定服务名的网络。现在给出一个适合生产环境基础使用的docker-compose示例你可以按需要调整参数version: 3.8 services: redis: image: redis:7.0 container_name: redis-prod restart: always command: redis-server --appendonly yes --maxmemory 4gb --maxmemory-policy allkeys-lru --requirepass mypassword ports: - 6379:6379 volumes: - /data/redis/data:/data - /data/redis/conf/redis.conf:/usr/local/etc/redis/redis.conf environment: - TZAsia/Shanghai这里重点解释几个命令参数--appendonly yes开启AOF持久化--maxmemory 4gb限制Redis最大可用内存多余的key会根据后面的--maxmemory-policy allkeys-lru策略淘汰掉避免内存溢出--requirepass设置访问密码不要用默认空密码部署到公网否则分分钟被扫描攻击。5. 我把这些坑都踩了一遍现在告诉你5.1 缓存穿透、击穿、雪崩三种“缓存放倒”的姿势这三个词估计你在面试题里见过几百次了但实际项目里遇到时能不能快速判断并处理完全是另一回事。我用最直白的语言说说它们之间的区别。缓存穿透指的是请求查一个“根本不存在”的数据。比如用user:10001当key查用户但用户表里压根没有10001缓存里也不可能命中于是每次请求都打到数据库。如果有人恶意循环发起大量这种请求数据库压力会瞬间爆表。应对办法有两个一是把查不到的数据也缓存起来value设置为空字符串过期时间设置短一些比如30秒这样同一个key短时间内不会再次穿透到数据库二是用布隆过滤器把所有可能存在的数据key提前加到布隆过滤器里请求来了先判断key是否存在不存在直接返回连缓存都不用查。我更推荐两者结合布隆过滤器挡住大部分不存在的key空值缓存兜底。缓存击穿指的是一个热点key到了过期时间突然大批请求同时来查它缓存未命中所有请求都扎到数据库上数据库可能扛不住。最简单的缓和思路是“互斥锁”发现缓存没有数据时先去拿一个分布式锁只有拿到锁的线程才能去查数据库并重新填缓存其他线程等待一会儿重新查缓存。锁的粒度要控制好不同key用不同锁别一把锁全锁住。缓存雪崩的范围更大通常指大量key在同一时间段集体失效或者Redis本身崩了导致数据库瞬间涌入大量请求。应对办法有几个一是给缓存过期时间加一个随机值比如每个key的过期时间在基础值上再加0到300秒的随机数打散过期时间二是提前做好Redis的高可用哨兵、集群不让Redis单点挂掉三是做双级缓存Redis之外再加一层本地缓存Redis挂了本地缓存还能顶一阵子。5.2 大Key和热Key慢查询的头号元凶Redis是单线程执行的所以只要有某个命令执行时间过长整个实例都会被拖慢。两类坑是最常见的源头大Key和热Key。大Key是指那个key对应的value特别大比如一个Hash里有几百万个field一个List里有上千万条记录一个String在内存里占了几百兆。对这样的大Key执行HGETALL、LRANGE等操作时单次命令就要消耗大量内存和网络IO执行时间可能达到几秒期间Redis把所有其他操作都堵住。我在排查生产故障时最常见的场景就是某个接口突然变慢查慢日志发现一条HGETALL命令执行了2000多毫秒一查value里有上百万个filed。大Key的预防远远重要于治理。设计阶段就要避免单个key无限膨胀可以通过拆分key范围、把大的Hash拆成多个小Hash、大的List换成Stream等方式来规避。发现已经存在的大Key建议把数据迁移出去然后删除旧key。删除时不要直接DEL因为这会阻塞要用UNLINK命令让Redis在后台异步回收内存。热Key则是指某个key访问频率极高比如某个明星的粉丝数key在活动期间每秒被读几万次。虽然读取本身不慢但它会把Redis单实例的CPU打满影响全局。应对方案有给热key建立多个副本在key后面加多级不超过实例数的后缀把访问分散到多个key上或者把你的热点数据做本地缓存让应用进程内存扛掉第一层流量再去访问Redis。热key问题非常考验架构能力因为没有统一的解法得结合业务形态来做取舍。5.3 序列化问题存进去是String读出来是乱码这是一个新手经常踩的坑尤其在SpringBoot项目里用Redis时。默认的RedisTemplate使用JdkSerializationRedisSerializer存入Redis的值经过Java序列化之后变成一串\xAC\xED开头的编码肉眼根本看不懂。在另一个服务里如果使用不同的序列化器读取这个key就会得到乱码甚至直接反序列化报错。我的建议是一开始就规范化序列化方案。如果只存String类型直接使用StringRedisTemplate如果存对象在网上一般配置Jackson的GenericJackson2JsonRedisSerializer将对象序列化为JSON字符串。这样存进去的value长什么样能一眼看懂排查问题也会容易很多。还要注意一个点key也可以设置一个字符串前缀比如order:create:{id}这种带业务语义的命名规则方便在Redis Desktop Manager之类的可视化管理工具里按前缀搜索定位。这看起来是个小事但对排障效率的提升非常明显。热词里反复出现的“redis desktop manager”和“another redis desktop manager”都是这个用途可视化管理工具能让人直观地看到key的结构和数据形态。顺便说一句另一个Redis桌面客户端 [Another Redis Desktop Manager] 更推荐因为它开源免费界面和性能都不错。5.4 SpringBoot集成Redis的几个细节SpringBoot里集成Redis非常快引入spring-boot-starter-data-redis配置一下连接信息注入StringRedisTemplate就能用。但几个细节容易出错。连接池配置。默认情况下Lettuce连接池是禁用的意思是并发请求多的时候真的可能把Redis连接数打爆从而出现连接超时。需要显式在配置里声明连接池参数spring.redis.lettuce.pool.max-active20、spring.redis.lettuce.pool.max-idle10、spring.redis.lettuce.pool.min-idle5。这里max-active不是越大越好要结合业务并发量和Redis的连接能力来定一般20到50够用。还有一个是IPv6的坑。有些云服务器默认启用了IPv6而Spring Boot配置的Redis地址如果写成域名解析时会优先解析到IPv6地址但Redis没配置IPv6监听结果就是“Connection refused”。排查这个问题最快的方式是配置Redis地址时直接写IPv4或者在系统层面禁用不必要的IPv6解析。热词里有“springboot2.1 redis 连接ipv6地址”说明不少人被这个坑卡过。事务支持也要谨慎。Redis的事务和关系型数据库事务概念不完全一样它只是把一组命令打包起来顺序执行中间不会被其他客户端插入命令但不支持回滚。如果一条命令执行失败前序命令的结果仍然会被保留。所以在SpringBoot里用Transactional控制Redis操作时要有这个预期不要指望它会像MySQL事务那样回滚。6. 高频面试题汇总与学习建议6.1 面试官最爱问的那几个问题热词列表里“redis面试题”出现频率非常高说明很多人在准备面试时都比较关心这个话题。我以技术面试官的角度把最常考的问题整理一下并附上回答时应该突出的重点。第一个是“Redis为什么这么快”。面试官想知道你是否理解单线程、IO多路复用、纯内存操作这些核心点。答题时先说清楚内存再提单线程避免锁竞争最后补充IO多路复用能支撑高并发连接。第二个是“Redis持久化机制说一下RDB和AOF的区别”。能答出RDB是按时间点生成快照、恢复快但可能有数据丢失AOF是追加日志文件、数据更安全但体积大且恢复慢以及两者可以同时开启就差不多了。面试官如果追问一般会问“如果RDB和AOF都开启了以哪个为准”答案是AOF因为AOF的数据通常更新。第三个是“缓存穿透、击穿、雪崩的区别以及解决方案”。这题基本是必考把5.1节的内容讲清楚就够他点头了。第四个是“Redis的过期删除策略和内存淘汰策略”。过期删除有定期删除和惰性删除两种结合使用内存淘汰策略里问到maxmemory-policy的配置项时要能答出allkeys-lru、volatile-lru、allkeys-random、volatile-ttl等并说清楚各自适用场景。第五个是“怎么用Redis实现分布式锁”。要能答出SET key value NX EX seconds的原生做法、释放锁需要Lua脚本比较value、以及Redisson看门狗续期机制。如果面试官问到RedLock了解过即可能说出它实现高可用锁的思路但也要指出它有一定争议。最后一个是“你们项目里Redis是怎么用的”。这个问题看起来开放但其实是考察你是否真的干过活。建议按场景归类来答缓存了哪些数据、怎么保证一致性、排行榜怎么做、分布式锁怎么用、Redis宕机了会有什么后果怎么防止。能把这些讲清楚面试官基本不会觉得你是背题背出来的。6.2 新手学习Redis的路线与工具推荐Redis上手其实不难难的是深入和踩坑之后能总结出经验。我建议新手按这个路线走第一步先把官网的“Introduction to Redis”文档过一遍搞清楚基本概念和数据结构定义。第二步本地装一个Redis环境用命令直接操作每一种数据结构。不用背命令但至少要亲手敲一遍。这一步可以配合可视化管理工具观察数据形态把命令行和界面结合起来理解。推荐几个工具redis-cli官方自带的命令行客户端防火墙查问题必备。Redis Desktop Manager / Another Redis Desktop Manager可视化管理工具浏览key、查看value、执行命令都方便。redisinsightRedis官方出的GUI工具功能很全支持数据可视化分析适合做更深入的性能观测。第三步找一个具体业务场景做小项目。比如给自己的博客增加一个“今日热榜”功能或者写一个带用户登录态的模块把String、Hash、ZSet、分布式锁都用到。全流程做一遍比看一堆面试题记得牢。第四步深入读一下《Redis设计与实现》这类经典书籍把底层数据结构、持久化机制、事件驱动的实现原理补上。只要把这本书啃下来上边说的面试题绝大多数都能做到“知其所以然”。最后的几句大实话文章断断续续写了这么多其实Redis的生态远不止上面这些内容。你会发现真正把一个工具用好的关键不是背会了多少命令和面试题而是在动手过程中反复试错、总结出来的那份体感。我自己踩过最大的一个坑就是刚接触Redis时总觉得“它就是个缓存”于是项目里所有数据都往里塞、过期时间随便定、序列化不规划。等到线上出故障面对一堆看不懂的key和慢日志时才幡然醒悟越是简单的工具越需要提前设计。现在每接入一个新功能我都会先想清楚三个问题——这个数据适合用什么结构存、它的生命周期是多长、如果Redis挂了会有什么后果。这三个问题想清楚了Redis这块基本不会出大乱子。如果你正准备学Redis我给的建议只有一条先动手别先去背题。把一个简单的登录、排行榜、限流小功能从头到尾实现一遍比看十篇文章都管用。毕竟真正的理解都藏在踩过坑之后。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号