백엔드 데이터 인프라 79편. Java Redis Client — Jedis (sync) vs Lettuce (sync+async+reactive) 정확한 비교. Connection 모델·thread-safety·성능·Spring Boot 2+ 기본 Lettuce 인 이유·Redisson 의 위치까지 풀어쓴 학습 노트. Part 4 Redis 33편 마무리.
이 글은 백엔드 데이터 인프라 시리즈 130편 중 79편이에요. Redis 33편(47~79편) 의 마지막 글이고, 78편 clients-overview 에서 모든 언어 클라이언트를 훑었다면 이번 79편은 Java 클라이언트 — Jedis vs Lettuce 를 깊이 비교해요. 시리즈 1 자바 백엔드 입문 (59편) 의 자연스러운 후속이에요.
Jedis vs Lettuce가 어렵게 느껴지는 이유
Java 환경에서는 둘 다 공식 클라이언트인 데다 둘 다 충분히 좋아서, 선택이 한눈에 떨어지지 않아요.
첫째로 두 클라이언트의 설계 철학이 달라요. Jedis 는 전통적인 sync 방식에 connection pool 을 얹은 모델이고, Lettuce 는 Netty(Java 비동기 네트워크 프레임워크) 기반 비동기에 공유 connection 을 쓰는 모델이에요. 모델이 전혀 다르다 보니 한쪽에 익숙해진 사람이 다른 쪽을 처음 보면 어색하게 느껴져요.
둘째, Spring Boot 2.0 이상에서는 기본 클라이언트가 Lettuce 로 바뀌었어요. 왜 바뀌었는지, 계속 Jedis 를 써도 되는지가 의문이 되는데, 답은 비동기·반응형 환경과의 일관성, 그리고 thread-safety 때문이에요.
셋째, Redisson 의 위치가 헷갈려요. Jedis·Lettuce 와 다른 3번째 옵션으로, 분산 객체와 고급 HA 패턴을 제공해요. 처음에는 어디에 자리하는 라이브러리인지 잘 안 잡혀요.
이 글에서 두 클라이언트의 설계 철학·Connection 모델·thread-safety·성능·기능 비교·Spring 통합·Redisson 위치·선택 가이드까지 한 번에 풀어 봐요.
Jedis — Synchronous 클래식
설계 철학
- 전통 sync — 각 명령이 호출자 스레드에서 블로킹
- Connection 당 한 클라이언트 — Jedis 인스턴스 = 한 connection
- Thread-safe X — 여러 스레드 공유 불가
- JedisPool 로 connection 재사용
사용
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(50);
config.setMaxIdle(10);
config.setMinIdle(2);
JedisPool pool = new JedisPool(config, "localhost", 6379, 2000, "pass");
try (Jedis jedis = pool.getResource()) {
jedis.set("key", "value");
String val = jedis.get("key");
}
try-with-resources 로 자동 connection 반환. 까먹으면 pool 누수.
장점
- 학습 곡선 낮음 — 단순 동기 API
- API 가 Redis 명령에 1:1 대응 —
jedis.set·get·hget·zadd·...직관적 - 메모리 효율 (Netty 의존 X)
단점
- Thread-safe X — JedisPool 필수
- 비동기 X — 반응형 환경에서는 wrapping 필요
- Cluster 환경 마이그레이션 약간 복잡 (JedisCluster 별도 클래스)
Lettuce — Netty 기반 다목적
설계 철학
- Netty 비동기 I/O 기반
- Connection multiplexing — 하나의 connection 으로 여러 스레드 안전 공유
- Thread-safe ◯ — JedisPool 같은 pool 보통 불필요
- 동기·비동기·반응형 3가지 API 모두 제공
사용
RedisClient client = RedisClient.create("redis://pass@localhost:6379");
StatefulRedisConnection<String, String> connection = client.connect();
// 동기 API
RedisCommands<String, String> sync = connection.sync();
sync.set("key", "value");
// 비동기 API
RedisAsyncCommands<String, String> async = connection.async();
RedisFuture<String> future = async.get("key");
// 반응형 API
RedisReactiveCommands<String, String> reactive = connection.reactive();
Mono<String> mono = reactive.get("key");
같은 connection 에서 3가지 API 모두 사용 가능.
장점
- Thread-safe — pool 없이 단일 connection 공유
- 비동기·반응형 1급 지원 — WebFlux(Spring 반응형 웹 프레임워크)·Reactor(JVM 반응형 스트림 라이브러리) 환경 자연스러움
- Auto-reconnect — 네트워크 끊김 자동 복구
- Cluster·Sentinel(Redis 자동 failover 관리자)·Master/Replica 다 자연스러움
단점
- 학습 곡선 약간 높음 — async·reactive 모델
- 메모리 사용량 — Netty 의존성으로 약간 큼
- API 가 조금 더 추상화 — Redis 명령과 1:1 매칭 직관성 약간 ↓
Connection 모델 — 핵심 차이
Jedis
┌─ 스레드 1 ─ Jedis 인스턴스 1 ── connection 1 ── Redis
├─ 스레드 2 ─ Jedis 인스턴스 2 ── connection 2 ── Redis
└─ 스레드 3 ─ Jedis 인스턴스 3 ── connection 3 ── Redis
스레드마다 connection 을 하나씩 잡고, JedisPool 로 그 connection 을 재사용하는 풀을 둬요. 100 스레드면 100 connection 이 만들어지고, pool 한계에 닿으면 그 이후 요청은 대기에 들어가요.
Lettuce
┌─ 스레드 1 ─┐
├─ 스레드 2 ─┼── 공유 connection ── Redis (Netty event loop)
└─ 스레드 3 ─┘
하나의 connection 으로 모든 스레드를 multiplex(한 채널로 다중 처리) 해요. 명령 순서는 Netty 가 내부 큐로 보장해 주고요.
여기서 정말 중요한 자리가 하나 있어요. BLPOP·SUBSCRIBE 같은 블로킹 명령 을 Lettuce 의 공유 connection 에 박으면 전체가 멈춰요. 별도 connection 을 둬야 하고, 공유 connection 으로 보낼 건 블로킹 안 쓰는 일반 명령 만 보내야 해요.
성능 비교
일반 명령 (단순 GET/SET)
거의 동등해요. 둘 다 Redis 자체 처리 속도가 병목이라 클라이언트 차이는 미세해요.
Pipelining
비슷.
고동시성 (Spring Boot WebFlux, 수천 동시 요청)
Lettuce 압도적 유리 — connection multiplexing 으로 적은 리소스로 많은 요청.
단순 sync 환경
Jedis 가 약간 더 직관적이고 메모리도 적게 써요. 다만 큰 차이는 아니에요.
기능 비교
| 기능 | Jedis | Lettuce |
|---|---|---|
| 동기 API | ◯ | ◯ |
| 비동기 API | X (JedisPooled 일부) | ◯ |
| 반응형 API | X | ◯ |
| Cluster | ◯ (JedisCluster) | ◯ (RedisClusterClient) |
| Sentinel | ◯ | ◯ |
| Master/Replica 자동 라우팅 | △ | ◯ |
| Auto-reconnect | △ | ◯ |
| Topology auto-refresh | X | ◯ |
| Pub/Sub | ◯ | ◯ |
| Sharded Pub/Sub | ◯ | ◯ |
| Pipelining | ◯ | ◯ |
| Transactions | ◯ | ◯ |
| Lua scripting | ◯ | ◯ |
| RedisJSON·Search·TS | △ (별도 모듈) | △ (별도 모듈) |
기능 격차는 크지 않아요. 연결 모델·thread-safety·반응형 지원이 결정적이에요.
Spring Boot 2.0+ — Lettuce 기본
기본값이 Lettuce 인 이유는 세 가지예요. 우선 thread-safe 라서 pool 관리가 자동으로 따라오고, Auto-reconnect 와 topology refresh 가 있어 Cluster·Sentinel 환경에서 안정적이에요. 마지막으로 WebFlux 와 일관돼서, 같은 클라이언트로 sync 와 reactive 를 다 처리할 수 있어요.
설정
spring:
data:
redis:
host: localhost
port: 6379
password: pass
timeout: 2000ms
lettuce:
pool:
max-active: 8
max-idle: 8
min-idle: 0
cluster:
refresh:
adaptive: true
period: 60s
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>
spring:
data:
redis:
jedis:
pool:
max-active: 50
max-idle: 10
lettuce → jedis 로 키만 변경.
Redisson — 3번째 옵션
Jedis·Lettuce 와 결이 달라요. Redisson 은 분산 객체와 고급 HA 패턴을 들고 와요.
차이
- 분산 객체 —
RLock·RMap·RList·RBucket같은 Java Collection 인터페이스를 Redis 위에 구현. 마치 로컬 객체처럼 사용. - Redlock(Redis 분산 락 알고리즘) 알고리즘 (63편) 자동 구현
- Watchdog(락 잡은 동안 TTL 자동 연장) — 락 잡고 작업 길어지면 자동 TTL 연장
- Reactive·RxJava 지원
사용
Config config = new Config();
config.useSingleServer().setAddress("redis://localhost:6379");
RedissonClient redisson = Redisson.create(config);
// 분산 락 (63편 패턴)
RLock lock = redisson.getLock("my-lock");
lock.lock(30, TimeUnit.SECONDS);
try {
// 작업
} finally {
lock.unlock();
}
// 분산 Map
RMap<String, String> map = redisson.getMap("my-map");
map.put("key", "value");
// 분산 Queue
RQueue<String> queue = redisson.getQueue("my-queue");
queue.add("job-1");
위치
- 단순 Redis 명령 → Jedis·Lettuce
- 분산 락·고급 패턴 → Redisson
- 둘 다 사용 = 일반 패턴 (Lettuce 로 명령 + Redisson 으로 락)
선택 가이드
이 프로젝트는?
├─ Spring Boot 2+ + Spring MVC + 단순 캐시
│ └─ Lettuce (기본값 그대로) ★
├─ Spring Boot 2+ + Spring WebFlux + 반응형
│ └─ Lettuce reactive ★★
├─ 기존 Jedis 사용 중 + 만족
│ └─ Jedis 유지 (마이그레이션 불필요)
├─ 분산 락·복잡한 HA 패턴 자주
│ └─ Lettuce + Redisson 조합
└─ 단순 sync + 비-Spring 환경
└─ Jedis 도 OK
99% 신규 Spring Boot 환경 = Lettuce.
Cluster·Sentinel 통합 차이
Lettuce 의 강점
- adaptive refresh — MOVED(Cluster 키 이동 알림 응답) 감지 시 자동 topology 갱신
- Master/Replica 자동 라우팅 — 읽기는 replica, 쓰기는 master 자동
- Sentinel failover 자동 감지·재연결
Jedis
- JedisCluster·JedisSentinelPool 별도 클래스
- 기본 동작 OK, 자동화 정도가 Lettuce 보다 약간 낮음
한계·실무 함정
1. Lettuce 공유 connection 에 blocking 명령
위에서 강조한 그 자리예요. BLPOP·SUBSCRIBE 는 별도 connection 으로 빼야 해요.
2. Jedis 의 try-with-resources 누락
Jedis jedis = pool.getResource();
jedis.set(...);
// jedis.close() 누락 → connection leak
반드시 try-with-resources 로 감싸야 해요.
3. Spring Data Redis 통한 사용 — 직접 클라이언트 API 안 쓰는 게 일반적
Spring 환경에서는 RedisTemplate 이나 @Cacheable 추상화를 거쳐서 써요. Jedis·Lettuce API 를 직접 호출하는 건 특수한 경우에만 해당해요.
4. 클라이언트 버전 + 서버 버전 호환
오래된 Jedis (~3.x) 는 Redis 7 의 신규 기능 일부를 못 따라가요. 최신 권장이에요.
5. Redisson 의 약간 더 무거움
Redisson 은 풍부한 추상화에 Netty, 그리고 여러 의존성을 함께 가져와요. 단순 캐시만 필요한 환경에는 Lettuce 가 더 가벼워요.
Part 4 Redis 마무리
시리즈 2 Part 4 — Redis 33편 끝. 지금까지 풀어 본 영역:
- 4-1 자주 쓰는 6종 (47~54편) — String·Hash·List·Set·Sorted Set·Stream
- 4-2 키·만료·알림 (55~57) — TTL·notifications·pipelining
- 4-3 상호작용·프로그래밍 (58~61) — Pub/Sub·transactions·Lua·Functions
- 4-4 패턴 (62~65) — 9가지 패턴·distributed lock·twitter clone·secondary indexing
- 4-5 운영 (66~71) — persistence·replication·cluster·sentinel·ACL·TLS
- 4-6 성능·확장 (72·73) — memory optimization·Spring integration
- 4-7 모듈 (74~77) — JSON·Search·Time Series·Vector
- 4-8 클라이언트 (78·79) — 종합·Java 깊이
Redis 의 거의 모든 영역 을 한 시리즈로. 다음 영역 — Part 5 Kafka 51편 (80~130) — 이벤트 스트리밍의 표준.
시험 직전 한 번 더 — Jedis vs Lettuce 함정 압축 노트
- Jedis = sync 클래식, JedisPool 필수, thread-safe X
- Lettuce = Netty 기반, 공유 connection multiplexing, thread-safe ◯, 비동기·반응형 1급
- Spring Boot 2.0+ 기본 = Lettuce
- Connection 모델 — Jedis 스레드당 / Lettuce 공유 multiplexing
- 100 스레드 = Jedis 100 connection / Lettuce 1 connection
- Lettuce 공유 connection 에 blocking 명령 = 전체 멈춤 → 별도 connection
- 성능 — 일반 명령은 동등, 고동시성은 Lettuce 압도적
- 기능 — 둘 다 풍부, 결정적 차이는 반응형·thread-safety·auto-reconnect
- Spring Boot 통합 — yaml
spring.data.redis.lettuce.*또는jedis.* - Jedis 마이그레이션 = pom 의존성 교체 + yaml 설정 키 변경
- Redisson = 3번째 옵션, 분산 객체·Redlock·Watchdog
- 위치 — 단순 = Jedis/Lettuce / 분산 락·HA = Redisson
- Lettuce + Redisson 조합 = 일반 패턴
- 선택 — Spring Boot 2+ MVC = Lettuce 기본 / WebFlux = Lettuce reactive / 기존 Jedis = 유지 / 분산 락 = + Redisson
- Lettuce 강점 — adaptive refresh, Master/Replica 자동 라우팅, Auto-reconnect
- 함정 — Jedis try-with-resources 누락 = leak
- 함정 — Redisson 약간 더 무거움 → 단순 캐시는 Lettuce 가 가벼움
- 함정 — 오래된 클라이언트 = 신규 기능 미지원
- 99% 신규 Spring Boot 환경 = Lettuce
공식 문서: Jedis 와 Lettuce, Redisson 에서 자세한 사양과 예제를 확인할 수 있어요.
시리즈 다른 편 (앞뒤 글 모음)
이전 글:
- 74편 — RedisJSON (JSON.SET · JSONPath · PG JSONB 비교)
- 75편 — RediSearch (FT.CREATE · FT.SEARCH · FT.AGGREGATE)
- 76편 — Redis Time Series (TS.ADD · Labels · Compaction)
- 77편 — Redis Vector Database (HNSW · 코사인 유사도 · RAG)
- 78편 — Redis Client 라이브러리 종합
다음 글: