点 快速的未来即将来到你所在城市的某个活动中。

加入我们,共同参加 Redis 发布会

Jedis 对比 Lettuce:探索

我天生就是个探索者,因此当我必须做出技术决策(比如选择 Redis 客户端)时,我会去深入探究一下。本文记录了我的探索历程,内容涉及一对 Java 客户端的押韵组合:JedisLettuce

让我们从基础开始,分别研究每个客户端,以了解两者之间的差异。

什么是 Lettuce?

Lettuce 是一个完全非阻塞的 Redis Java 客户端。它同时支持同步和异步通信。其复杂的抽象使您可以轻松扩展产品和nbsp;

将 Lettuce 视为支持集群、哨兵、管道和编解码器的更高级客户端

什么是 Jedis?

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 连接不是线程安全的。因此请不要共享它们。如果您跨线程共享 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 软件的使用难度更大,但能够以同步、异步和响应方式与集群进行交互。

这是反复出现的主题。并且这并不奇怪。根据其自身的描述,“Jedis 被认为易于使用”。而且 Lettuce 声明,“Lettuce是一种可扩展的 Redis 客户端,用于构建非阻塞响应式应用程序”,就在其 主页

当然,如果您正在使用 Redis Enterprise,则不必担心集群,因为这是在服务器端处理的。只需使用 Jedis 或 Lettuce 的非集群 API,管理您的密钥,以便将其插入到正确的分片中,一切都会顺利进行。