Redis的客户端介绍
# Redis的客户端介绍
# Redis客户端
首先明确下redis的客户端是什么?
Redis是一个客户端-服务端架构的程序。服务端负责处理数据存储、处理数据的增删改查操作,并确保数据的持久性和安全性。客户端则是与Redis服务端进行通信的应用程序,通过发送命令来操作存储在服务端的数据。客户端可以是任何编程语言编写的应用程序,连接到Redis服务端并使用Redis提供的命令来操作数据。
通过以上的介绍,似乎redis客户端就只是一个发送执行给服务端的程序。但实际上,它做的不仅仅只有发送数据,而上述的介绍也只是一个简单版。Redis客户端,它除了发送数据,它还做了以下这些:
- 结果处理:接收并解析来自 Redis 服务器的响应。将结果转换为适合应用程序使用的格式,例如将字符串响应转换为 Java 对象或 Python 字典。
- 连接管理:建立、维护和关闭与 Redis 服务器的网络连接。某些高级客户端还提供连接池功能,优化多个请求之间的连接复用,提高性能。
- 事务支持:实现对 Redis 事务的支持,允许开发者将多个命令打包成一个原子操作。
- 分布式特性:在 Redis 集群模式下,自动发现集群拓扑结构,并智能路由请求到正确的节点。处理节点故障转移和重新配置等情况,保证服务的连续性。
当然,Redis的客户端能做的,远不止这些,这里就不展开介绍了。
我们使用的命令行操作redis就是一个客户端————
redis-cli
(命令行客户端) 是 Redis 官方提供的命令行客户端,它不仅能够发送命令给 Redis 服务器,还可以进行其它的一些操作。Another Redis Desktop Manager (ARCM):开源的 Redis GUI 客户端,支持 Windows、Linux 和 MacOS。它也是一个客户端,很好用,推荐。
# Redis客户端的种类
这里介绍在Java语言中,最常用的三种Redis客户端。它们分别是:
- Jedis:同步、阻塞式的 Redis Java 客户端,广泛应用于各种 Java 应用。
- Lettuce:默认被 Spring Boot 使用的异步、非阻塞 Redis Java 客户端。
- Redisson:不仅是一个 Redis 客户端,还是一个分布式对象和服务的实现库,提供了丰富的数据结构和分布式特性。
在springboot项目的开发中,如果我们想使用Redis,通常会在pom.xml
文件中引入如下坐标:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2
3
4
那么此时,springboot中默认使用的redis客户端就是Lettuce
。
Lettuce一开始就是springboot中默认的redis客户端吗?它有哪些优势,为什么不是其它的比如Redisson?
# Lettuce
Lettuce 并不是一开始就作为 Spring Boot 中默认的 Redis 客户端。在早期版本中,Spring Boot 默认使用的是 Jedis 作为其 Redis 客户端。然而,随着版本的演进和对性能及功能需求的提升,Spring Boot 在较新的版本中切换到了 Lettuce 作为默认的 Redis 客户端。
# 历史变迁
- 早期版本(Spring Boot 1.x 和早期的 2.x):
- 默认使用的 Redis 客户端是 Jedis。
- Jedis 是一个同步、阻塞式的客户端,适用于简单的 Redis 操作。
- 过渡期(Spring Boot 2.x 中期):
- Spring Boot 开始支持 Lettuce,并允许开发者通过配置选择使用 Jedis 或 Lettuce。
- 这一时期,开发者可以根据项目需求自行选择适合的客户端。
- 现代版本(Spring Boot 2.2 及之后):
- 自 Spring Boot 2.2 版本开始,默认使用 Lettuce 作为 Redis 客户端。
- Lettuce 是一个
异步、非阻塞
的客户端,提供了更好的性能和对 Redis 集群的支持。
之所以选择它,是因为它有以下几个优势:
- 性能优势:Lettuce 使用 Netty 进行网络通信,支持异步操作,能够更好地处理高并发场景。
- 集群支持:Lettuce 对 Redis 集群模式的支持更加友好,简化了集群环境下的开发和维护。
- 连接池管理:Lettuce 提供了更灵活的连接池管理机制,优化了连接复用和资源利用。
- 哨兵支持:Lettuce 对 Redis Sentinel 的支持也更为完善,提高了系统的高可用性。
当然,如果你仍然希望使用 Jedis 作为 Redis 客户端,也是可以的,下文会说明。
# 为何不采用Redisson
那为什么不使用Redisson来作为默认客户端呢?似乎它的作用更多。还支持分布式相关功能。
设计目标和定位不同
- Lettuce 和 Jedis:这两个客户端主要专注于提供与 Redis 服务器通信的基本功能,如命令执行、连接管理和事务支持。它们的设计更加轻量级,适合大多数应用场景。
- Redisson:Redisson 不仅仅是一个简单的 Redis 客户端,它还提供了大量的分布式数据结构和服务(如分布式锁、队列、集合等)。这些高级特性虽然非常有用,但并不是所有应用都需要。
性能考虑
- Lettuce:作为一个异步、非阻塞的客户端,Lettuce 提供了更好的性能,特别是在高并发场景下。它的设计使得它可以高效地处理大量请求,并且对 Redis 集群的支持也非常好。
- Redisson:虽然 Redisson 也有很好的性能表现,但由于其内置了许多高级特性和额外的功能,可能会增加一定的复杂性和开销,对于一些只需要基本 Redis 功能的应用来说,可能不是最优选择。
默认适用性
- 广泛适用性:Lettuce 和 Jedis 作为默认客户端,能够满足大部分应用场景的需求。许多开发者不需要复杂的分布式数据结构或服务,因此这两个客户端足以应对日常开发任务。
- 特定需求:Redisson 更适合那些需要利用其丰富分布式特性的项目。对于这类项目,开发者可以选择引入 Redisson 作为额外依赖。
以上三点就是不选择Redisson的主要原因,当然可能还有一些其他原因,以上只是个人观点。或许在日后默认客户端会切换成Redisson也说不定。
# 查看客户端类型
那springboot中引入data-redis 坐标后,如何查看它使用的是哪种redis客户端呢?
以下是一些常用的方式:
- 通过maven查看依赖树
如果你使用的为IDEA,那你在maven窗口中,应该可以找到对应引用jar包。如:你应该会发现 io.lettuce:lettuce-core
或 redis.clients:jedis
存在的情况。默认情况下,你应该能看到 lettuce-core
。
- 查看日志输出
Spring Boot 默认会在启动时打印出大量信息,包括使用的依赖和配置。你可以通过查看应用程序的日志输出来确定使用的 Redis 客户端。通常,在应用程序启动日志中会有关于 Redis 连接的信息,其中会提到是使用了 Lettuce 还是 Jedis。
例如,如果你看到类似以下的日志条目,说明正在使用 Lettuce:
o.s.d.r.c.LettuceConnection : Establishing new connection to Redis using Lettuce...
LettuceConnection 表示你使用的redis客户端正是lettuce。
- 通过代码调试
你可以在应用程序启动时添加一些调试代码或断点,查看实际使用的连接工厂类型:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.stereotype.Component;
@Component
public class RedisClientChecker implements ApplicationListener<ContextRefreshedEvent> {
@Autowired
private RedisConnectionFactory redisConnectionFactory;
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
// 检查 Redis 连接工厂的类型
if (redisConnectionFactory.getClass().getName().contains("Lettuce")) {
System.out.println("Using Lettuce as Redis client.");
} else if (redisConnectionFactory.getClass().getName().contains("Jedis")) {
System.out.println("Using Jedis as Redis client.");
} else {
System.out.println("Unknown Redis client in use.");
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 切换客户端
如果你想在 Spring Boot 项目中使用 Jedis 或 Redisson 作为 Redis 客户端,可以通过以下步骤进行配置。下面是详细的实现方法:
# 使用Jedis
确保你已经添加了 spring-boot-starter-data-redis
依赖,并排除默认的 Lettuce 依赖,然后引入 Jedis 依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
2
3
4
5
6
7
8
9
10
11
12
13
14
到此,使用jedis替换lettuce就完成了。在这种情况下,Spring Boot 会自动配置 JedisConnectionFactory
和 RedisTemplate
等组件,无需额外编写配置类。
尽管如此,对于大多数生产环境或更复杂的项目,推荐实现一个 RedisConfig
配置类以获得更多的控制权。这包括但不限于:
- 自定义连接池设置:例如调整最大活动连接数、空闲连接数等。
- 自定义序列化策略:为 RedisTemplate 设置特定的键值序列化器。
- 添加拦截器或其他扩展:例如日志记录、性能监控等。
- 集成分布式锁或其他高级特性:如果需要使用 Redisson 或其他高级功能。
# 配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Bean
public JedisConnectionFactory redisConnectionFactory() {
// 可以在这里进行更多自定义配置
return new JedisConnectionFactory();
}
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory());
// 设置序列化器
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new StringRedisSerializer());
return template;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
扩展一问:
为什么需要设置序列化器?
如果不进行适当的序列化就将数据存储到 Redis 中,确实可能会导致数据乱码或无法正确读取的问题。这是因为 Redis 本质上是一个键值存储系统,它只理解字节流(即二进制数据),而不直接理解高级语言中的复杂数据类型(如 Java 对象、列表、集合等)。因此,当你尝试存储这些复杂的数据结构时,必须确保它们被正确地转换为 Redis 能够理解和存储的格式。
常用的序列化器有哪些?
Spring Data Redis 提供了几种常用的序列化器,可以根据具体需求选择最适合的一种:
StringRedisSerializer
:用于字符串类型的键和值。它是最简单的序列化器,适合大多数场景。JdkSerializationRedisSerializer
:使用 Java 的内置序列化机制。适用于需要存储 Java 对象的情况,但需要注意其性能和安全性问题。JacksonJsonRedisSerializer
:基于 Jackson 库,用于 JSON 格式的序列化和反序列化。非常适合 Web 应用程序,因为它可以很好地与 RESTful API 集成。GenericToStringSerializer
:可以将任意类型的对象转换为字符串,常用于简单类型的序列化。OxmMarshaler
:使用 Spring OXM 模块进行 XML 或 JSON 序列化,适用于特定的 XML 或 JSON 数据格式。为什么向关系型数据库(如:mysql等)插入数据时不需要显式地进行序列化?
总结下,对于配置类是否实现,可以根据你的需求是否简单。
简单场景:如果你的应用非常简单,且不需要特殊配置,可以依赖 Spring Boot 的自动配置功能,不一定要实现 RedisConfig
配置类。
复杂场景:对于大多数实际项目,特别是那些需要对 Redis 行为进行精细控制的情况,实现 RedisConfig
配置类是推荐的做法,以便更好地管理和优化 Redis 的使用。
# 使用Redisson
确保你的项目中只包含 redisson-spring-boot-starter
依赖,而不要引入 spring-boot-starter-data-redis
。
因为Redisson 提供了独立且完整的 API 来与 Redis 进行交互,并且它有自己的 Spring Boot Starter (redisson-spring-boot-starter
),可以满足大多数应用场景的需求。同时spring-boot-starter-data-redis
提供的功能和 Redisson 有重叠部分,例如连接管理和数据操作。如果同时引入两者,可能会导致配置上的冗余或冲突。
# 引入依赖
所以使用Redisson只引入一个Redisson-starter就好。
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.23.5</version> <!-- 使用最新版本 -->
</dependency>
2
3
4
5
# 编写配置文件
通过 application.properties
或 application.yml
文件进行配置,根据你的 Redis 部署情况选择合适的模式(单服务器、集群、哨兵等)。
以下是单机模式的一个简单示例:
spring:
redission:
single-server:
address: "redis://localhost:6379"
connection-minimum-idle-size: 10
connection-pool-size: 64
database: 0
2
3
4
5
6
7
# 使用Redisson
直接注入 RedissonClient
并使用 Redisson 提供的各种 API。
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class MyService {
private final RedissonClient redisson;
@Autowired
public MyService(RedissonClient redisson) {
this.redisson = redisson;
}
public void performTask() {
RLock lock = redisson.getLock("myLock");
try {
if (lock.tryLock()) {
// 执行需要锁定的任务
System.out.println("Lock acquired, performing task...");
} else {
System.out.println("Failed to acquire lock.");
}
} finally {
lock.unlock();
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Redisson 提供了许多高级特性,如分布式锁、队列等,直接使用其 API 可以更高效地利用这些功能。
扩展一问:
在springboot项目中,可以同时使用Redisson和lettuce吗?