
๐ Redis ์ฐ๋ํ๊ธฐ
Spring Boot ํ๋ก์ ํธ์ Redis๋ฅผ ๋ถ์ด๋ ค๋ฉด ๋จผ์ ๋ ์ฌ์ด๋ฅผ ์ฐ๊ฒฐํ๋ ํต๋ก๋ฅผ ์ด์ด์ฃผ์ด์ผ ํ๋ค.
์๋ ์ฝ๋๋ ์ฐ๊ฒฐ ํต๋ก๋ฅผ ์ด์ด์ฃผ๊ธฐ ์ํด์ ๋ด๊ฐ ์ฌ์ฉํ ์ค์ ํด๋์ค์ธ๋ฐ, ์ด์ ๊ด๋ จํ ๊ฐ๋ ๋ค์ ์ ๋ฆฌํด๋ณด๊ณ ์ ํ๋ค.
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Slf4j
@EnableCaching
@Configuration
public class RedisConfig {
@Value("${spring.data.redis.host}")
private String redisHost;
@Value("${spring.data.redis.port}")
private int redisPort;
@Value("${spring.data.redis.password:}")
private String redisPassword;
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(new RedisStandaloneConfiguration(redisHost, redisPort));
}
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory cf) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
// โ ์ปค๋ฅ์
ํฉํ ๋ฆฌ ์ฃผ์
template.setConnectionFactory(cf);
// โก ์ง๋ ฌํ ์ ๋ต(Serializer) ์ค์
StringRedisSerializer stringSer = new StringRedisSerializer();
template.setKeySerializer(stringSer); // ํค : ์ฌ๋์ด ์ฝ์ ์ ์๋ ๋ฌธ์์ด
template.setHashKeySerializer(stringSer); // ํด์ ํค๋ ๋ฌธ์์ด๋ก!
// “๊ฐ” ์ชฝ์ ์ํฉ์ ๋ฐ๋ผ ์ ๋ต์ด ๊ฐ๋ฆฐ๋ค
// โโ ๋จ์ ๋ฌธ์์ด๋ง ์ ์ฅ โ StringRedisSerializer
// โโ ์๋ฐ ๊ฐ์ฒด(DTO, Map ๋ฑ)๊น์ง ์ ์ฅ โ GenericJackson2JsonRedisSerializer
template.setValueSerializer(stringSer); // ← ์์๋ ๋ฌธ์์ด ์ ์ฉ
template.setHashValueSerializer(stringSer);
template.afterPropertiesSet(); // ๋ด๋ถ ์ด๊ธฐํ
return template;
}
}
๐ ํด๋์ค ์ ์ธ๋ถ
- @Configuration ๐๐ป ์ด๊ฒ์ ๋ช ์ํ๋ฉด "๋๋ ์ค์ ํ์ผ์ด์ผ!" ํ๊ณ Spring ์ปจํ ์ด๋์ ๋ฑ๋ก๋๋ค.
- @EnableCaching ๐๐ป ์ดํ์ @Cacheable ๋ฑ์ ์ฌ์ฉํ๋ฉด, Redis๋ฅผ ์บ์ ์ ์ฅ์๋ก ํ์ฉํ ์ค๋น๊ฐ ์๋ฃ๋๋ค.
- @Slf4j ๐๐ป ๋ก๊น ์ ํธํ๊ฒ ์ฐ๊ธฐ ์ํ Lombok ์ด๋ ธํ ์ด์ ์ด๋ค.
๐ ํ๋กํผํฐ ์ฃผ์
@Value("${spring.data.redis.host}")
private String redisHost;
@Value("${spring.data.redis.port}")
private int redisPort;
@Value("${spring.data.redis.password:}")
private String redisPassword;
application.yml์ ์ ์ด ๋ host, port, password ๊ฐ์ ์ฃผ์ ํด์ค๋ค.
ํ๊ฒฝ๋ณ๋ก ๊ฐ๋ง ๋ฐ๊พธ๋ฉด ์ฝ๋ ์์ ์์ด ๋ค๋ฅธ Redis ์ธ์คํด์ค์ ์ฐ๊ฒฐํ ์ ์๋ค.
๐ redisConnectionFactory
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(new RedisStandaloneConfiguration(redisHost, redisPort));
}
Spring Data ๊ณ์ด์์๋ DB๋ ์บ์ ์๋ฒ์ ์ง์ ์ฐ๊ฒฐ์ ๋ง๋ค๊ณ ๊ด๋ฆฌํ๋ ์ฑ ์์ ...ConnectionFactory๋ผ๋ ์ธํฐํ์ด์ค์ ์์ํ๋ค.
์ด ๋๋ถ์ ์ฐ๋ฆฌ๋ JdbcTemplate · RedisTemplate ๊ฐ์ ๊ณ ์์ค API๋ฅผ ์ฌ์ฉํ ๋,
์ปค๋ฅ์ ์ ์ด๋ป๊ฒ ์ป์์ง ๊ณ ๋ฏผํ ํ์ ์์ด ConnectionFactory๋ฅผ ์ฃผ์ ๋ฐ์์ ํ์ํ ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ณ ์ฐ๊ธฐ๋ง ํ๋ฉด ๋๋ ๊ฒ์ด๋ค.
ํนํ, ์ด๋ฒ์ ์์๋ณผ Redis์์๋ ์ด ConnectionFactory์ ๊ตฌ์ฒด ๊ตฌํ์ฒด๋ก LettuceConnectionFactory๋ฅผ ์ฌ์ฉํ๋ค.
Jedis์ ๋น๊ตํ์ ๋ Lettuce๊ฐ ๊ฐ๋ ๊ฐ์ ์ ๋ช ๊ฐ์ง ์ดํด๋ณด๋ฉด, ์๋์ ๊ฐ๋ค.
- Netty ๊ธฐ๋ฐ ๋
ผ๋ธ๋กํน I/O
- Lettuce๋ Netty ์์์ ๋์ํ๋ ๋๋ผ์ด๋ฒ๋ก, ๋ ผ๋ธ๋กํน I/O๋ฅผ ์ง์ํ๋ค.
- ์ด๋ฅผ ํตํด ํ๋์ ์ปค๋ฅ์ ์ ์ฌ๋ฌ ์ค๋ ๋๊ฐ ๊ณต์ ํ ์ ์๊ณ , I/O ์ด๋ฒคํธ๋ ๋ชจ๋ ์ด๋ฒคํธ ๋ฃจํ๋ผ๋ ์ค์ ์ฅ์น์์ ์ฒ๋ฆฌ๋๋ค.
- ๋ฐ๋ผ์ ๊ฒฐ๊ณผ์ ์ผ๋ก๋, ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋๊ณผ ์ค๋ ๋ ์๋ฅผ ๋ํญ ์ค์ผ ์ ์๊ธฐ์ ๊ณ ์ฑ๋ฅ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ํฉํ๋ค.
- Reactive & Pub / Sub ์ง์
- Lettuce๋ Mono, Flux๋ฅผ ํตํด ๋ฆฌ์กํฐ๋ธ ๋ฐฉ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃฐ ์ ์์ด์ WebFlux ํ๊ฒฝ๊ณผ ์ ๋ง๋๋ค.
- ๋ํ, Pub / Sub ๋ฉ์์ง ๊ธฐ๋ฅ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ง์ํ๋ค.
- ์๋ ๋ณต๊ตฌ (Auto-Reconnect & Backoff)
- ๋คํธ์ํฌ ์ค๋ฅ๋ Redis ๋ค์ด์ผ๋ก ์ปค๋ฅ์ ์ด ๋ํ๋, ์๋ ์ฌ์๋ ๋ฐ ์ง์ ๋ฐฑ์คํ ์ ๋ต์ด ๋ด์ฅ๋์ด ์์ด์ ์ด์ ์ค ์์ ์ฑ์ด ๋ฐ์ด๋๋ค.
- Topology Refresh ์ง์
- Sentinel ๋๋ Cluster ํ๊ฒฝ์์ ๋ง์คํฐ ๋ ธ๋๊ฐ ๋ณ๊ฒฝ๋๋ฉด, ์๋์ผ๋ก ๊ฐ์งํด์ ์ฐ๊ฒฐ์ ๊ฐฑ์ ํ ์ ์๋ค.
LettuceConnectionFactory๋ ๋จ์ํ ์ปค๋ฅ์ ํ๋๋ฅผ ์ด๊ณ ๋ง๋ ๊ฐ์ฒด๊ฐ ์๋๋ผ, ๋ด๋ถ์ ์ผ๋ก ๊ฝค ๋ณต์กํ ์ด๊ธฐํ ๊ณผ์ ์ ๊ฑฐ์น๋ค.
๊ทธ ๊ณผ์ ์ ์๋์ ๊ฐ๋ค.
- ํด๋ผ์ด์ธํธ ์์ ์์ฑ
- ๋จผ์ ClientResources ๋ผ๋ ๊ฐ์ฒด๋ฅผ ํตํด Netty ์ด๋ฒคํธ๋ฃจํ, DNS ๋ฆฌ์กธ๋ฒ, ํ์ด๋จธ ๋ฑ์ ์์์ ์ค๋นํ๋ค.
- ์ด ์์์ ์ฌ๋ฌ Redis ์ธ์คํด์ค ๊ฐ์๋ ์ฌ์ฌ์ฉํ ์ ์์ด ํจ์จ์ ์ด๋ค.
- LettuceClient ์ธ์คํด์ค ์ค๋น
- Redis ํด๋ผ์ด์ธํธ๋ฅผ ์ด๊ธฐํํ๋ค.
- ์ด๋ Standalone, Sentinel, ๋๋ Cluster ๊ฐ๊ฐ์ ๋ง๋ ํด๋ผ์ด์ธํธ ๊ฐ์ฒด๊ฐ ์ฌ์ฉ๋๋ค.
- ๋ด๊ฐ ์์์ ์ค์ ํ ์ฝ๋๋ RedisStandaloneConfiguration์ด๋ฏ๋ก ๋จ์ผ ๋ ธ๋์ฉ RedisClient๊ฐ ๋ง๋ค์ด์ง ๊ฒ์ด๋ค.
- Connection Pool ์ด๊ธฐํ (์ ํ ์ฌํญ)
- commons-pool2๋ฅผ ํตํด ์ปค๋ฅ์ ํ์ ํ์ฑํํ ์ ์๋ค.
- ํ์ ์ค์ ํ๋ฉด ์ต๋ ์ฐ๊ฒฐ ์, idle ์ ์ง ์๊ฐ, ์ต์ ์ ํด ์ปค๋ฅ์ ์ ๋ฑ์ ์ง์ ํ ์ ์์ด์ ์ค์๋น์ค์ ์์ ์ ์ผ๋ก ๋์ํ ์ ์๋ค.
- Lazy Connect
- ํฉํ ๋ฆฌ๋ฅผ ์์ฑํ ๋ Redis์ ๋ฐ๋ก ์ฐ๊ฒฐํ์ง ์๊ณ , ์ฒ์์ผ๋ก getConnection()์ ํธ์ถํ๋ ์์ ์ ์ค์ ์ฐ๊ฒฐ์ด ์ด๋ฃจ์ด์ง๋ค.
- ๋๋ถ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ถํ ์๋๊ฐ ๋นจ๋ผ์ง๊ณ , ๋ถํ์ํ ์ด๊ธฐ ์ปค๋ฅ์ ๋ ์ค์ผ ์ ์๋ค.
- Exception Translation
- Redis ๋ช ๋ น ์ค ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ฉด Lettuce๋ ์์ฒด ์์ธ๋ฅผ ๋์ง๋ค.
- ์คํ๋ง์ ์ด ์์ธ๋ฅผ DataAccessException ๊ฐ์ ๊ณตํต ์์ธ๋ก ๊ฐ์ธ์ ๋ฐํํ๋ค.
- ์ด ๋๋ถ์ DB, Redis ๋ฑ ๋ค์ํ ์ ์ฅ์์ ์์ธ๋ฅผ ํ๋์ ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌํ ์ ์๊ณ , ๊ตญ์ ํ ๋ฉ์์ง ์ฒ๋ฆฌ์๋ ์ ๋ฆฌํ๋ค.
โ๏ธ redisTemplate
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory cf) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
// โ ์ปค๋ฅ์
ํฉํ ๋ฆฌ ์ฃผ์
template.setConnectionFactory(cf);
// โก ์ง๋ ฌํ ์ ๋ต(Serializer) ์ค์
StringRedisSerializer stringSer = new StringRedisSerializer();
template.setKeySerializer(stringSer); // ํค : ์ฌ๋์ด ์ฝ์ ์ ์๋ ๋ฌธ์์ด
template.setHashKeySerializer(stringSer); // ํด์ ํค๋ ๋ฌธ์์ด๋ก!
// “๊ฐ” ์ชฝ์ ์ํฉ์ ๋ฐ๋ผ ์ ๋ต์ด ๊ฐ๋ฆฐ๋ค
// โโ ๋จ์ ๋ฌธ์์ด๋ง ์ ์ฅ โ StringRedisSerializer
// โโ ์๋ฐ ๊ฐ์ฒด(DTO, Map ๋ฑ)๊น์ง ์ ์ฅ โ GenericJackson2JsonRedisSerializer
template.setValueSerializer(stringSer); // ← ์์๋ ๋ฌธ์์ด ์ ์ฉ
template.setHashValueSerializer(stringSer);
template.afterPropertiesSet(); // ๋ด๋ถ ์ด๊ธฐํ
return template;
}
RedisTemplate์ด ํ์ํ ์ด์ ๋ ์๋์ ๊ฐ๋ค.
- ๊ณ ์์ค API ์ ๊ณต
- template.opsForValue().set("foo", "bar") ๊ฐ์ ๋ฉ์๋ ํ ์ค๋ก SET foo bar ๋ช ๋ น์ ๋ ๋ฆด ์ ์๋ค.
- ๋ฐ๋ผ์ ์์ผ, ๋ฐ์ดํธ ๋ฐฐ์ด, ์์ธ ์ฒ๋ฆฌ ๋ฑ ์ ์์ค ์ฝ๋๋ฅผ ์ง์ ๋ค๋ฃฐ ํ์๊ฐ ์๋ค.
- ํ์
์์ & ์ง๋ ฌํ ์๋ํ
- ํค-๊ฐ ํ์ ์ ์ ๋ค๋ฆญ์ผ๋ก ๋ช ์ํ๊ณ , Serializer๋ฅผ ํ ๋ฒ๋ง ์ง์ ํ๋ฉด ์ดํ ํธ์ถ๋ถํฐ๋ ์๋ ๋ณํ๋๋ค.
- ๋ฐ๋ผ์ JSON → ๋ฐ์ดํธ → Redis ๊ณผ์ ์ ์์ผ๋ก ๋ฐ๋ณตํ ํ์๊ฐ ์๋ค.
- ํธ๋์ญ์ , ํ์ดํ๋ผ์ธ, Pub / Sub ๋ฑ ๊ณ ๊ธ ๊ธฐ๋ฅ๋ ๋์ผ ๊ฐ์ฒด๋ก ์ฌ์ฉ ๊ฐ๋ฅํ๋ค.
๋ํ, Serializer๋ฅผ ์ง์ ํด์ฃผ๋ ์ด์ ๋ Redis ๋ด๋ถ๋ ๋ฐ์ดํธ ๋ฐฐ์ด๋ง ๋ค๋ฃจ๊ธฐ ๋๋ฌธ์
์๋ฐ ๊ฐ์ฒด ↔ ๋ฐ์ดํธ ๋ณํ ๊ท์น (Serializer)์ ๋ช ํํ ์ ํด์ฃผ์ด์ผ ๋ฐ์ดํฐ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์ฝ๊ณ ์จ์ง๊ธฐ ๋๋ฌธ์ด๋ค.
๋ํ์ ์ธ Serializer ์ข ๋ฅ๋ ์๋์ ๊ฐ๋ค.
- StringRedisSerializer
- UTF-8 ๋ฌธ์์ด์ ๊ทธ๋๋ก ์ ์ฅํ๊ณ ์ถ์ ๋ ์ฌ์ฉํ๋ค.
- ํค-๊ฐ์ด ๋ชจ๋ ์งง์ ๋ฌธ์์ด์ด๋ฉด ๊ฐ์ฅ ๋จ์ํ๊ณ ๋น ๋ฅด๋ค.
- GenericJackson2JsonRedisSerializer
- ์๋ฐ ๊ฐ์ฒด๋ฅผ JSON ๋ฌธ์์ด๋ก ๋ณํํด์ ์ ์ฅํ๋ค.
- ์ด๋ ํด๋์ค ์ ๋ณด๊น์ง ํจ๊ป ๋ณด๊ดํ๊ธฐ์ ์ญ์ง๋ ฌํ์ ์์ ํ๋ค.
- ํนํ, DTO, Map, ๋ณต์ก ๊ฐ์ฒด๋ฅผ ์บ์์ ๊ทธ๋๋ก ๋ฃ๊ณ ์ถ์ ๋ ์ ์ฉํ๋ค.
- ์ปค์คํ
Serializer
- ์ฑ๋ฅ ๊ทน๋ํ๋ฅผ ์ํ๋ฉด Kryo, ProtoBuf ๊ฐ์ ๋ฐ์ด๋๋ฆฌ ํฌ๋งท์ผ๋ก ์ปค์คํ ๊ตฌํ์ด ๊ฐ๋ฅํ๋ค.
- ๋จ, ์์ชฝ ๋ชจ๋ ๊ฐ์ Serializer๋ฅผ ์จ์ผ ์ญ์ง๋ ฌํ ์ค๋ฅ๊ฐ ์๋ค.
๐ ๊ฒฐ๋ก
Spring Boot์์ Redis๋ฅผ ์์ ์ ์ผ๋ก ์ฌ์ฉํ๋ ค๋ฉด
RedisConnectionFactory๋ก ์ฐ๊ฒฐ์ ์ด๊ณ ,
RedisTemplate์ ํตํด ์ง๋ ฌํ ์ค์ ๊ณผ ๋ฐ์ดํฐ ๋ช ๋ น์ ๊ณ ์์ค API๋ก ๋ค๋ฃจ๋ ๊ฒ์ด ํต์ฌ์ด๋ค.
๊ทธ ๋์์ ์ฝ๋ ํ ์ค ํ ์ค์ด ์ด๋ค ์ญํ ์ ํ๋์ง๋ ๋ชจ๋ฅด๊ณ ,
์์ ์ ์ผ๋ ์ฝ๋๋ฅผ ๋ณต์ฌํด์์ ์ฐ๊ธฐ๋ง ํ๋๋ฐ,
์ด์ ๋ ๊ทธ ์๋ฏธ๋ฅผ ๋ช ํํ ์ดํดํ๊ณ ๋ ๋์ ๊ตฌ์กฐ๋ฅผ ์ํด ๊ณ ๋ฏผํ๋ ์ต๊ด์ ๊ธธ๋ฌ์ผ๊ฒ ๋ค.
'๐ป๊ณต๋ถ ๊ธฐ๋ก > ๐ Backend' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [Backend] @Transactional (3) | 2025.07.07 |
|---|---|
| [Backend] RedisTemplate (1) | 2025.06.28 |
| [Backend] Redis TTL + JWT (0) | 2025.06.22 |
| [Backend] JWT (0) | 2025.06.21 |
| [Backend] Java 17 VS Java 21 (2) | 2025.06.17 |