๐ Redis๋ก Key๊ด๋ฆฌํ๊ธฐ
๋ํ, redis๋ ๋ณด์กฐ๊ธฐ์ต์ฅ์น(HDD / SSD)๊ฐ ์๋ ๋ฉ๋ชจ๋ฆฌ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ์ฌ ํ์ํ ์๋, ์์ ์ฑ, ์ฑ๋ฅ์ ์ ๊ณตํ ์ ์๋ค.
์ ํ์ด์ผ์ด์ ์ด ์ธ๋ถ ๋ฐ์ดํฐ ์์ค์ ์์กดํ๋ ๊ฒฝ์ฐ ํธ๋ ํฝ์ด ์ฆ๊ฐํ๊ฑฐ๋, ์ ํ๋ฆฌ์ผ์ด์ ์ด ํ์ฅ๋ ๋ ์์ค์ ์ง์ฐ ์๊ฐ๊ณผ ์ฒ๋ฆฌ๋์ผ๋ก ์ธํ์ฌ ๋ณ๋ชฉํ์์ด ๋ฐ์ํ ์ ์๋ค. ์ด๋ Redis๋ฅผ ์ ์ฉํ๋ฉด, ๋ฐ์ดํฐ๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํ์ฌ ์ฝ๊ฑฐ๋ ์ธ๋ ์ง์ฐ ์๊ฐ์ ์ต์ํ ํ ์ ์๋ค.
๊ฐ์ฉ์ฑ : ์๋ฒ ๋๋ ๋คํธ์ํฌ ๋ฑ์ ์ ๋ณด ์์คํ
์ด ์ ์์ ์ผ๋ก ์ฌ์ฉ ๊ฐ๋ฅํ ์ ๋๋ฅผ ์๋ฏธ.
== ์ ์์ ์ธ ์ฌ์ฉ์๊ฐ
/ ์ ์ฒด ์ฌ์ฉ์๊ฐ
= ์์คํ
๊ฐ๋๋ฅ
(๊ฐ์ฉ์ฑ)
์ฌ๊ธฐ์, ๊ณ ๊ฐ์ฉ์ฑ์ด๋ ๊ฐ์ฉ์ฑ์ด 99%, 99.9% ๋ฑ๊ณผ ๊ฐ์ด ๋์ ๊ฐ์ฉ์ฑ์ ์ง๋ ์์คํ ์ ์๋ฏธํ๋ค.
build.gradle์ ์์กด์ฑ ์ถ๊ฐ
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
yml redis ์์ฑ ์ถ๊ฐ
cache:
type: redis
redis:
cache-null-values: true
redis:
host: `๋ ๋์ค ํธ์คํธ`
port: `๋ ๋์ค ํฌํธ`
@Configuration
public class RedisConfiguration {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
}
Redis ์๋ฒ์ ์ฐ๊ฒฐ์ ์์ฑ ๋ฐ ๊ด๋ฆฌํด์ฃผ๋ ์ธํฐํ์ด์ค
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(host, port);
}
๋ฐ๋ผ์ ํด๋น ์ฝ๋์๋ ๋น๋๊ธฐ ์ฑ๋ฅ์ด ๋์ ์ข์ Lettuce ์ ํ.
Redis์ ์ ์ฅ๋ ์บ์์ ๊ธฐ๋ณธ ์ง๋ ฌํ ๋ฐ ๋ง๋ฃ ์๊ฐ(TTL) ๋ฑ์ ์ค์ ์ ๋ด๋น.
private RedisCacheConfiguration redisCacheDefaultConfiguration() {
return RedisCacheConfiguration
.defaultCacheConfig()
.serializeKeysWith(RedisSerializationContext.SerializationPair
.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer());
}
StringRedisSerializer
๋ฅผ ์ฌ์ฉํ์ฌ ํค๋ฅผ ๋ฌธ์์ด๋ก ์ง๋ ฌํํฉ๋๋ค.GenericJackson2JsonRedisSerializer
์ ObjectMapper
๋ฅผ ์ฌ์ฉํด JSON ํ์์ผ๋ก ์ง๋ ฌํ
GenericJackson2JsonRedisSerializer
: ์ง๋ ฌํ ๋ฐฉ์ ์ค ํ๋๋ก, JSONํ์์ ์ง์.
์ฌ๋ฌ ์บ์ ์ด๋ฆ์ ๋ํด ๊ฐ๊ธฐ ๋ค๋ฅธ TTL(Time To Live)์ ๋์ ์ผ๋ก ์ค์ .
private Map<String, RedisCacheConfiguration> redisCacheConfigurationMap() {
Map<String, RedisCacheConfiguration> cacheConfigurations = new HashMap<>();
for (Map.Entry<String, Long> cacheNameAndTimeout : cacheProperties.getTtl().entrySet()) {
cacheConfigurations
.put(cacheNameAndTimeout.getKey(), redisCacheDefaultConfiguration().entryTtl(
Duration.ofSeconds(cacheNameAndTimeout.getValue())));
}
return cacheConfigurations;
}
//cacheProperties.yml
cache:
ttl:
CacheName: 10 #๋ง๋ฃ ์๊ฐ
CacheProperties
)์์ ์บ์๋ณ TTL ์ ๋ณด๋ฅผ ์ฝ์ด์ ๊ฐ ์บ์์ ๋ง๋ฃ ์๊ฐ์ ์ง์
์ด๋ฅผ ํตํด ํน์ ์บ์๋ง ๋ณ๋์ ๋ง๋ฃ ์ ์ฑ
๋ฑ์ ์ ์ฉํ ์ ์๋ค.Spring์ ์บ์ ์ถ์ํ์์ Redis๋ฅผ ์บ์ ์ ์ฅ์๋ก ์ฌ์ฉํ๊ธฐ ์ํ ์บ์ ๋งค๋์ ๋ฅผ ์์ฑ
์์์ ์ค์ ํ redisCacheDefaultConfiguration
๊ณผ cacheConfigurations
(์ปค์คํ
) ์ด ์ฝ์
๋๋ค.
@Bean
public CacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
return RedisCacheManager.RedisCacheManagerBuilder
.fromConnectionFactory(redisConnectionFactory)
.cacheDefaults(redisCacheDefaultConfiguration())
.withInitialCacheConfigurations(redisCacheConfigurationMap())
.build();
}
withInitialCacheConfigurations
: RedisCacheManager๋ฅผ ์์ฑํ ๋ ๋ฏธ๋ฆฌ ์ ์๋ ํน์ ์บ์ ์ด๋ฆ์ ๋ํด ๊ฐ๋ณ์ ์ธ ์ค์ ์ ์ ์ฉํ ์ ์๋๋ก ํด์ฃผ๋ ๋ฉ์๋์
๋๋ค.โถ ๐จ RSA ์ํธํ ๋ฐฉ์์ ์ดํด์ ์ ์ฉ (feat.์ทจ์ฝ์ฑ์ ๊ฒ) ์์ ์ด์ด์ง๋ค.
@Service
public class TestServiceImpl {
private final CacheManager cacheManager;
private final RedisTemplate<String, Object> redisTemplate;
public TestServiceImpl(CacheManager cacheManager, RedisTemplate<String, Object> redisTemplate) {
this.cacheManager = cacheManager;
this.redisTemplate = redisTemplate;
}
}
(์์ฑ์ ์ฃผ์ )
๋ง์ฝ, Bean์ผ๋ก ์์ฑ๋ CacheManager๊ฐ์ฒด๋, RedisTemplate๊ฐ์ฒด๊ฐ ์ฌ๋ฌ๊ฐ๋ผ๋ฉด,
@Qualifier ์ด๋
ธํ
์ด์
์ผ๋ก Bean์ด๋ฆ์ ๋ช
์ํด์ผํ๋ค.
`ex) @Qualifier("CustomCacheManager") CacheManager cacheManager ...`
Cache privateKeyCache = cacheManager.getCache("CacheName");
public void putCache() {
if (privateKeyCache != null) {
privateKeyCache.put(keyId, ๋ฒจ๋ฅ);
} else {
// ์บ์๊ฐ ์์ผ๋ฉด ์์ธ ์ฒ๋ฆฌ ๋๋ ๋ก๊น
throw new IllegalStateException("privateKeyCache ๊ฐ ์ ์ํ์ง ์์ต๋๋ค.");
}
}
public void getCache() {
if (privateKeyCache == null) {
throw new IllegalStateException("rsaPrivateKeyCache ๊ฐ ์ ์ํ์ง ์์ต๋๋ค.");
}
String privateKeyValue = privateKeyCache.get(keyId, String.class);
// 1ํ์ฉ ์ฌ์ฉ์ ์ํด ์กฐํ ํ ์บ์์์ ์ ๊ฑฐํ ์ ์๋ค.
rsaPrivateKeyCache.evict(keyId); // 1ํ์ฉ ์ฌ์ฉ: ์บ์์์ ์ ๊ฑฐ
}
put(keyId, ๋ฒจ๋ฅ);
/ get(keyId, String.class);
๋ก ์ฝ์
/ ๊ฐ์ ธ์ค๊ธฐ๊ฐ ๊ฐ๋ฅํ๋ค..evict(keyId)
๋ก ์ญ์ ( 1ํ์ฑ ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค. )๋์ ๊ฒฝ์ฐ์ RSAํค๋ฅผ ๋งค๋ฒ ๋ฐ๊ธ ๋ฐ๊ธฐ ๋๋ฌธ์ ๊ฐ์ ๊บผ๋๊ณผ ๋์์ ํด๋น ํค๋ฒจ๋ฅ๋ฅผ ์ญ์ ํ๋ค.
Exception์ด ํฐ์ง๋๋ผ๋, cacheProperties ์ ์ค์ ํ TTL์ด ์ด๊ณผ๋๋ฉด ์ญ์ ๋๋ค.
application.yml / properties
โ
CacheProperties (ttl map ๊ด๋ฆฌ)
โ
redisCacheConfigurationMap() โ ์บ์๋ณ TTL ๋งคํ
โ
redisCacheDefaultConfiguration() โ ๊ธฐ๋ณธ ์ค์ (ex: serializer, ๊ธฐ๋ณธ TTL)
โ
redisCacheManager() โ ์ต์ข
CacheManager ์์ฑ
๋ค์๊ณผ ๊ฐ์ด TTL ์๊ฐ ๋ฐ Redis ๋ง๋ฃ ์ ์ฑ ์ ๋งตํ ํ ์ ์๋ค.