《程序猿之Redis缓存实战(1) · 基础知识》
📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗
🌻 CSDN入驻不久,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数,欢迎多多交流。👍
文章目录
- 写在前面的话
- Redis 技术简介
- Redis 数据结构
- Redis 客户端工具
- Key 的专栏
- Key 定义规范
- Key 层级结构
- SpringBoot 整合 Redis
- 专栏预告
- 总结陈词
写在前面的话
近期博客正在更新设计模式和微信小程序专栏,工作流引擎LiteFlow也才更新了一集。但由于工作繁忙起来,又忘记推迟更新进度了。
这天,刚好工作中遇到有新人提问Redis相关内容,顺势温习了之前的Redis知识,发现内容还不少,就先插播介绍一下。
荒废不多说,直接先从枯燥的基础部分来介绍。
Redis 技术简介
Redis是一个基于内存的 key-value 键值存储的、可持久化的数据库,并且提供了非常丰富的数据结构,同时还支持非常丰富的功能特性。
Redis官网:https://redis.io/
特征:
- 键值(Key-Value)型,Value支持多种不同的数据结构,功能丰富
- 单线程,每个命令具有原子性
- 低延迟,速度快(基于内存、IO多路复用、良好的编码)
- 支持数据持久化
- 支持主从集群、分片集群
- 支持多语言客户端
Redis 数据结构
Redis是典型的key-value数据库,key一般是字符串,而value包含很多不同的数据类型。
先看一下五大基础数据结构:
● 字符串(Strings): 存储字符串类型的值。
● 哈希表(Hashes): 存储字段和对应值的映射。
● 列表(Lists): 存储有序的字符串列表。
● 集合(Sets): 存储不重复的字符串集合。
● 有序集合(Sorted Sets): 类似集合,但每个元素都关联一个分数,可以按分数排序。
再看看新增的高级数据结构:
- 位图(Bitmap)
- 超日志(HyperLogLog)
- 地理空间(Geospatial)
注意事项:
学习不同的数据结构,除了掌握他们的基础命令外,应该明确各种类型分别运用在什么场景,才是最主要的。
Redis 客户端工具
【使用官方 Redis Insight】
RedisInsight 是一个强大的图形用户界面工具,旨在帮助用户更好地管理和监控 Redis 数据库。它提供了丰富的功能,包括数据浏览、性能监控、查询分析等。如果你在寻找 Redis 的可视化工具,RedisInsight 是一个非常不错的选择。你可以从 Redis 的官方网站下载并安装它。
Redis Insight 是 Redis 官方推荐的客户端工具,功能非常的齐全,不过不支持中文。
【使用第三方工具 Tiny】
强烈推荐大家使用 Tiny RDM,UI 很好看,支持中文和字体设置。
官网地址:https://redis.tinycraft.cc/zh/
下载地址:https://github.com/tiny-craft/tiny-rdm/tree/main
Key 的专栏
Key 定义规范
【背景说明】
在 Spring Boot 项目中,Redis Key 的定义需要遵循一定的规范,以确保代码的可读性、可维护性和可扩展性。
在团队开发中,制定并遵循 Redis key 的命名规范不仅能提高代码的可读性和可维护性,还能减少潜在的错误和冲突。因此,团队应该重视并共同遵循这些规范,以提高整体开发效率和代码质量。
【规范说明】
1、Key 命名规范
- 使用前缀:为不同的业务模块或功能使用不同的前缀,以避免 key 冲突,例如:user:1001:session。
- 使用冒号分隔:使用冒号(:)分隔 key 的各个部分,使其结构清晰,例如:app:module:submodule:key。
- 避免使用特殊字符:尽量避免使用空格、斜杠等特殊字符,以防止在某些情况下出现解析错误。
- 使用有意义的: Key 的名称应该清晰地描述存储的数据类型和用途,避免使用过于简短或模糊的名称。
- 使用小写字母: 为了保持一致性,建议使用小写字母命名 Key。
2、Key 的长度
控制 key 的长度:尽量保持 key 的简短,避免过长的 key 影响性能。一般建议不超过 64 个字符。
3、使用常量类
在 Spring Boot 项目中,可以定义一个常量类来集中管理 Redis 的 key。
这样可以避免硬编码,提高代码的可读性和可维护性。
另外,如果项目中有多个模块,建议集中管理 Redis 的 key 定义,避免各个模块之间的 key 冲突。
public class RedisKeys {
public static final String USER_SESSION_PREFIX = "user:";
public static String getUserSessionKey(Long userId) {
return USER_SESSION_PREFIX + userId + ":session";
}
}
4、版本控制(可选)
在 key 中加入版本号,以便在需要时进行 key 的迁移或更新。例如:user:v1:1001:session。
5、使用 Hash 数据结构(按需)
使用 Hash:对于相关联的数据,可以使用 Redis 的 Hash 数据结构来存储,减少 key 的数量。
例如,存储用户信息时,可以使用 user:1001 作为 key,用户的各个属性作为 Hash 的字段。
6、设置过期时间(按需)
对于临时数据,设置合理的过期时间,避免 Redis 中存储过多无用数据。
7、监控和清理(可选)
监控使用情况,定期监控 Redis 的 key 使用情况,清理不再使用的 key。
8、文档化(可选)
文档化 key 的用途:为每个 key 的命名和用途编写文档,方便团队成员理解和使用。
9、避免使用用户输入(可选)
避免直接使用用户输入:在生成 key 时,避免直接使用用户输入的内容,以防止注入攻击或意外的 key 冲突。
Key 层级结构
【问题背景】
Redis 没有类似数据库表空间和表的概念,那么我们该如何区分不同业务类型的Key呢?
如果都根据id直接作为Key,那如果用户ID和订单ID重复的话,岂不是乱套了?
答案是,我们可以通过给key添加前缀加以区分,不过这个前缀不是随便加的,有一定的规范。
【层级结构】
- key允许有多个单词形成层级结构,多个单词之间用
:
隔开,格式:项目名:业务名:id - 以项目名称是portal,业务是user,以此缓存为例,可以是
portal:user:001
- 注意如果业务是通用的,也可以省去项目层级,直接使用
user:001
- 在Redis的客户端工具中,也会以相同前缀作为层次结构,让数据看起来层次分明,关系清晰。
SpringBoot 整合 Redis
【知识介绍】
SpringData是Spring中数据操作的模块,包含对各种数据库的集成,其中对Redis的集成模块就叫做SpringDataRedis
官网地址:https://spring.io/projects/spring-data-redis
- 提供了对不同Redis客户端的整合(Lettuce和Jedis)
- 提供了RedisTemplate统一API来操作Redis
- 支持Redis的发布订阅模型
- 支持Redis哨兵和Redis集群
- 支持基于Lettuce的响应式编程
- 支持基于JDK、JSON、字符串、Spring对象的数据序列化及反序列化
- 支持基于Redis的JDKCollection实现
SpringDataRedis中提供了RedisTemplate工具类,其中封装了各种对Redis的操作。并且将不同数据类型的操作API封装到了不同的类型中:
【具体步骤】
Step1、引入依赖
<!-- 整合Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- JSON处理 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
Step2、添加配置
spring:
data:
redis:
host: 192.168.75.129 # Redis服务器地址
port: 6379 # Redis服务器连接端口
password: lyd # Redis服务器连接密码(默认为空)
database: 0 # Redis数据库索引(默认为0)
# 建议不要采用url的方式
# url: redis://192.168.75.129:6379 # Redis服务器的连接URL,在Spring中相当于是password+ip+port,格式为:redis://[password@]host:port[/database]
timeout: 60s # 连接空闲超过N(s秒、ms毫秒,不加单位时使用毫秒)后关闭,0为禁用,这里配置值和tcp-keepalive值一致
# Lettuce连接池配置
lettuce:
pool:
max-active: 10 # 允许最大连接数,默认8(负值表示没有限制),推荐值:大于cpu * 2,通常为(cpu * 2) + 2
max-idle: 8 # 最大空闲连接数,默认8,推荐值:cpu * 2
min-idle: 0 # 最小空闲连接数,默认0
max-wait: 5s # 连接用完时,新的请求等待时间(s秒、ms毫秒),超过该时间抛出异常,默认-1(负值表示没有限制)
Step3、添加自定义RedisTemplate
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
// 设置键序列化器为 StringRedisSerializer,所有的键都会被序列化为字符串
redisTemplate.setKeySerializer(StringRedisSerializer.UTF_8);
redisTemplate.setHashKeySerializer(StringRedisSerializer.UTF_8);
// 设置值序列化器为 GenericJackson2JsonRedisSerializer,所有的值都会被序列化为 JSON 格式
GenericFastJsonRedisSerializer serializer = new GenericFastJsonRedisSerializer();
redisTemplate.setValueSerializer(serializer);
redisTemplate.setHashValueSerializer(serializer);
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
Step4、测试效果
@SpringBootTest
@RunWith(SpringRunner.class)
public class SpringBaseTest {
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Test
public void test() {
redisTemplate.opsForValue().set("K1", "战神");
System.out.println(redisTemplate.opsForValue()
.get("K1"));
System.out.println(stringRedisTemplate.opsForValue()
.get("K1"));
}
}
专栏预告
本篇仅仅是为了知识连贯性,先介绍一篇基础部分的,后续会针对Redis各项专栏进行实战讲解。
包含但不限于:
1、五大基础结构以及三大高级结构;
2、发布订阅模式;
3、流处理模式;
4、延迟队列;
5、分布式锁;
6、各类部署方案;
7、缓存数据库一致性;
8、持久化策略;
9、缓存三大问题;
10、其他专栏,比如序列化、事务等等。。。
总结陈词
本篇算是Redis系列文章的开篇,仅简单介绍了Redis的基础知识。后续会逐个将前面提到的知识领域在实战中的用法,全部展示出来。
💗 后续会逐步分享企业实际开发中的实战经验,有需要交流的可以联系博主。