-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Elasticache for Redis를 도입하여 캐싱 적용 (#86)
* feat: redis 의존성 추가 * feat: redis 관련 설정 추가 * feat: 카페 미리보기에 `@Cacheable` 설정 추가 * feat: 로컬 yml redis 설정 추가 * feat: 리뷰 또는 즐겨찾기 등록 시 캐시 삭제 * feat: 즐겨찾기 해제 시 캐시 삭제 * feat: 목적에 따른 CacheManager 분리 및 로그인 시 캐시 적용 * feat: Apple OAuth Public key 캐싱 적용 * refactor: 인증 캐시 ttl 변경 및 주석 추가 * fix: accessToken 캐시 만료 ttl 수정 * feat: 테스트용 내장 임베디드 의존성 및 환경변수 추가 * test: 테스트 임베디드 redis 설정 * test: 테스트 격리를 위한 `DatabaseCleaner` 캐시 제거 * test: 같은 메서드 내에 캐시로 남아있는 현상 제거 * style: 실제값 하나뿐인 변수명 `actual1` -> `actual` 변경
- Loading branch information
Showing
15 changed files
with
213 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
79 changes: 79 additions & 0 deletions
79
src/main/java/mocacong/server/config/RedisCacheConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package mocacong.server.config; | ||
|
||
import java.time.Duration; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.cache.CacheManager; | ||
import org.springframework.cache.annotation.EnableCaching; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.context.annotation.Primary; | ||
import org.springframework.data.redis.cache.RedisCacheConfiguration; | ||
import org.springframework.data.redis.cache.RedisCacheManager; | ||
import org.springframework.data.redis.connection.RedisConnectionFactory; | ||
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; | ||
import org.springframework.data.redis.serializer.RedisSerializationContext; | ||
import org.springframework.data.redis.serializer.StringRedisSerializer; | ||
|
||
@EnableCaching | ||
@Configuration | ||
public class RedisCacheConfig { | ||
|
||
private static final long DELTA_TO_AVOID_CONCURRENCY_TIME = 30 * 60 * 1000L; | ||
|
||
@Value("${security.jwt.token.expire-length}") | ||
private long accessTokenValidityInMilliseconds; | ||
|
||
@Bean | ||
@Primary | ||
public CacheManager cafeCacheManager(RedisConnectionFactory redisConnectionFactory) { | ||
/* | ||
* 카페 관련 캐시는 충분히 많이 쌓일 수 있으므로 OOM 방지 차 ttl 12시간으로 설정 | ||
*/ | ||
RedisCacheConfiguration redisCacheConfiguration = generateCacheConfiguration() | ||
.entryTtl(Duration.ofHours(12L)); | ||
|
||
return RedisCacheManager.RedisCacheManagerBuilder | ||
.fromConnectionFactory(redisConnectionFactory) | ||
.cacheDefaults(redisCacheConfiguration) | ||
.build(); | ||
} | ||
|
||
@Bean | ||
public CacheManager oauthPublicKeyCacheManager(RedisConnectionFactory redisConnectionFactory) { | ||
/* | ||
* public key 갱신은 1년에 몇 번 안되므로 ttl 3일로 설정 | ||
* 유저가 하루 1번 로그인한다고 가정, 최소 1일은 넘기는 것이 좋다고 판단 | ||
*/ | ||
RedisCacheConfiguration redisCacheConfiguration = generateCacheConfiguration() | ||
.entryTtl(Duration.ofDays(3L)); | ||
return RedisCacheManager.RedisCacheManagerBuilder | ||
.fromConnectionFactory(redisConnectionFactory) | ||
.cacheDefaults(redisCacheConfiguration) | ||
.build(); | ||
} | ||
|
||
@Bean | ||
public CacheManager accessTokenCacheManager(RedisConnectionFactory redisConnectionFactory) { | ||
/* | ||
* accessToken 시간만큼 ttl 설정하되, | ||
* 만료 직전 캐시 조회하여 로그인 안되는 동시성 이슈 방지를 위해 accessToken ttl 보다 30분 일찍 만료 | ||
*/ | ||
RedisCacheConfiguration redisCacheConfiguration = generateCacheConfiguration() | ||
.entryTtl(Duration.ofMillis(accessTokenValidityInMilliseconds - DELTA_TO_AVOID_CONCURRENCY_TIME)); | ||
|
||
return RedisCacheManager.RedisCacheManagerBuilder | ||
.fromConnectionFactory(redisConnectionFactory) | ||
.cacheDefaults(redisCacheConfiguration) | ||
.build(); | ||
} | ||
|
||
private RedisCacheConfiguration generateCacheConfiguration() { | ||
return RedisCacheConfiguration.defaultCacheConfig() | ||
.serializeKeysWith( | ||
RedisSerializationContext.SerializationPair.fromSerializer( | ||
new StringRedisSerializer())) | ||
.serializeValuesWith( | ||
RedisSerializationContext.SerializationPair.fromSerializer( | ||
new GenericJackson2JsonRedisSerializer())); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package mocacong.server.config; | ||
|
||
import org.springframework.beans.factory.annotation.Value; | ||
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.GenericJackson2JsonRedisSerializer; | ||
import org.springframework.data.redis.serializer.StringRedisSerializer; | ||
|
||
@Configuration | ||
public class RedisConfig { | ||
|
||
@Value("${spring.redis.host}") | ||
private String redisHost; | ||
|
||
@Value("${spring.redis.port}") | ||
private int redisPort; | ||
|
||
@Bean | ||
public RedisConnectionFactory redisConnectionFactory() { | ||
return new LettuceConnectionFactory(new RedisStandaloneConfiguration(redisHost, redisPort)); | ||
} | ||
|
||
@Bean | ||
public RedisTemplate<String, Object> redisTemplate() { | ||
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); | ||
redisTemplate.setConnectionFactory(redisConnectionFactory()); | ||
redisTemplate.setKeySerializer(new StringRedisSerializer()); | ||
|
||
/* Java 기본 직렬화가 아닌 JSON 직렬화 설정 */ | ||
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); | ||
|
||
return redisTemplate; | ||
} | ||
} |
2 changes: 2 additions & 0 deletions
2
src/main/java/mocacong/server/security/auth/apple/AppleClient.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,13 @@ | ||
package mocacong.server.security.auth.apple; | ||
|
||
import org.springframework.cache.annotation.Cacheable; | ||
import org.springframework.cloud.openfeign.FeignClient; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
|
||
@FeignClient(name = "apple-public-key-client", url = "https://appleid.apple.com/auth") | ||
public interface AppleClient { | ||
|
||
@Cacheable(value = "oauthPublicKeyCache", cacheManager = "oauthPublicKeyCacheManager") | ||
@GetMapping("/keys") | ||
ApplePublicKeys getApplePublicKeys(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.