Jedis vs. Lettuce: An Exploration

I’m an explorer by heart, so when I have to make a technical decision—like, say, choosing a Redis client—I go a-spelunking. Herein is the account of my exploration of the rhyming duo of Java clients: Jedis versus Lettuce.

Let’s start with the basics, and examine each client, to understand the differences between the two.

What is Lettuce?

Lettuce is a Redis Java client that is fully non-blocking. It supports both synchronous and asynchronous communication. Its complex abstractions allow you to scale products easily. 

Consider Lettuce as a more advanced client that supports Cluster, Sentinel, Pipelining, and codecs.

What is Jedis?

Jedis is a client library inside Redis that’s designed for performance and ease of use. Jedis is a lightweight offering compared to other Redis Java clients; it offers fewer features but can still handle large amounts of memory.

Due to its simpler functionality, Jedis is easier to use, but it only works with clusters synchronously. If you choose Jedis, you may find it less challenging to focus on the application and data rather than the data storage mechanism.

My plan was simple:

  • Try some simple things in code
  • Try some advanced things in code
  • Arrive at some sort of selection criteria
  • Profit!

The gnomic goal of profit, like underpants, is always there. But the part that you can benefit from is the selection criteria. It will allow us to decide when Jedis is the right call and when Lettuce is the way to go. This is super important because we all know the answer to any question when selecting tools is, “it depends.”

Jedis is a client library inside Redis that’s designed for performance and ease of use. Jedis is a lightweight offering compared to other Redis Java clients; it offers fewer features but can still handle large amounts of memory.

Due to its simpler functionality, Jedis is easier to use, but it only works with clusters synchronously. If you choose Jedis, you may find it less challenging to focus on the application and data rather than the data storage mechanism. 

My comparison plan was simple:

  • Try some simple things in code
  • Try some advanced things in code
  • Arrive at some sort of selection criteria
  • Profit!

The gnomic goal of profit, like underpants, is always there. But the part that you can benefit from is the selection criteria. It allows us to decide when the Java client, Jedis, is the right call and when Lettuce software is the way to go. This is super important because we all know the answer to any tool selection question is, “It depends.”

A simple kind of code

To get to the bottom of the Jedis versus Lettuce debate, let’s compare code for the simplest of all exercises: setting and getting a value from a single instance of Redis.

First, we do this with Jedis:

Looking at the code, this is pretty simple. Create a connection. Use it. Close it.

Next, we do it with Lettuce:

This looks a bit more involved. There’s a Java client, a connection, and a command object. And their names and templated nature suggest that there might be multiple varieties of them. Maybe in addition to a  StatefulRedisConnection<String, String> type, we have a stateless variety that takes a byte[]]? (Spoiler: there are multiple connection types for clustering and master/replica configurations, but not stateless ones.)

Once you’re beyond the setup and teardown, however, it’s the same basic code in either client: Create a connection. Use it. Close it.

Right now, for something as simple as this, Jedis looks easier. That makes sense since it has less code. But I am certain that the Lettuce software has all this stuff for a reason—probably to handle more advanced scenarios.

Jedis pipelines, sync, and async

Jedis is entirely synchronous with the exception of pipelines. Pipelines allow Jedis asynchronous usage of Redis, but, unfortunately, they cannot be used alongside clustering. However, pipelines are easy enough to use:

Lettuce libraries support synchronous, asynchronous, and even reactive interfaces if you’re into that sort of thing (which I am). However, here’s an important note to make about the Lettuce library: These are all just layers of syntactic sugar on top of Lettuce’s multithreaded, event-based model that uses pipelining as a matter of course. Even when you use it synchronously, it’s asynchronous underneath.

We’ve seen the synchronous interface in action already with our super sophisticated set and get an example. But let’s take a look at the asynchronous example:

This sets and gets, just like the synchronous example, but clearly, this is more involved code. It’s also multi-threaded.

Jedis and multi-threaded code

Jedis can handle multi-threaded applications just fine, but a Jedis connection is not thread-safe. So don’t share them. If you share a Jedis connection across threads, Redis blurts out all sorts of protocol errors, like:

expected '$' but got ' '

To solve these sorts of problems, use JedisPool—a thread-safe object that dispenses thread-unsafe Jedis objects. Using it is simple, like the rest of Jedis. Just ask for a thread and return it to the pool via .close() when you’re done. Here it is in action:

Each of these Jedis objects encapsulates a single connection to Redis, so (depending on how large your pool is) there may be blocking or idle connections. Furthermore, these connections are synchronous, so there’s always a degree of idleness.

Jedis, Lettuce, and clustering

I feel like I should talk about clustering, but there’s not much to say—at least in terms of comparisons. There’s plenty of capability to discuss, but both libraries support clustering. Unsurprisingly, Jedis is easier to use, but it works with clusters only synchronously. The Lettuce software is more difficult to use but is capable of synchronous, asynchronous, and reactive interaction with the cluster.

This is the recurring theme. And that shouldn’t be surprising. By its own admission, “Jedis was conceived to be EASY to use.” And Lettuce states, “Lettuce is a scalable Redis client for building non-blocking Reactive applications” right on its homepage.

Of course, if you’re using Redis Enterprise, you don’t have to worry about clustering as it’s handled server-side. Just use the non-clustered APIs of Jedis or Lettuce, manage your keys so they’re slotted to the correct shards, and you’re good to go.

Making the decision

So, Jedis or Lettuce? Well, it depends. (See, I told you we’d end up here!) This is a classic trade-off between code complexity and application scalability.

If you need something highly scalable, use the Lettuce software. Its more sophisticated abstractions provide the capabilities to make scalable products more easily. Lettuce is a powerful solution that lets you use the full set of Redis’ capabilities.

If you need to build something fast and scalability isn’t and probably won’t be a concern, use Jedis. It’s simple, easy to use, and makes it easier for you to focus on your application and data rather than the mechanism of your data’s storage.

If you still can’t decide, you can always use Spring Data Redis, which will abstract away Jedis and Lettuce so you can change your mind in the future. Of course, that comes with its own set of tradeoffs. But that is a topic for a future blog post!