1. 从零搭建Linux环境下的Redis安装与基础配置说起Redis它在Linux服务器里的地位基本等同于“缓存界的一把瑞士军刀”。不管你是做后端开发、运维还是自己在折腾个人项目只要跟高并发、热点数据、分布式锁这类词沾边Redis十有八九是绕不开的。我之前在一台腾讯云的Ubuntu服务器上从零配过也在CentOS 7的老机器上挪过说实话流程大差不差但有几个坑值得提前说清楚。这篇文章我尽量按“拿到一台空机器从零开始把Redis跑起来”这个场景来讲。标题说“简单操作”那我就默认你是刚接触这个组合的入门者能看懂Linux基本命令就行。内容会覆盖安装、常用命令、数据类型、客户端工具外加几个生产环境容易踩的坑比如Java里用RedisTemplate做自增报错的排查思路。如果你已经玩Redis有一阵子了也可以直接跳到后面看问题排查那部分。1.1 先搞清楚你要装哪个版本Redis的安装方式主要有三种用系统包管理器直接装、去官网下源码自己编译、用Docker起容器。对于新手我建议从系统包管理器开始原因很简单依赖自动处理路径基本固定卸载也方便。但这里有个坑apt或yum源里的Redis版本往往偏老。我在Ubuntu 20.04上直接用apt装过默认给的是5.0.x虽然够用但6.0之后引入的ACL、多线程IO等特性你是享受不到的。所以我的建议是如果是自己学习或测试环境用包管理器装省事如果是生产环境去官网下载最新的稳定版源码编译安装或者直接上Docker镜像可控性更好。下面是包管理器安装的常规操作以Ubuntu系和CentOS系分别说明# Ubuntu/Debian sudo apt update sudo apt install redis-server -y # CentOS/RHEL 7 sudo yum install epel-release -y sudo yum install redis -y装完之后先别急着用。Redis默认配置有几个安全隐患我会在后面的配置小节里专门讲。1.2 源码编译安装的完整流程如果你决定用源码编译步骤也不复杂。先确认机器上有gcc编译器然后是标准的“下载、解压、编译、安装”四连# 安装依赖以Ubuntu为例 sudo apt install build-essential tcl -y # 下载并解压这里以7.0.x系列版本为例 wget https://download.redis.io/releases/redis-7.0.12.tar.gz tar -xzvf redis-7.0.12.tar.gz cd redis-7.0.12 # 编译如果机器核数多可以用 -j 参数加速 make -j4 # 安装到 /usr/local/bin 目录 sudo make install编译这一步我吃过亏说两个细节。第一个如果机器内存太小make可能会被OOM打断建议至少在2GB内存的机器上编译否则就得加swap。第二个编译报错最常见的原因是缺gcc执行gcc --version先确认一下别一上来就百度各种奇怪的报错。make install成功后redis-server、redis-cli这两个核心二进制文件就会被放到/usr/local/bin下。这一步完成Redis其实已经能跑了但为了让它在后台稳定运行、开机自启还需要配置和systemd服务化。1.3 最小化安全配置避免一台裸奔的数据库这是我最想强调的部分。网上很多教程装完Redis直接redis-server 就跑这在隔离的内网环境也许还能接受但只要机器有公网IP这种裸奔状态等于把你的数据当礼物送人。我之前做过渗透测试的朋友提过互联网上一直有扫描器在扫6379端口找到没设密码的Redis就尝试写SSH公钥进去中招的机器基本秒变肉鸡。所以安装完成后至少要完成这三件事第一修改bind配置。编辑redis.conf把bind 127.0.0.1 -::1这一行保留这是只监听本机回环地址。如果你的场景需要其他机器访问比如让应用服务器连这台Redis再单独加白名单IP比如bind 127.0.0.1 192.168.1.100。千万不要直接设成0.0.0.0。第二设置访问密码。在redis.conf里找到# requirepass foobared去掉注释并改成你自己的强密码requirepass YourStrongPassword_2024设置之后每次用redis-cli连接都要先认证redis-cli -a YourStrongPassword_2024或者进入交互模式后执行AUTH YourStrongPassword_2024。第三关闭危险命令。Redis有KEYS、FLUSHALL这类破坏性命令或者像CONFIG这样能修改运行时配置的命令生产环境建议用rename-command把它们禁用掉或者改名rename-command KEYS rename-command FLUSHALL rename-command CONFIG 当然这只是最小化建议。生产环境还有部署在专用内网、防火墙限制端口、开启TLS等更严格的手段这里不展开。2. Redis核心操作五大数据类型与高频命令装好Redis之后真正的日常就是跟命令打交道。Redis的“简单操作”绝大部分是围绕五种基本数据类型展开的也就是字符串String、哈希Hash、列表List、集合Set、有序集合ZSet再加上后面补充的Bitmaps、HyperLogLog、Geo等扩展类型。不说废话常用的就这些。2.1 String最基础也是最好用的类型String是Redis里最常用的类型键值对都是字符串value最大能放512MB。它在缓存方面用得最多比如缓存用户信息、接口返回的JSON串、页面片段等。# 设置键值 127.0.0.1:6379 SET user:name zhangsan OK # 获取键值 127.0.0.1:6379 GET user:name zhangsan # 设置过期时间单位是秒 127.0.0.1:6379 SET session:token abc123 EX 3600 OK # 惰性更新键不存在时才会设置成功典型应用是分布式锁的加锁 127.0.0.1:6379 SET lock:order 001 NX EX 10 OK # 自增操作计数器必用 127.0.0.1:6379 INCR page:view (integer) 1这里有个我用过的实用场景在接口层做防重复提交。前端提交订单时先以用户ID加订单号为key执行SET lock:order NX EX 5如果返回OK说明第一次提交放行如果返回空说明5秒内已有重复请求直接拒绝。原子性和过期时间都靠Redis保证了不用自己写锁。2.2 Hash适合存对象Hash类型有点像一个key底下挂了很多field-value非常适合存对象。比如用户信息有name、age、email多个字段用String存要拼成一个大JSON改一个字段就得重新SET整个串用Hash就能精确操作单个字段。# 设置多个字段 127.0.0.1:6379 HSET user:1001 name lisi age 25 email lisiexample.com (integer) 3 # 获取单个字段 127.0.0.1:6379 HGET user:1001 name lisi # 获取所有字段和值 127.0.0.1:6379 HGETALL user:1001 1) name 2) lisi 3) age 4) 25 5) email 6) lisiexample.com # 对某个字段做自增 127.0.0.1:6379 HINCRBY user:1001 age 1 (integer) 26有人物对象、订单详情之类结构化数据的强烈建议用Hash而不是直接怼一个大String。内存占用更小读写效率更高语义也更清晰。2.3 List消息队列的轻量方案List底层是双向链表支持从两端推入和弹出。LPUSH、RPUSH、LPOP、RPOP这四个命令一组合就能玩出队列和栈的效果。对于小型项目如果没有引入消息中间件用Redis List做简单的异步队列是个很务实的方案。# 右侧推入三个任务 127.0.0.1:6379 RPUSH task:queue task1 task2 task3 (integer) 3 # 左侧弹出任务实现FIFO 127.0.0.1:6379 LPOP task:queue task1 # 阻塞弹出队列空时等待10秒 127.0.0.1:6379 BRPOP task:queue 10 1) task:queue 2) task2BRPOP这个阻塞版本很重要。生产环境做任务队列时如果队列空了还一直LPOP会变成CPU空转的轮询。BRPOP会在队列里没数据时阻塞等待直到有数据或超时这才是消息队列应该有的行为。2.4 Set与ZSet集合操作和排行榜Set是去重的无序集合适合标签、好友关系、去重统计之类的场景。它支持交集、并集、差集很多社交类功能都能靠这几个命令轻松完成。# 给用户添加标签 127.0.0.1:6379 SADD user:tags:1001 java redis linux (integer) 3 # 查看用户标签 127.0.0.1:6379 SMEMBERS user:tags:1001 1) java 2) redis 3) linux # 计算两个集合的交集 127.0.0.1:6379 SINTER tag:java tag:redisZSet是排序版Set每个成员带一个score按score排序。最经典的应用就是排行榜。比如直播平台的礼物榜# 给主播增加人气值 127.0.0.1:6379 ZINCRBY anchor:rank 50 anchor:10001 50 127.0.0.1:6379 ZINCRBY anchor:rank 80 anchor:10002 80 # 查看前10名从高到低 127.0.0.1:6379 ZREVRANGE anchor:rank 0 9 WITHSCORES 1) anchor:10002 2) 80 3) anchor:10001 4) 50ZSet能高效做到按score排序和范围查询是因为底层用了跳表加哈希表的结构。排行榜这类需求用数据库SQL做数据量大点就慢得不行Redis这边几乎是毫秒级返回。2.5 Key通用命令与过期策略不管什么数据类型日常管理都离不开几个通用命令# 查看所有键生产环境慎用 127.0.0.1:6379 KEYS user:* # 判断键是否存在 127.0.0.1:6379 EXISTS user:1001 (integer) 1 # 设置/查看过期时间 127.0.0.1:6379 EXPIRE user:1001 3600 (integer) 1 127.0.0.1:6379 TTL user:1001 (integer) 3598 # 删除键 127.0.0.1:6379 DEL user:1001 (integer) 1KEYS在生产环境千万慎用。它的实现是遍历所有键数据量大时会造成Redis阻塞整个实例可能卡住几秒钟线上事故就是这么来的。如果真需要扫描键用SCAN命令配合游标去遍历虽然慢点但不阻塞主线程。关于过期策略Redis用的是惰性删除加定期删除的组合拳。惰性删除就是每次读键时检查是否过期过期就删定期删除就是后台周期性地抽查部分过期键。这两种方式配合能在不占用大量CPU的情况下把大部分过期键清掉。3. 可视化与运维推荐好用的Redis客户端工具之前我在终端里用redis-cli敲命令敲了很久说实话命令行虽然灵活但要查看一堆键的值、观察过期时间、查看内存使用情况体验真的一般。后来换了可视化客户端效率明显提升。这里按三种场景推荐。3.1 Redis Desktop Manager与Another Redis Desktop ManagerRedis Desktop Manager是老牌的可视化工具界面清晰支持树形展示所有key还能直接查改删。它的社区版后来变成了RedisInsight。现在很多人用的Another Redis Desktop Manager简称ARDM是国产的开源工具界面是中文的代码托管在GitHub上Windows、macOS、Linux三端都有安装包。我推荐用ARDM理由是免费开源、中文界面、支持多语言。第一次连接时填上IP、端口和密码就行。如果连不上九成是bind配置问题或防火墙没放行端口按前文说的配置策略检查即可。连接上之后你能看到所有数据库默认是db0到db15一共16个还能直接看每个key的value和类型甚至直接修改。调试缓存数据的时候比命令行方便太多。3.2 命令行增强工具redis-cli的高级用法就算有可视化工具redis-cli在很多时候仍然是绕不开的。它支持直接执行命令还能做一些批量操作。# 从标准输入读取命令批量执行 cat commands.txt | redis-cli # 以CSV格式输出结果 redis-cli --csv GET user:name # 监控实时写入的key redis-cli MONITOR # 查看慢查询日志 redis-cli SLOWLOG GET 10 redis-cli SLOWLOG LENMONITOR命令在生产环境慎用它会实时输出所有命令在高并发时会对性能带来影响。慢查询日志则很有用它记录了执行时间超过阈值的命令通过CONFIG SET slowlog-log-slower-than 10000设置慢查询阈值单位微妙再配合SLOWLOG GET就能定位哪些命令拖慢了Redis。3.3 跨Redis迁移数据RIOT工具推荐如果遇到要换服务器、合并实例的场景推荐看一下Redis官方提供的RedisRIOT全称是Redis Input/Output Tool。它能在两个Redis实例间实时同步数据还支持把数据从其他数据源导入Redis。安装方式参考官方仓库支持二进制直接跑。这个工具相对小众知道的人不多但在迁移场景能省不少事。4. 面试高频与开发实战Redis分布式锁和缓存坑点热搜词里“redis分布式锁”“redis面试题”出现频率很高说明很多人正在准备面试或者在工作里实际遇到了这些问题。我挑两个最常被问、也最容易出问题的点来聊。4.1 Redis分布式锁的正确姿势分布式锁是个必考面试题。原理说白了就是利用SET key value NX EX timeout这个原子操作保证同一时刻只有一个客户端能设置成功。# 加锁 SET lock:order:12345 uuid-xxx NX EX 30 # 解锁推荐用Lua脚本保证原子性 if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end为什么加锁时value要用一个唯一标识因为只用DEL直接删锁的话可能出现这样的问题一个线程的锁到期自动释放了另一个线程拿到锁此时前一个线程执行完业务去DEL把别人的锁误删了。用唯一标识确认“是我加的锁”再用Lua脚本把“比对标识”和“删除键”两步做原子化执行就能避免误删。至于锁过期时间设多长要结合业务执行时间去估。典型的极端情况是业务没执行完锁先到期了另一个线程进来了分布式锁失去保护意义。针对这个场景常用的方案有看门狗自动续期比如Redisson框架里就有实现或者退一步接受锁过期这个概率极低的风险。当然如果追求绝对严格的一致性可能需要引入Redlock算法但它在业界争议不小这里不展开。4.2 Redis缓存治理穿透、击穿、雪崩“缓存治理”这个热搜词也值得好好聊一下。这三个“兄弟”是后端开发的经典问题。缓存穿透指的是查询一个不存在的数据Redis和数据库里都没有请求每次都打到数据库上。解决方案有缓存空值也就是即使查不到也把空结果放进缓存设置一个较短的过期时间或者使用布隆过滤器在请求之前就过滤掉肯定不存在的key。缓存击穿指的是一个热点key的过期瞬间大量并发请求同时打到数据库。解决方案是实现“互斥锁”让同一个key同一时刻只有一个请求去重建缓存其他请求等一等或者设置逻辑过期就是不设置真正过期时间而是在value里存一个过期逻辑标记后台异步去重建。缓存雪崩指的是大量key在同一时间集体失效或者Redis实例宕机请求全部打到数据库。解决方案有给缓存过期时间加随机偏移用多级缓存比如本地缓存加Redis做好Redis的高可用部署比如主从加哨兵。这些面试题背后的核心思想是一致的缓存层是用来挡在数据库前面的屏风任何让这个屏风失效的情况都要提前想到对应预案。4.3 Java实战RedisTemplate调用increment()报错排查最后聊一个特别具体、已经被问了很多次的问题Java项目里用RedisTemplate执行increment()时抛了异常报错提示“ERR value is not an integer or out of range”或者无法正常自增。我遇到的那次情况是这样的用RedisTemplate的默认序列化器往Redis里存了一个字符串然后对这个key调用increment结果Redis回了个“value不是整数”的报错反复确认value就是个数字串一度非常困惑。后来一查根因是序列化策略。Spring Data Redis默认的key和value序列化器是JDK序列化JdkSerializationRedisSerializer存的时候value被序列化成一串二进制字节码并不是纯文本数字串。INCR命令要求value是能解析成整数的字符串遇到二进制数据自然报错。解决思路有两个。一个是修改全局配置把value序列化器换成StringRedisSerializerBean public RedisTemplateString, Object redisTemplate(RedisConnectionFactory factory) { RedisTemplateString, Object template new RedisTemplate(); template.setConnectionFactory(factory); StringRedisSerializer stringRedisSerializer new StringRedisSerializer(); template.setKeySerializer(stringRedisSerializer); template.setValueSerializer(stringRedisSerializer); template.setHashKeySerializer(stringRedisSerializer); template.setHashValueSerializer(stringRedisSerializer); template.afterPropertiesSet(); return template; }另一个是用专门提供的increment方法并且确保操作的是字符串序列化后的key。这个问题为什么值得单讲因为它说明了一个很本质的道理一样的Redis命令在Java里如果不理解底层序列化机制就会莫名其妙地踩坑。建议还在用RedisTemplate的同学们都去检查一下自己的序列化配置。5. 运维必备Redis备份恢复与常见故障排查5.1 RDB与AOF持久化备份策略Redis虽然快但它本质上是内存数据库数据在内存里一旦进程退出或机器断电内存中的数据说没就没。持久化是Redis运维的底线要求。默认情况下Redis是开启RDB快照的配置在redis.conf里save 900 1 save 300 10 save 60 10000这三行配置的意思分别是900秒内有1次写操作就做一次快照300秒内有10次写操作做一次快照60秒内有10000次写操作做一次快照。如果业务数据量不算特别大这个默认配置基本够用。另一种持久化是AOF它记录的是每一条写命令更安全但文件更大恢复时也更慢。我一般建议如果数据不容丢失两个都开RDB用于快速恢复AOF用于兜底。配置方式appendonly yes appendfsync everysecappendfsync everysec表示每秒刷盘一次在性能和数据安全之间取一个平衡点。备份的常规操作是执行BGSAVE生成RDB文件再把这个dump.rdb文件拷贝到异地服务器或云存储上。恢复时把dump.rdb文件放进Redis工作目录覆盖原文件重启Redis即可。5.2 内存淘汰策略与响应变慢排查Redis内存是有限的如果一直往里写数据迟早会满。当内存到达maxmemory阈值时Redis会根据maxmemory-policy配置来淘汰键。常见的策略有noeviction不淘汰写命令直接报错读命令正常。allkeys-lru在所有键中按照LRU算法淘汰最少使用的键。volatile-lru只在设置了过期时间的键里淘汰最少使用的键。allkeys-random随机淘汰任意键。默认是noeviction也就是说内存满了会停止写入给线上业务带来影响。如果业务允许建议改成allkeys-lru或volatile-lru。至于响应变慢的排查我一般按这个顺序来先用redis-cli --latency看网络延迟是否正常再用SLOWLOG GET看有没有慢查询命令最常见的元凶就是KEYS、大数据量的HGETALL、或一次操作太多key的MGET接着用redis-cli info memory检查内存碎片率是否过高过高时可以考虑重启或执行MEMORY PURGE最后检查RDB和AOF的持久化配置尤其是RDB在写一个大快照时fork子进程会暂停主线程一小段时间量大的话影响明显。我曾经遇到过一台Redis实例响应时不时抖动排查了一圈最后是AOF重写时产生的磁盘IO争抢。当时那个实例部署在机械硬盘上AOF重写过程密集刷盘拖累了主进程。后来把AOF重写触发阈值调大并且关掉了同一时段的其他磁盘密集型任务问题就消停了。5.3 常见问题速查表现象排查方向与解决远程连接不上Redis检查bind是否为本机IP、防火墙是否放行6379、Redis是否开启requirepass执行命令卡顿/响应慢SLOWLOG查看慢查询检查KEYS等阻塞命令检查内存碎片率内存居高不下INFO memory确认used_memory合理设置maxmemory和淘汰策略数据突然丢了检查是否设置了过期时间、是否有FLUSHALL操作确认持久化策略写入命令报OOM错误检查maxmemory是否触顶确认maxmemory-policy是否为noevictionJava里increment报错检查RedisTemplate的序列化配置改成StringRedisSerializer这张表是我自己日常排查时最常用到的。Redis本身是个很稳定的组件大部分问题其实都出在配置、网络和客户端使用方式上。6. 聊聊我对Redis上手的个人体会记得我第一次在Linux上装Redis是在一台只有512MB内存的小机器上跑通redis-server之后激动得不行接着就傻乎乎地执行了FLUSHALL把测试数据全清空了。现在回头看那些看起来简单的命令背后藏着数据安全、性能优化、并发一致性这些足够深入到很长一段时间的内容。我个人的建议是入门阶段先把五种基本数据类型玩熟尤其是String和Hash它们覆盖了绝大多数业务场景。然后趁早装上可视化客户端日常操作会直观很多。等到工作里真正开始接触高并发、分布式场景再回来啃分布式锁、缓存一致性这些进阶话题那时你对着面试题就不会再觉得它们在为难你而是在考察你是否真的理解Redis的边界和特性。这个学习路径按部就班走下去比我当年东一榔头西一棒子要顺得多。希望这篇东西能帮你在Redis这条路上少踩几个坑。