Skip to content

Commit

Permalink
refactor: Lettuce 타임아웃 시간 상수화
Browse files Browse the repository at this point in the history
기존에 하드코딩 되어있던 타임아웃 시간을 상수로 추출
  • Loading branch information
jemin committed Jan 28, 2024
1 parent de376e9 commit bdd954e
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
Expand All @@ -33,6 +32,8 @@
@Configuration
public class CacheConfig {

private static final Duration COMMAND_TIMEOUT = Duration.ofMillis(200);

@Value("${spring.redis.cache.host}")
private String cacheHost;

Expand All @@ -46,42 +47,20 @@ RedisConnectionFactory redisCacheConnectionFactory() {
redisStandaloneConfiguration.setPort(cachePort);

LettuceClientConfiguration lettuceClientConfiguration = LettuceClientConfiguration.builder()
.commandTimeout(Duration.ofMillis(200)).build();
.commandTimeout(COMMAND_TIMEOUT).build();

return new LettuceConnectionFactory(redisStandaloneConfiguration, lettuceClientConfiguration);
}

/*
설정 종류
- JavaTimeModule : 해당 모듈을 등록해줘야 Java 8의 date/time을 사용해서 string으로 직렬화 가능합니다.
- SerializationFeature.WRITE_DATES_AS_TIMESTAMP : 해당 속성을 true로 설정하면 Long 타입으로 직렬화됩니다. 현재 Disable로 설정해서 String으로 직렬화되도록 설정했습니다.
- DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES : 역직렬화시 클래스 변수에 매핑되지 않는 값이 있을때 예외를 발생시킬지 체크, 현재는 예외가 발생하지 않도록 false로 설정했습니다.
*/
@Bean
public ObjectMapper objectMapper() {

return new ObjectMapper()
.registerModule(new JavaTimeModule())
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}

/*
캐시 TTL 시간 설정 기준
- USER 프로필 캐시는 조회에 비해 변경 가능성이 적고 TTL로 1일을 설정했습니다.
- SCRAP 캐시는 변경 가능성이 높지만 개인화된 데이터이고 TTL로 1일을 설정했습니다.
- MEMORY 상세 페이지 캐시는 메모리 이외에도 그룹 정보, 장소 정보들이 혼합되기 때문에 TTL을 10분으로 짧게 설정했습니다.
- GROUP 상세 페이지 캐시는 그룹 이외에도 유저 정보가 혼합되기 때문에 TTL을 10분으로 짧게 설정했습니다.
Circuit breaker를 통한 HA 보장
레디스로 분산 캐시를 구현 시 레디스 서버가 다운될 수 있습니다. 이때 Spring Cache는 자동으로 DB 조회를 하는 것이 아니라 예외가 발생합니다.
이를 해결하기 위해 레디스 서버 장애시 fallback으로 DB 조회를 수행하고, 임계치 이상 예외 발생 시, Circuit을 Open하고 Redis 서버 조회 자체를
막음으로써 Fail Fast를 통한 Redis Server Recovery를 유도했습니다.
*/
@Bean
public CacheManager customCacheManager(
@Qualifier("redisCacheConnectionFactory") RedisConnectionFactory connectionFactory,
CircuitBreakerFactory circuitBreakerFactory) {
public CacheManager customCacheManager(CircuitBreakerFactory circuitBreakerFactory) {

/* Serializer 설정 */
RedisCacheConfiguration defaultConfig = RedisCacheConfiguration.defaultCacheConfig()
Expand All @@ -91,16 +70,30 @@ public CacheManager customCacheManager(

/* Cache TTL 설정 */
Map<String, RedisCacheConfiguration> redisCacheConfigMap = new ConcurrentHashMap<>();
redisCacheConfigMap.put(CacheNames.USER, defaultConfig.entryTtl(Duration.ofDays(1L)));
redisCacheConfigMap.put(CacheNames.SCRAP, defaultConfig.entryTtl(Duration.ofDays(1L)));
redisCacheConfigMap.put(CacheNames.MEMORY, defaultConfig.entryTtl(Duration.ofMinutes(30)));
redisCacheConfigMap.put(CacheNames.USER, defaultConfig.entryTtl(Duration.ofDays(1)));
redisCacheConfigMap.put(CacheNames.SCRAP, defaultConfig.entryTtl(Duration.ofDays(1)));
redisCacheConfigMap.put(CacheNames.MEMORY, defaultConfig.entryTtl(Duration.ofMinutes(10)));
redisCacheConfigMap.put(CacheNames.GROUP, defaultConfig.entryTtl(Duration.ofMinutes(10)));

RedisCacheManager redisCacheManager = RedisCacheManager.builder(connectionFactory)
.withInitialCacheConfigurations(redisCacheConfigMap)
.build();
RedisCacheManager redisCacheManager = RedisCacheManager.builder(redisCacheConnectionFactory())
.withInitialCacheConfigurations(redisCacheConfigMap).build();

CircuitBreaker circuitBreaker = circuitBreakerFactory.create(CACHE_CIRCUIT);
return new CustomCacheManager(redisCacheManager, circuitBreaker);
}

/*
설정 종류
- JavaTimeModule : Java 8의 date/time을 사용해서 string으로 직렬화
- SerializationFeature.WRITE_DATES_AS_TIMESTAMP : 해당 속성을 true 시 Long 타입 직렬화, false는 String으로 직렬화
- DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES : 역직렬화시 클래스 변수에 매핑되지 않는 값이 있을때 예외 발생 여부
*/
@Bean
public ObjectMapper objectMapper() {

return new ObjectMapper()
.registerModule(new JavaTimeModule())
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
@Configuration
public class RedisConfig {

private static final Duration COMMAND_TIMEOUT = Duration.ofMillis(200);

@Value("${spring.redis.token.host}")
private String tokenHost;

Expand All @@ -30,7 +32,7 @@ public RedisConnectionFactory redisConnectionFactory() {
redisStandaloneConfiguration.setPort(tokenPort);

LettuceClientConfiguration lettuceClientConfiguration = LettuceClientConfiguration.builder()
.commandTimeout(Duration.ofMillis(200)).build();
.commandTimeout(COMMAND_TIMEOUT).build();

return new LettuceConnectionFactory(redisStandaloneConfiguration, lettuceClientConfiguration);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ public void save(String key, String value) {
redisTemplate.opsForValue().set(key, value);
}

public void save(String key, String value, Long expiredTime) {
redisTemplate.opsForValue().set(key, value, expiredTime, TimeUnit.MILLISECONDS);
public void save(String key, String value, Long expiredTime, TimeUnit timeUnit) {
redisTemplate.opsForValue().set(key, value, expiredTime, timeUnit);
}

public String get(String key) {
Expand Down

0 comments on commit bdd954e

Please sign in to comment.