很多朋友刚接触Linux上的Redis时,第一反应是去搜“redis命令大全”,觉得操作无非就是set、get、incr这几个命令来回用。但真到了自己上手,卡人的往往不是命令,而是安装、配置、排查这一整条链路。你在网上看到的所有教程都默认你已经有了一套能跑起来的Redis环境,可现实是,光是“在Linux上把它装好并配到能安全使用”这一关,就能拦住不少人。
这篇文章想解决的,就是“Linux上Redis的简单操作”这件事本身。我会从安装开始讲,把配置文件里那些“改不改都行,可真出事”的参数挑出来逐个说明,再把五种数据类型的常用命令和适用场景串一遍,最后聊一聊日常排查、可视化连接和安全加固,以及进入生产环境前必须知道的持久化和分布式锁那些事。不管你是刚接触服务器的学生、转行运维的开发,还是准备面试时被Redis基础题问到过的求职者,照着这篇文章走一遍,至少不会再在“点亮Redis”这一步上翻车。
1. 装对Redis:apt一键装与源码编译的真实差异
1.1 最省事的安装方式与我对它的态度
如果你用的Debian系系统,安装Redis基本上就是两条命令:
sudo apt update sudo apt install redis-server -y装完之后Redis会自动注册成systemd服务,开机自启、日志管理、崩溃重启全都帮你处理好了。一条systemctl status redis-server就能看到运行状态,redis-cli ping返回PONG就说明已经能用。对于追求效率的开发者来说,这就是最舒服的打开方式。
但这里有个我不能不提的坑:软件源里的Redis版本通常偏旧,而且不同发行版的差异很大。Ubuntu 22.04的源里大约是Redis 6.0.x,CentOS 7自带源里的Redis甚至可能停留在3.x。Redis 3.x连unlink这种基础命令都没有,更别提后来引入的set命令的多种选项、更好的内存管理和各种性能优化了。
我自己在真实的开发环境里碰到过一次特别糟心的情况:线上用的是apt装的老版本Redis,本地测试用的是Redis 7.x,结果本地写好的Lua脚本片段在线上直接语法警告加逻辑表现不一致,最后排查了一圈才意识到是版本差异导致的。所以我的建议是:
- 开发测试环境、临时体验环境:直接
apt install redis-server,怎么快怎么来。 - 生产环境、长时间运行的环境:优先源码编译安装,或者至少用一个可信的源装一个“够新”的版本。
1.2 源码编译安装的完整过程
有人一听“编译安装”就头疼,其实Redis是个C语言项目,编译过程出奇地干净。步骤如下:
# 安装基础编译工具 sudo apt update sudo apt install gcc make -y # 下载源码,选一个稳定版本 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 -j$(nproc) sudo make install只要gcc版本不是老得离谱,make基本一遍过。我编译过很多次Redis,唯一一次遇到问题是在一台内存只有512MB的云主机上,make过程中OOM被系统直接杀掉。解决办法也简单,不要用-j并行编译,老老实实跑单线程的make,或者先临时开一点swap空间。
sudo make install会把redis-server、redis-cli、redis-sentinel等二进制文件装到/usr/local/bin下。注意,源码编译默认不会自动配置systemd服务,要么手写一个service文件,要么用源码目录里utils/install_server.sh脚本。
1.3 装完之后的第一轮验证
不管哪种方式装的,装完我都建议做一次系统性的体检:
# 查看版本 redis-server --version # 启动服务 sudo systemctl start redis-server # 确认状态 redis-cli ping redis-cli info server | grep redis_versionredis-cli ping返回PONG看似简单,但它是“服务器活着且网络端口通”的最直接证据。很多朋友配置完就以为万事大吉,结果ping一敲直接Connection refused,才发现Redis进程根本没起来。所以别跳过这一步。
2. redis.conf关键开关逐个过:每个改动背后都有代价
Redis装好之后,那个默认配置文件里的大多数参数其实都可以用,但如果你直接这么跑生产,迟早会出事。/etc/redis/redis.conf(apt安装)或/usr/local/etc/redis.conf(编译安装,看install_server.sh的路径设置)里有一些配置我建议你一定亲手过一遍。
2.1 后台运行和进程管理
daemonize yes pidfile /var/run/redis/redis-server.piddaemonize yes表示让Redis以守护进程方式在后台运行,否则redis-server会占着终端不放手。你可能想问:加了systemd管理为什么还要daemonize?实际上systemd管理时更推荐daemonize no,让systemd直接托管前台进程。如果两个都想要,优先保证systemd能正常管理就行,这个细节在排查“为什么服务起不来/重启异常”时很关键。
2.2 bind、protected-mode和密码:安全三件套
这是全篇文章里最重要的配置段,没有之一。默认配置通常是:
bind 127.0.0.1 protected-mode yes requirepass 你的密码bind 127.0.0.1意味着Redis只监听本机回环地址,外部的任何机器都连不上。protected-mode yes是在没有设置密码时,对未授权访问做一层保护。requirepass则是给客户端认证加了一道锁。
很多人图省事,直接把bind改成0.0.0.0,觉得“反正我设置了密码,怕什么”。我劝你千万别这么做。我自己的云服务器曾经就因为Redis裸奔造成过严重事故:只是跑了个demo,没设密码没设bind,第二天早上起来发现服务器CPU拉满,redis-cli一进去看到一堆奇怪的键,里面还有矿工程序的痕迹。那次之后我才明白,互联网上的扫描攻击是按小时甚至按分钟级进行的,6379端口一旦暴露,被爆破只是时间问题。
如果确实需要从别的机器连接Redis,正确姿势是:
bind 0.0.0.0 protected-mode no requirepass 一个足够复杂的密码这不是零风险,但这已经是缓解方案了。更稳妥的玩法是设置bind为具体的内网网段,比如bind 192.168.1.100,或者在云安全组里只放行指定IP。我建议安全组/防火墙层面做白名单,而不是在Redis配置里放开所有接口。
2.3 持久化开关:RDB和AOF的基础选择
默认配置下Redis开了RDB快照,但没开AOF。这意味着如果服务器突然断电,你可能会丢失最后一次快照之后的所有写入。开发环境无所谓,生产环境得按数据特征来:
appendonly yes appendfsync everysec save 3600 1 300 100 60 10000appendonly yes开启AOF日志,appendfsync everysec表示每秒刷一次磁盘,这是性能和安全性比较平衡的选择。save那一行是RDB快照触发条件,3600 1表示“3600秒内至少有一次键变更就触发快照”。两个持久化机制可以同时开,Redis重启时会优先用AOF文件恢复,因为AOF的数据更完整。
关于持久化,我在第五部分会展开更多,这里先有个概念就够了。
2.4 内存上限和淘汰策略
这个配置真的被无数人忽略。Redis装好之后默认maxmemory是0,也就是64位系统下不限制内存使用。听起来没什么问题,但如果你拿Redis当缓存,塞了一堆数据又不清理,它会一路吃到机器物理内存耗尽,最后触发系统OOM或者把整个Linux主机搞到Swap颠簸。
我的习惯是一开始就根据机器内存规划:
maxmemory 512mb maxmemory-policy allkeys-lrumaxmemory指定Redis能使用的最大内存,maxmemory-policy allkeys-lru表示内存满了之后,按照LRU算法淘汰所有键里最近最少用的数据。如果你有只允许过期键被淘汰的需求,就用volatile-lru。这行配置在开发机上的意义不大,但在生产上,它就是“Redis会不会拖垮整个Linux系统”的保命符。
2.5 动态修改配置的两个命令
配置文件改完要重启才能生效,这在很多场景下不太灵活。Redis提供了两个运行时命令:
# 在线查看和修改 redis-cli config get maxmemory redis-cli config set maxmemory 1gb # 把运行时的配置同步写回配置文件 redis-cli config rewrite注意config set是直接作用于内存中的,不写进文件的话重启后还是老配置。config rewrite则会把当前生效的配置持久化到配置文件里。日常运维中,临时调大内存上限、临时把慢日志阈值调低,都可以用这种方式,最后再config rewrite落盘。
3. 数据类型实操:五类命令与对应业务场景
Redis有五种基本数据类型:String、Hash、List、Set、ZSet。不少面试题让你背它们的区别,但实际工作中更重要的是“什么时候该用哪个”。下面按真实业务场景逐个过一遍。
3.1 String:最基础但不是最无用
String在Redis里是一个二进制安全的字符串,可以存文本、数字序列化后的JSON、字节内容。常用命令是:
SET product:1001:detail '{"name":"Linux手册","price":99}' GET product:1001:detail SET counter 0 INCR counter DECR counter SET token "abc123" EX 3600INCR这种原子自增操作在分布式环境下尤其好用。比如统计文章阅读量、记录用户当天访问次数、生成单调递增序号,很多人想用数据库里的自增字段,但高并发下Redis的INCR成本和速度都完胜。另外SET ... EX 3600是“写入并同时设置过期时间”的惯用法,比先SET再单独EXPIRE省一次网络往返,还能避免中间那几毫秒键没设置过期时间的窗口期。
3.2 Hash:对象结构的最佳归宿
如果你要存一个用户信息、商品信息这种“多个字段”的数据,别用String序列化整个对象,用Hash:
HSET user:1001 name "zhangsan" age 28 city "beijing" HGET user:1001 name HGETALL user:1001 HINCRBY user:1001 age 1HINCRBY可以对对象里的某个数字字段原子自增,这在维护用户积分、商品库存时很好用。我最喜欢Hash的原因是:字段级的读写开销远小于“整体序列化再反序列化”的方式。设想一个100个字段的JSON对象,只是改其中一个字段,如果用String,你得把整个JSON读出来、反序列化、改完、再序列化写回去;用Hash,一次HSET就结束了。
3.3 List:消息队列的轻量版
List是一组有序的字符串,支持从两头压入和弹出。常用命令:
RPUSH msg:queue "task-001" LPUSH msg:queue "task-002" LPOP msg:queue RPOP msg:queue LRANGE msg:queue 0 -1经典组合是BRPOP,阻塞式读取:如果队列里没有数据,客户端会一直等待,直到有新消息进来或者超时返回。这套“阻塞队列”能力在小型项目里完全可以充当消息队列中间件的平替,别上来就上Kafka。
我实际项目管理过一个简单的订单处理流程:用户下单后往队列里丢一个订单号,后端消费者用BRPOP取出订单号再执行后续操作。高峰期几千个订单也没出过问题。当然,它没有消费确认、重试、持久化这些Kafka才有的高级能力,业务规模大了以后该迁移还是得迁移。
3.4 Set:去重、交集和随机抽取
Set是一个无序、元素不可重复的集合。常用命令:
SADD tag:1001 "redis" "linux" "server" SISMEMBER tag:1001 "redis" SMEMBERS tag:1001 SCARD tag:1001 SINTER tag:1001 tag:1002Set的应用场景很经典:用户标签系统、好友关系、文章点赞用户集合、抽奖候选池。它有个很实用的命令SPOP可以随机弹出一个元素,做抽奖正好;SINTER可以做“共同好友”式的集合交集运算。
有一回我们做活动抽奖,奖品有限、参与人数巨大,如果用数据库去重用户再随机抽,SQL写起来麻烦,性能也差。后来全部扔进Redis Set,SADD去重天然搞定,抽奖用SRANDMEMBER取一个随机成员(不弹出)、或者SPOP弹出(不可重复发奖),一把梭。
3.5 ZSet:带权重的有序集合,排行榜神器
ZSet,又叫有序集合,每个成员关联一个double类型的分数(score),按分数排序。常用命令:
ZADD leaderboard:2024 98.5 "user_A" ZADD leaderboard:2024 76.0 "user_B" ZINCRBY leaderboard:2024 5.5 "user_A" ZRANGE leaderboard:2024 0 -1 WITHSCORES ZREVRANGE leaderboard:2024 0 9 WITHSCORES ZRANGEBYSCORE leaderboard:2024 80 100排行榜、实时热点榜、积分榜这类应用,ZSet是绝对主力。ZINCRBY可以原子修改分数,ZREVRANGE从高到低取前N名,天然就是榜单接口要的数据。
延时队列也可以基于ZSet做:score存到期时间戳,消费者轮询ZRANGEBYSCORE score -inf now拿到所有到期任务并处理。这属于ZSet比较进阶的玩法,你要是面试能说出这一手,绝对加分。
3.6 全局键管理:为什么生产环境禁用KEYS
前面五种类型的操作基本都围绕单个key,但日常管理还有一个高频需求——查看所有键。很多人会顺手用:
KEYS *这个命令在开发环境只有几十个键的时候无所谓,但在生产环境有几十万键的时候,KEYS *会阻塞Redis事件循环,导致所有读写请求排队,反应直接就是“命令超时”。我见过一次真实事故:有人在线上跑了一个带KEYS前缀的通配查找,Redis直接卡了十几秒,后面全都堵着。
正确做法是用SCAN:
SCAN 0 MATCH user:* COUNT 100SCAN是游标式迭代,每次返回一小批键,不会阻塞太久。写脚本时要循环调用,直到游标返回0为止。如果需要统计总量可以用DBSIZE,不要用KEYS *。
键的过期操作也值得私藏一套:
EXPIRE token:abc 3600 TTL token:abc PERSIST token:abc DEL token:abcTTL返回剩余秒数,-1表示永久有效,-2表示键已不存在。排查“为什么缓存没失效”时,TTL是第一排查工具。
4. 日常排查、可视化连接与安全加固的完整清单
Redis装好了、命令也会了,但线上出了故障怎么办?这里分享一套我平时用得最多的排查手法。
4.1 用redis-cli做实时监控
redis-cli --stat这个命令能持续输出服务器的实时状态,包括ops(每秒操作数)、连接数、内存占用等。它的输出频率是每秒一行,连续刷屏,看起来非常直观:
redis-cli --stat我排查生产事故时的惯用套路是:如果ops从几千骤降到几百,而且连接数不断上涨,基本可以先怀疑是不是发生了阻塞;这时候去查慢日志。
config set slowlog-log-slower-than 5000 slowlog get 10slowlog-log-slower-than 5000表示命令执行时间超过5000微秒(5ms)就记录下来。slowlog get 10取最近10条慢日志,能看到是哪些命令拖慢了服务。排查“Redis为什么卡”,这两个命令比瞎猜强一百倍。
4.2 内存和Key的体检
redis-cli info memory redis-cli --bigkeysinfo memory里重点看used_memory和used_memory_human,这会告诉你Redis实际占了多少内存,配合系统层面的free -h判断是不是内存吃紧。used_memory_rss是Redis向系统申请的内存总量,如果它远大于used_memory,说明内存碎片化严重,可以考虑重启或者调activedefrag参数。
redis-cli --bigkeys会自动扫描整个数据库,找出每种类型里占用空间最大的前几个key,这是排查“Redis里到底什么东西塞了这么多内存”的最快方法。我线上的一个大key问题就是靠它定位的——一个List里塞了一百多万个元素,把内存干爆了。
注意--bigkeys本质也是遍历所有key,虽然在实现上做了分批扫描,比KEYS *温和,但高峰期还是尽量避开。
4.3 远程连接、可视化工具和防火墙
命令行适合服务器上操作,但开发和日常管理我更常用可视化客户端。另一个九江的“AnotherRedisDesktopManager”是我最近用得最多的跨平台工具,界面干净,支持Linux、Windows、macOS,连接管理也方便。
连接远程Redis最常遇到的问题就是连不上,原因多半是这几类:
- Redis只绑定了
127.0.0.1,外部访问不到——除非用SSH隧道,否则需要按第二节那样调整bind。 - 云厂商安全组没放行6379端口——这个在云控制台操作,跟Redis本身无关。
- Redis设置了
requirepass但客户端没有输密码——NOAUTH Authentication required报错就非常典型。 - 客户端工具本身连接超时设置太短,比如我之前用Lettuce遇到过
Redis command timed out报错,就是网络抖动加上客户端超时时间设置过短导致的。
这里顺带说一个我踩过的坑:直接在命令行用redis-cli -a 密码 ping确实能用,但Redis会提示你命令行里带密码可能不安全。更稳妥的做法是用环境变量:
redis-cli -a 'yourpassword' PING # 或者 REDISCLI_AUTH='yourpassword' redis-cli4.4 安全加固:别裸奔,也别过度焦虑
安全这块我在配置章节提过,再加一个更实用的清单:
- 设置redis密码:
requirepass,这是底线。 - 不要开放公网接口:必须开放时,配合安全组/IP白名单。
- 禁用危险命令:比如
FLUSHALL、FLUSHDB、KEYS、SHUTDOWN,可以在配置里改名或者置空:
rename-command FLUSHALL "" rename-command FLUSHDB "" rename-command KEYS "command-keys-never-use"- 最小权限运行:不要让Redis以root用户跑,尽量创建一个专有的redis用户。
- 日志审计:把Redis日志输出到固定日志文件,别默认打到stdout。排查攻击记录的时候,日志是唯一的脚印。
这些操作做完,至少能挡住99%的“扫描-爆破-植入”型攻击。剩下那1%,需要更专业的安全团队来处理,不是这篇文章的范围。
5. 简单操作之外:从持久化、分布式锁到缓存三大坑
把前面基础操作跑通后,很多人的下一步是“把Redis用到业务里”。这一节相当于一个过渡,讲讲那些你在面试和日常讨论中迟早会碰到的知识点。
5.1 RDB和AOF到底怎么选
一句话概括:RDB是内存快照,重启恢复快但可能丢最后一次快照之后的数据;AOF是写操作日志,数据保全性好但文件更大、恢复也更慢。两者对比如下:
| 维度 | RDB | AOF |
|---|---|---|
| 数据完整性 | 可能丢最近一次快照后的数据 | 最多丢最后一次fsync之后的数据(视策略) |
| 恢复速度 | 快 | 慢,需重放操作日志 |
| 文件大小 | 小而紧凑 | 大,需定期重写压缩 |
| 性能影响 | 快照保存时fork子进程有开销 | everysec策略下性能影响很小 |
| 建议 | 缓存类、可容忍丢数据 | 数据重要、需快速恢复少丢数据 |
生产环境稳妥做法是两者都开,Redis重启时优先读AOF恢复。我自己的服务器就是appendonly yes加默认RDB都开,既保底又能快速备份。
备份恢复的操作就简单两句话:
# 手动触发快照 redis-cli BGSAVE # 然后把dump.rdb拷贝走,就完成了备份 cp /var/lib/redis/dump.rdb /backup/redis-$(date +%F).rdb5.2 分布式锁:简单实现与天然缺陷
SET命令带NX和EX选项,就是分布式锁的最简形态:
SET lock:order:1001 "unique-token" NX EX 30NX表示键不存在时才写入,也就是“拿到锁”;EX 30表示锁30秒后自动释放,防止持有锁的进程崩了导致死锁。释放时要小心,得先确认锁是自己持有的再删除,避免误删别人的锁。这需要用Lua脚本保证原子性:
if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end通过redis-cli EVAL执行核心逻辑。但分布式锁有个天然缺陷:锁过期时间怎么定都不完美。如果业务执行时间超过锁过期时间,锁会自动释放,别的进程又拿锁进来,等于同时有两个进程进入临界区。解决思路是“看门狗”机制自动续期,或者从设计上让业务操作具备幂等性。真要讨论严谨的分布式锁,还涉及RedLock那些话题,但在大多数内部系统里,简单的SET NX EX足够用了。面试时你要能说出它的缺陷和规避思路,就已经超过不少人。
5.3 缓存穿透、击穿、雪崩:Redis面试三大问
这几个名词在“redis面试题”热搜里出现频率极高,这里用最通俗的方式解释一下:
- 缓存穿透:查询一个根本不存在的数据,每次都会绕过缓存打到数据库。别人可以伪造大量不存在的ID让你数据库压力爆炸。对策是缓存空值(不存在也缓存一个空结果)或者用布隆过滤器拦一下。
- 缓存击穿:某个热点key过期瞬间,大量请求同时打到数据库。对策是热点数据不设过期时间(后台定时更新)或者加互斥锁,让并发只放行一个请求去更新缓存。
- 缓存雪崩:大量key集中在同一时段过期,数据库瞬间被没有缓存的请求压垮。对策是过期时间加随机值,让失效时间分散开。
这三个概念理解起来不难,但我实际体会是“知道名词”和“上线时能想到怎么设计”之间还差着距离。比如缓存穿透,在写接口时就要养成“查到null也写缓存”的习惯,而不是出事故了再亡羊补牢。
5.4 顺带说说Redis为什么快
这是个烂大街的面试题,但同时也是理解Redis操作原理的一把钥匙。Redis之所以顶着单线程也能扛住高并发,核心在于三点:数据全在内存、线程切换代价小、IO多路复用(类似Linux下的epoll机制)。单线程还有个隐藏好处是避免了多线程加锁的复杂性和上下文切换开销。所以你在Linux上使用Redis时,别动不动就纠结它是不是单线程不够用,真正的瓶颈往往在网络和网络带宽,而不是CPU。
我自己的体会是,把Redis当“高性能内存字典”来用,把合理的数据结构和合理的键设计放第一位,比什么性能调优都管用。有一次我们有个接口响应特别慢,排查到最后发现是用了KEYS *扫全库,改成SCAN之后立竿见影。这就是“操作规范”比“性能参数”更重要最典型的例证。
最后说一个跟所有“简单操作”有关的体会:Redis看着简单,但正因为简单,很多人就低估了它背后的设计取舍。我见过太多人在Linux上把Redis装起来就开始天天当作只有String一种类型的工具,而Redis给我们的那五种数据类型,任何一种都对应一大类真实世界的业务结构。把基础命令练熟,把配置和安全先打好底,剩下的就是在具体场景里一遍遍地试错和加深理解。你只要认真走完这篇文章里的每一步,再用redis-cli --stat看到自己的服务器稳定运行时,那种从“会敲命令”到“敢上生产”的进步感,是很踏实的。