当前位置:首页 > 问答 > 正文

Redis那些快速缓存指令,教你怎么用才更溜点儿

基础中的战斗机:SET 和 GET,但你真的会用吗?

这俩命令是人都会用,SET key value 存,GET key 取,但“溜”的关键在于玩转它的选项。

  • 自动过期(EX/PX): 这是缓存最核心的功能,你肯定不想手动去删除过期数据,下次设置缓存时,别光秃秃地SET了,带上过期时间。

    • SET user:1001 "{"name": "张三"}" EX 3600 // EX后面跟的是秒数,这里表示3600秒(1小时)后自动消失。
    • SET user:1001 "..." PX 300000 // PX后面跟的是毫秒数,这里表示30万毫秒(5分钟)。
    • 怎么溜? 根据业务场景设置合理的过期时间,比如验证码用 EX 300(5分钟),热点新闻数据用 EX 3600(1小时),用户会话Token可以用 EX 86400(一天)。
  • 不存在才设置(NX): 这玩意用于实现简单的或者防止重复写入,只有当这个key不存在时,SET操作才会成功。

    • SET lock:order123 "1" EX 10 NX // 尝试获取一个名为"lock:order123"的锁,有效期10秒,如果返回OK,说明你拿到锁了;如果返回nil,说明锁被别人占着,你得等会儿再试。
    • 怎么溜? 抢购商品、防止重复提交等并发场景下,用NX做个简单的互斥锁,虽然简单但很有效。
  • 存在才设置(XX): 与NX相反,只有key已经存在时,才会更新它的值,这个场景相对少一点,但当你需要确保只更新已有数据时就用得上。

    Redis那些快速缓存指令,教你怎么用才更溜点儿

威力强大的批量操作:MSET 和 MGET

如果你要一次性存取多个key,别用循环一个个地GET/SET,那会产生多次网络开销,慢死了,直接用批量命令。

  • MSET user:1001:name "张三" user:1001:age 30 user:1001:city "北京" // 一次性设置多个key-value。
  • MGET user:1001:name user:1001:age user:1001:city // 一次性获取多个key的值,返回一个列表。
  • 怎么溜? 在项目启动时预热缓存,或者从数据库里查询出一批数据后,用MSET批量塞进Redis,同样,渲染一个页面需要多个独立的数据时,用MGET一次拿齐,效率极高。

计数神器:INCR 和 INCRBY

Redis能保证原子性地对数字进行增加操作,这在多线程、多进程环境下非常关键。

Redis那些快速缓存指令,教你怎么用才更溜点儿

  • INCR article:10086:view_count // 给文章10086的阅读数加1,即使一万人同时点,这个数字也会准确增加一万,不会错乱。
  • INCRBY user:1001:points 10 // 给用户1001的积分增加10点。
  • 怎么溜? 所有需要计数的场景都用它:网站点击量、点赞数、分享数、库存扣减(注意,这里只是计数,实际业务逻辑要更复杂),这比从数据库读出来、在程序里加一、再写回去的方式快得多也安全得多。

处理复杂数据的利器:Hash(哈希)

很多时候,我们要缓存的是一个对象(比如用户信息),而不是一个简单的字符串,用多个key存(如user:1001:name, user:1001:age)很麻烦,这时就用Hash。

  • HSET user:1001 name "李四" age 28 email "lisi@example.com" // 一次性设置一个用户对象的多个字段。
  • HGET user:1001 name // 只获取用户的姓名。
  • HGETALL user:1001 // 获取这个用户的所有字段和值。
  • HINCRBY user:1001 age 1 // 专门对Hash里的数字字段进行增加操作,比如给用户年龄加1(开个玩笑,别真这么用)。
  • 怎么溜?
    • 部分更新: 用户只修改了昵称,你用 HSET user:1001 name "新昵称" 即可,不用动其他字段,也比把整个对象序列化成JSON再SET回去要高效。
    • 避免数据膨胀: 相比将整个大JSON字符串存入String类型,Hash结构在存储上可能更节省空间(取决于具体数据)。
    • 注意权衡: 如果字段非常多,且你总是要获取所有字段,HGETALL可能会慢一点,这时候可能还不如直接用String存JSON,根据实际情况选择。

管理key的必备技能

  • EXPIRE key seconds:给一个已有的key设置过期时间,比如用户退出登录,你可以手动让他Token对应的key过期 EXPIRE token:abc123 0
  • DEL key [key ...]:删除一个或多个key。
  • KEYS pattern:按模式查找key,KEYS user:* 找出所有以user:开头的key。但要小心! 这个命令在生产环境慎用,如果Redis里key很多,这个操作会阻塞其他请求,可以用 SCAN 命令来代替,它是一个渐进式的遍历,不会阻塞。

保证性能的秘诀:管道(Pipeline)

Redis那些快速缓存指令,教你怎么用才更溜点儿

这不算一个具体指令,而是一种技术,参考了很多性能优化的文章,这是提升吞吐量的大杀器。

即使你用了MSET/MGET,如果你的程序需要连续执行多个不相关的Redis命令,比如先GET A,然后根据结果INCR B,再SET C,这依然是3次网络来回,管道可以将这些命令打包,一次性发送给Redis服务器,服务器再一次性把所有结果返回给你。

怎么溜? 几乎所有支持Redis的客户端库都提供了管道支持,你只需要在代码中开启一个管道,把要执行的命令“装”进去,最后统一提交,这能极大减少网络延迟带来的影响,特别是在需要连续执行多个命令的场景下,性能提升非常明显。

一个实战小例子:缓存文章详情页

假设有个文章详情页,需要显示标题、内容、作者、阅读数。

  1. 设计Key: 用Hash类型,article:文章ID
  2. 缓存数据:
    • HSET article:123 title "Redis教程" content "..." author "老王" view_count 0
    • EXPIRE article:123 7200 // 设置2小时过期
  3. 读取数据:
    • 先用 EXISTS article:123 判断缓存是否存在。
    • 如果存在,直接用 HGETALL article:123 拿到所有数据展示,可以用管道发送一个 HINCRBY article:123 view_count 1 命令来增加阅读数。
  4. 更新数据: 如果管理员修改了文章标题,只需 HSET article:123 title "新标题",缓存的其他内容不受影响,并自动延期2小时(取决于你的过期策略)。

用“溜”Redis的核心思想就是:善用数据结构和命令选项、多用批量操作减少网络开销、理解原子操作应对并发、管道技术提升整体吞吐量。 别把它当成一个简单的键值存储,而是把它当作一个在内存中的多功能数据结构服务器,这样你的水平就真的“溜”起来了。