资讯动态

Redis常用命令实战:从基础操作到线上排查避坑

发布时间:2026/10/19 2:41:52 来源:尧图企业网站定制
Redis装完redis-cli一敲能ping通然后呢说句实话很多人对redis基础常用命令的了解就停在SET一个值、GET一个值。真实业务里一踩坑连查一个key还剩多久过期都要翻半天文档。这篇文章就想把这层地基夯实。按理说这是最简单的内容可越简单的东西越容易用糙。我会按实际业务里用到它们的频次来讲把每个命令为什么这么设计、在什么场景下选它、有哪些坑我踩过或带新人时见过一起摊开说。不管你是刚上手还是用了一阵子但没系统整理过命令都值得花三四十分钟过一遍。1. 先把Redis命令的共同套路摸清后面全是顺水推舟如果你把Redis所有命令摊开看会发现它们长得特别像一个动词后面跟着key再跟若干参数。这其实是刻意的设计Redis把命令当成了一个动作 操作对象来设计所以记忆成本很低。下面把几个通用的底层规律先讲透后面敲每类命令时你就能举一反三。1.1 命令格式一个动作、一把钥匙、若干参数绝大多数Redis命令长这样命令动词 key 可选参数/值。所谓动词比如字符串的SET、GET哈希的HSET、HGET列表的LPUSH、RPUSH集合的SADD有序集合的ZADD。命令名本身就是动作LPUSH就是List PushZADD就是Sorted Set Add看着英文字面就能猜个大概。真遇到没见过的命令先猜再查文档十有八九能猜中这种设计对记忆特别友好。有两个细节容易被忽略但它们影响所有命令。第一命令关键字不区分大小写SET和set都行但key区分大小写Name和name是两个完全不同的key。我写脚本时吃过亏同一个业务里有人拼key用userId有人拼成userID结果缓存命中率肉眼可见地掉了一大截。第二Redis把key当二进制字节流处理你塞空格、换行甚至中文进去都不会报错但排查问题时极其痛苦。所以从一开始就要把key命名规范定下来别等到线上几百万key才后悔。1.2 返回值类型决定业务代码怎么写Redis命令的返回值可以分成几类状态回复、整数回复、批量字符串、多行字符串、nil以及错误。SET成功返回OKINCR返回自增后的整数值GET返回对应的字符串值MGET返回一组值key不存在时GET返回nil类型不匹配时返回类似WRONGTYPE的错误。最容易被忽略的是nil和空对象的区别。GET一个不存在的key返回nil但某个key存在而value是空字符串时返回的是空字符串不是nil。哈希的HGET也是字段不存在和整个key不存在都可能返回nil但这两种场景的业务语义完全不同——前者是对象在但属性没设后者是对象压根不存在。写代码判断要不要回源数据库时最好先用EXISTS或TYPE确认一下别把两种情况都当成直接查数据库。1.3 key命名规范冒号分层一眼看懂Redis本身不强制key长什么样但实际项目中我强烈推荐业务:实体:ID:属性这种冒号分层风格。比如order:123:status、user:10086:profile。好处有三个可读性好出问题一眼看出归属不同业务之间天然隔离不容易冲突方便后续用SCAN按前缀做批量操作。没有了规范时间一长线上全是没人认识的key想清理都无从下手。另外key长度也要控制。极端情况下一个key是一大串无意义的哈希值value才几十字节内存大头全浪费在key上。我以前帮项目清理过历史冗余光key本身的无谓占用就占了内存的两三成。短一点、有语义一点准没错。2. 字符串类型缓存与计数场景的顶梁柱字符串是Redis里最基础的结构也是业务中使用频率最高的类型。它既简单又有一些容易被忽视的参数和场景我先从最常用的命令说起再讲那些知道的人不多但特别好用的细节。2.1 SET/GET/MSET/MGET最基础但参数经常被忽略最基本的SET key value和GET key不用多说但很多人不知道的是SET后面其实可以跟一堆参数来扩展行为。比如EX seconds表示多少秒后过期、PX milliseconds表示多少毫秒后过期、NX表示只有key不存在时才写入、XX表示只有key已存在时才写入。一个SET能省掉后续好几条命令。我日常最喜欢用的是SET EX NX的组合。举个例子登录token缓存可以直接写成SET login:token:abc123 user_10001 EX 7200一条命令就完成了写入 设置过期时间。再比如最简单的分布式锁原型SET lock:order:123 1 NX EX 30只有key不存在时才能写入成功配合过期时间防止持锁进程崩溃后锁永远不释放。这条命令不复杂但它就是很多分布式锁方案的地基。MSET和MGET是批量版本的SET和GET。一次MGET几十个key比循环GET几十次快非常多省的是网络往返时间。要注意MGET返回的数组顺序和传入key的顺序对应某个key不存在就返回nil不会报错。批量虽好也别一次传几千个key响应包太大会让网络和内存都很难受。2.2 INCR/DECR/INCRBY计数器为什么非它不可Redis的INCR是对key的值做原子自增这个特性在并发场景下非常关键。假如你用GET - 加1 - SET三步去更新计数并发一高两个请求同时读到同一个旧值都会写回同一个新值计数必然丢。而INCR把读、加、写在服务端一步完成天然没有这种竞态问题。常见用法包括INCR counter:visit:20240101 INCR post:1001:like INCRBY cart:1001:version 5第一个统计某天的访问量第二个做点赞计数第三个给某个对象的版本号叠加步长。配套的DECR和DECRBY用于减少INCRBYFLOAT用于浮点数自增。它们都遵守相同的原子语义。但这里有一个边界要讲清楚INCR只保证单条命令内部的原子性。如果你要表达的是先看当前值是否小于100小于才自增这个逻辑靠三条命令拼不起来并发下会有人超限。要么用Lua脚本把判断和自增写在一个脚本里要么用Redis的事务WATCH/MULTI不能指望分段执行还顺便原子。2.3 字符串里到底该放什么JSON还是拆字段字符串是最通用的缓存容器新手第一反应就是把对象序列化成JSON丢进去比如SET user:1 {name:xiao,age:18}。对于字段少、总是整体读写的对象这是最省事的方案我推荐这么做。但如果对象字段多、业务频繁只改其中一个字段整体序列化就有问题改一个字段也得整个覆盖并发修改同一个对象容易后写覆盖前写网络传输还带着一堆冗余字段。这个时候应该考虑哈希结构也就是把对象拆成一个个字段单独存。字符串本身还有APPEND、SETRANGE、STRLEN等命令但实用频率不高知道有这些命令即可。我更想提醒的是别让单个value太大。一个5MB的字符串GET一次就可能阻塞几十毫秒如果被高频访问整个Redis实例都会跟着抖动。超过几百KB的内容先想清楚是不是该拆开、压缩或者干脆换一种结构。3. 哈希、列表、集合、有序集合先把结构选对再聊命令这是整篇内容里最值得花时间的一章。很多人把Redis当一个大号Map来用只会在字符串上打转结果业务复杂了以后只能硬撑等改结构时成本巨大。实际上哈希、列表、集合、有序集合这四种结构几乎覆盖了常见业务的所有数据组织方式而且每种结构都有自己的为什么。3.1 哈希HSET/HGET/HGETALL/HMGET存对象比JSON更精细哈希在Redis里是field-value映射最典型的场景就是存对象属性。比如用户对象可以这样HSET user:100 name xiaowang age 28 HGET user:100 name HMGET user:100 name age跟字符串里的JSON方案相比哈希能局部更新、局部读取。改一个年龄字段不用把整个对象提出来再序列化回去读姓名也不用拉一整个JSON然后解析。字段多、访问频繁的对象哈希优势非常明显。有几个细节必须记住HSET返回1表示新增字段0表示覆盖旧字段HDEL删除字段HEXISTS判断字段是否存在HLEN看字段个数。HGETALL会一次返回所有field和value时间复杂度O(N)字段很多时慎用。我见过有人对几千个字段的哈希反复执行HGETALL把单线程Redis打到阻塞最后换成HMGET只取需要的字段才缓过来。3.2 列表LPUSH/RPUSH/LPOP/RPOP/LRANGE队列栈都能干列表按插入顺序存储成员头尾操作是O(1)中间访问是O(N)。简化理解它天生适合队列和栈。经典用法有生产者LPUSH消息消费者RPOP取出每次LPUSH新内容再用LRANGE取最近十条做时间线记录用户操作日志LRANGE翻页查看。BRPOP和BLPOP是阻塞版本队列为空时客户端会挂起等待新数据而不是空转轮询这对写一些粘合脚本非常方便。要注意两个细节。LRANGE的索引是左闭右闭LRANGE list 0 -1 表示整个列表。列表很大时LRANGE 0 -1同样危险只取尾部N条的话用LRANGE list -N -1。另外频繁访问列表中间元素说明结构选错了普通列表随机访问是O(N)量大之后会慢得离谱这种场景应该用ZSET或者哈希结构。3.3 集合SADD/SREM/SISMEMBER/SMEMBERS去重与标签的利器集合的核心特点是成员唯一、无序。它最常见的两类用途一是去重二是标签和权限判断。举个例子SADD article:100 tags redis cache SISMEMBER article:100 tags redis SREM article:100 tags cacheSADD的返回值是1表示新增、0表示已存在这个返回值经常被用来判断这个用户是不是第一次来。SISMEMBER判断成员是否存在是O(1)比把整个集合拉回来在代码里contains强得多。SMEMBERS返回全部成员是O(N)大集合上要非常谨慎。集合运算也是选它的理由。SINTER取交集可以做共同好友SDIFF取差集可以做不在某个白名单里的用户SUNION取并集可以合并多个标签桶。这些运算在服务端一次完成不用把数据拉到客户端再手写网络开销和代码量都能省。3.4 有序集合ZADD/ZINCRBY/ZREVRANGE排行榜就指望它ZSET是带分数的集合每个成员对应一个double类型的分数Redis按分数排序。最经典的应用就是排行榜。基本操作ZADD leaderboard 100 user1 ZINCRBY leaderboard 5 user1 ZREVRANGE leaderboard 0 9 WITHSCORESZINCRBY给某个成员加分ZREVRANGE取分数从高到低的前十名ZRANK/ZREVRANK查排名ZSCORE查某个成员当前分数。这套组合做实时排行榜几乎零成本根本不用去数据库排序。两个容易踩的细节需要单独说一下。同分时ZSET会按成员字典序排列做在线榜单时如果分数一样排名顺序可能和你预想的不一样做前端展示时要有所预期。另一个是分数类型Redis的ZSET分数是double精度不要用来存精确金额或商品价格金额计算还是老老实实用数据库或整数分Redis的ZSET分数只适合做排序依据和权重不适合做账单。这两个细节看着不起眼真到业务上线了都是事故点。4. 过期时间与内存淘汰这几个命令是保命用的如果说前三章是在教你怎么写数据那这一章就是教你怎么防止数据把自己搞死。Redis是内存型存储不设置过期时间的key会一直占着内存很多线上事故回头看根因都是缓存忘了设TTL。这章把过期相关的命令和内存淘汰策略讲透。4.1 EXPIRE/TTL/PERSIST缓存不设过期时间等于定时炸弹日常开发中写缓存默认都应该带过期时间。哪怕你的数据几乎永不过期也最好给一个足够长的TTL将来代码改版、数据结构变化时可以靠过期自然淘汰旧数据而不是手动清理。几个命令要记熟EXPIRE key 3600 TTL key PERSIST key SETEX key 3600 valueTTL返回剩余秒数返回-1表示没设过期时间返回-2表示key已经不存在。PERSIST可以把key变成永不过期。SETEX等价于SET加EXPIRE适合一次写入带过期时间的场景。一个容易忽略的点是Redis的过期删除不是实时的而是惰性删除和定期删除结合。被访问时才检查是否过期后台也会周期抽样清理。所以当一批大key同时过期时Redis可能会瞬间卡一下或内存抖动明显。大量key需要同一时刻过期时建议给过期时间加一个随机偏移把集中过期摊平防止缓存雪崩。4.2 SETNX与SET NX EX一起上的最简分布式锁SETNX的意思是Set if Not eXists即只有key不存在时设置成功返回1成功、0失败。它是做分布式锁最早期的方案之一。但有一个历史教训很多人只用SETNX加锁忘了设置过期时间一旦持锁进程崩溃锁永远不释放线上直接死锁。更稳的写法是用我前面提到的SET命令带NX和EX参数一条命令完成加锁和过期SET lock:pay:order123 1 NX EX 30释放锁也不能简单DEL。原因是锁可能已经因为超时被自动释放了后续另一个线程拿到了新锁此时第一个线程执行DEL会把别人的锁删掉。正确做法是先用GET比对值确认锁持有者的标识是自己再DEL。这个比对加删除需要原子执行最简单的是用Lua脚本。这里不展开Lua但你要记住加锁要NXEX解锁要校验身份这两点是基础命令层面必须养成的肌肉记忆。4.3 CONFIG GET/SET与INFO查内存、看淘汰心里有数内存淘汰策略maxmemory-policy决定Redis内存满了怎么办。默认的noeviction是不淘汰直接拒绝写操作开发环境没什么感觉到了生产就是莫名其妙的写入失败。常用策略有allkeys-lru所有key按最近最少使用淘汰适合通用缓存volatile-lru只淘汰设置了过期时间的key适合混合存储volatile-ttl优先淘汰剩余时间短的key适合有时效性的数据对应命令是CONFIG GET maxmemory和CONFIG GET maxmemory-policy修改用CONFIG SET。但生产环境不建议直接CONFIG SET改完就完事最好在配置管理里同步成文件否则重启后配置又丢了。排查内存问题时我一般按INFO memory、INFO stats、DBSIZE的顺序先看宏观used_memory是多少expired_keys和evicted_keys增长情况当前key总量。然后才去定位具体key。先看数据再下结论而不是一上来就瞎猜。5. 线上排查先摸家底再定位问题别上来就KEYS *前面四章已经把常用命令过了一遍。这一章专门讲线上排查时怎么组合这些命令因为实际生产环境和本地练习完全是两回事。很多人第一次上线上Redis就手抖一个KEYS * 打下去整个实例都跪了。我把排查思路和套路整理出来希望能帮你少踩几个雷。5.1 摸清现场DBSIZE、TYPE、EXISTS、TTL的组合拳收到Redis告警或业务反馈缓存不生效第一件事不是急着找某个key而是先用低代价命令摸清整体状态。DBSIZE看当前库有多少keyINFO memory看内存占用INFO stats看命中率、过期数量和淘汰数量。这几个命令本身都很轻不会打爆Redis。然后再定位单个keyTYPE看这个key是什么类型EXISTS看它到底存不存在TTL看剩余过期时间。举个实际场景同事说缓存不生效我先EXISTSkey不存在再查代码发现写入用的前缀和读取用的前缀差一个字符。这种情况靠EXISTS和DBSIZE就能慢慢缩小范围。如果业务反馈类型错误TYPE命令一眼就能看出是SET成了字符串还是哈希。5.2 为什么KEYS * 是生产环境的地雷SCAN才是正确姿势KEYS pattern会一次性返回所有匹配的key。开发环境几十个key时完全没问题到了线上几百万个keyKEYS * 会一次性扫描全部key并返回Redis是单线程模型这个操作会让所有读写请求排队几秒甚至几十秒线上直接雪崩。所以任何生产环境都应该把KEYS当作禁用词。替代方案是SCAN增量遍历。基本用法SCAN 0 MATCH user:* COUNT 100返回一批key和下一个游标客户端拿着游标继续调用直到游标为0才算遍历完。SCAN不保证一次遍历期间的key变化也不保证不会重复但用来批量删除批量设TTL导出key清单完全够用。如果真要在线上做全量操作我习惯在低峰期用脚本分批SCAN每批之间稍做停顿避免给Redis太大压力。5.3 定位大Key和慢命令redis-cli --bigkeys 与 SLOWLOG GET线上卡顿最常见的原因就两块大key和慢命令。排查工具一个是redis-cli --bigkeys它会遍历当前实例统计每种类型里占用空间最大的key输出最大字符串、最大哈希、最大列表之类的报告。注意它本身也是遍历有开销建议低峰期执行。另一个是SLOWLOG GET看慢查询记录。SLOWLOG GET 10能取出最近10条超过阈值的命令每条包含执行时间、命令参数、发生时间戳。我用这套排查过一次很典型的卡顿某服务每到午后定期卡住SLOWLOG GET里全是SMEMBERS耗时一秒钟以上操作的集合有上百万成员。定位到具体key以后把全量拉取的逻辑改成SSCAN分批读取卡顿就消失了。这类问题的本质不是命令写错而是没考虑O(N)命令在数据量大时的代价基础命令真正值钱的地方就在这里。6. 常用命令速查表与我的运维习惯最后整理一份速查表方便你平常翻。同时也把我在运维中用到的习惯列出来这些习惯看着不起眼但真到排查故障时能省下很多时间。6.1 按数据类型整理的一份速查表类型常用命令一句话场景通用PING / SELECT / DBSIZE / EXISTS / TYPE / DEL / TTL / EXPIRE / PERSIST / SCAN连接、查看状态、判断存在、查类型、设过期、增量遍历StringSET / GET / MSET / MGET / INCR / DECR / INCRBY / APPEND / STRLEN缓存、计数器、token、分布式锁的NX/EX组合HashHSET / HGET / HMGET / HGETALL / HDEL / HEXISTS / HLEN存对象、局部更新属性、配置项ListLPUSH / RPUSH / LPOP / RPOP / LRANGE / LLEN / BRPOP队列、栈、最新动态时间线SetSADD / SREM / SISMEMBER / SMEMBERS / SCARD / SINTER / SDIFF去重、标签、共同好友、集合运算ZSetZADD / ZINCRBY / ZSCORE / ZRANGE / ZREVRANGE / ZRANK / ZREM排行榜、实时热度、带权重的队列这张表不是让你背而是建议放在手边。你在实际开发里要做的是看着一条业务需求先问自己它该放进哪种结构再去找对应的命令千万不要反过来——先想到一个命令再硬套业务。比如要做排行榜就先想到ZSET要做去重就先想到SET要做消息队列就先想到LIST数据结构选对了命令基本就是那几条剩下的只是写熟练度的问题。6.2 我在实际运维中养成的几个习惯第一新写缓存默认带TTL哪怕是理论上永久不变的数据也都给一个很长的过期时间方便将来改版和清理。第二生产环境直接封掉KEYS、FLUSHALL这类高危命令通过Redis的命令重命名或ACL来做别考验人性。第三批量操作之前先看DBSIZE和INFO memory评估一下规模再决定是一次跑还是SCAN分批。第四大key一定不能在高峰期处理拆key、压缩、换结构都得在低峰期操作还要留好回滚方案。第五排查问题的固定顺序是SLOWLOG、bigkeys、DBSIZE、INFO memory拿日志和数据说话而不是靠猜。最后再说一点个人的体会我把上面这些习惯贴在终端旁边每次动手写Redis命令前都会过一遍脑子——这条命令会不会阻塞、这个key会不会占太多内存、不设TTL会不会出事。等你想清楚了这几点redis基础常用命令才算真正掌握往后遇到更复杂的分布式锁、缓存穿透、集群迁移心里也有底。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑