Day65-66 - Redis 核心原理与数据类型
本部分涵盖 Redis 核心知识,包括 NoSQL 概述、数据类型、持久化和发布订阅。
1. NoSQL 概述
1.1 NoSQL 分类
| 类型 |
代表产品 |
特点 |
| KV 存储 |
Redis, Memcached |
高性能,简单 |
| 文档数据库 |
MongoDB, Elasticsearch |
半结构化存储 |
| 列式存储 |
HBase, ClickHouse |
海量存储 |
| 图数据库 |
Neo4j |
关系图谱 |
1.2 Redis 特点
据《Redis 核心知识点》(掘金),Redis 的核心特点:
- 纯内存存储:纳秒级访问,性能极高
- 单线程模型:避免锁竞争,简化实现
- IO 多路复用:epoll 高效处理并发
- 丰富数据结构:8 种数据类型
1.3 Redis vs Memcached
| 特性 |
Redis |
Memcached |
| 数据类型 |
8 种 |
简单 KV |
| 持久化 |
支持 |
不支持 |
| 集群 |
支持 |
不支持 |
| 事务 |
支持 |
不支持 |
| 内存管理 |
自有实现 |
slab |
2. Redis 数据类型
2.1 String 类型
# 基本操作
SET key value
GET key
MSET key1 value1 key2 value2
MGET key1 key2
# 数值操作
INCR counter # +1
INCRBY counter 10 # +10
DECR counter # -1
DECRBY counter 5 # -5
INCRBYFLOAT score 1.5 # +1.5
# 过期时间
SET key value EX 60 # 60秒过期
SET key value PX 60000 # 60000毫秒过期
SETEX key 60 value # 设置值并指定过期时间
TTL key # 查看剩余过期时间
2.2 Hash 类型
# 基本操作
HSET user:1001 name "张三"
HSET user:1001 age 25
HGET user:1001 name
HGETALL user:1001
# 批量操作
HMSET user:1002 name "李四" age 30 email "li@example.com"
HMGET user:1002 name age
# 计数操作
HINCRBY user:1001 login_count 1
HINCRBYFLOAT user:1001 score 0.5
# 其他操作
HLEN user:1001 # 字段数量
HEXISTS user:1001 name # 字段是否存在
HKEYS user:1001 # 获取所有字段名
HVALS user:1001 # 获取所有值
2.3 List 类型
# 基本操作
LPUSH list_key item1 # 左侧插入
RPUSH list_key item2 # 右侧插入
LPOP list_key # 左侧弹出
RPOP list_key # 右侧弹出
# 范围操作
LRANGE list_key 0 -1 # 获取全部元素
LRANGE list_key 0 9 # 获取前10个
# 阻塞操作
BLPOP list_key 0 # 阻塞左侧弹出
BRPOP list_key 0 # 阻塞右侧弹出
# 其他操作
LLEN list_key # 列表长度
LINSERT list_key BEFORE "item1" "item0" # 插入
LREM list_key 2 "item" # 删除指定元素
2.4 Set 类型
# 基本操作
SADD tags "java" "redis" "mysql"
SREM tags "mysql"
SMEMBERS tags
SISMEMBER tags "java" # 判断是否成员
# 集合运算
SINTER tags1 tags2 # 交集
SUNION tags1 tags2 # 并集
SDIFF tags1 tags2 # 差集
# 计数
SCARD tags # 集合大小
SRANDMEMBER tags 2 # 随机获取N个
# 移动
SMOVE source dest member
2.5 ZSet 类型
# 基本操作
ZADD leaderboard 100 "张三"
ZADD leaderboard 200 "李四"
ZADD leaderboard 150 "王五"
# 按分数排序
ZRANGE leaderboard 0 -1 WITHSCORES # 升序
ZREVRANGE leaderboard 0 -1 WITHSCORES # 降序
# 按分数范围查询
ZRANGEBYSCORE leaderboard 100 200 # 100-200分
ZRANGEBYSCORE leaderboard -inf +inf # 所有
# 排名
ZRANK leaderboard "张三" # 获取排名(0开始)
ZREVRANK leaderboard "张三" # 降序排名
# 计数
ZCARD leaderboard # 成员数量
ZCOUNT leaderboard 100 200 # 分数范围内数量
2.6 Bitmap 类型
# 位操作
SETBIT user:login:20240101 10086 1 # 设置用户10086登录
GETBIT user:login:20240101 10086 # 获取登录状态
BITCOUNT user:login:20240101 # 统计登录人数
# 位运算
BITOP AND result key1 key2
BITOP OR result key1 key2
2.7 HyperLogLog 类型
# 基数统计(百万级数据只需12KB)
PFADD page:20240101 "192.168.1.1"
PFADD page:20240101 "192.168.1.2"
PFCOUNT page:20240101 # 估算UV数量
# 合并
PFMERGE result page20240101 page20240102
2.8 GEO 类型
# 地理位置
GEOADD cities 116.40 39.90 "北京"
GEOADD cities 121.47 31.23 "上海"
# 距离计算
GEODIST cities "北京" "上海" km
# 附近的人
GEORADIUS cities 116.40 39.90 100 km WITHDIST
3. Redis 持久化
3.1 RDB 持久化
# 手动触发
BGSAVE # 后台异步保存
SAVE # 同步保存(阻塞)
# 配置自动触发
save 900 1 # 900秒内≥1个key变化
save 300 10 # 300秒内≥10个key变化
save 60 10000 # 60秒内≥10000个key变化
# 配置文件
dir /var/lib/redis
dbfilename dump.rdb
# rdb 通过 fork 子进程实现
# 1. fork 出一个子进程
# 2. 子进程遍历内存数据写入临时文件
# 3. 写入完成后替换原文件
3.2 AOF 持久化
# 开启 AOF
appendonly yes
appendfilename "appendonly.aof"
# 同步策略
appendfsync always # 每次写入都同步(最安全,性能差)
appendfsync everysec # 每秒同步(默认,推荐)
appendfsync no # 操作系统决定(性能最好,可能丢数据)
# AOF 重写
BGREWRITEAOF # 手动触发重写
auto-aof-rewrite-percentage 100 # 文件大小增长100%时重写
auto-aof-rewrite-min-size 64mb # 文件≥64MB时可能重写
3.3 混合持久化
# 开启混合持久化
aof-use-rdb-preamble yes
# 工作原理
# 1. 重写时,先以 RDB 格式写入
# 2. 然后追加 AOF 操作
# 3. 恢复时,先加载 RDB,再执行增量 AOF
3.4 持久化对比
| 特性 |
RDB |
AOF |
混合 |
| 文件大小 |
小 |
大 |
中 |
| 恢复速度 |
快 |
慢 |
快 |
| 数据完整性 |
可能丢数据 |
可配置 |
较完整 |
| 资源消耗 |
fork 消耗 |
持续 IO |
中 |
| 复杂度 |
简单 |
中 |
中 |
4. 发布订阅
4.1 发布订阅模式
# 订阅频道
SUBSCRIBE channel1 channel2
UNSUBSCRIBE channel1
# 订阅模式
PSUBSCRIBE news.*
# 发布消息
PUBLISH channel1 "Hello Redis"
# 查看活跃频道
PUBSUB CHANNELS
4.2 使用场景
| 场景 |
说明 |
| 消息通知 |
系统事件通知 |
| 实时聊天 |
聊天室消息推送 |
| 订阅计数 |
文章订阅功能 |
5. Redis 客户端
5.1 Python 客户端
import redis
r = redis.Redis(host='localhost', port=6379, db=0)
# String 操作
r.set('name', '张三')
r.get('name')
r.incr('counter')
# Hash 操作
r.hset('user:1', mapping={'name': '张三', 'age': 25})
r.hgetall('user:1')
# 批量操作
r.mset({'key1': 'v1', 'key2': 'v2'})
r.mget(['key1', 'key2'])
5.2 Jedis 连接池
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Jedis;
JedisPool pool = new JedisPool("localhost", 6379);
try (Jedis jedis = pool.getResource()) {
jedis.set("key", "value");
String value = jedis.get("key");
}
6. Redis 键管理
6.1 键操作
# 基本操作
EXISTS key # 检查是否存在
DEL key1 key2 # 删除
RENAME key newkey # 重命名
TYPE key # 查看类型
# 过期管理
EXPIRE key 60 # 设置过期时间(秒)
PEXPIRE key 60000 # 设置过期时间(毫秒)
EXPIREAT key timestamp # 设置过期时间戳
PERSIST key # 移除过期
# 渐进式遍历
SCAN 0 MATCH pattern COUNT 100
SSCAN set_key 0 MATCH pattern COUNT 100
HSCAN hash_key 0 MATCH pattern COUNT 100
ZSCAN zset_key 0 MATCH pattern COUNT 100