Redis 中文教程
1. 核心概念
Redis(Remote Dictionary Server)是一个开源的内存数据结构存储,用作数据库、缓存和消息代理。Redis 支持多种数据结构,如字符串、哈希表、列表、集合、有序集合、位图、超日志等,使其成为一个功能强大的工具。
1.1 主要特点
- 内存存储:数据存储在内存中,提供极高的读写速度
- 持久化:支持 RDB 和 AOF 两种持久化方式
- 多种数据结构:支持字符串、哈希表、列表、集合、有序集合等
- 发布/订阅:支持消息发布和订阅功能
- 事务:支持原子性事务操作
- Lua 脚本:支持 Lua 脚本执行
- 主从复制:支持主从复制,实现高可用性
- 集群:支持 Redis Cluster 集群模式
1.2 技术栈特点
- 内存存储:数据存储在内存中,读写速度极快
- 持久化:支持 RDB 和 AOF 两种持久化方式
- 数据结构丰富:支持多种数据结构,适应不同场景
- 高可用性:支持主从复制和集群模式
- 可扩展性:支持水平扩展
2. 安装配置
2.1 安装
2.1.1 Windows 安装
- 从 Redis 官方网站 下载 Windows 版本的 Redis
- 解压到指定目录
- 运行
redis-server.exe启动服务器 - 运行
redis-cli.exe启动客户端
2.1.2 Linux 安装
使用包管理器安装:
# Ubuntu/Debian
apt-get update
apt-get install redis-server
# CentOS/RHEL
yum install redis
# 启动服务
systemctl start redis
# 设置开机自启
systemctl enable redis2.1.3 macOS 安装
使用 Homebrew 安装:
brew install redis
# 启动服务
brew services start redis2.2 基本配置
Redis 的配置文件通常位于 /etc/redis/redis.conf(Linux)或 Redis 安装目录下的 redis.windows.conf(Windows)。
主要配置项:
# 绑定地址
bind 127.0.0.1
# 端口号
port 6379
# 守护进程模式
daemonize yes
# 密码
requirepass your_password
# 持久化配置
# RDB 持久化
save 900 1
save 300 10
save 60 10000
# AOF 持久化
appendonly yes
appendfsync everysec2.3 启动 Redis
2.3.1 启动服务器
# Linux/macOS
redis-server /etc/redis/redis.conf
# Windows
redis-server.exe redis.windows.conf2.3.2 启动客户端
# 基本连接
redis-cli
# 指定主机和端口
redis-cli -h host -p port
# 使用密码连接
redis-cli -a password3. 基本使用
3.1 字符串操作
3.1.1 设置和获取值
# 设置键值对
SET key value
# 获取值
GET key
# 设置键值对并指定过期时间(秒)
SETEX key seconds value
# 设置键值对并指定过期时间(毫秒)
PSETEX key milliseconds value
# 仅当键不存在时设置
SETNX key value
# 同时设置多个键值对
MSET key1 value1 key2 value2
# 同时获取多个值
MGET key1 key23.1.2 字符串操作
# 获取字符串长度
STRLEN key
# 追加字符串
APPEND key value
# 自增
INCR key
# 自增指定值
INCRBY key increment
# 自减
DECR key
# 自减指定值
DECRBY key decrement
# 自增浮点数
INCRBYFLOAT key increment3.2 哈希表操作
3.2.1 设置和获取哈希字段
# 设置哈希字段
HSET key field value
# 获取哈希字段
HGET key field
# 仅当字段不存在时设置
HSETNX key field value
# 同时设置多个哈希字段
HMSET key field1 value1 field2 value2
# 同时获取多个哈希字段
HMGET key field1 field2
# 获取所有哈希字段和值
HGETALL key
# 获取所有哈希字段
HKEYS key
# 获取所有哈希值
HVALS key
# 获取哈希字段数量
HLEN key
# 检查字段是否存在
HEXISTS key field
# 删除哈希字段
HDEL key field1 field23.2.2 哈希表数值操作
# 自增哈希字段值
HINCRBY key field increment
# 自增哈希字段浮点数
HINCRBYFLOAT key field increment3.3 列表操作
3.3.1 基本操作
# 从左侧插入元素
LPUSH key value1 value2
# 从右侧插入元素
RPUSH key value1 value2
# 从左侧弹出元素
LPOP key
# 从右侧弹出元素
RPOP key
# 获取列表长度
LLEN key
# 获取列表元素(索引从0开始)
LRANGE key start stop
# 获取指定索引的元素
LINDEX key index
# 设置指定索引的元素
LSET key index value
# 在指定元素前插入元素
LINSERT key BEFORE pivot value
# 在指定元素后插入元素
LINSERT key AFTER pivot value
# 删除指定数量的元素
LREM key count value
# 保留指定范围的元素
LTRIM key start stop
# 阻塞弹出元素
BLPOP key1 key2 timeout
BRPOP key1 key2 timeout3.4 集合操作
3.4.1 基本操作
# 添加元素
SADD key member1 member2
# 移除元素
SREM key member1 member2
# 获取所有元素
SMEMBERS key
# 检查元素是否存在
SISMEMBER key member
# 获取集合大小
SCARD key
# 随机获取元素
SRANDMEMBER key [count]
# 随机弹出元素
SPOP key [count]3.4.2 集合运算
# 交集
SINTER key1 key2
# 并集
SUNION key1 key2
# 差集
SDIFF key1 key2
# 交集存储到新集合
SINTERSTORE destination key1 key2
# 并集存储到新集合
SUNIONSTORE destination key1 key2
# 差集存储到新集合
SDIFFSTORE destination key1 key23.5 有序集合操作
3.5.1 基本操作
# 添加元素(带分数)
ZADD key score1 member1 score2 member2
# 移除元素
ZREM key member1 member2
# 获取元素分数
ZSCORE key member
# 获取元素排名(从小到大)
ZRANK key member
# 获取元素排名(从大到小)
ZREVRANK key member
# 获取指定范围的元素(从小到大)
ZRANGE key start stop [WITHSCORES]
# 获取指定范围的元素(从大到小)
ZREVRANGE key start stop [WITHSCORES]
# 获取指定分数范围的元素(从小到大)
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
# 获取指定分数范围的元素(从大到小)
ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]
# 获取集合大小
ZCARD key
# 获取指定分数范围的元素数量
ZCOUNT key min max
# 增加元素分数
ZINCRBY key increment member
# 删除指定排名范围的元素
ZREMRANGEBYRANK key start stop
# 删除指定分数范围的元素
ZREMRANGEBYSCORE key min max3.6 通用操作
# 删除键
DEL key1 key2
# 检查键是否存在
EXISTS key
# 设置键过期时间(秒)
EXPIRE key seconds
# 设置键过期时间(毫秒)
PEXPIRE key milliseconds
# 设置键的过期时间戳(秒)
EXPIREAT key timestamp
# 设置键的过期时间戳(毫秒)
PEXPIREAT key milliseconds-timestamp
# 移除键的过期时间
PERSIST key
# 获取键的剩余过期时间(秒)
TTL key
# 获取键的剩余过期时间(毫秒)
PTTL key
# 重命名键
RENAME key newkey
# 仅当新键不存在时重命名
RENAMENX key newkey
# 查看键的类型
TYPE key
# 查找匹配的键
KEYS pattern
# 随机获取一个键
RANDOMKEY
# 清空当前数据库
FLUSHDB
# 清空所有数据库
FLUSHALL4. 高级功能
4.1 持久化
4.1.1 RDB 持久化
RDB(Redis Database)是一种快照持久化方式,将某个时间点的数据库状态保存到磁盘。
配置:
# 900秒内有1个键变化时保存
save 900 1
# 300秒内有10个键变化时保存
save 300 10
# 60秒内有10000个键变化时保存
save 60 10000
# RDB 文件路径
dir /var/lib/redis
# RDB 文件名
dbfilename dump.rdb
# 压缩 RDB 文件
rdbcompression yes手动触发 RDB 持久化:
SAVE # 同步保存
BGSAVE # 异步保存4.1.2 AOF 持久化
AOF(Append Only File)是一种追加式持久化方式,将所有写操作命令追加到文件中。
配置:
# 启用 AOF
appendonly yes
# AOF 文件名
appendfilename "appendonly.aof"
# 同步策略:always(每次操作)、everysec(每秒)、no(由操作系统决定)
appendfsync everysec
# 重写时是否同步
no-appendfsync-on-rewrite no
# 重写触发条件
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb手动触发 AOF 重写:
BGREWRITEAOF4.2 主从复制
主从复制允许将一个 Redis 服务器(主服务器)的数据复制到多个 Redis 服务器(从服务器)。
4.2.1 配置主从复制
主服务器配置:
# 绑定地址
bind 0.0.0.0
# 端口
port 6379
# 密码
requirepass your_password从服务器配置:
# 绑定地址
bind 0.0.0.0
# 端口
port 6380
# 主服务器地址和端口
replicaof 127.0.0.1 6379
# 主服务器密码
masterauth your_password4.2.2 查看复制状态
# 主服务器查看从服务器信息
INFO replication
# 从服务器切换为主服务器
REPLICAOF NO ONE4.3 事务
Redis 事务允许将多个命令打包执行,保证原子性。
# 开始事务
MULTI
# 执行命令(入队)
SET key1 value1
SET key2 value2
GET key1
# 执行事务
EXEC
# 取消事务
DISCARD4.4 Lua 脚本
Redis 支持执行 Lua 脚本,提供原子性操作。
# 执行 Lua 脚本
EVAL "return redis.call('SET', KEYS[1], ARGV[1])" 1 key value
# 执行 Lua 脚本(使用脚本缓存)
SCRIPT LOAD "return redis.call('SET', KEYS[1], ARGV[1])"
# 返回脚本 SHA1 值
# 使用脚本 SHA1 值执行
EVALSHA sha1 1 key value
# 查看脚本是否存在
SCRIPT EXISTS sha1
# 清除所有脚本缓存
SCRIPT FLUSH
# 杀死正在执行的脚本
SCRIPT KILL4.5 发布/订阅
Redis 支持发布/订阅模式,用于消息传递。
4.5.1 发布消息
# 发布消息到频道
PUBLISH channel message4.5.2 订阅频道
# 订阅频道
SUBSCRIBE channel1 channel2
# 订阅模式
PSUBSCRIBE pattern*
# 取消订阅
UNSUBSCRIBE channel1 channel2
# 取消模式订阅
PUNSUBSCRIBE pattern*4.6 集群
Redis Cluster 提供了自动分片和高可用性。
4.6.1 配置集群
- 创建集群配置文件:
# 端口
port 7000
# 集群模式
cluster-enabled yes
# 集群配置文件
cluster-config-file nodes-7000.conf
# 集群超时时间
cluster-node-timeout 15000
# 绑定地址
bind 0.0.0.0启动多个 Redis 实例(至少 3 个主节点)
创建集群:
redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 --cluster-replicas 14.6.2 集群操作
# 查看集群信息
CLUSTER INFO
# 查看集群节点
CLUSTER NODES
# 查看键所在的槽
CLUSTER KEYSLOT key
# 查看槽的节点
CLUSTER GETKEYSINSLOT slot count5. 最佳实践
5.1 性能优化
5.1.1 内存优化
- 合理设置内存限制:使用
maxmemory配置限制 Redis 使用的最大内存 - 选择合适的内存淘汰策略:根据业务场景选择
maxmemory-policy - 使用小数据类型:如使用整型而非字符串存储数字
- 压缩数据:对于大型字符串,考虑使用压缩
- 避免大键:将大型数据结构拆分为多个小键
5.1.2 命令优化
- 使用批量命令:如
MSET、HMSET等 - 避免使用阻塞命令:如
BLPOP、BRPOP等,在生产环境中谨慎使用 - 使用管道:通过管道减少网络往返时间
- 限制
KEYS命令使用:在生产环境中使用SCAN代替KEYS - 合理使用事务:避免事务中包含过多命令
5.1.3 持久化优化
- 根据业务场景选择持久化方式:RDB 适合备份,AOF 适合数据安全
- 调整 AOF 同步策略:
everysec平衡性能和安全性 - 定期执行 AOF 重写:减少 AOF 文件大小
- 使用混合持久化:Redis 4.0+ 支持 RDB 和 AOF 混合持久化
5.2 安全性
5.2.1 访问控制
- 设置密码:使用
requirepass配置密码 - 绑定地址:限制 Redis 只监听特定地址
- 使用防火墙:限制 Redis 端口的访问
- 避免使用默认端口:修改默认端口 6379
5.2.2 数据安全
- 定期备份:定期备份 RDB 和 AOF 文件
- 使用哨兵模式:实现高可用性
- 使用集群模式:实现数据分片和高可用性
5.3 监控和维护
5.3.1 监控
- 使用
INFO命令:查看 Redis 运行状态 - 使用
MONITOR命令:实时监控命令执行 - 使用 Redis 监控工具:如 Redis Exporter + Prometheus + Grafana
5.3.2 维护
- 定期清理过期键:使用
EXPIRE设置过期时间 - 定期检查内存使用:避免内存溢出
- 定期检查持久化文件:确保数据安全
- 定期重启服务:在维护窗口重启服务,释放内存
6. 实际应用
6.1 缓存
Redis 最常见的应用场景是作为缓存,提高系统性能。
6.1.1 基本缓存
const redis = require('redis');
const client = redis.createClient({
url: 'redis://localhost:6379'
});
// 连接客户端
client.connect();
// 缓存数据
async function cacheData(key, value, expiration = 3600) {
await client.set(key, JSON.stringify(value), {
EX: expiration
});
}
// 获取缓存数据
async function getCachedData(key) {
const data = await client.get(key);
return data ? JSON.parse(data) : null;
}
// 示例使用
async function getUserData(userId) {
// 尝试从缓存获取
const cachedData = await getCachedData(`user:${userId}`);
if (cachedData) {
console.log('从缓存获取数据');
return cachedData;
}
// 缓存未命中,从数据库获取
console.log('从数据库获取数据');
const userData = {
id: userId,
name: '张三',
email: 'zhangsan@example.com'
};
// 存入缓存
await cacheData(`user:${userId}`, userData);
return userData;
}
// 使用示例
getUserData(123).then(console.log);6.1.2 缓存预热
// 缓存预热
async function warmUpCache() {
// 预加载热点数据
const hotUsers = [1, 2, 3, 4, 5];
for (const userId of hotUsers) {
const userData = {
id: userId,
name: `用户${userId}`,
email: `user${userId}@example.com`
};
await cacheData(`user:${userId}`, userData);
}
console.log('缓存预热完成');
}
// 启动时执行缓存预热
warmUpCache();6.1.3 缓存更新
// 更新缓存
async function updateCache(key, value, expiration = 3600) {
await client.set(key, JSON.stringify(value), {
EX: expiration
});
}
// 删除缓存
async function deleteCache(key) {
await client.del(key);
}
// 示例:更新用户数据
async function updateUserData(userId, updates) {
// 更新数据库
console.log('更新数据库');
// 更新缓存
const updatedUserData = {
id: userId,
name: updates.name || '张三',
email: updates.email || 'zhangsan@example.com'
};
await updateCache(`user:${userId}`, updatedUserData);
return updatedUserData;
}6.2 会话存储
Redis 适合存储用户会话,支持分布式部署。
const express = require('express');
const session = require('express-session');
const RedisStore = require('connect-redis')(session);
const redis = require('redis');
const app = express();
// 创建 Redis 客户端
const redisClient = redis.createClient({
url: 'redis://localhost:6379'
});
redisClient.connect();
// 配置会话中间件
app.use(session({
store: new RedisStore({ client: redisClient }),
secret: 'your-secret-key',
resave: false,
saveUninitialized: false,
cookie: {
maxAge: 24 * 60 * 60 * 1000 // 24小时
}
}));
// 示例路由
app.get('/login', (req, res) => {
// 模拟登录
req.session.user = {
id: 123,
name: '张三'
};
res.send('登录成功');
});
app.get('/profile', (req, res) => {
if (req.session.user) {
res.send(`欢迎,${req.session.user.name}`);
} else {
res.send('请先登录');
}
});
app.get('/logout', (req, res) => {
req.session.destroy();
res.send('登出成功');
});
app.listen(3000, () => {
console.log('服务器运行在 http://localhost:3000');
});6.3 消息队列
Redis 可以用作简单的消息队列,使用列表或发布/订阅模式。
6.3.1 基于列表的消息队列
const redis = require('redis');
const client = redis.createClient({
url: 'redis://localhost:6379'
});
// 连接客户端
client.connect();
// 发送消息
async function sendMessage(queue, message) {
await client.lPush(queue, JSON.stringify(message));
console.log('消息发送成功:', message);
}
// 接收消息
async function receiveMessage(queue) {
const message = await client.rPop(queue);
if (message) {
console.log('消息接收成功:', JSON.parse(message));
return JSON.parse(message);
}
return null;
}
// 阻塞接收消息
async function receiveMessageBlocking(queue, timeout = 0) {
const result = await client.brPop(queue, timeout);
if (result) {
console.log('消息接收成功:', JSON.parse(result.element));
return JSON.parse(result.element);
}
return null;
}
// 示例使用
async function example() {
// 发送消息
await sendMessage('tasks', { id: 1, name: '任务1' });
await sendMessage('tasks', { id: 2, name: '任务2' });
// 接收消息
await receiveMessage('tasks');
// 阻塞接收消息
await receiveMessageBlocking('tasks');
}
example();6.3.2 基于发布/订阅的消息队列
const redis = require('redis');
// 创建发布客户端
const publisher = redis.createClient({
url: 'redis://localhost:6379'
});
publisher.connect();
// 创建订阅客户端
const subscriber = redis.createClient({
url: 'redis://localhost:6379'
});
subscriber.connect();
// 订阅频道
subscriber.subscribe('notifications', (message) => {
console.log('收到通知:', JSON.parse(message));
});
// 发布消息
async function publishNotification(notification) {
await publisher.publish('notifications', JSON.stringify(notification));
console.log('通知发布成功:', notification);
}
// 示例使用
async function example() {
await publishNotification({ id: 1, title: '通知1', content: '这是一条通知' });
await publishNotification({ id: 2, title: '通知2', content: '这是另一条通知' });
}
example();6.4 计数器
Redis 适合实现各种计数器,如访问量、点赞数等。
const redis = require('redis');
const client = redis.createClient({
url: 'redis://localhost:6379'
});
// 连接客户端
client.connect();
// 增加计数器
async function incrementCounter(key) {
const count = await client.incr(key);
console.log(`${key} 计数器值: ${count}`);
return count;
}
// 增加指定值
async function incrementCounterBy(key, value) {
const count = await client.incrBy(key, value);
console.log(`${key} 计数器值: ${count}`);
return count;
}
// 获取计数器值
async function getCounter(key) {
const count = await client.get(key);
return count ? parseInt(count) : 0;
}
// 重置计数器
async function resetCounter(key) {
await client.set(key, 0);
console.log(`${key} 计数器已重置`);
}
// 示例使用
async function example() {
// 页面访问量
await incrementCounter('page:views:home');
// 文章点赞数
await incrementCounter('post:likes:123');
// 获取计数器值
const homeViews = await getCounter('page:views:home');
console.log('首页访问量:', homeViews);
// 重置计数器
await resetCounter('page:views:home');
}
example();6.5 实时排行榜
Redis 的有序集合适合实现实时排行榜。
const redis = require('redis');
const client = redis.createClient({
url: 'redis://localhost:6379'
});
// 连接客户端
client.connect();
// 添加分数
async function addScore(leaderboard, member, score) {
await client.zAdd(leaderboard, {
score: score,
value: member
});
console.log(`${member} 分数已更新: ${score}`);
}
// 获取排行榜(从高到低)
async function getLeaderboard(leaderboard, start = 0, stop = 9) {
const result = await client.zRevRangeWithScores(leaderboard, start, stop);
console.log('排行榜:');
result.forEach((item, index) => {
console.log(`${index + 1}. ${item.value}: ${item.score}`);
});
return result;
}
// 获取成员排名
async function getRank(leaderboard, member) {
const rank = await client.zRevRank(leaderboard, member);
if (rank !== null) {
console.log(`${member} 排名: ${rank + 1}`);
return rank + 1;
}
console.log(`${member} 不在排行榜中`);
return null;
}
// 获取成员分数
async function getScore(leaderboard, member) {
const score = await client.zScore(leaderboard, member);
if (score !== null) {
console.log(`${member} 分数: ${score}`);
return score;
}
console.log(`${member} 不在排行榜中`);
return null;
}
// 示例使用
async function example() {
const leaderboard = 'game:leaderboard';
// 添加分数
await addScore(leaderboard, '玩家1', 1000);
await addScore(leaderboard, '玩家2', 1500);
await addScore(leaderboard, '玩家3', 1200);
await addScore(leaderboard, '玩家4', 1800);
await addScore(leaderboard, '玩家5', 900);
// 获取排行榜
await getLeaderboard(leaderboard);
// 获取玩家排名
await getRank(leaderboard, '玩家3');
// 获取玩家分数
await getScore(leaderboard, '玩家2');
}
example();7. 总结
Redis 是一个功能强大的内存数据结构存储,具有极高的性能和丰富的功能。本文介绍了 Redis 的核心概念、安装配置、基本使用、高级功能、最佳实践和实际应用示例,希望能够帮助开发者更好地理解和使用 Redis。
7.1 主要优势
- 高性能:内存存储,读写速度极快
- 数据结构丰富:支持多种数据结构,适应不同场景
- 持久化:支持 RDB 和 AOF 两种持久化方式
- 高可用性:支持主从复制和集群模式
- 可扩展性:支持水平扩展
- 功能丰富:支持事务、Lua 脚本、发布/订阅等高级功能
7.2 适用场景
- 缓存:提高系统性能,减轻数据库压力
- 会话存储:支持分布式部署
- 消息队列:实现简单的消息传递
- 计数器:如访问量、点赞数等
- 排行榜:实时排行榜
- 实时数据:如实时监控数据
- 分布式锁:实现分布式系统的锁机制
7.3 未来展望
Redis 作为一个成熟的开源项目,不断发展和完善。未来的 Redis 可能会:
- 进一步提高性能:优化内存使用和命令执行速度
- 增强数据结构:添加更多新的数据结构和功能
- 改进集群模式:提高集群的稳定性和可靠性
- 增强安全性:提供更多安全特性
- 更好的云原生支持:适应云环境的需求
通过本文的学习,相信开发者已经对 Redis 有了全面的了解,可以开始在实际项目中使用 Redis 构建高性能的应用了。