Redis学习文档
1. Redis原理讲解
1.1 Redis基本概念
Redis(Remote Dictionary Server)是一个开源的、高性能的键值对存储数据库,具有以下特点:
- 内存存储:数据主要存储在内存中,访问速度极快(读写速度可达10万+ QPS)
- 持久化:支持RDB和AOF两种持久化机制,保证数据不丢失
- 多种数据结构:支持String、List、Hash、Set、Sorted Set、HyperLogLog、Geo等多种数据结构
- 单线程模型:采用单线程事件循环模型,避免了线程切换开销
- 支持分布式:通过Redis Cluster支持分布式部署
- 支持事务:支持简单的事务操作
- 支持Lua脚本:可以执行Lua脚本,实现复杂业务逻辑
1.2 Redis数据结构
项目中主要使用了以下数据结构:
| 数据结构 | 特点 | 项目中的应用 |
|---|---|---|
| String | 简单的键值对,最大512MB | 存储token、验证码、心跳时间、系统设置 |
| List | 有序的字符串列表,支持两端操作 | 存储联系人列表、会话列表 |
1.3 Redis持久化机制
Redis支持两种持久化机制:
-
RDB(Redis Database):
- 定时快照,将内存中的数据写入磁盘
- 优点:文件小,恢复速度快
- 缺点:可能丢失最后一次快照后的所有数据
-
AOF(Append Only File):
- 记录所有写操作,恢复时重新执行这些操作
- 优点:数据安全性高,最多丢失1秒数据
- 缺点:文件大,恢复速度慢
项目中使用了默认配置,通常生产环境建议同时开启RDB和AOF。
1.4 Redis连接池
项目中使用了Lettuce连接池,相比Jedis具有以下优点:
- 线程安全:Lettuce是线程安全的,一个连接可以被多个线程共享
- 异步操作:支持异步操作,提高并发性能
- 支持Redis Cluster:内置支持Redis Cluster
- 支持SSL:支持SSL连接
2. 重要参数讲解
2.1 Redis配置参数
application.yml中的Redis配置:
yaml
spring:
data:
redis:
database: 0 # Redis数据库索引(默认为0)
host: 127.0.0.1 # Redis服务器地址
port: 6379 # Redis服务器端口
timeout: 2000ms # 连接超时时间(毫秒)
lettuce: # Lettuce连接池配置
pool:
max-active: 20 # 连接池最大连接数(使用负值表示没有限制)
max-wait: PT10S # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 10 # 连接池中的最大空闲连接
min-idle: 0 # 连接池中的最小空闲连接
2.2 Redis过期时间常量
Constants.java中的Redis过期时间定义:
| 常量名 | 值 | 描述 |
|---|---|---|
| REDIS_KEY_EXPIRES_ONE_MIN | 60 | 1分钟过期时间(秒) |
| REDIS_KEY_EXPIRES_HEART_BEAT | 6 | 心跳过期时间(秒),用于维护用户在线状态 |
| REDIS_KEY_EXPIRES_DAY | 86400 | 1天过期时间(秒) |
| REDIS_KEY_TOKEN_EXPIRES | 172800 | 2天过期时间(秒),用于token过期时间 |
2.3 Redis Key前缀常量
Constants.java中的Redis Key前缀定义:
| 常量名 | 值 | 描述 |
|---|---|---|
| REDIS_KEY_CHECK_CODE | easychat:checkcode: | 验证码Key前缀 |
| REDIS_KEY_WS_TOKEN | easychat:ws:token: | WebSocket token前缀 |
| REDIS_KEY_WS_TOKEN_USERID | easychat:ws:token:userid | 用户ID到token的映射前缀 |
| REDIS_KEY_WS_USER_HEART_BEAT | easychat:ws:user:heartbeat | 用户心跳Key前缀 |
| REDIS_KEY_WS_ON_LINE_USER | easychat:ws:online: | 在线用户Key前缀 |
| REDIS_KEY_USER_CONTACT | easychat:ws:user:contact: | 用户联系人列表前缀 |
| REDIS_KEY_USER_SESSION | easychat:ws:user:session: | 用户会话列表前缀 |
| REDIS_KEY_SYS_SETTING | easychat:syssetting: | 系统设置Key前缀 |
3. 重要方法讲解
3.1 RedisUtils核心方法
RedisUtils.java是基础Redis操作封装类,提供了常用的Redis操作方法:
3.1.1 基本操作
java
// 获取指定key的值
public V get(String key)
// 普通缓存放入
public boolean set(String key, V value)
// 普通缓存放入并设置时间
public boolean setex(String key, V value, long time)
// 删除缓存
public void delete(String... key)
// 设置键的过期时间
public boolean expire(String key, long time)
3.1.2 List操作
java
// 获取列表中所有元素
public List<V> getQueueList(String key)
// 将元素插入到列表左侧(头部)
public boolean lpush(String key, V value, long time)
// 从列表中移除元素
public long remove(String key, Object value)
// 将多个元素插入到列表左侧(头部)
public boolean lpushAll(String key, List<V> values, long time)
3.2 RedisComponet业务方法
RedisComponet.java是业务层Redis操作封装类,提供了与业务相关的Redis操作:
3.2.1 用户认证相关
java
// 根据token获取用户信息
public TokenUserInfoDto getTokenUserInfoDto(String token)
// 根据用户ID获取用户信息
public TokenUserInfoDto getTokenUserInfoDtoByUserId(String userId)
// 保存用户token信息到Redis
public void saveTokenUserInfoDto(TokenUserInfoDto tokenUserInfoDto)
// 根据用户ID清除用户的token信息
public void cleanUserTokenByUserId(String userId)
3.2.2 心跳检测相关
java
// 保存用户最后心跳时间
public void saveUserHeartBeat(String userId)
// 删除用户心跳记录
public void removeUserHeartBeat(String userId)
// 获取用户心跳时间
public Long getUserHeartBeat(String userId)
3.2.3 联系人管理相关
java
// 获取用户联系人列表
public List<String> getUserContactList(String userId)
// 添加用户联系人
public void addUserContact(String userId, String contactId)
// 清空用户联系人列表
public void cleanUserContact(String userId)
// 删除用户联系人
public void removeUserContact(String userId, String contactId)
// 批量添加用户联系人
public void addUserContactBatch(String userId, List<String> contactIdList)
3.2.4 会话管理相关
java
// 获取用户会话列表
public List<String> getUserSessionList(String userId)
// 添加用户会话
public void addUserSession(String userId, String sessionId)
// 清空用户会话列表
public void cleanUserSession(String userId)
3.2.5 系统设置相关
java
// 保存系统设置
public void saveSysSetting(SysSettingDto sysSettingDto)
// 获取系统设置
public SysSettingDto getSysSetting()
4. 具体例子
4.1 用户认证示例
场景:用户登录成功后,生成token并保存到Redis中。
实现代码:
java
// 生成token
String token = StringTools.getRandomString(32);
// 创建用户信息DTO
TokenUserInfoDto tokenUserInfoDto = new TokenUserInfoDto();
tokenUserInfoDto.setToken(token);
tokenUserInfoDto.setUserId(userInfo.getUserId());
tokenUserInfoDto.setNickName(userInfo.getNickName());
// 保存到Redis
redisComponet.saveTokenUserInfoDto(tokenUserInfoDto);
Redis中存储的数据:
- Key:
easychat:ws:token:{token} - Value: TokenUserInfoDto对象(JSON格式)
- 过期时间: 2天
4.2 验证码示例
场景:用户注册或登录时,生成验证码并发送到邮箱,同时保存到Redis中。
实现代码:
java
// 生成验证码
String code = StringTools.getRandomNumber(6);
// 生成验证码key
String checkCodeKey = StringTools.getRandomString(32);
// 保存到Redis,10分钟过期
redisUtils.setex(Constants.REDIS_KEY_CHECK_CODE + checkCodeKey, code, 60 * 10);
Redis中存储的数据:
- Key:
easychat:checkcode:{checkCodeKey} - Value: 6位数字验证码(字符串)
- 过期时间: 10分钟
4.3 心跳检测示例
场景:WebSocket连接中,客户端定期发送心跳消息,服务器保存心跳时间到Redis。
实现代码:
java
// 接收到心跳消息
public void handleHeartBeat(String userId) {
// 保存心跳时间到Redis,6秒过期
redisComponet.saveUserHeartBeat(userId);
}
// 定期检查用户在线状态
public void checkOnlineStatus() {
// 获取所有在线用户
List<String> onlineUsers = getAllOnlineUsers();
for (String userId : onlineUsers) {
// 获取用户心跳时间
Long heartBeatTime = redisComponet.getUserHeartBeat(userId);
// 如果心跳时间超过10秒,则认为用户离线
if (heartBeatTime == null || System.currentTimeMillis() - heartBeatTime > 10000) {
// 处理用户离线逻辑
handleUserOffline(userId);
}
}
}
Redis中存储的数据:
- Key:
easychat:ws:user:heartbeat{userId} - Value: 心跳时间戳(Long)
- 过期时间: 6秒
4.4 联系人管理示例
场景:用户添加新联系人后,更新Redis中的联系人列表。
实现代码:
java
// 添加联系人
public void addContact(String userId, String contactId) {
// 数据库操作:添加联系人记录
userContactService.addContact(userId, contactId);
// Redis操作:添加到联系人列表
redisComponet.addUserContact(userId, contactId);
}
// 获取联系人列表
public List<String> getContactList(String userId) {
// 先从Redis获取
List<String> contactList = redisComponet.getUserContactList(userId);
if (CollectionUtils.isEmpty(contactList)) {
// Redis中没有,从数据库获取
contactList = userContactService.getContactList(userId);
// 保存到Redis
redisComponet.addUserContactBatch(userId, contactList);
}
return contactList;
}
Redis中存储的数据:
- Key:
easychat:ws:user:contact:{userId} - Value: 联系人ID列表(List)
- 过期时间: 2天
5. Redis使用最佳实践
5.1 Key设计规范
- 使用前缀 :为不同业务场景的Key添加不同前缀,如
easychat:checkcode: - 使用冒号分隔 :使用冒号分隔不同层级,如
easychat:ws:token:{token} - 避免过长Key:Key长度不宜过长,建议不超过100字节
- 使用统一命名规范:使用小写字母、数字和冒号,避免特殊字符
5.2 过期时间设置
-
根据业务场景设置合理的过期时间:
- 验证码:5-10分钟
- Token:1-7天
- 心跳:根据心跳间隔设置,建议为心跳间隔的1.5倍
- 缓存数据:根据数据更新频率设置
-
避免设置永久过期时间:除非必要,否则不要设置永久过期时间,避免Redis内存溢出
5.3 数据序列化
- 使用JSON序列化:项目中使用了JSON序列化,便于调试和跨语言使用
- 避免使用Java序列化:Java序列化效率低,且不便于跨语言使用
- 根据数据类型选择合适的序列化方式 :
- String类型:直接使用String序列化
- 对象类型:使用JSON序列化
- 二进制数据:使用二进制序列化
5.4 连接池配置
- 合理设置连接池大小:根据业务并发量设置,建议最大连接数为CPU核心数的2-4倍
- 设置合理的最大等待时间:避免线程长时间阻塞
- 设置合理的空闲连接数:根据业务低谷期的连接数设置
5.5 监控和维护
- 监控Redis使用情况:使用Redis自带的INFO命令或第三方监控工具(如RedisInsight、Prometheus+Grafana)
- 定期备份数据:开启RDB或AOF持久化,定期备份数据文件
- 避免大Key:避免存储过大的Key,如超过1MB的字符串或包含大量元素的List
- 使用Pipeline批量操作:对于批量操作,使用Pipeline提高效率
6. 总结
Redis是一个高性能的键值对存储数据库,在项目中广泛应用于用户认证、验证码、心跳检测、联系人管理、会话管理和系统设置等场景。通过合理的配置和使用,可以显著提高系统的性能和可靠性。
本文档结合项目中的实际使用情况,讲解了Redis的基本原理、重要参数、核心方法和最佳实践,希望对学习和使用Redis有所帮助。
在实际开发中,需要根据业务场景选择合适的Redis数据结构和过期时间,同时注意监控Redis的使用情况,及时发现和解决问题。