【Redis从入门到精通】第01篇:Redis是什么——从缓存神器到全栈数据库的进化之路
下一篇【第02篇】手把手安装Redis——Win/Mac/Linux三平台实战教程摘要RedisRemote Dictionary Server是一个开源的、基于内存的键值存储系统但千万别被键值存储四个字骗了——它远不止这么简单。Redis支持字符串、哈希、列表、集合、有序集合等丰富的数据结构提供持久化、主从复制、Lua脚本、事务、发布订阅等高级特性。本文从Redis的起源故事讲起梳理其版本演进历程深入对比Redis与Memcached的差异并通过实战示例展示Redis在缓存、计数器、排行榜、分布式锁等场景中的威力。无论你是准备面试还是即将在生产环境引入Redis这篇文章都能给你一个扎实的起点。一、一场意大利黑客的叛逆——Redis的起源故事要从2009年说起。意大利西西里岛一位名叫Salvatore Sanfilippo网名 antirez的程序员正忙着搞一个实时统计分析系统 LLOOGG。这个系统需要记录大量网页访问日志并做实时聚合当时他用的 MySQL 实在扛不住——不是 MySQL 不行而是关系型数据库在这种高频写入 简单查询的场景下太笨重了。antirez 心想我就是想存个计数器至于每次都建表建索引写SQL吗于是一个黑客的本能发作了——自己写一个。他用 C 语言撸了一个内存数据库数据全放在内存里操作全部 O(1)就叫它Redis (REmote DIctionary Server)。第一版代码只有几万行但核心特性已经到位五大数据结构、持久化、事务。// Redis的核心数据结构之一简单动态字符串SDSstructsdshdr{intlen;// 已使用长度intfree;// 剩余可用空间charbuf[];// 实际存储数据的字符数组};antirez 把 Redis 的初始版本发到了 Hacker News 上。然后……炸了。社区反响热烈大家发现这东西好用得离谱。于是 antirez 干脆全职维护 Redis并在 2010 年被 VMware 招安——专门写 Redis。Redis的诞生时间线 2009年 ─┬─ 2月antirez 开始写 Redis └─ 3月第一个版本发布在 GitHub 2010年 ─── VMware 聘请 antirez 全职开发 2011年 ─── Redis 2.0增加虚拟内存 2012年 ─── Redis 2.6引入 Lua 脚本支持 2013年 ─── Redis 2.8Sentinel 高可用方案 2015年 ─── Redis 3.0正式引入 Redis Cluster 2017年 ─── Redis 4.0模块系统 混合持久化 2018年 ─── Redis 5.0Stream 数据类型 2020年 ─── Redis 6.0多线程I/O ACL 2022年 ─── Redis 7.0Redis Functions ACLv2 2024年 ─── Redis 正式换用双协议许可RSALv2 SSPLv1antirez 在 2020 年宣布退出 Redis 的核心维护把接力棒交给了 Redis Labs 团队。但他写的这个小工具已经成了全球最流行的键值数据库GitHub 上 65k star被数百万开发者使用。二、Redis到底是什么换个方式理解如果你去 Google “Redis 是什么”大概率会看到一堆让人头疼的术语NoSQL、缓存、消息队列、数据结构服务器……咱们换个通俗的理解方式。2.1 一张图看懂Redis的本质┌─────────────────────────────────────────────────────────┐ │ 应用服务器群 │ │ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │ │ │ App │ │ App │ │ App │ │ App │ │ │ │ #1 │ │ #2 │ │ #3 │ │ #4 │ │ │ └──┬───┘ └──┬───┘ └──┬───┘ └──┬───┘ │ │ │ │ │ │ │ │ └─────────┼─────────┼─────────┘ │ │ │ │ │ └────────────────┼─────────┼───────────────────────────────┘ │ │ ▼ ▼ ┌─────────────────────────────────────────────────────────┐ │ Redis 服务器 │ │ ┌──────────────────────────────────────────────────┐ │ │ │ 内存数据存储 (RAM) │ │ │ │ ┌─────────┐ ┌─────────┐ ┌───────┐ ┌─────────┐ │ │ │ │ │ String │ │ Hash │ │ List │ │ Set │ │ │ │ │ │ Key→Val │ │Key→{} │ │Key→[] │ │Key→{x} │ │ │ │ │ └─────────┘ └─────────┘ └───────┘ └─────────┘ │ │ │ │ ┌─────────┐ ┌──────────────────────────────┐ │ │ │ │ │ ZSet │ │ Pub/Sub │ Lua │ Stream │ │ │ │ │ │Key→{..} │ │ 消息队列 │ 脚本│ 流式数据 │ │ │ │ │ └─────────┘ └──────────────────────────────┘ │ │ │ └──────────────────────────────────────────────────┘ │ │ │ │ │ ┌────▼─────┐ │ │ │ 持久化到 │ │ │ │ 磁盘 │ │ │ └──────────┘ │ └─────────────────────────────────────────────────────────┘ │ │ ▼ ▼ ┌─────────────────────┐ ┌──────────────────────┐ │ MySQL/PostgreSQL │ │ ElasticSearch │ │ (持久化存储) │ │ (全文搜索) │ └─────────────────────┘ └──────────────────────┘Redis 不是一个用来替代 MySQL 的数据库它是站在 MySQL 前面、为它挡子弹的缓冲区。请求先打 Redis命中就返回没命中再查 MySQL顺便把结果塞进 Redis 缓存。这套组合拳能把系统吞吐量提升几个数量级。2.2 Redis的核心特性一览特性说明一句话白话内存存储所有数据存内存读写极快跟直接访问程序变量差不多快丰富的数据结构String/Hash/List/Set/ZSet等不是只能存字符串持久化RDB快照 AOF日志断电重启数据不丢主从复制一主多从读写分离读压力大了就加从库高可用Sentinel哨兵自动故障转移主库挂了自动顶上集群Redis Cluster水平分片数据太多就分到多台机器Lua脚本原子性执行复杂操作把多个命令打包成原子操作发布订阅Pub/Sub消息模式简单的实时消息通知事务MULTI/EXEC批量命令一组命令一起执行过期策略给Key设TTL自动删除自动清理不需要手动维护三、Redis vs Memcached——谁才是缓存之王这是面试必考题也是选型时绕不开的问题。先说结论如果需要更多数据类型、持久化、高可用选Redis如果只需要简单的KV缓存Memcached也可以考虑。但下面这个表会告诉你为什么大多数公司都选了 Redis对比维度RedisMemcached谁更好数据结构String/Hash/List/Set/ZSet/Stream/Geo等仅StringRedis完胜持久化RDB AOF支持多种策略不支持重启数据全丢Redis完胜集群模式Redis Cluster原生分片需客户端一致性哈希Redis更好高可用Sentinel哨兵自动故障转移无内置方案Redis完胜单线程/多线程单线程处理命令(核心)6.0I/O多线程多线程Memcached理论更高内存管理更精细的内存管理支持压缩Slab分配可能有碎片Redis更优数据淘汰8种淘汰策略(volatile-lru/allkeys-lfu等)仅LRURedis更灵活事务MULTI/EXECLua原子操作无Redis独有发布订阅内置Pub/Sub无Redis独有Lua脚本支持原子性执行不支持Redis独有Value大小最大512MB最大1MBRedis更大网络模型epoll/kqueue异步I/O多线程锁各有优势社区活跃度GitHub 65k stars约13k starsRedis更活跃学习成本中等数据结构多低操作简单Memcached更低适用场景缓存/计数器/排行榜/分布式锁/队列纯KV缓存Redis更广补充一个冷知识Memcached 的多线程模型理论上可以榨取更多CPU性能但实际生产中Redis 6.0 引入 I/O 多线程后性能差距已大幅缩小。而且 Redis 的功能丰富度是 Memcached 无法比拟的。四、Redis的六大典型应用场景4.1 缓存Cache——最经典这是 Redis 最常见的使用方式没有之一。把热点数据放 Redis设置过期时间减少对数据库的直接访问。请求流程 用户请求 ──► Nginx ──► 应用服务 ──► Redis查缓存 │ 命中(hit) │ 未命中(miss) │ │ │ ▼ │ ▼ 返回数据 │ 查数据库获取数据 │ │ │ ▼ │ 写回Redis缓存 │ │ └────────────┘ │ ▼ 返回数据给用户# 缓存设置10秒自动过期SET user:1001:info{name:张三,level:5}EX10# 第一次查询GET user:1001:info# 返回数据# 10秒后...GET user:1001:info# (nil)缓存已过期4.2 计数器Counter——最顺手点赞数、阅读量、库存扣减、限流计数器……凡是需要1的场景Redis 的 INCR 命令都是首选。# 文章阅读量1INCR article:8848:views# 返回 1INCR article:8848:views# 返回 2INCR article:8848:views# 返回 3# 商品库存扣减SET stock:sku123100# 初始库存100DECR stock:sku123# 卖出一件库存99INCRBY stock:sku12350# 补货50件库存149为什么不用 MySQL 做计数器因为频繁UPDATE ... SET countcount1会引发行锁竞争高并发下直接拖垮数据库。而 Redis 的 INCR 是 O(1) 原子操作10万QPS轻松搞定。4.3 排行榜Leaderboard——最炫酷游戏积分榜、文章热度排行、投票排名……这些需要排序的场景ZSet有序集合简直是为此而生。# 添加玩家分数ZADD game:rank1000player:AZADD game:rank950player:BZADD game:rank1200player:CZADD game:rank880player:D# 查看排行榜Top3ZREVRANGE game:rank02WITHSCORES# 1) player:C 2) 1200# 3) player:A 4) 1000# 5) player:B 6) 950# 给C加200分ZINCRBY game:rank200player:C# 返回 14004.4 分布式锁Distributed Lock——最硬核多台服务器同时处理任务时需要保证同一时间只有一台机器在操作。Redis 的 SETNX 命令可以优雅地解决这个问题。# 获取锁NX不存在才设置EX过期时间SET lock:order:20240001server-001NX EX30# 业务处理...# 释放锁用Lua脚本保证原子性EVALif redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end1lock:order:20240001server-001⚠️ 注意简单版分布式锁如上有单点故障风险。生产环境建议使用 Redlock 算法或 Redisson 等成熟框架它们处理了锁续期、主从切换等边界情况。4.5 消息队列Message Queue——最轻量Redis 的 List 数据结构天然就是一个消息队列。LPUSH 生产消息RPOP / BLPOP 消费消息。# 生产者往队列左边塞消息LPUSH task:queuesend_email:1001LPUSH task:queuegenerate_report:2002LPUSH task:queuecompress_image:3003# 消费者从队列右边取消息阻塞等待BLPOP task:queue0# 返回task:queue, send_email:1001Redis 5.0 引入了 Stream 数据类型支持消费者组、消息确认、消息回溯等更高级的队列特性功能接近 Kafka 的简化版。4.6 去重与集合运算Set Operations——最巧妙抽奖去重防止重复中奖、共同好友、标签系统、推荐系统……Set 的交集、并集、差集运算威力巨大。# 张三的好友SADD friends:zhangsanlisiwangwuzhaoliu# 李四的好友SADD friends:lisizhangsanwangwusunqi# 共同好友交集SINTER friends:zhangsan friends:lisi# wangwu# 你可能认识的人张三好友中李四没有的SDIFF friends:zhangsan friends:lisi# zhaoliu五、5分钟跑通Redis——快速开始说再多不如跑一把。下面带你从零开始5分钟内用 Redis 完成一个计数器 排行榜的 demo。# 第1步安装RedisMac)brewinstallredis# 第2步启动Redis服务redis-server--daemonizeyes# 第3步连接Redisredis-cli# 第4步验证连接PING# 返回 PONG大功告成# 第5步玩一把计数器SET pv:homepage0INCR pv:homepage# 1INCR pv:homepage# 2INCR pv:homepage# 3GET pv:homepage# 3# 第6步搞个排行榜ZADD hot:articles100Redis入门指南ZADD hot:articles250Spring Boot实战ZADD hot:articles88Vue3从零到一ZADD hot:articles320Go语言并发编程ZREVRANGE hot:articles0-1WITHSCORES# 1) Go语言并发编程 2) 320# 3) Spring Boot实战 4) 250# 5) Redis入门指南 6) 100# 7) Vue3从零到一 8) 88# 第7步退出EXIT# 第8步停止Redisredis-clishutdown是不是超简单这六行命令已经涵盖了 Redis 最核心的两个数据类型String 和 ZSet以及日常开发中最常见的两个场景计数器、排行榜。六、Redis 到底快在哪很多人问Redis 为什么快答案是多管齐下为什么 Redis 这么快 │ ├── 1. 纯内存操作最根本原因 │ 数据全在内存中无磁盘I/O │ 单条命令通常几微秒完成 │ ├── 2. 单线程模型简化了并行控制 │ 无上下文切换开销 │ 无锁竞争所以没有死锁问题 │ 命令天然原子性 │ ├── 3. I/O多路复用epoll / kqueue │ 一个线程处理千上万的并发连接 │ ┌──────────────────────┐ │ │ Redis 单线程 │ │ │ │ │ │ epoll监听 ──► 有数据 ──► 处理命令 ──► 返回 │ │ │ │ └──────────┬───────────┘ │ │ │ ┌─────────┼─────────┐ │ ▼ ▼ ▼ │ 连接1 连接2 ... 连接N │ ├── 4. 高效的数据结构实现 │ SDS (简单动态字符串) │ 压缩列表 (ziplist) │ 跳跃表 (skiplist) —— ZSet的底层结构 │ 字典 (dict) —— Hash的底层结构 │ └── 5. Redis 6.0 I/O多线程 读写网络数据可以是多线程 命令执行仍是单线程保持原子性一句话总结Redis 是把简单做到极致的那类软件。数据结构简单、线程模型简单、通信协议简单这些简单加在一起造就了令人瞠目的性能。七、Redis 的黑历史与未来Redis 并非完美了解它的短板能帮你更好地做技术决策内存成本高数据全放内存200GB 内存的服务器比 200GB 磁盘贵得多。不过现在也有 Redis on Flash 方案。持久化问题RDB 快照有时间间隔AOF 日志可能比 RDB 大很多。虽然有混合持久化Redis 4.0但仍不能保证 100% 不丢数据。复杂的 SQL 查询Redis 不支持 SQL连范围查询都得靠有序集合的设计。复杂查询还是得用 MySQL / PostgreSQL。集群模式限制Redis Cluster 不支持跨 slot 的事务某些多 key 操作需要所有 key 在同一个 hash slot。许可证变化2024Redis 7.4 开始从 BSD 换为 RSALv2 SSPLv1 双协议许可对云厂商有限制。社区 fork 版本 Valkey 因此诞生。Redis 生态现状2024-2026 Redis (Redis Ltd.) ├── Redis 7.4 采用 RSALv2 / SSPLv1 许可 └── 云服务商需单独商业授权 Valkey (Linux Foundation) ├── Redis 7.2.4 分支保持 BSD 许可 ├── AWS / Google / Oracle 背书 └── 活跃开发中 其他兼容方案 ├── DragonflyDBRedis 协议兼容多线程 ├── Garnet微软出品C# 实现 └── KeyDB多线程版 Redis 分支本篇小结Redis 从一个黑客的小工具成长为互联网基础设施这个过程本身就是一段传奇。它用简洁的设计、直观的数据结构和极致的性能重新定义了数据库的模样。它不替代 MySQL但它让 MySQL 更加从容它不取代消息队列但它是最快上手的那一个它不是瑞士军刀但它是你工具箱里那把最好用的扳手。下一篇文章我们来动手三平台安装 Redis让你的本机真正跑起来。下一篇【第02篇】手把手安装Redis——Win/Mac/Linux三平台实战教程