Lettuce ๊ฐ ๋ฌด์์ธ์ง, Spring Data Redis์ RedisTemplate ์ Lettuce ๋ฅผ ์ด๋ป๊ฒ ์ถ์ํํ๋์ง ์์๋ณด๊ณ ์ ํฉ๋๋ค.
๋จผ์ , Spring Data Redis ๋ Lettuce์ Jedis ๋ผ๋ 2๊ฐ์ ์คํ ์์ค ๋ผ์ด๋ธ๋ฌ์ ํตํฉ๋์์ต๋๋ค.
Spring Data Redis integrates with Lettuce and Jedis, two popular open-source Java libraries for Redis.
Lettuce์ Jedis๋ "Java์์ Redis์ ์ ๊ทผํ์ฌ ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ์ ์ ์๋๋ก ๋์์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ"์ ๋๋ค.
๊ทธ๋ ๋ค๋ฉด ๊ฐ๊ฐ ๋ฌด์์ธ์ง Lettuce๋ถํฐ ์์๋ณด๊ฒ ์ต๋๋ค.
Lettuce ๋?
Lettuce is a scalable thread-safe Redis client for synchronous, asynchronous and reactive usage. Multiple threads may share one connection if they avoid blocking and transactional operations such as BLPOP and MULTI/EXEC. Lettuce is built with netty.
- Lettuce ๋ ๋๊ธฐ(Synchronous), ๋น๋๊ธฐ(Asynchronous), ๋ฆฌ์กํฐ๋ธ(Reactive) ๋ฐฉ์์ ์ง์ํ๋ฉฐ, Thread-Safe ํฉ๋๋ค.
- BLPOP, MULTI/EXEC๊ณผ ๊ฐ์ ๋ธ๋กํน(Blocking) ๋ฐ ํธ๋์ญ์ ๋ช ๋ น์ด๋ฅผ ํผํ๋ ๊ฒฝ์ฐ, 1๊ฐ์ Native Connection(StatefulRedisConnection)์ ์ฌ๋ฌ ์ค๋ ๋์์ ๊ณต์ ํ ์ ์์ต๋๋ค.
- Lettuce ๋ Netty (๋น๋๊ธฐ I/O ๋ผ์ด๋ธ๋ฌ๋ฆฌ) ๊ธฐ๋ฐ์ ๋๋ค.
Spring Data Redis ์์ Lettuce ์ฌ์ฉ ๋ฐฉ์
Spring Boot์์ Spring Data Redis ์์กด์ฑ์ ์ถ๊ฐํ๋ฉด, ๊ธฐ๋ณธ์ ์ผ๋ก Jedis๊ฐ ์๋ Lettuce๊ฐ ์๋ ๊ตฌ์ฑ(auto configuration)๋จ์ ํ์ธํ ์ ์์ต๋๋ค.
์ด ์์กด์ฑ์ด ์ถ๊ฐ๋๋ฉด Lettuce ๋ฅผ ์ถ์ํํ์ฌ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์๋๋ก Spring Data Redis๊ฐ LettuceConnectionFactory์ LettuceConnection์ ์ ๊ณตํฉ๋๋ค.(Redis Config ํ ๋, ์์ฃผ ๋ณด๋ ์ ๋ค์ ๋๋ค)
Spring Data Redis์ ๋ด๋ถ ์ฝ๋์์๋ RedisConnection ์ ๊ตฌํ์ฒด๋ LettuceConnection ์ด๋ฉฐ, ํธ์์ LettuceConnection ์ด๋ผ๊ณ ํ๊ฒ ์ต๋๋ค.
์ ๋ฆฌํ์๋ฉด Spring ์ LettuceConnectionFactory ์ LettuceConnection, Lettuce ๋ Native Connection ์ ์ ๊ณตํ๋ค๋ ๊ฒ์ ๊ธฐ์ตํด์ฃผ์ธ์.
LettuceConnectionFactory์ ๊ธฐ๋ณธ ๋์
LettuceConnectionFactory์ Javadoc์ ๋ณด๋ฉด, ๊ธฐ๋ณธ์ ์ผ๋ก ์ฌ๋ฌ ๊ฐ์ LettuceConnection์ ํ๋์ Native Connection์ ๊ณต์ ํ์ฌ ์ฌ์ฉํฉ๋๋ค. ๋ฐ๋ผ์, Blocking ์ฐ์ฐ์ ์คํํ๋ฉด Native Connection์ด ๋งํ๊ฒ ๋ฉ๋๋ค.
While multiple LettuceConnections share a single thread-safe native connection by default
๋ง์ฝ BLPOP๊ณผ ๊ฐ์ Blocking ๋ช ๋ น์ด๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค๋ฉด, LettuceConnectionFactory.setShareNativeConnection(false)๋ก ์ค์ ํ๋ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค. ๋ค๋ง, LettuceConnection ๋ฅผ ์ฌ์ฉํ๊ฒ ๋ ๋๋ง๋ค TCP ์์ผ์ด ์ด๋ฆฌ๊ณ ๋ซํ๊ฒ ๋ ๊ฒ์ ๋๋ค.
LettuceConnection ์์ฑ ๋ฐฉ์๊ณผ RedisTemplate ์ ์ญํ
LettuceConnection(RedisConnection) ๋ Thread-safe ํ์ง ์์ต๋๋ค.
์ฆ, LettuceConnection์ ์ฌ๋ฌ ์ค๋ ๋์์ ๊ณต์ ํ๋ฉด ์ ๋๋ฏ๋ก, ์ค๋ ๋๋ง๋ค ์๋ก์ด ์ธ์คํด์ค๋ฅผ ์์ฑํด์ผ ํฉ๋๋ค.
RedisConnection classes are not Thread-safe. Spring Data Redis’s LettuceConnection class itself is not. Therefore, you should not share instances of a RedisConnection across multiple Threads.
์ด ์ญํ ์ RedisTemplate์ด ์ํํฉ๋๋ค.
RedisTemplate์ Redis๋ก ์์ฒญ์ ๋ณด๋ผ ๋ ๋ง๋ค ์๋ก์ด LettuceConnection์ ์์ฑํฉ๋๋ค.
RedisTemplate์ Connection ํ๋ ๊ณผ์
RedisTemplate์ execute() ๋ฉ์๋๋ฅผ ํตํด Redis์ ํต์ ํ๋ฉฐ, ์ด๋ ๋ด๋ถ์ ์ผ๋ก RedisConnectionUtils.getConnection()์ ํธ์ถํ์ฌ Connection์ ๊ฐ์ ธ์ต๋๋ค.
RedisConnectionUtils.getConnection ์ ํ๊ณ ๋ด๋ ค๊ฐ๋ค ๋ณด๋ฉด doGetConnection ๋ฉ์๋๋ฅผ ๋ณผ ์ ์์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ , doGetConnection ์ fetchConnection ์ผ๋ก ๋ค์ด๊ฐ๊ฒ ์ต๋๋ค.
fetchConnection ์๋ factory.getConnection( )์ด ์์ต๋๋ค.
ํด๋น ๋ฉ์๋๋ RedisConnectionFactory์ getConnection() ๋ก, ํธ์ถํ ๋๋ง๋ค LettuceConnection ์ธ์คํด์ค๋ฅผ ์์ฑํฉ๋๋ค.
์ด๋ฌํ ๋์ ๋ฐฉ์์ผ๋ก ์ธํด RedisTemplate์ ์์ฒญ๋ง๋ค ์๋ก์ด LettuceConnection์ ํ๋ํ๊ฒ ๋ฉ๋๋ค.
๋ฐ๋ผ์, RedisTemplate์ Bean์ผ๋ก ๋ฑ๋กํ์ฌ ์ฑ๊ธํค์ผ๋ก ์ฌ์ฉํ๊ฒ ๋๊ณ , ๋ด๋ถ์ ์ผ๋ก ๊ฐ ์์ฒญ๋ง๋ค ์๋ก์ด LettuceConnection ์ธ์คํด์ค๋ฅผ ์์ฑํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ , ์์ฑ๋ LettuceConnection๋ค์ด ์ฌ์ฉํ๋ Native Connection์ ์ฌํ์ฉ๋ฉ๋๋ค.
์คํ 1. LettuceConnection์ ์ฌ์ฌ์ฉ๋์ง ์์
@DataRedisTest
public class RedisConnectionTest {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@DisplayName("RedisTemplate์์ Lettuce Connection์ ์ฌ์ฌ์ฉ๋์ง ์๋๋ค.")
@Test
void test() {
// given
RedisConnectionFactory connectionFactory = redisTemplate.getConnectionFactory();
RedisConnection connection1 = connectionFactory.getConnection();
System.out.println("์ฒซ ๋ฒ์งธ Connection: " + connection1);
RedisConnection connection2 = connectionFactory.getConnection();
System.out.println("๋ ๋ฒ์งธ Connection: " + connection2);
// when then
System.out.println("๊ฐ์ LettuceConnection์ธ๊ฐ? " + (connection1 == connection2));
Assertions.assertThat(connection1).isNotSameAs(connection2);
}
}
์คํ ๊ฒฐ๊ณผ - false
์ฒซ ๋ฒ์งธ Connection: org.springframework.data.redis.connection.lettuce.LettuceConnection@37fca349
๋ ๋ฒ์งธ Connection: org.springframework.data.redis.connection.lettuce.LettuceConnection@86377d5
๊ฐ์ LettuceConnection์ธ๊ฐ? false
์คํ 2. Native Connection์ ์ฌ์ฌ์ฉ๋จ
@DisplayName("RedisTemplate์์ Native Connection์ ์ฌ์ฌ์ฉ๋๋ค.")
@Test
void test1() {
// given
RedisConnectionFactory connectionFactory = redisTemplate.getConnectionFactory();
Object nativeConnection1 = connectionFactory.getConnection().getNativeConnection();
System.out.println("์ฒซ ๋ฒ์งธ Native Connection: " + nativeConnection1);
Object nativeConnection2 = connectionFactory.getConnection().getNativeConnection();
System.out.println("๋ ๋ฒ์งธ Native Connection: " + nativeConnection2);
// when then
System.out.println("๊ฐ์ Native Connection์ธ๊ฐ? " + (nativeConnection1 == nativeConnection2));
Assertions.assertThat(nativeConnection1).isSameAs(nativeConnection2);
}
์คํ ๊ฒฐ๊ณผ - true
์ฒซ ๋ฒ์งธ Native Connection: io.lettuce.core.RedisAsyncCommandsImpl@37fca349
๋ ๋ฒ์งธ Native Connection: io.lettuce.core.RedisAsyncCommandsImpl@37fca349
๊ฐ์ Native Connection์ธ๊ฐ? true
Lettuce ๋ ํธ๋์ญ์ ๋๊ธฐํ๋ฅผ ํ์ง ์๋๋ค
Lettuce์์ ๋จ์ผ Native Connection์ ์ฌ๋ฌ ์ค๋ ๋/ํ๋ก์ธ์ค์์ ๊ณต์ ํ๋ฉด,
- Spring์์๋ ์ฌ๋ฌ ๊ฐ์ LettuceConnection์ด ํ๋์ Native Connection์ ๊ณต์ ํฉ๋๋ค
ํธ๋์ญ์ ์ฐ์ฐ ์ ์ธ๋ถ์์ ๋๊ธฐํ๊ฐ ํ์ํฉ๋๋ค.
- Spring ์์ ํธ๋์ญ์ ๋ช ๋ น์ด์ธ MULTI ๋ฅผ Redis์๊ฒ ๋ณด๋ผ ๊ฒฝ์ฐ, Spring์์ ํธ๋์ญ์ ์ ์ํด ๋๊ธฐํ๊ฐ ํ์ํฉ๋๋ค.
Transactional use requires external synchronization when a single connection is used by multiple threads/processes.
์ถ์ฒ - https://github.com/redis/lettuce/wiki/Transactions
Spring์ Redis ํธ๋์ญ์ ์ง์
RedisTemplate์ setEnableTransactionSupport(true) ๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด, Spring์ ํธ๋์ญ์ ์ RedisTemplate์ด ์ฐธ์ฌํ๋๋ก ์ค์ ํ ์ ์์ต๋๋ค.
ํธ๋์ญ์
์ง์์ ํ์ฑํํ๋ฉด, ํ๋์ LettuceConnection๋ง ํ์ฌ ํธ๋์ญ์
์ ๋ฐ์ธ๋ฉ๋๋ฉฐ,
์ด๋ ThreadLocal์ ๊ธฐ๋ฐ์ผ๋ก ๊ด๋ฆฌ๋์ด ํธ๋์ญ์
๋ด์์ ๋์ผํ LettuceConnection์ ์ ์งํ ์ ์๋๋ก ํฉ๋๋ค.
"Enabling transaction support binds RedisConnection to the current transaction backed by a ThreadLocal"
๊ทธ๋ฆฌ๊ณ , Spring์์ Redis ํธ๋์ญ์ ์ ์ฌ์ฉํ๋ ค๋ฉด ๋ค์ 3๊ฐ์ง๋ฅผ ๋ง์กฑํด์ผ ํฉ๋๋ค.
- Spring ์ปจํ ์คํธ์์ ์ ์ธ์ ํธ๋์ญ์ ๊ด๋ฆฌ ํ์ฑํ (@EnableTransactionManagement ์ถ๊ฐ)
- RedisTemplate์ด ํธ๋์ญ์ ์ ์ฐธ์ฌํ๋๋ก ์ค์ (setEnableTransactionSupport(true))
- ํธ๋์ญ์
์ ๊ด๋ฆฌํ๊ธฐ ์ํ PlatformTransactionManager ๋ฑ๋ก
- Spring Data Redis ์์ฒด์ ์ผ๋ก PlatformTransactionManager ๊ตฌํ์ฒด๋ฅผ ์ ๊ณตํ์ง ์์
- JDBC ๊ธฐ๋ฐ์ ํธ๋์ญ์ ๊ด๋ฆฌ์๋ฅผ ํ์ฉํ์ฌ Redis ํธ๋์ญ์ ์ ํจ๊ป ๊ด๋ฆฌ ๊ฐ๋ฅ
ํ์ง๋ง, Spring Boot ์์๋ RedisTemplate ์ setEnableTransactionSupport(true) ์ค์ ๋ง์ ์ถ๊ฐํ๋ฉด ๋ฉ๋๋ค.
@EnableTransactionManagement ์ PlatformTransactionManager ๋ฑ๋ก์ spring-data* ์์กด์ฑ์ด ์๋ค๋ฉด(redis ์ ์ธ), 'TransactionAutoConfiguration.class' ์ ์ํด Spring Boot์์ ์๋ ๊ตฌ์ฑ๋ฉ๋๋ค.
์ถ์ฒ - @EnableTransactionManagement in Spring Boot ์ 3๋ฒ์งธ ๋ต๋ณ์ ๋ณด์๋ ๊ฒ์ ์ถ์ฒ๋๋ฆฝ๋๋ค.
Spring Data Redis์์ ํธ๋์ญ์ ์ ์ฝ๊ธฐ/์ฐ๊ธฐ ๋ช ๋ น ๊ตฌ๋ถ
Spring Data Redis๋ ์งํ ์ค์ธ ํธ๋์ญ์ ๋ด์์ ์ฝ๊ธฐ(Read) ๋ช ๋ น๊ณผ ์ฐ๊ธฐ(Write) ๋ช ๋ น์ ๊ตฌ๋ถํฉ๋๋ค.
- ์ฝ๊ธฐ ๋ช ๋ น(์: KEYS)์ ์๋ก์ด(non-thread-bound) RedisConnection์ ํตํด ์คํ๋ฉ๋๋ค. ์ด๋ ํธ๋์ญ์ ์ด ์งํ๋๋ ๋์์๋ ์ฝ๊ธฐ ์์ ์ ์ํํ ์ ์๋๋ก ํ๊ธฐ ์ํจ์ ๋๋ค.
- ์ฐ๊ธฐ ๋ช ๋ น(์: SET)์ RedisTemplate์์ ํ์ ์ ์ฅ๋์๋ค๊ฐ ํธ๋์ญ์ ์ด ์ปค๋ฐ๋ ๋ ํ๊บผ๋ฒ์ ์คํ๋ฉ๋๋ค.
Transaction ๊ด๋ จ Code ๋ Spring Data Redis - Redis Transactions ์ฐธ๊ณ ํด์ฃผ์ธ์.
Lettuce์ Jedis ๋น๊ต
Lettuce๋ ์ด์ธ์๋ ๋ฉ์์ง๋ฅผ ๋ฐํํ๊ณ ๊ตฌ๋ ํ๋ Pub/Sub ๊ธฐ๋ฅ, Reactive API, ๋น๋๊ธฐ API๋ฅผ ์ง์ํฉ๋๋ค.
๋ํ, Redis Replication, Sentinel, Cluster ๊ธฐ๋ฅ๋ค๋ ์ง์ํฉ๋๋ค.
* replication, sentinel, cluster ๋ Redis ์ํคํ ์ฒ์ด๋ฉฐ, ์ ๋ ํ์ตํด์ผํ ๋ด์ฉ์ด๋ผ ์์ธํ๊ฒ ์ค๋ช ๋๋ฆด ์ ์์ง๋ง, ๊ถ๊ธํ์๋ค๋ฉด '[Youtube] Redis ์ผ๋ฌด์ง๊ฒ ์ฌ์ฉํ๊ธฐ' ์์ ํ์ธํ ์ ์์ต๋๋ค.
๋ฐ๋ฉด Jedis๋ ๋๊ธฐI/O ๋ฐฉ์์ด๊ธฐ ๋๋ฌธ์ ๋น๋๊ธฐ I/O์ธ Lettuce๋ณด๋ค ๋๋ฆฌ๋ค๊ณ ํ๋๋ฐ์. ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฐ์ ์ฑ๋ฅ์ ์คํํ ๊ธ์ธ 'Jedis ๋ณด๋ค Lettuce ๋ฅผ ์ฐ์' ์์๋ ๋ง์ ์ฑ๋ฅ ์ฐจ์ด๋ฅผ ๋ณด์ ๋๋ค.
ํ์ง๋ง, Lettuce๋ ๋น๋๊ธฐI/O์ธ ๋งํผ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ ๋, ๋๋ฒ๊น ํ๊ธฐ๊ฐ ์ด๋ ต๋ค๋ ๋จ์ ์ด ์กด์ฌํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ , Jedis๋ณด๋ค ์ฝ์ด์ผ ํ ๋ด๋ถ ์ฝ๋๋ ๋ ๋ง์ ๊ฒ์ด๊ตฌ์.
๊ฒฐ๋ก
- Spring Boot ์์ ๊ธฐ๋ณธ์ ์ผ๋ก LettuceConnectionFactory๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ, ์ฌ๋ฌ ๊ฐ์ LettuceConnection์ด ํ๋์ Native Connection์ ๊ณต์ ํ๋ ๋ฐฉ์์ด ๊ธฐ๋ณธ ์ค์
- Lettuce๋ Pub/Sub ๊ธฐ๋ฅ, Reactive API, ๋น๋๊ธฐ API, ๊ณ ๊ฐ์ฉ์ฑ์ ์ํ Redis Replication, Sentinel, Cluster ๊ธฐ๋ฅ๋ค๋ ์ง์
- ์ค์ ์ ํตํด Redis์ ๋ช ๋ น์ด๋ค์ Spring Boot์์ ์์์ ์ด๊ฒ ์คํ๋๋๋ก ๊ตฌํ์ด ๊ฐ๋ฅํ๋ค.
- RedisTemplate์ Bean์ผ๋ก ๋ฑ๋กํ์ฌ ์ฑ๊ธํค์ผ๋ก ์ฌ์ฉํ๊ฒ ๋๊ณ , ๋ด๋ถ์ ์ผ๋ก ๊ฐ ์์ฒญ๋ง๋ค ์๋ก์ด LettuceConnection ์ธ์คํด์ค๋ฅผ ์์ฑํ๋ค. ํ์ง๋ง, ์์ฑ๋ LettuceConnection๋ค์ด ์ฌ์ฉํ๋ Native Connection์ ์ฌํ์ฉ๋๋ค.
๋ง์น๋ฉฐ
์บ์ฑ ์ ๋ต์ ๊ณต๋ถํ๋ ค๋ค Redis ํด๋ผ์ด์ธํธ๋ฅผ ์ดํด๋ณด๊ฒ ๋์๋๋ฐ, ๋๋ถ์ RedisTemplate์ ์ฌ์ฉํ๊ธฐ ์ ์ ๊ทธ ๋์ ๋ฐฉ์๊น์ง ๊น์ด ์ดํดํ๊ฒ ๋ ๊ฒ ๊ฐ์ต๋๋ค. ๋ํ, ๊ณผ๊ฑฐ์ Spring Data JPA๋ฅผ ๊ณต๋ถํ ๋ JPA ์์ฒด๋ฅผ ๋จผ์ ์ดํดํด์ผ Data JPA๋ฅผ ์ ๋๋ก ํ์ฉํ ์ ์์๋ ๊ฒ์ฒ๋ผ, ์ด๋ฒ์๋ Spring Data Redis๊ฐ Lettuce๋ฅผ ์ผ๋ง๋ ์ถ์ํํ๋์ง, RedisTemplate ์ ํตํด ์๊ฒ ๋๋ ์ข์ ๊ธฐํ์์ต๋๋ค.
์ฐธ๊ณ ๋ฌธ์
Spring Data Redis - RedisTemplate
Jedis vs. Lettuce: An Exploration
Spring Data Redis - Redis Transactions
Spring data redis(lettuce connector) ์ฐ๊ธฐ ์ ์ ์์๋ค๋ฉด ์ข์์ ๊ฒ๋ค
'Redis' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
์ฝ๋๋ก ์์๋ณด๋ Spring Data Redis์ @Cacheable ๋์ ์๋ฆฌ์ ํธ๋์ญ์ ์์ @CachePut/@CacheEvict ์คํ ์์ (0) | 2025.02.20 |
---|