前面将多线程、锁、线程安全部分内容完整了解了一遍,接下来准备点啥呢?发现最开始Redis部分的内容写的有些凌乱,想着趁着这次机会把Redis部分从头到尾梳理一遍,如果想了解或者梳理Redis知识的小伙伴,看这个系列的几篇Redis文章就够了~
第1章:Redis 简介与概览
1.1 什么是Redis?
如果把传统的关系型数据库(如MySQL)比作一个"大型仓库"------数据存放有序但存取较慢,那么Redis就是一个"超高速工作台"------所有常用工具都摆在手边,随取随用!
Redis(Remote Dictionary Server) 是一个开源的、基于内存的键值对存储系统。它不仅仅支持简单的Key-Value,还提供了丰富的数据结构,可以用作数据库、缓存和消息中间件。
1.2 Redis为什么这么快?核心优势解析
1. 基于内存操作
就像从书架上拿书(硬盘) vs 从桌面上拿便签(内存),Redis基于内存的操作让它拥有惊人的速度:
python
# 速度对比
硬盘读取速度: 约 100MB/s
内存读取速度: 约 10GB/s
Redis读取速度: 约 100,000次/秒
2. 单线程架构
听起来反直觉?但正是Redis的"独门绝技"!想象一下:银行只有一个超级高效的柜员,但他能同时处理多个窗口的客户请求,没有内部协调的混乱。这就是Redis的单线程+IO多路复用模型:
- 避免了线程切换和锁竞争的开销
- 一个线程同时处理多个客户端请求
3. 高效的数据结构
Redis不是简单的Key-Value,而是为不同场景量身定制的数据结构服务器,就像多功能工具箱,每种数据结构都是不同的专用工具。
1.3 Redis vs 其他数据库:什么时候该用Redis?
| 场景 | 推荐使用 | 不推荐使用 |
|---|---|---|
| 热点数据缓存 | ✅ 完美适合 | ❌ |
| 会话存储(Session) | ✅ 完美适合 | ❌ |
| 排行榜/计数器 | ✅ 完美适合 | ❌ |
| 交易记录存储 | ❌ | ✅ 用MySQL |
| 复杂关联查询 | ❌ | ✅ 用MySQL |
简单判断法则 :如果你的数据需要快速读写 且不要求100%持久化安全,就用Redis!
第2章:Redis 安装与配置
2.1 Linux (Ubuntu) 安装
bash
# 1. 更新包管理器
sudo apt update
# 2. 安装Redis
sudo apt install redis-server
# 3. 启动Redis服务
sudo systemctl start redis-server
# 4. 设置开机自启
sudo systemctl enable redis-server
# 5. 检查状态
sudo systemctl status redis-server
# 6. 测试连接
redis-cli ping
# 如果返回 PONG,恭喜安装成功!
2.2 macOS 安装
bash
# 1. 使用Homebrew安装
brew install redis
# 2. 启动Redis服务(后台运行)
brew services start redis
# 3. 或者手动启动(前台运行,方便调试)
redis-server /usr/local/etc/redis.conf
# 4. 测试连接
redis-cli ping
2.3 Windows 安装
注意:官方不支持Windows,但有以下选择:
方案一:WSL2(推荐)
bash
# 在Windows Terminal中开启WSL Ubuntu,然后按照Linux步骤安装
方案二:Microsoft维护的Windows版本
- 访问:https://github.com/microsoftarchive/redis/releases
- 下载
Redis-x64-3.2.100.msi - 双击安装,Redis会作为Windows服务运行
2.4 Docker 安装(跨平台通用)
bash
# 1. 拉取最新Redis镜像
docker pull redis:latest
# 2. 运行Redis容器
docker run -d --name my-redis \
-p 6379:6379 \
-v /path/on/host:/data \
redis:latest
# 参数解释:
# -d : 后台运行
# --name : 容器名称
# -p 6379:6379 : 端口映射(主机:容器)
# -v : 数据卷挂载,持久化数据
# 3. 进入容器执行命令
docker exec -it my-redis redis-cli
# 4. 或者直接在主机连接
redis-cli -h 127.0.0.1 -p 6379
2.5 核心配置文件解读
Redis的"大脑"是redis.conf文件,让我们看看关键配置:
bash
# 找到配置文件位置
find / -name redis.conf 2>/dev/null
# 通常位置:/etc/redis/redis.conf
# 查看关键配置
cat /etc/redis/redis.conf | grep -v "^#" | grep -v "^$"
重要配置项详解:
conf
# 网络相关
bind 127.0.0.1 # 只允许本地连接,远程访问改为 0.0.0.0
port 6379 # 默认端口号
protected-mode yes # 保护模式,生产环境建议yes
# 持久化相关
dir /var/lib/redis # 数据存储目录
dbfilename dump.rdb # RDB文件名
# 内存管理
maxmemory 100mb # 最大内存限制
maxmemory-policy allkeys-lru # 内存满时的淘汰策略
# 安全相关
requirepass your_strong_password # 设置访问密码
第3章:Redis 核心数据结构 (上) - 基础五虎将
数据结构总览
Redis不是简单的Key-Value,而是数据结构服务器!就像一个多功能工具箱,每种数据结构都是不同的工具:
| 数据结构 | 比喻 | 典型应用 |
|---|---|---|
| String | 📝 便利贴 | 缓存、计数器 |
| Hash | 📋 表格 | 用户信息、对象存储 |
| List | 📚 书架 | 消息队列、最新列表 |
| Set | 🎯 集合 | 标签、共同好友 |
| Sorted Set | 🏆 排行榜 | 排行榜、延迟队列 |
3.1 String(字符串) - 万能选手
就像办公室的便利贴,简单直接,什么都能记!
bash
# ========== 基础操作 ==========
# 设置键值对
SET username "redis_learner"
# ✅ 结果:OK
# 💡 使用建议:最简单的缓存用法
# ⚠️ 雷点:如果key已存在会覆盖,慎用!
# 获取值
GET username
# ✅ 结果:"redis_learner"
# ⚠️ 雷点:如果key不存在返回nil,注意空值处理
# 设置并获取原值(原子操作)
GETSET username "new_learner"
# ✅ 结果:"redis_learner" (返回旧值)
# ✅ 现在username的值是:"new_learner"
# ========== 数字操作 ==========
# 设置数字
SET page_views 100
# 递增
INCR page_views
# ✅ 结果:101
# 💡 使用建议:完美用于计数器,原子操作不怕并发
# 增加指定数值
INCRBY page_views 5
# ✅ 结果:106
# 递减
DECR page_views
# ✅ 结果:105
# ========== 批量操作 ==========
# 批量设置
MSET user:1000:name "Alice" user:1000:age 25 user:1000:city "Beijing"
# ✅ 结果:OK
# 💡 使用建议:减少网络开销,提升性能
# 批量获取
MGET user:1000:name user:1000:age user:1000:city
# ✅ 结果:1) "Alice" 2) "25" 3) "Beijing"
# ========== 生存时间 ==========
# 设置值并指定10秒后过期
SETEX session_token 10 "abc123"
# ✅ 结果:OK
# 💡 使用建议:Session管理、验证码场景
# 设置key的生存时间(秒)
EXPIRE username 60
# ✅ 结果:(integer) 1 (设置成功)
# 查看剩余生存时间
TTL username
# ✅ 结果:(integer) 57 (剩余57秒)
String使用场景:
- 🔥 缓存HTML片段、API响应
- 🔢 文章阅读量、点赞数计数器
- 🔑 Session存储、临时令牌
- ⏰ 验证码、限流器
3.2 Hash(哈希) - 对象存储器
就像Excel表格,一个key对应多个字段,完美存储对象!
bash
# ========== 基本操作 ==========
# 设置单个字段
HSET user:1000 name "Alice"
# ✅ 结果:(integer) 1 (新增字段数)
# 同时设置多个字段
HSET user:1000 age 25 city "Beijing" profession "Engineer"
# ✅ 结果:(integer) 3
# 获取单个字段
HGET user:1000 name
# ✅ 结果:"Alice"
# 获取所有字段和值
HGETALL user:1000
# ✅ 结果:
# 1) "name"
# 2) "Alice"
# 3) "age"
# 4) "25"
# 5) "city"
# 6) "Beijing"
# 7) "profession"
# 8) "Engineer"
# 💡 使用建议:适合存储对象,但字段不宜过多(建议<1000)
# ⚠️ 雷点:字段太多会占用大量内存,考虑分拆
# ========== 批量操作 ==========
# 批量获取指定字段
HMGET user:1000 name age
# ✅ 结果:1) "Alice" 2) "25"
# ========== 数字操作 ==========
# 字段值递增
HINCRBY user:1000 age 1
# ✅ 结果:(integer) 26
# 💡 使用建议:用户年龄更新、积分变动等
# ========== 查询操作 ==========
# 获取所有字段名
HKEYS user:1000
# ✅ 结果:1) "name" 2) "age" 3) "city" 4) "profession"
# 获取所有字段值
HVALS user:1000
# ✅ 结果:1) "Alice" 2) "26" 3) "Beijing" 4) "Engineer"
# 获取字段数量
HLEN user:1000
# ✅ 结果:(integer) 4
# 检查字段是否存在
HEXISTS user:1000 email
# ✅ 结果:(integer) 0 (不存在)
Hash使用场景:
- 👥 用户信息存储
- 🛒 购物车商品信息
- 📊 对象属性缓存
3.3 List(列表) - 有序队列
就像排队的人群,可以从队头或队尾加入,保持顺序!
bash
# ========== 从左侧操作 ==========
# 从左侧插入(类似队列头部)
LPUSH tasks "task1"
# ✅ 结果:(integer) 1
LPUSH tasks "task2" "task3"
# ✅ 结果:(integer) 3
# 💡 当前列表:["task3", "task2", "task1"]
# 从左侧弹出
LPOP tasks
# ✅ 结果:"task3"
# 💡 剩余列表:["task2", "task1"]
# ========== 从右侧操作 ==========
# 从右侧插入(类似队列尾部)
RPUSH tasks "task4"
# ✅ 结果:(integer) 3
# 💡 当前列表:["task2", "task1", "task4"]
# 从右侧弹出
RPOP tasks
# ✅ 结果:"task4"
# 💡 剩余列表:["task2", "task1"]
# ========== 查询操作 ==========
# 获取列表长度
LLEN tasks
# ✅ 结果:(integer) 2
# 获取指定范围的元素
LRANGE tasks 0 -1 # 0到-1表示获取所有
# ✅ 结果:1) "task2" 2) "task1"
LRANGE tasks 0 0 # 获取第一个元素
# ✅ 结果:1) "task2"
# ========== 高级操作 ==========
# 阻塞式弹出(等待任务,超时时间5秒)
BLPOP new_tasks 5
# 💡 使用建议:消息队列场景,队列为空时等待
# ✅ 结果:如果5秒内有元素返回元素,否则返回nil
# 修剪列表,只保留指定范围
LPUSH numbers 1 2 3 4 5
LTRIM numbers 0 2 # 只保留前3个元素
LRANGE numbers 0 -1
# ✅ 结果:1) "5" 2) "4" 3) "3"
List使用场景:
- 📨 消息队列(LPUSH + BRPOP)
- 🆕 最新文章列表
- 📝 操作日志记录
3.4 Set(集合) - 无序唯一
就像数学里的集合,元素无序但唯一,适合做关系运算!
bash
# ========== 基本操作 ==========
# 添加元素
SADD tags "redis" "database" "cache"
# ✅ 结果:(integer) 3
# 添加重复元素(自动去重)
SADD tags "redis" "new_tag"
# ✅ 结果:(integer) 1 (只新增了1个)
# 获取所有元素
SMEMBERS tags
# ✅ 结果:1) "cache" 2) "database" 3) "redis" 4) "new_tag"
# ⚠️ 雷点:元素无序!不要依赖返回顺序
# 检查元素是否存在
SISMEMBER tags "redis"
# ✅ 结果:(integer) 1 (存在)
# 获取集合大小
SCARD tags
# ✅ 结果:(integer) 4
# 随机弹出一个元素
SPOP tags
# ✅ 结果:"new_tag" (随机)
# 💡 使用建议:抽奖场景
# ========== 集合运算 ==========
# 创建两个集合
SADD group_A "user1" "user2" "user3"
SADD group_B "user3" "user4" "user5"
# 交集 - 共同好友
SINTER group_A group_B
# ✅ 结果:1) "user3"
# 并集 - 所有用户
SUNION group_A group_B
# ✅ 结果:1) "user1" 2) "user2" 3) "user3" 4) "user4" 5) "user5"
# 差集 - A有B没有
SDIFF group_A group_B
# ✅ 结果:1) "user1" 2) "user2"
# 将交集存储到新集合
SINTERSTORE common_users group_A group_B
SMEMBERS common_users
# ✅ 结果:1) "user3"
Set使用场景:
- 🏷️ 文章标签系统
- 👥 社交网络共同好友
- 🎲 随机抽奖、唯一值存储
3.5 Sorted Set(有序集合) - 带分队的集合
就像游戏排行榜,每个玩家都有分数,可以按分数排序!
bash
# ========== 基本操作 ==========
# 添加带分数的成员
ZADD leaderboard 1000 "Alice"
ZADD leaderboard 850 "Bob" 1200 "Charlie" 900 "David"
# ✅ 结果:(integer) 3
# 按分数升序获取(从小到大)
ZRANGE leaderboard 0 -1 WITHSCORES
# ✅ 结果:
# 1) "Bob" 2) "850"
# 3) "David" 4) "900"
# 5) "Alice" 6) "1000"
# 7) "Charlie" 8) "1200"
# 按分数降序获取(从大到小)
ZREVRANGE leaderboard 0 -1 WITHSCORES
# ✅ 结果:
# 1) "Charlie" 2) "1200"
# 3) "Alice" 4) "1000"
# 5) "David" 6) "900"
# 7) "Bob" 8) "850"
# ========== 分数操作 ==========
# 增加成员分数
ZINCRBY leaderboard 50 "Bob"
# ✅ 结果:"900"
# 💡 使用建议:实时更新排行榜分数
# 获取成员分数
ZSCORE leaderboard "Alice"
# ✅ 结果:"1000"
# 获取成员排名(从0开始,按分数升序)
ZRANK leaderboard "Alice"
# ✅ 结果:(integer) 2 (第三名)
# 获取成员排名(按分数降序)
ZREVRANK leaderboard "Alice"
# ✅ 结果:(integer) 1 (第二名)
# ========== 范围查询 ==========
# 按分数范围查询
ZRANGEBYSCORE leaderboard 900 1100 WITHSCORES
# ✅ 结果:
# 1) "David" 2) "900"
# 3) "Alice" 4) "1000"
# 查询分数大于1000的成员
ZRANGEBYSCORE leaderboard (1000 +inf WITHSCORES
# ✅ 结果:1) "Charlie" 2) "1200"
# 查询前3名
ZREVRANGE leaderboard 0 2 WITHSCORES
# ✅ 结果:
# 1) "Charlie" 2) "1200"
# 3) "Alice" 4) "1000"
# 5) "David" 6) "900"
# ========== 统计操作 ==========
# 统计成员数量
ZCARD leaderboard
# ✅ 结果:(integer) 4
# 统计分数范围内的成员数量
ZCOUNT leaderboard 800 1000
# ✅ 结果:(integer) 3
Sorted Set使用场景:
- 🏆 游戏排行榜、热度排名
- ⏰ 延迟队列(用时间戳作为分数)
- 📈 带权重的任务调度
本章总结
Redis的"基础五虎将"各有绝活:
- String - 简单直接,万能型选手
- Hash - 对象存储,结构化专家
- List - 有序队列,消息传递高手
- Set - 无序唯一,关系运算大师
- Sorted Set - 带分排序,排行榜王者
选择数据结构的心法:
- 要存单个值? → String
- 要存对象? → Hash
- 要维护顺序列表? → List
- 要保证唯一性? → Set
- 要按分数排序? → Sorted Set
记住:选择合适的数据结构,性能提升立竿见影!
在接下来的章节中,我们将深入Redis的持久化、高可用等高级特性。准备好迎接更精彩的Redis世界吧!