我天生就是个探索者,因此当我必须做出技术决策(比如选择 Redis 客户端)时,我会去深入探究一下。本文记录了我的探索历程,内容涉及一对 Java 客户端的押韵组合:Jedis 与 Lettuce。
让我们从基础开始,分别研究每个客户端,以了解两者之间的差异。
Lettuce 是一个完全非阻塞的 Redis Java 客户端。它同时支持同步和异步通信。其复杂的抽象使您可以轻松扩展产品和nbsp;
将 Lettuce 视为支持集群、哨兵、管道和编解码器的更高级客户端
Jedis 是 Redis 中的一个客户端库,旨在提高性能和易用性。与其他 Redis Java 客户端相比,Jedis 是一个轻量级的产品;它提供的功能更少,但仍能处理大量内存。
由于功能更简单,Jedis 更易于使用,但它只能用同步方式处理群集。如果您选择 Jedis,您可能会发现不再需要关注数据存储机制,而只需专注于应用程序和数据。
利润的终极目标,就像内裤一样,总是在那里。但您能受益的部分是选择标准。它将让我们决定何时 Jedis 是正确的选择,何时 Lettuce 是首选。这是非常重要的,因为我们都知道在选择工具时任何问题的答案都是“取决于”。
我的比较计划很简单
为了彻底了解 Jedis 与 Lettuce 的争论,让我们比较最简单的所有练习的代码:为 Redis 的单个实例设置并获取值。
首先,我们使用 Jedis 来做这件事
package com.guyroyse.blogs.lettucevsjedis;
import redis.clients.jedis.Jedis;
public class JedisSetGet {
private static final String YOUR_CONNECTION_STRING = "redis://:foobared@yourserver:6379/0";
public static void main(String[] args) {
Jedis jedis = new Jedis(YOUR_CONNECTION_STRING);
jedis.set("foo", "bar");
String result = jedis.get("foo");
jedis.close();
System.out.println(result); // "bar"
}
}
查看代码,这非常简单。创建一个连接。使用它。关闭它。
接下来,我们使用 Lettuce 来做这件事
package com.guyroyse.blogs.lettucevsjedis;
import io.lettuce.core.RedisClient;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;
public class LettuceSetGet {
private static final String YOUR_CONNECTION_STRING = "redis://:foobared@yourserver:6379/0";
public static void main(String[] args) {
RedisClient redisClient = RedisClient.create(YOUR_CONNECTION_STRING);
StatefulRedisConnection<String, String> connection = redisClient.connect();
RedisCommands<String, String> sync = connection.sync();
sync.set("foo", "bar");
String result = sync.get("foo");
connection.close();
redisClient.shutdown();
System.out.println(result); // "bar"
}
}
这看起来有点复杂。它有一个 Java 客户端、一个连接和一个命令对象。它们的名称和模板化特性表明它们可能有多种类型。除了 StatefulRedisConnection<String, String> 类型之外,我们可能有无状态的类型,它接受字节数组吗? (剧透:有很多用于集群和主/从配置的连接类型,但没有无状态类型。)
然而,一旦您完成了设置和拆除,在任一客户端中使用的基本代码都是相同的:创建一个连接。使用它。关闭它。
现在,对于像这么简单的事,Jedis 看起来更简单。这很有道理,因为它具有更少的代码。但我确信 Lettuce 软件拥有所有这些东西是有原因的——可能用于处理更高级的场景。
Jedis 可以很好地处理多线程应用程序,但 Jedis 连接不是线程安全的。因此请不要共享它们。如果您跨线程共享 Jedis 连接,Redis 会抛出各种协议错误,如
预期“$”但得到“ ”
要解决这些类型的问题,请使用JedisPool,这是一个线程安全的对象,用于提供非线程安全的Jedis对象。它的使用方法很简单,就像 Jedis 的其他用法一样。只需请求一个线程并在完成后通过.close()将其返回到池中即可。以下是如何操作的
package com.guyroyse.blogs.lettucevsjedis;
import redis.clients.jedis.*;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class JedisMultithreaded {
private static final String YOUR_CONNECTION_STRING = "redis://:foobared@yourserver:6379/0";
public static void main(String[] args) {
JedisPool pool = new JedisPool(YOUR_CONNECTION_STRING);
List<String> allResults = IntStream.rangeClosed(1, 5)
.parallel()
.mapToObj(n -> {
Jedis jedis = pool.getResource();
jedis.set("foo" + n, "bar" + n);
String result = jedis.get("foo" + n);
jedis.close();
return result;
})
.collect(Collectors.toList());
pool.close();
System.out.println(allResults); // "bar1, bar2, bar3, bar4, bar5"
}
}
每个这样的Jedis对象都会封装到 Redis 的一个连接,因此(根据池的大小),可能有阻塞连接或空闲连接。此外,这些连接是同步的,因此始终有一定程度的空闲。
我觉得应该谈论一下集群,但是没有太多可说的——至少在比较方面是如此。有大量的功能可以讨论,但是这两个库都支持集群。毫不奇怪,Jedis 的使用更简单,但它只能同步处理集群。Lettuce 软件的使用难度更大,但能够以同步、异步和响应方式与集群进行交互。
这是反复出现的主题。并且这并不奇怪。根据其自身的描述,“Jedis 被认为易于使用”。而且 Lettuce 声明,“Lettuce是一种可扩展的 Redis 客户端,用于构建非阻塞响应式应用程序”,就在其 主页上
当然,如果您正在使用 Redis Enterprise,则不必担心集群,因为这是在服务器端处理的。只需使用 Jedis 或 Lettuce 的非集群 API,管理您的密钥,以便将其插入到正确的分片中,一切都会顺利进行。