๐ก๋ฌธ๋ ๋๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ํ์ด์ง ํธ์ถ ์ ๋ง๋ค DB์ ์ ๊ทผํด์ ๊ฐ์ ธ์จ๋ค๋ฉด, ์ฑ๋ฅ ์ด์๊ฐ ์์ ์ ์์ง ์์๊น? ๋ผ๋ ์๊ฐ์ด ๋ค์๋ค.(๋ฐ์ดํฐ ์๊ฐ ๋ง์ ๋)
๊ทธ๋์ In-memory ๊ธฐ๋ฐ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ธ Redis๋ฅผ ์ฌ์ฉํด์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ณ ๋ถ๋ฌ์จ๋ค๋ฉด ์ฑ๋ฅ ๊ฐ์ ์ ํ ์ ์์ ๊ฒ ๊ฐ์๋ค. (TTL ์ค์ ์ ํตํ ํ๋ฐ์ฑ ๋ฐ์ดํฐ ์ ์ฅ)
๋ํ, Springboot์์๋ Redis์ ์ฐ๋ํ๊ธฐ ์ํ library๋ ์ง์ํด์ฃผ๊ณ , cache ๊ธฐ๋ฅ๋ ์ง์ํ๋ค๊ณ ํ๋ค.
Springboot์์ Redis๋ฅผ ํ์ฉํ์ฌ cache ๊ธฐ๋ฅ์ ์ค๊ณํ๊ธฐ ์ํ ์ ๋ต์ [Redis] ์บ์ ์ค๊ณ ์ ๋ต ์ง์นจ์ ์ฐธ๊ณ ํ์.
์ด์ ์๋๋ฅผ ํตํด Spring boot์ Redis๋ฅผ ์ฐ๋ํ๊ณ , cache๋ ์ฌ์ฉํด๋ณด๋๋ก ํ์!
1. ๋ ๋์ค ์ฐ๋ํ๊ธฐ(์์กด์ฑ ์ฃผ์ )
implementation 'org.springframework.boot:spring-boot-starter-data-redis’
Gradle์ด๋ผ๋ฉด build.gradle์ ํด๋น ๋ด์ฉ์ ์ถ๊ฐํ์ฌ Redis ์์กด์ฑ์ ์ถ๊ฐํด์ค๋ค.
๊ทธ๋ฆฌ๊ณ application.yml(application.properties) ํ์ผ์ ์๋ ๋ด์ฉ์ ์ถ๊ฐํด์ค๋ค.(host์ port๋ ๊ฐ์ ์์์→ redis ๊ธฐ๋ณธํฌํธ๋ 6379์)
spring:
cache:
type: redis # ์คํ๋ง์์ ์บ์ ์ฌ์ฉ์ redis๋ก ํ๊ฒ ๋ค ์ค์
data:
redis:
host: localhost
port: 6379
1-1. RedisConfig ์ค์ ํ๊ธฐ
๐ก Tip
Spring boot 2.0๋ถํฐ RedisTemplate์ StringTemplate๋ฅผ ์๋์์ฑ ๋์ด์ ๋ฐ๋ก ๋น์ ๋ฑ๋ก์ํด๋ ๋๋ค๊ณ ํ๋ค.
RedisTemplate์๋ serializer๋ฅผ ์ค์ ํด์ฃผ๋๋ฐ ์ค์ ํ์ง ์๋ ๋ค๋ฉด ์ง์ redis-cli๋ก ๋ฐ์ดํฐ ํ์ธ์ด ์ด๋ ต๋ค
@EnableCaching ์ค์ ์ ํตํด Spring Boot์ ์บ์ฑ ์ฌ์ฉ์ ํ๋ค๊ณ ์๋ฆฐ๋ค.
@Configuration
public class RedisConfig {
private final String redisHost;
private final int redisPort;
public RedisConfig(@Value("${spring.data.redis.host}") final String redisHost,
@Value("${spring.data.redis.port}") final int redisPort) {
this.redisHost = redisHost;
this.redisPort = redisPort;
}
@Bean
public RedisConnectionFactory redisConnectionFactory(){
return new LettuceConnectionFactory(
new RedisStandaloneConfiguration(redisHost, redisPort));
}
@Bean
public RedisTemplate<String, String> redisTemplate() {
// redisTemplate๋ฅผ ๋ฐ์์์ set, get, delete๋ฅผ ์ฌ์ฉ
RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
/**
* setKeySerializer, setValueSerializer ์ค์
* redis-cli์ ํตํด ์ง์ ๋ฐ์ดํฐ๋ฅผ ์กฐํ ์ ์์๋ณผ ์ ์๋ ํํ๋ก ์ถ๋ ฅ๋๋ ๊ฒ์ ๋ฐฉ์ง
*/
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
redisTemplate.setConnectionFactory(redisConnectionFactory());
return redisTemplate;
}
}
@Configuration
@EnableCaching
public class RedisCacheConfig {
@Bean(name = "cacheManager")
public CacheManager cacheManager(RedisConnectionFactory cf) {
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.disableCachingNullValues()
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
.entryTtl(Duration.ofMinutes(3L)); // ์บ์ฌ ์ ์ฅ ์๊ฐ 3๋ถ ์ค์
return RedisCacheManager
.RedisCacheManagerBuilder
.fromConnectionFactory(cf)
.cacheDefaults(redisCacheConfiguration)
.build();
}
}
2. ๋ฉ์๋์ ์บ์ ์ ์ฉํ๊ธฐ
@Cacheable ์ ์บ์๊ฐ ์๋ค๋ฉด ๋ฑ๋กํ๊ณ , ์๋ค๋ฉด ํด๋น ์บ์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ์ด๋ ธํ ์ด์ ์ด๋ค.
์บ์ ์ ์ฉ์ ์ํ๋ ๋ฉ์๋์ ๋ฑ๋กํด๋ณด์.
// ํ์์ ๋ณด ์ ์ฒด์กฐํ(findAll)
@Cacheable(cacheNames = "getAccount", key = "'ALL'", cacheManager = "cacheManager")
public List<AccountDto> findAll() {
List<AccountDto> accountDto = accountRepository.findAll();
return accountDto;
}
์ด๋ ๊ฒ ํ๋ฉด ์บ์ ์ ์ฉ์ ์๋ฃ๋์๋ค.
API๋ฅผ ํธ์ถํ์ฌ Redis์ ์ ๋ฐ์๋๋์ง ํ์ธํด๋ณด์.
3. ๊ฒฐ๊ณผ
1. ์ฒ์ API๋ฅผ ํธ์ถํ์์ ๋ ๊ฑธ๋ฆฌ๋ ์๊ฐ: 88ms
์ฒ์ ํธ์ถ ์์ DB์ ์ ๊ทผํ๊ธฐ ๋๋ฌธ์, ์กฐํ ์ฟผ๋ฆฌ๋ ๋ณด์ด๋ ์ํฉ์ด๋ค.
2. ๋ ๋ฒ์งธ ํธ์ถ๋ถํฐ ๊ฑธ๋ฆฌ๋ ์๊ฐ: 11ms
๋ ๋ฒ์งธ ์ฟผ๋ฆฌ๋ถํฐ๋ DB๊ฐ ์๋, Redis์ ์ ์ฅ๋ ์บ์(Cache)์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ๋๋ฌธ์ ์กฐํ์ฟผ๋ฆฌ๊ฐ ๋ณด์ด์ง ์๋๋ค.
์์ ๋ด์ฉ์ ๋ฐ์ดํฐ ์กฐํ๋ฅผ ์ํ ์บ์ ์ ๋ต์ด์๋ค.(Look Aside + Write Around)
- Look Aside(์ฝ๊ธฐ ์ ๋ต) - ์บ์๋ฅผ ๋จผ์ ํ์ธํ๊ณ , ์บ์์ ๋ฐ์ดํฐ๊ฐ ์์ ๊ฒฝ์ฐ DB์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ์ ๋ต
- Write Around(์ฐ๊ธฐ ์ ๋ต) - ๋ฐ์ดํฐ๋ฅผ ์ ๋ฐ์ดํธ ํ ๋๋ง๋ค ๋ฐ๋ก ์บ์์ ๋ฐ์ํ์ง ์๊ณ , ๋ณ๊ฒฝ๋ ๋ด์ฉ๋ง DB์ ๋ฐ์ํ๊ณ ํด๋น ์บ์๋ ์ ๊ฑฐ ๋๋ ๋ฌดํจํ ํ๋ ์ ๋ต
๋ค์ ํฌ์คํ ์ ์๋ ๋ด์ฉ์ ๋ฐ๋ผ ์บ์ ์ญ์ ํ๋ ๋ฒ์ ์์๋ณด๊ฒ ๋ค.
๐ก redis cache๋ฅผ ์ฌ์ฉํ๋ฉด ์กฐํ ์ ์บ์๋ฅผ ์ฝ์ด์ค๊ธฐ ๋๋ฌธ์ DB์ ์ ์ฅ๋ ๋ฐ์ดํฐ๊ฐ ์์ , ์ถ๊ฐ, ์ญ์ ๋ ๋๋ง๋ค Cache ๋ํ ์ญ์ ํด์ฃผ์ด์ผ ํ๋ค.
๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ๋ ๋๋ง๋ค ์บ์๋ฅผ ๋น์์ฃผ์ง ์์ผ๋ฉด ์บ์ DB(Redis)์ ํ๋ DB(MySQL)์ ๋ฐ์ดํฐ๊ฐ ์๋ก ๋ค๋ฅธ ๋ฐ์ดํฐ๋ฅผ ๊ฐ๊ณ ์์ด ์บ์DB์์ ๋ฐ์ดํฐ๋ฅผ ๊บผ๋ด ์ฌ ๋ ๋ณ๊ฒฝ๋๊ธฐ ์ ์ธ ์ค๋๋ ์ ๋ณด๋ฅผ ์ฌ์ฉํ๋ ๋ฐ์ดํฐ ์ ํฉ์ฑ ๋ฌธ์ ์ ์ด ๋ฐ์ํ๋ค.
'Languages | Frameworks > Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[QueryDSL] N + 1 ํ์ ํด๊ฒฐ ๊ณผ์ (0) | 2023.07.26 |
---|---|
@ControllerAdvice๋ฅผ ํตํ ์์ธ์ฒ๋ฆฌ ๋ถ๋ฆฌ, ํตํฉํ๊ธฐ (0) | 2022.12.20 |
[IntelliJ] ์์ฃผ์ฐ๋ ๋จ์ถํค ์ ๋ฆฌ (0) | 2022.11.21 |
[Springboot] spring-security ์ ์ฉ๊ธฐ(2) - OAuth2 ๊ตฌ๊ธ ์์ ๋ก๊ทธ์ธ (2) | 2022.11.02 |
@Autowired, @Component, @Service, @Repository ๋ฑ ์คํ๋ง ์ด๋ ธํ ์ด์ ์ ๊ดํด.. (0) | 2022.11.02 |