
1. Redis到底解决了什么问题为什么大家都在装它我一向不喜欢那种某某技术很火所以你应该学的说法但Redis确实是个例外。这几年我经手的后端项目里十个有七个都躺着Redis剩下三个也正在往里面搬数据。如果你在技术社区里搜redis跳出来的前几屏内容几乎都是下载、安装、数据类型这几件事可见它的普及程度已经到了后端标配的级别。那Redis到底是什么简单说它是一个跑在内存里的键值对数据库。注意两个关键词内存和键值对。内存意味着它的读写速度能跑到十万甚至几十万QPS级别远远甩开传统关系型数据库键值对意味着它的数据模型足够简单简单到你可以用最少的思维负担去操纵它。相比MySQL这种需要建表、设计索引、考虑事务隔离级别的重型武器Redis更像一把锋利的小刀——用好了切菜飞快用不好也确实容易切到手。它解决的核心问题我总结成三类。第一类是缓存热点数据不再每次去MySQL里捞先把Redis挡住减轻数据库压力。第二类是临时状态存储比如短信验证码、登录Token、分布式锁这些数据天生就带过期时间属性Redis的数据结构天然支持TTL生存时间用完自动消失省去一堆定时清理任务。第三类是简单的实时统计和队列场景比如文章的点赞数、网站UV统计、异步任务的消息队列用Redis的对应数据结构做起来比用数据库优雅得多。这篇文章就围绕下载、安装、数据类型这条主线展开但我会把每个环节里那些文档里不写、只有真正跑过生产环境才知道的细节一并塞进去。说实话光是把Redis装上很容易难的是装完之后你知道每个数据类型怎么用、知道哪些坑在前面等着你。这篇文章适合两种人一种是刚接触Redis、想把它跑起来的入门者另一种是已经用了半年Redis、但总觉得自己停留在SET/GET阶段、想系统梳理一遍的初级后端开发。不管你是哪一类下面的内容应该都能帮你把Redis的骨架立起来。2. 从零开始Redis安装与基础配置的实操记录2.1 不同平台的安装方式对比如果你去搜索redis安装能找到的教程五花八门但我建议你先明确一件事Redis官方不支持Windows。这话不是说Windows上完全跑不了而是说官方从没提供过Windows原生版本。微软曾经维护过一个老旧的移植分支只到3.x版本就停止维护了现在Windows上最常见的跑法是用WSLWindows Subsystem for Linux或者Docker。如果你非要一个纯Windows下的exe文件网上那些下载源往往来路不明安全性没保障我不推荐在生产环境里用。我个人平时最常用的三种安装方式直接列成表格方便你对照安装方式适用场景命令/步骤备注包管理器Linux/macOS开发环境最快上手Ubuntu/Debianapt install redis-serverCentOS/RHELyum install redismacOSbrew install redis版本可能不是最新但胜在简单系统会自动处理依赖和启动脚本源码编译生产环境或需要定制版本见下方2.2节可控性最强可以选择编译参数和安装路径Docker隔离环境、快速起服务docker run --name my-redis -p 6379:6379 -d redis:7.2适合本地测试数据卷建议挂载到宿主机不然容器一删数据全没为什么我不建议开发环境也上源码编译因为太耗时间了。编译Redis其实很快但要处理gcc、make、依赖库这些前置条件对一些没配过C编译环境的同学来说就是无底洞。开发环境的目标是十五分钟内跑起来包管理器一条命令搞定没必要折腾。2.2 源码编译的完整路径如果你需要在生产环境部署我更推荐源码编译这条路。原因很简单生产环境通常对内网外网隔离包管理器可能连不上镜像源而且编译安装能把Redis装到你指定的目录方便统一管理。整个过程我实测过无数遍步骤非常稳定# 1. 下载源码包我用的是官网稳定版本7.2.x wget https://download.redis.io/releases/redis-7.2.4.tar.gz # 2. 解压 tar xzf redis-7.2.4.tar.gz # 3. 进入目录并编译 cd redis-7.2.4 make # 4. 可选运行测试强烈建议后面还会用到 make test # 5. 安装到系统目录默认装到 /usr/local/bin make install这里有几个细节值得展开说说。首先编译之前确认系统有gccgcc --version没有的话得先装。CentOS为什么比Ubuntu容易在这一步卡住因为CentOS默认没装开发工具组你得敲一句yum install -y gcc gcc-c make才能继续。我有一次帮朋友排查他卡在make报错jemalloc相关的提示其实就是因为没装好编译依赖。其次make test这步很多人会跳过我觉得在Redis这儿不建议省。Redis的测试套件非常完善它会同时起一个临时实例跑几百个测试用例如果你后续要改配置文件、改源码这步能帮你第一时间发现问题。跑一次耗时大概两三分钟性价比超高。编译完成后Redis会生成多个可执行文件很多人分不清redis-server服务端主程序真正干活的进程。redis-cli命令行客户端连接和管理Redis的交互工具。redis-benchmark性能压测工具用来测读写QPS。redis-check-aof和redis-check-rdb数据文件修复工具。初学阶段你只需要关心前两个后面三个等用到再了解就行。2.3 启动前的配置文件必须知道的几个参数装完之后不要急着启动我强烈建议你先看一眼配置文件。Redis的配置项非常多但新手阶段真正需要操作的也就几个。默认配置文件在源码目录下的redis.conf启动时用redis-server /path/to/redis.conf指定。如果不指定Redis会使用内置的默认配置启动这时可以跑但有两个风险没有开启持久化、没有设置密码。我实际部署时一定会改这几个参数# 绑定地址允许哪些IP访问 bind 127.0.0.1 -::1 # 端口默认就是6379 port 6379 # 守护进程模式是否后台运行 daemonize yes # 进程PID文件位置 pidfile /var/run/redis_6379.pid # 日志级别和位置排查问题必备 loglevel notice logfile /var/log/redis/redis-server.log # 数据库数量默认16个 databases 16 # 最大内存上限不设等于裸奔 maxmemory 256mb maxmemory-policy allkeys-lrubind这条非常重要。默认配置只让本地访问生产环境我会根据实际情况改成内网IP。这里有个安全常识不要把Redis直接暴露到公网它本身没有特别强的鉴权机制历史上因为裸奔被攻击导致数据被清空的事件非常多。如果业务必须要远程访问请用VPC或者安全组把端口限制到极小范围同时一定要设置密码。maxmemory和maxmemory-policy这两个参数国内很多团队居然不设置这是个隐患。Redis不是永动机内存总有满的一天。不配置maxmemoryRedis会一直吃内存直到操作系统把它杀掉配置了之后配合maxmemory-policy策略它才会在你设定的上限内优雅淘汰旧数据。allkeys-lru的意思是所有键里优先淘汰最久没被使用的这是绝大多数缓存场景下的最佳解。改完配置就可以启动了redis-server /etc/redis/redis.conf # 或者如果你希望以后开机自启 systemctl start redis # 包管理器安装的话通常自带systemd服务验证是否成功打开一个终端敲redis-cli ping如果返回PONG恭喜你的Redis已经活了。2.4 验证安装一些比PING更实用的自检命令redis-cli ping能返回PONG只能说明进程在跑代表不了服务的健康程度。我每次装完Redis还会顺手执行下面这几条命令确保各方面都没问题# 查看当前所有配置项 redis-cli CONFIG GET * # 查看数据库里有多少个key刚装完应该是0 redis-cli DBSIZE # 获取Redis内部统计信息 redis-cli INFO stats # 实时监控命令执行日志非常有画面感 redis-cli MONITORINFO命令返回的信息量很大新手容易眼花。我一般只看这几个段redis_version确认版本号connected_clients看当前连接数used_memory和used_memory_human看实际占用内存判断是否接近maxmemory上限total_keyspace_hits和total_keyspace_misses加起来看缓存命中率命中率低于80%说明缓存设计可能有问题。MONITOR命令是排查问题的神器它会实时打印出Redis收到的每一条命令。调试线上诡异问题时开着MONITOR同时操作业务系统能直接看到应用层发过来的到底是什么命令、什么参数。不过生产环境慎用这个命令会拖慢性能而且日志量巨大。3. 五个核心数据类型使用场景与踩坑经验3.1 String最基础却最容易用错String类型是Redis里最简单的数据结构一个key对应一个字符串值但别因为它简单就掉以轻心。很多人第一反应是拿它做缓存数据比如把用户信息序列化成JSON字符串塞进去key是user:10086。这个用法没问题只是有几个细节值得注意。String的底层实现不是C语言的字符串而是一种叫做SDSSimple Dynamic String简单动态字符串的结构。SDS相比传统C字符串有几个优势获取长度是O(1)操作、追加字符串时避免缓冲区溢出、通过预分配空间减少内存重新分配次数。这也是为什么Redis里连计数器操作都推荐用String而不是用别的结构。实际开发中的经典用法# 设置带过期时间的键用户登录Token SET token:9527 a1b2c3 EX 7200 # 计数操作文章阅读数自增 INCR article:readcount:101 # 批量获取减少网络往返 MGET user:1 user:2 user:3 # 设置不存在才生效这是分布式锁的基础 SET lock:order:9527 locked NX EX 30这里有个很多人踩过的坑INCR操作虽然只有一条命令但它在底层确实是原子的哦不应该说它是原子操作因为Redis是单线程执行命令。正因为单线程模型多个客户端同时INCR同一个key时Redis会把每次命令串行执行不会出现并发叠加把数据写乱的情况。这个特性让Redis在很多计数器场景里远比从数据库读出来1再写回去这种方案可靠。另一个坑是String类型的存储值大小。单个String类型的value最大支持512MB但这只是理论值实际中塞一个几兆的字符串进去内存开销就很可观。我见过一个团队把整整一张报表的JSON塞进一个key结果内存涨得飞快而且读取时要网络传输好几兆数据速度一点都不Redis。记住String适合小数据量的缓存大块内容请另想办法。3.2 List队列和栈的双重身份List类型在Redis里是一个双向链表你可以从左边push、从右边弹出也可以反过来。这种结构决定了它天生适合做两类事情消息队列和最新列表。最早期的Redis没有专门的队列类型大家用LPUSH配合BRPOP模拟队列原理是生产者往左侧推入消息消费者从右侧阻塞弹出。BRPOP命令带阻塞语义如果列表为空客户端会一直等待而不是立刻返回这比轮询空转强太多了。代码长这样# 生产者将任务推入队列 LPUSH task:queue job-001 # 消费者阻塞式地从右侧取任务timeout 0表示永久等待 BRPOP task:queue 0这里要提醒你一个重要区别LPUSHBRPOP组合是经典的可靠队列实现但它有一个特点——消息被弹出去之后就没了。如果消费者处理任务时崩溃这个消息就永久丢失了。所以现代实践里往往会配合备份列表或者改用Stream类型Redis 5.0之后引入来做更可靠的消息队列。List做最新列表时也常被滥用。比如你有一个论坛要展示用户最近发布的10条帖子你可以每次发帖时LPUSH进去一条帖子ID然后LTRIM命令只保留前10条LPUSH user:9527:posts post_id_123 LTRIM user:9527:posts 0 9这个组合拳非常高效一条插入命令加一条裁剪命令就完成了新增清理过期数据两个动作不需要额外写定时任务。但要注意List的长度如果上到几十万甚至上百万某些Range操作的性能会很差因为链表遍历是O(n)的。做分页查询时别指望LRANGE在大List上能多快该分片就分片。3.3 Hash对象字段级操作的利器Hash类型适合存储一个对象的多个字段每个Hash本身是一个类似Map的集合。如果你用String存一个用户对象你得把整个用户信息序列化成一个大JSON想修改其中一个字段得先把整个JSON取回来再整体写回去效率极低。用Hash就优雅多了字段是独立存在的# 设置用户信息单个字段操作 HSET user:9527 username 张三 HSET user:9527 age 28 HSET user:9527 email zhangsanexample.com # 同时设置多个字段 HMSET user:9527 username 张三 age 28 email zhangsanexample.com # 只获取某一个字段 HGET user:9527 username # 获取所有字段注意生产环境慎用 HGETALL user:9527Hash最核心的价值在于你可以只修改对象的某一个属性而不必把整个对象读写一遍。这对性能敏感的场景是实打实的优化。我做过一个购物车功能每个用户的购物车是一个Hashkey是商品IDvalue是数量。用户修改数量时只需HSET cart:{userid} {productid} 3不需要把整个购物车数据取出来重算。这里还说一个经验HGETALL会返回所有字段如果用户的购物车有几百个商品这个命令的响应体就很大既占内存也占网络。所以批量获取字段时尽量使用HMGET指定你关心的字段名而不是一股脑拿全部。Hash的另一个使用场景是存储配置数据。比如说每个客户有各自的业务配置项但配置项的数量和名称可能会迭代变化。用Hash存储配置项天然可以动态增加不用改表结构的概念在这里就是字面意思上的随意加字段。3.4 Set与ZSet去重、标签与排行榜Set类型是一个无序、不重复的字符串集合。它的最大卖点是O(1)时间判断某个元素是否存在以及支持集合运算——交集、并集、差集。实际用起来最常见的场景是做标签和去重。比如一个文章系统你需要记录哪些用户点赞了某篇文章防止重复点赞传统方案还得先查库再判断Redis轻松搞定# 用户给文章点赞把用户ID丢进集合 SADD like:article:10086 user:9527 # 判断这个人是否已经点过赞 SISMEMBER like:article:10086 user:9527 # 取消点赞 SREM like:article:10086 user:9527 # 获取所有点赞用户统计点赞数 SCARD like:article:10086如果说Set是无序的数据结构那么ZSet有序集合就相当于在Set上加了分数score维度集合里的每个元素都关联一个分值Redis按分值排序你可以随时取TopN。这基本是排行榜功能的标配# 记录游戏玩家得分 ZADD leaderboard 9527 player_alice ZADD leaderboard 8800 player_bob # 获取排行榜前10名 ZREVRANGE leaderboard 0 9 WITHSCORES # 查看某玩家排名从0开始计数 ZRANK leaderboard player_alice # 给玩家加分 ZINCRBY leaderboard 100 player_aliceZSet的底层实现是跳表加哈希表插入和查询的时间复杂度都是O(log n)数据量在几千万级别时依然能跑得飞快。做排行榜、延迟队列用score存时间戳、滑动窗口限流ZSet都是好用的工具。3.5 数据类型的选型思路总结在具体项目里纠结应该用哪种数据类型的人不少我给一个简单的判断流程如果你只缓存一个序列化后的整体对象字段之间的独立性不重要用String。 如果你需要频繁增删改某个对象的子字段且不想为一次修改而读写整个对象用Hash。 如果你只是按顺序存一批数据需要从两端压入弹出用List。 如果你只关心一个元素是否存在以及哪些元素跟哪些元素有交集用Set。 如果你需要排顺序、取TopN、做范围查询用ZSet。 如果你要存一份毫秒级自动过期的键值对String配EX参数就够了。还有一个容易忽略的点同一种数据用不同结构存内存开销差异可能好几倍。同样是存100万个数字字符串String可能比Hash费更多内存因为每个键都有独立的SDS头、dictEntry等元数据。Redis里有个命令MEMORY USAGE key可以查看单个键的内存占用当你怀疑内存增长不合理时用它做排查非常高效。4. 生产环境里的高频坑位清单4.1 键过期机制的误解不是到了时间就立刻删除很多人以为Redis的过期键在TTL一到就立刻被物理删除这是对惰性删除策略最典型的误解。实际情况是键到了过期时间只是被视为不可用真正被物理删除发生在后续访问它的时候。Redis主流的过期删除策略是惰性删除加定期删除惰性删除的触发点是某次访问发现该键已过期。这个机制带来的直接后果是一个键过期了如果一直没人访问它它可能会在内存里多存活一段时间直到Redis的周期任务扫描到它并清理。这个周期任务默认每秒运行10次每次随机采样一部分过期键进行删除。如果过期键太多、清理速度跟不上过期键会短暂占用内存。在高写入场景下内存拐点往往就出现在这里。我踩过一次真实案例某活动接口设置了大量5分钟过期的key结果活动结束瞬间MySQL慢查询暴涨。排查后发现是大量访问命中了那些过期但未物理删除的keyRedis在访问时执行惰性删除删除过程虽然快但删除命令的批量触发挤占了部分CPU时间片间接拖慢了整体请求。后来我调整了hz配置默认10可适当提高到30清理频率高了过期键占内存的窗口自然变小。这个参数增加也会消耗一点CPU生产环境调优时需要权衡。4.2 持久化该怎么选RDB与AOF的相爱相杀Redis是内存数据库如果配置没做好持久化进程一崩内存里的数据全没。这是新手最容易忽略的灾难级问题。RDBRedis Database Backup是定期把内存里的全部数据快照写入磁盘优点是恢复速度快、文件体积小、冷备方便缺点是两次快照之间的数据如果进程崩溃就会丢失。AOFAppend Only File是把每一条写命令追加到日志文件优点是数据丢失窗口小默认每秒刷盘一次缺点是文件体积大、恢复时重放日志比较慢。我生产环境采用的方案是AOF开启且appendfsync设为everysec同时保留RDB做定期备份。这个折中方案能保证最多丢失一秒的数据性能损耗也基本可以接受。如果你对数据丢失完全零容忍那应该是everysec改写为always但每写一条命令就刷盘一次的代价是吞吐量明显下降业务量大的场景别轻易用。补充一个运维细节Redis 7.x开始Redis可以自动触发AOF文件的重写把重复命令合并压缩。老版本需要手动执行BGREWRITEAOF。不管哪个版本定期关注磁盘上AOF文件有没有无限膨胀都是合格运维的基本功。4.3 慢查询日志发现性能瓶颈的第一把火不要等到Redis响应变慢才开始怀疑代码。我习惯了在生产环境配置慢查询日志把执行时间超过指定阈值的命令全部记录下来然后定期分析# 执行时间超过10毫秒的命令记入慢查询日志 slowlog-log-slower-than 10000 # 最多保留128条慢日志 slowlog-max-len 128设置好后用SLOWLOG GET就能查看最近记录的慢命令用SLOWLOG RESET清空。我实际排查过的慢命令主要有三类不带限制的KEYS *遍历所有键生产环境千万不能执行会阻塞Redis单线程直接卡死正确替代方案是用SCAN游标式遍历HGETALL一个大HashLRANGE一个大List的深分页。Redis是单线程处理命令任何一个慢命令执行期间其他所有命令都得排队等它。这不是慢一点点的概念而是整条时间线上的所有客户端都被拖住。所以性能优化的思路永远是找到那个最耗时的操作干掉它全盘提速。4.4 大Key和热KeyRedis性能的头号杀手大Key指的是某个key的value特别大比如一个Hash里有几百万个字段或者一个String值有几MB。这种key就像队伍里的拖油瓶操作它耗时删除它也耗时传输它也耗时。我在一次运维中见过一个List存了千万条消息光是LLEN命令返回长度都要几十毫秒因为链表的长度统计需要遍历。处理大Key的套路是拆分。比如一个大Hash可以按用户ID范围拆成多个子Hashkey设计为user:hash:1、user:hash:2这种带分片标识的形式。这个过程看起来要动业务代码但它换来的是整个Redis实例的稳定投入产出比极高。热Key则是一个key被超高频率访问导致单个Redis实例上的某个分片负载剧增其他分片闲着。最常见的解法是给热Key加上随机后缀拆成多个key分散到不同分片上读的时候随机挑一个。比如一个爆款文章的阅读数readcount:article:12345这个key如果访问量巨大可以拆成readcount:article:12345:01到readcount:article:12345:10十个键每次INCR随机选一个读取时SUM十个再展示。这是老运维们心照不宣的实用招数。5. 让Redis跑得稳监控、备份与内存策略5.1 你至少要盯住的四个监控指标很多公司对Redis的监控就停留在CPU高不高内存满没满这其实远远不够。我在实践中总结出四个必看指标任何一个有异常都值得立刻排查命中率。命令INFO stats里的keyspace_hits和keyspace_misses命中率 hits / (hits misses)。如果命中率持续低于80%说明你的缓存设计可能在大量查询根本不存在的key缓存的意义被削弱。要么提前把热点数据预热进去要么调整过期时间。内存碎片率。命令INFO memory里的mem_fragmentation_ratio这个值正常情况下在1到1.5之间。如果远大于1.5说明内存碎片严重Redis无法有效利用内存可考虑重启实例有一定代价或用MEMORY PURGE需要开启jemalloc。如果小于1说明Redis使用了swap性能会急剧下降必须立刻排查是不是内存超配了。键值总数与过期键占比。INFO keyspace里能看到每数据库的键数量、有过期时间的键数量、平均TTL。如果过期键占比异常高说明很多缓存注定是短期流量需要检查业务设计是否合理。连接数。INFO clients里的connected_clients。Redis的默认最大连接数是10000由maxclients控制。连接数告警并不总是因为客户端太多有时候是某个服务端的连接池配置没释放连接导致连接泄漏。这类问题常见的特征就是连接数随时间持续单调上升不回落。5.2 备份和恢复别等数据没了才想起这份笔记Redis备份说白了就两条路RDB快照文件和AOF日志。我的固定备份策略是每天凌晨低峰期执行BGSAVE生成RDB快照把快照文件加上日期后缀复制到异地存储。AOF因为开启everysec模式本身也有秒级恢复能力两者配合既保证了越快越好的故障恢复又降低了丢失窗口。恢复流程先说RDB把备份的dump.rdb文件放到Redis的dir目录配置文件里的dir参数或者CONFIG GET dir确认一下重启Redis即可加载。注意别放错目录加载的是当前dir目录下的rdb文件。再说AOF恢复Redis启动时优先加载AOF文件如果AOF文件存在Redis会忽略RDB直接加载AOF。如果你同时开启了两者而AOF文件因为意外被截断了Redis会拒绝启动并报错这时用redis-check-aof --fix工具修复。我遇到过AOF文件损坏的事故当时用这个工具修完了数据恢复了一大部分但有些尾部数据确实救不回来。这也是为什么我坚持RDBAOF双保险的原因。5.3 内存淘汰策略里那些文档没写透的底层逻辑内存淘汰策略是Redis的兜底机制它决定了内存达到maxmemory上限时Redis会怎么对待新写入的请求。maxmemory-policy有多个可选值我在实际项目里见到最多的抽查是allkeys-lru和volatile-lru。allkeys-lru是对所有键不论有没有设置过期时间按最近最少使用优先级淘汰适合纯粹的缓存场景。volatile-lru则只淘汰设置了过期时间的键如果你有些键希望永久保留就设置volatile策略让它们逃过淘汰但我个人不推荐这种依赖有没有设过期时间来决定生死的做法因为一旦某天你给一个关键键忘了设过期时间它在内存压力下反而成了幸存者而真正该保留的数据可能被淘汰逻辑本末倒置。说完LRU说LFU。如果你用的是Redis 4.0之后的版本allkeys-lfu和volatile-lfu也是可选方案。LRU只看多久没访问“LFU”看多不常被访问——一个每两天被访问一次的键按LRU可能在别的键被频繁访问时被淘汰但按LFU就会保留因为它的访问频率高于那些只在某一天爆发的热点键。在访问模式呈周期性或者脉冲形的业务里LFU往往比LRU更贴切。这个配置没有绝对的对错最好根据业务的访问模型做一个小实验再定。如果拿不准默认的allkeys-lru在大多数缓存场景下不会出大错这是无数工程实践验证过的一个稳妥起点。5.4 高可用怎么搭主从复制与哨兵的第一课等到你的Redis开始承载真实流量单机模式就不太保险了。任何一个宕机都意味着缓存雪崩、数据库被压垮的可能所以高可用不是以后再说而是迟早要做。最基础的高可用架构是主从复制加哨兵。主节点Master负责写从节点Slave负责读和冗余备份哨兵进程监控主节点如果主节点挂了哨兵自动把一个从节点提升为主节点客户端通过哨兵获取当前主节点地址。这个过程在Redis里叫故障转移做到这一步你的Redis才算勉强具备生产级别的高可用能力。配置文件里的关键设置# 从节点配置指定主节点地址和端口 replicaof 192.168.1.10 6379 # 主节点如果设置了密码从节点也需要配置 masterauth your_password # 只做备份不参与选举的从节点 replica-read-only yes主从复制有一个刚上手时容易蒙的细节主从复制是异步的。也就是说主节点写成功后立即返回客户端ACK复制数据到从节点是后台异步进行的。如果主节点还没把数据同步给从节点就挂了这些最新写入的数据会丢失。Redis复制机制在默认配置下存在丢失窗口这也是很多银行、支付类项目坚持不用Redis存核心交易数据的原因之一。哨兵配置本身也是一套独立的配置文件至少需要三个哨兵实例才能组成一个合法的投票集群防止误判。这块配置相对繁琐但如果你打算做架构升级值得提前花时间了解因为它是Redis生产环境的最后一道防线。6. 写了这么多最后给你两条实在建议第一如果你刚开始用Redis别急着把花里胡哨的结构都塞进代码。先用好String和Hash这两个类型解决八成日常需求等真实业务场景出现不得不的时刻再引入其他类型。Redis这个东西的设计哲学就是简单工具灵活组合硬套结构反而容易制造复杂度。第二把redis-cli --stat和redis-cli --bigkeys这两条命令存进收藏夹。前者每秒输出一次实时统计信息看着不费脑后者扫描整个实例里最大的若干key帮你发现潜在的大Key用户。工具其实已经非常完善难的是你愿不愿意花几分钟在代码写完后检查一下自己的键设计是否合理。我见过很多线上故障本质上不是Redis有问题而是使用它的人没有摸清它的脾性。Redis学到这个程度安装、数据结构、持久化、高可用这些骨架已经在你脑子里了剩下的就是在真实的业务流里不断摩擦、补丁、再迭代。希望这篇横跨下载-安装-数据类型-生产运维的长文能成为你路上的那份参考手册遇到问题随时翻出来看看。踩坑这种事前人记录得越详细后人走弯路的时间就越短。