
要写Redis入门文章我其实犹豫了很久。不是因为它难而是Redis太“常见”了——常见到很多新手把它当成一个单纯的缓存往里set个key、get个value就算入门等真正碰到性能瓶颈、数据不一致、网络抖动那一堆破事才发现自己连Redis最基本的脾气都没摸透。所以这一篇我想从一个用过Redis多年、也被它坑过多次的人的角度带你重新走一遍基础中的基础。这是系列的第一篇我会把重点放在“理解Redis是什么、它能干什么、怎么把它用起来”这三个层面而不是上来就讲集群、讲哨兵、讲分布式锁那些进阶话题。适合刚接触Redis的开发者也适合用过一段时间但总感觉缺一块拼图的人。1. 先搞清楚Redis到底是个什么东西1.1 它不是数据库它是内存里的高速驿站我第一次接触Redis时犯了一个几乎所有新手都会犯的错误把它当成一个“另一种数据库”。表面上好像也没错因为Redis确实支持持久化数据可以存到磁盘上但它真正的舞台是内存。Redis的全称是Remote Dictionary Server翻译过来就是“远程字典服务”。这个词本身就透露了它的核心本质它就是一个非常大的、跑在内存里的键值字典。你可以把数据库想象成一个大仓库东西放进去能保存很久但是每次取件都要跑一趟路上还得过几道关卡慢。而Redis像是快递站旁边的一个临时货架顺手一拿就能用速度极快但货架容量受限于内存大小而且断电后东西有可能会丢。这个定位决定了Redis最擅长的事在数据量可控、且访问频率极高的场景下提供接近内存级别的读取速度。官方数据里Redis单实例QPS能到十万级别实际项目里受网络、序列化方式影响稍微打些折扣但依然远高于传统关系型数据库。1.2 为什么这么多团队都在用Redis我认为Redis能火这么多年光靠快是不够的。数据库快的方案不少但Redis有一个别人很难替代的组合优势。第一个优势是数据结构足够“讲武德”。Redis不只是能存字符串它提供了String、List、Hash、Set、Sorted Set这五种基本结构每一种都对应着实际开发中非常常见的数据模型。比如排行榜需要有序排列直接可以用Sorted Set共同好友这种集合运算Set天然就支持交集并集对象缓存用Hash存比存一个大JSON字符串更灵活。这种贴合的建模能力让开发者不需要在应用层做太多二次加工。第二个优势是操作粒度细、原子性强。Redis是单线程执行命令这意味着它处理的每个命令天然不会被打断。这个特性太有用了比如计数器累加在关系型数据库里你得考虑并发锁在Redis里直接一个INCR就搞定安全得很。这种“原子性红利”在后面的实战中会反复体现。第三个优势是生态成熟。Redis有丰富的数据淘汰策略、持久化方案、主从复制机制、甚至能在不重启的情况下进行各种运维操作。你永远不是第一个遇到问题的人官方文档和社区资料足够让你走得稳。对一个基础组件来说存活这么多年、被这么多公司使用本身就是一种信任背书。1.3 和MySQL、Memcached比边界在哪里很多入门文章会陷入一个比较死板的问题Redis和MySQL谁更好这其实不是一个二选一的问题他们的角色完全不同。MySQL这类关系型数据库核心价值是持久化存储、事务一致性、复杂查询。你不可能把几亿行的订单数据全塞进Redis代价太高也根本没必要。Redis的核心价值是高性能访问和灵活的数据结构操作。我见过不少项目规划阶段就规定“MySQL存事实Redis存热数据”这个思路基本是对的。至于Memcached它和Redis在“缓存”这个领域确实有直接竞争。Memcached更纯粹性能很高但它只支持简单的String类型没有持久化也没有Lua脚本之类的扩展能力。用了一段时间Redis之后我个人的感觉是除非项目里已经深度依赖Memcached的历史结构否则新项目直接用Redis会更省心一个组件能覆盖缓存、队列、计数等多种需求不用再引入额外服务。2. 环境准备先让Redis跑在你的机器上2.1 三种主流安装方式新手建议这样做很多入门教程第一步就让去源码编译安装我不太推荐新手直接那么做除非你是在学习Linux编译流程。绝大多数情况下用系统包管理器安装就够了快速且稳定。在Ubuntu/Debian上sudo apt update sudo apt install redis-server在CentOS/RHEL上sudo yum install redis在macOS上如果你装了Homebrewbrew install redis至于WindowsRedis官方并不支持Windows版本但社区有移植版而且微软的WSLWindows Subsystem for Linux也可以跑Linux版Redis。我的建议是如果你是正经学习和开发优先搞一个Linux环境或者用Docker跑一个Redis容器这比在Windows原生环境里折腾适配问题省心得多。Docker方式也很简单docker run -d --name my-redis -p 6379:6379 redis:7.2注意生产环境不要再用docker run不加密码裸跑了先把服务跑起来只是为了让你能练习命令。2.2 配置文件里几个直接影响命脉的参数Redis装好后默认配置其实能直接用但如果你完全不了解里面几个关键参数后面会遇到莫名其妙的坑。我挑几个聊一下。首先是daemonize默认通常为no意思是Redis以前台方式运行一旦关掉终端Redis就停。有些安装包默认改为yes也就是后台守护进程方式。初学者我建议先保持前台运行能看到日志输出对理解Redis启动过程很有帮助。然后是bind和protected-mode这俩是安全相关的重头戏。默认情况下Redis只监听本机回环地址127.0.0.1也就是说只有你自己机器能访问这其实是一个很安全的默认值。如果你改成了0.0.0.0并且开启了远程访问同时没设置密码那就等于把数据裸奔在公网里。前几年无数Redis被入侵挖矿基本都是这个原因。再来就是requirepass设置客户端连接需要密码的字段。生产环境务必设置。最后是dir和持久化文件的路径比如dump.rdb会写到哪个目录。这个看似无所谓但如果你从不同目录启动Redis可能发现“数据怎么不见了”其实只是持久化文件路径变了对不上。2.3 判断Redis是不是真的在工作的几个命令安装好服务并启动后别急着开始写代码先用redis-cli做几个体检。连接自检redis-cli ping如果返回PONG那说明服务和客户端都正常。查看服务信息redis-cli info stats这个命令会列出连接数、命令执行次数等信息能直观感受到Redis的运行状态。快速写入读取验证redis-cli set hello world redis-cli get hello能看到world就说明你的Redis环境已经完全可用可以开始折腾数据结构了。3. 基本功五种核心数据类型与常用命令3.1 String最简单的一层也是最容易忽视的一层String是Redis最基础的数据类型所有key对应的值最终在内部都会有一种String的表示形式。常用的命令就有SET、GET、MSET、MGET、INCR、DECR、EXPIRE等。set user:10001 zhangsan get user:10001 mset product:1 apple product:2 banana mget product:1 product:2String最常见的场景大家都能猜到缓存。但是有几个容易被忽视的点我提一下。第一单个String值的体积不宜过大网上有说法建议单值不要超过几十KB或者1MB。原因很简单Redis是单线程服务处理一个超大字符串时网络传输、内存分配、序列化这些操作都会阻塞后续命令一次get一个大对象可能让整个Redis卡顿几十毫秒。第二INCR命令非常实用可以当作计数器用。set login:count 0 incr login:count incr login:count get login:count这段命令执行完后login:count就变成2了而且在整个过程中不会出现并发覆盖问题。后面我会专门说计数器场景。3.2 List既能当队列也能当时间线List是一个双向链表支持从两端推入和弹出元素。常用命令是LPUSH、RPUSH、LPOP、RPOP、LRANGE。rpush notification:1 message-1 rpush notification:1 message-2 lrange notification:1 0 -1 lpop notification:1第二行执行完列表里是message-1、message-2。LPOP后拿到的第一个元素是message-1它就类似于一个先进先出的队列。很多人在入门时会听说“Redis List能做消息队列”这个说法方向是对的但理解不能太过。Redis List可以模拟队列的入队出队行为适合做简单的异步任务分发比如发送邮件通知这类延迟不敏感、偶尔丢一次也能接受的场景。它最大的局限是没有消费者确认机制如果消费者把任务LPOP出来以后处理过程中崩溃了那这个任务就永久丢失了。所以生产级的可靠消息队列建议还是用专门的消息中间件。3.3 Set与Sorted Set天生为集合运算和排序而生Set是无序集合元素唯一。常用命令包括SADD、SREM、SMEMBERS、SISMEMBER、SINTER、SUNION。sadd wechat:friends:1 user:2 sadd wechat:friends:1 user:3 sadd wechat:friends:2 user:3 sinter wechat:friends:1 wechat:friends:2这个SINTER返回两个集合的交集也就是用户1和用户2共同好友是谁。如果这个逻辑放MySQL里可能需要写join还容易在数据量大时慢查询在Redis里一个命令就搞定方向不同效率完全不同。Sorted Set比Set多了一个分数维度每个元素都关联一个double类型的分数Redis会按分数从小到大排序。常用命令是ZADD、ZRANGE、ZREVRANGE、ZRANGEBYSCORE、ZINCRBY。zadd hotsearch:2025 100 redis入门 zadd hotsearch:2025 80 缓存穿透 zincrby hotsearch:2025 20 缓存穿透 zrevrange hotsearch:2025 0 1这个场景就是热搜榜、排行榜的经典实现。每次搜索就ZINCRBY给关键词加一次热度要拿榜单就ZREVRANGE取前几名全程不需要额外排序逻辑。3.4 Hash像操作对象一样操作数据Hash是一个string类型的field和value的映射表非常适合存储对象。比如一个用户信息对象hset user:10001 name zhangsan age 18 city beijing hget user:10001 name hgetall user:10001和直接塞一个JSON字符串相比Hash的好处是你可以单独读写某个字段不用为了改一个年龄把整个对象取出来再序列化回写。这在缓存用户信息、商品详情这类场景里非常香。坏处是如果你想缓存整个对象并且大多数时候都是整体读取Hash的field管理反而多了一层复杂性这时候一个序列化后的String可能更简单。选择哪种取决于业务访问模式。3.5 那些让你恍然大悟的通用命令别以为每个类型记住几个操作就完事了有几个通用命令是贯穿所有数据类型的比如过期时间。set verify:token abc123 ex 300 expire hotsearch:2025 3600 ttl hotsearch:2025SET的时候直接带EX 300意味着300秒后这个key自动销毁EXPIRE是给已有key设置过期时间TTL能查看还有多久过期。这个机制是Redis作为缓存组件最重要的一环。没有过期机制的话你的Redis迟早会被一堆永远用不到的key撑爆内存。到时候你就不得不面对另一个问题——内存淘汰策略怎么在key达到maxmemory之后决定踢掉哪些旧key。4. 把需求落地三个最常见的入门实战4.1 给数据库加一层缓存读写流程设计入门阶段最典型的需求就是给MySQL加个Redis缓存。这个流程听上去简单但设计不当会出各种问题。最基本的流程是读请求先查Redis命中就直接返回没命中就去查MySQL查到数据之后回写Redis并设置过期时间。写请求有两种常见方式先更新数据库再更新Redis或删除Redis里的旧缓存。我个人的习惯是更新数据库后优先删除缓存而不是直接更新缓存。原因是直接更新缓存容易引入并发问题两个线程同时写缓存最后写的结果可能不是最新的那个。删除缓存则是“懒加载”思路下次读请求自然会去数据库取最新值再回填看起来多个一次miss但一致性风险小很多。这也就是很多人说的Cache Aside模式。这个流程虽然基础但必须防范三个问题缓存穿透查询一个不存在的key每次都打到数据库、缓存击穿某一个热点key失效瞬间大量请求同时打到数据库、缓存雪崩大量key同时失效。入门阶段你不一定要立刻解决它们但至少要能说出这三个词代表什么问题。4.2 用Redis实现一个排行榜和计数器排行榜是Sorted Set最经典的应用。假如我们在做一个数据公开平台给每篇文章维护一个阅读量排行。每次有人查看文章时zincrby article:rank 1 article:1001 zincrby article:rank 1 article:1002取排行前100zrevrange article:rank 0 99 withscores一个排行榜就完成了。这里面的WITHSCORES参数会把每篇文章对应的分数一起返回方便展示阅读量。计数器就更简单了。比如统计每日活跃用户数可以用Set的SADD去重统计某个接口调用次数直接用INCR统计实时在线人数可以用Hash记录心跳时间。它们的共同点都是Redis的原子操作让并发正确性白送给你了。4.3 会话管理和“半入门”的分布式锁会话管理是Redis最早期的应用场景之一。用户登录成功后生成一个唯一的sessionId然后以sessionId作为key、用户信息作为value写入Redis设置过期时间比如30分钟。每次请求带过来sessionId服务端查一下Redis就能确认用户身份。相比传统Tomcat Session这种方案的优势是无状态、服务可以随便横向扩展。再来聊分布式锁。最常见的入门写法是使用SET命令的扩展参数set lock:order:10001 token-unique nx ex 30这个命令的意思是只有这个key不存在的时候才能设置成功并且30秒后自动释放。如果返回OK说明当前线程获取到了锁处理完业务后要删除这个key释放锁。为什么要用唯一token因为防止误删别人持有的锁。你在排查中会发现问题线程A的锁因为执行时间太长锁自动过期了线程B又拿到了锁此时线程A执行完后直接DEL key就把B的锁删了。加上唯一token后删除前先比对值是不是自己写的就能避免这种情况。但说句实在话生产级分布式锁还要考虑锁续期、重入、red lock算法争议等一堆问题。入门阶段先用这个“半入门”版本理解思想别急着在生产核心链路里上。5. 入门阶段最容易踩的那些坑5.1 新手问题速查表我挑几个入门时高频出现的问题整理成一张表。现象大概率原因排查与解决方式redis-cli 连接不上Redis没有启动或网络不通systemctl status redis-server或直接 ps -ef外部程序连接总是超时bind配置局限在127.0.0.1检查配置文件的bind、protected-mode和防火墙AUTH报错设置了requirepass但客户端没带密码redis-cli -a 你的密码或者在程序配置里加密码读取中文乱码客户端展示编码问题redis-cli 加--raw参数程序侧注意UTF-8用keys * 查一个key服务卡顿keys命令会阻塞Redis主线程生产环境用scan代替keys开发环境随意数据重启后丢了持久化配置没做好或没用AOF/RDB学习RDB和AOF机制入门至少明白触发时机内存涨得停不下来很多key没有设过期时间给缓存key加上EXPIRE并规划maxmemory策略某个key特别大其他命令跟着变慢大key导致单线程阻塞避免存超大对象必要时拆分或压缩5.2 新手必学的三个学习习惯第一多敲命令少看视频。Redis入门内容网上多得很但看到和做到是两码事。redis-cli本身就是最好的练习场你只需要打开终端把这篇里的命令逐一敲一遍再自己变形出几个新场景理解速度会比自己看十篇笔记都快。第二学会读官方文档。Redis官方的command文档已经写得非常清晰每个命令的语法、复杂度、返回值都有。遇到不确定的命令复杂度比如为什么不能乱用KEYS去官方文档查一下复杂度标记能避免不少误用。第三不要一上来就研究集群。有些人入门刚开始就问“主从复制怎么做、哨兵怎么部署、集群怎么搭建”我理解这种焦虑但基础的数据类型、过期策略、持久化机制都没吃透的话直接上集群只会让你在故障定位时更加被动。先把单机版玩明白集群只是往下走的自然延伸。5.3 我之前使用Redis的一些感受说实话Redis是一个“越用越会觉得它设计聪明”的组件。如果你只是 set 和 get它就像一个快一点的内存数据库感受不到太多惊艳但当你开始用 Sorted Set 做排行榜用 List 做任务队列用 Lua 脚本保证多条命令原子执行时你会发现自己设计应用的方式都跟着变了。有一个很直观的变化是以前很多需要数据库语句和程序逻辑配合的活儿现在一个Redis命令加上一次内存读取就能完成系统的响应时间就降下来了。还有一个经验是对任何组件保持敬畏。Redis看起来很轻量但轻量不等于简单。我曾经在一个项目里因为没想清楚缓存key前缀的规范导致线上出现大量互相覆盖的数据也见过团队因为查询用了SMEMBERS处理超大集合Redis CPU飙升到极限。所以入门阶段养成好习惯——命名规范、设置过期时间、理解命令的执行复杂度、警惕大key——比写多少业务代码都重要。写到这里Redis入门的第一篇也差不多该收了。下一篇我会接着讲持久化机制RDB与AOF的取舍和主从复制的工作原理但在那之前希望你把今天这篇里的命令都亲手试一遍让数据在自己的Redis里流动起来。毕竟所有深入的理解都建立在一个能跑的实例之上。