1. Spring Boot 프로젝트에 Redis 셋팅 추가하기
Redis 의존성 추가하기
build.gradle에 아래 코드를 추가하고 gradle 새로고침 버튼을 눌러야 갱신한 의존성이 반영된다.
dependencies {
...
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
}
application.yml 수정하기
# local 환경
spring:
profiles:
default: local
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
data:
redis:
host: localhost
port: 6379 # Redis 기본 포트 번호
logging:
level:
org.springframework.cache: trace # Redis 사용에 대한 로그가 조회되도록 설정
Redis 설정 추가하기
a. config/RedisConfig
@Configuration
public class RedisConfig {
@Value("${spring.data.redis.host}")
private String host;
@Value("${spring.data.redis.port}")
private int port;
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
// Lettuce라는 라이브러리를 활용해 Redis 연결을 관리하는 객체를 생성하고
// Redis 서버에 대한 정보(host, port)를 설정한다.
return new LettuceConnectionFactory(new RedisStandaloneConfiguration(host, port));
}
}
b. config/RedisCacheConfig
아래 boardCacheManager을 게시글 조회용 캐시 매니저 역할을 하는 빈으로 등록한다.
- 캐시 매니저를 여러 개 만들어 필요할 때 다양하게 활용할 수도 있다.
@Configuration
@EnableCaching // Spring Boot의 캐싱 설정을 활성화
public class RedisCacheConfig {
// 게시글 조회용 캐시 매니저
@Bean
public CacheManager boardCacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration
.defaultCacheConfig()
// Redis에 Key를 저장할 때 String으로 직렬화(변환)해서 저장
.serializeKeysWith(
RedisSerializationContext.SerializationPair.fromSerializer(
new StringRedisSerializer()))
// Redis에 Value를 저장할 때 Json으로 직렬화(변환)해서 저장
.serializeValuesWith(
RedisSerializationContext.SerializationPair.fromSerializer(
new Jackson2JsonRedisSerializer<Object>(Object.class)
)
)
// 데이터의 만료기간(TTL) 설정
.entryTtl(Duration.ofMinutes(1L));
return RedisCacheManager
.RedisCacheManagerBuilder
.fromConnectionFactory(redisConnectionFactory)
.cacheDefaults(redisCacheConfiguration)
.build();
}
}
캐싱 로직 추가하기
@Cacheable 어노테이션을 붙이면 Cache Aside 전략으로 캐싱이 적용된다. 즉, 해당 메서드로 요청이 들어오면 Redis를 먼저 확인하고,
- 데이터가 있다면 Redis의 데이터를 조회해 바로 응답한다.
- 데이터가 없다면 메서드의 내부 로직을 실행시킨 뒤에 return 값으로 응답한다. 그리고 그 return 값을 Redis에 저장한다.
@Service
@RequiredArgsConstructor
public class BoardService {
private BoardRepository boardRepository;
private Pageable pageable;
// cacheNames: 캐시 이름을 설정
// key: Redis에 저장할 Key의 이름을 설정
// cacheManager: 사용할 cacheManager의 Bean 이름을 지정
@Cacheable(cacheNames = "getBoards", key = "'boards:page:' + #page + ':size:' + #size",
cacheManager = "boardCacheManager")
public List<Board> getBoards(int page, int size) {
Pageable pageable = PageRequest.of(page - 1, size);
Page<Board> pageOfBoards = boardRepository.findAllByOrderByCreatedAtDesc(pageable);
return pageOfBoards.getContent();
}
}
테스트 해보기
Spring Boot 서버를 실행시켜서 API를 실행해보면 로그를 통해 확인할 수 있다.
redis-cli.exe를 실행하고 keys *을 입력하면 정상적으로 캐싱이 됐는지 확인할 수 있다.
keys * # boards:page:1:size:10 출력
get getBoards::boards:page:1:size:10 # 저장된 JSON 값 출력
ttl getBoards::boards:page:1:size:10 # 남은 만료 시간 출력
2. Redis 적용 전후 성능 비교하기
성능 개선을 할 땐 반드시 수치로 측정하면서 비교해야 한다.
캐싱을 적용시키는 @Cacheable 어노테이션을 주석 처리한 뒤 Postman으로 테스트 해보면 평균 200ms 정도의 속도가 나오는 걸 확인할 수 있다.
@Service
public class BoardService {
...
// @Cacheable(cacheNames = "getBoards", key = "'boards:page:' + #page + ':size:' + #size",
// cacheManager = "boardCacheManager")
public List<Board> getBoards(int page, int size) {
Pageable pageable = PageRequest.of(page - 1, size);
Page<Board> pageOfBoards = boardRepository.findAllByOrderByCreatedAtDesc(pageable);
return pageOfBoards.getContent();
}
}
주석 처리를 해제한 뒤 다시 테스트 해보면 평균 20ms 정도의 속도가 나온다. Redis를 캐시로 사용해 10배 정도 속도를 향상시킬 수 있다.