Cache
성능 향상을 위해 사용하며(빠른 처리), 임시로 데이터를 저장하는 공간이다.
Redis
- Key-Value
- 인메모리 데이터 스토어
- 다양한 형태의 데이터 타입 지원
- 주로 캐시 서버 용도로 많이 사용한다.
디스크가 아닌 메모리에 접근해서 데이터를 꺼내오기 때문에 RDBMS에서보다 속도가 빠르다.
Redis는 인메모리 방식으로 데이터의 저장용도가 휘발성이지만 영속성 또한 지원한다. 하지만 데이터의 저장방식이 일반 DB보다 안정적이지는 않다. 그렇기 때문에 주로 Cache 서버의 용도로 많이 사용된다.
Reids 명령어
redis-cli 명령어를 통해 들어온 후
set key value -> key-value 설정
get key -> value 값 나옴
del key -> key-value 삭제
get key -> nil, key가 없는 경우 nil은 null과 같음
keys * -> 모든 key를 꺼내옴. 성능에 문제를 줄 수 있기 때문에 운영서버에서는 사용X
redisgate.kr -> redis docs 사이트
Redis 설정하기
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
추가
data:
redis:
host: localhost
port: 6379
추가
캐싱 기능을 사용하기 위한 애노테이션 추가
@SpringBootApplication
@EnableScheduling
@EnableCaching // -> 추가
public class StockDividendsApplication {
public static void main(String[] args) throws IOException {
SpringApplication.run(StockDividendsApplication.class, args);
}
}
캐시 기능을 위한 CacheConfig 추가
@Configuration
@RequiredArgsConstructor
public class CacheConfig {
@Value("${spring.data.redis.host}")
private String host;
@Value("${spring.data.redis.port}")
private int port;
@Bean
public RedisConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(host, port);
return new LettuceConnectionFactory(config);
}
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheConfiguration conf = RedisCacheConfiguration.defaultCacheConfig()
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
return RedisCacheManager.RedisCacheManagerBuilder
.fromConnectionFactory(redisConnectionFactory)
.cacheDefaults(conf)
.build();
}
}
직렬화 과정
자바 객체를 바이트 배열로 변환하여 Redis와 같은 외부 저장소에 저장할 수 있게 하는 과정입니다. 이 과정을 통해 Redis에 자바 객체를 저장할 때, 객체가 문자열이나 바이트 배열로 변환됩니다.
• 역직렬화(Deserialization): 외부 저장소(여기서는 Redis)에서 바이트 배열로 저장된 데이터를 자바 객체로 복원하는 과정입니다. Redis에서 데이터를 가져올 때, 원래의 자바 객체 형태로 변환하여 애플리케이션 내에서 사용할 수 있게 해줍니다.
해당 코드에서는 자바의 코드를 레디스 서버에서 사용시키려면 해당 직렬화 하는 과정이 필요하기 때문에 넣어준것.
• serializeKeysWith(new StringRedisSerializer()):
• 키 직렬화에 사용됩니다. 여기서는 StringRedisSerializer를 사용하여 키를 문자열로 직렬화합니다. Redis의 키는 일반적으로 사람이 읽을 수 있는 문자열로 저장되기 때문에, 이 부분에서는 직렬화를 통해 키를 문자열로 변환하고 Redis에 저장합니다.
• serializeValuesWith(new GenericJackson2JsonRedisSerializer()):
• 값 직렬화에 사용됩니다. 값은 일반적으로 자바 객체로 처리되므로, GenericJackson2JsonRedisSerializer를 사용하여 자바 객체를 JSON 형태로 직렬화합니다. 이는 자바 객체를 JSON 형식의 문자열로 변환한 후, Redis에 저장합니다. JSON은 다른 시스템에서도 읽고 쓸 수 있는 형식이기 때문에, Redis에 저장된 데이터를 다른 시스템에서도 쉽게 사용할 수 있습니다.
• 또한, JSON 형식으로 직렬화된 데이터는 나중에 Redis에서 가져올 때 역직렬화되어 다시 자바 객체로 복원됩니다.
Redis Cache 적용하기
@Cacheable(key = "#companyName", value = "finance")
public ScrapedResult getDividendByCompanyName(String companyName) {
//1. 회사명을 기준으로 회사 정보 조회
CompanyEntity companyEntity = companyRepository.findCompanyEntityByName(companyName)
.orElseThrow(() -> new RuntimeException("not found -> " + companyName));
//2. 조회된 회사 ID로 배당금 정보 조회
List<DividendEntity> dividendEntities = dividendRepository
.findAllByCompanyId(companyEntity.getId());
//3. 결과 조합 후 반환
return new ScrapedResult(Company.fromEntity(companyEntity), dividendEntities.stream()
.map(Dividend::fromEntity)
.toList());
}
}
@Cacheable 애노테이션을 적용하여 해당 설정으로 진행해준다. 그럼 Redis Server에서 키를 조회해보면
get "finance::3M Company"
"{\"@class\":\"com.cheolhyeon.stockdividends.web.model.ScrapedResult\",\"company\":{\"@class\":\"com.cheolhyeon.stockdividends.web.model.Company\",\"id\":1,\"ticker\":\"MMM\",\"name\":\"3M Company\"},\"dividends\":[\"java.util.ImmutableCollections$ListN\",[{\"@class\":\"com.cheolhyeon.stockdividends.web.model.Dividend\",\"date\":[1970,5,18,0,0],\"dividend\":\"0.02\"},{\"@class\":\"com.cheolhyeon.stockdividends.web.model.Dividend\",\"date\":[1970,8,17,0,0],\"dividend\":\"0.02\"},{\"@class\":\"com.cheolhyeon.stockdividends.web.model.Dividend\",\"date\":[1970,11,16,0,0],\"dividend\":\"0.02\"},{\"@class\":\"com.cheolhyeon.stockdividends.web.model.Dividend\",\"date\":[1971,2,11,0,0],\"dividend\":\"0.02\"},{\"@class\":\"com.cheolhyeon.stockdividends.web.model.Dividend\",\"date\":[1971,5,17,0,0],\"dividend\":\"0.02\"}
이렇게 키를 조회하면 해당 형식으로 나오게 된다.
key 속성의 의미
• key = "#companyName"은 캐시의 키를 설정하는 방식입니다. 여기서 #companyName은 메서드의 매개변수인 companyName의 값을 참조합니다.
• 즉, 이 메서드에 대한 첫 번째 호출에서 companyName이 “AAPL”이라면, 결과는 "finance"라는 캐시에서 "AAPL"이라는 키를 사용하여 저장됩니다.
• 이후에 동일한 companyName으로 메서드를 호출하면, 실제 메서드를 실행하지 않고 캐시에서 저장된 값을 반환합니다. 이는 성능을 높이고 불필요한 데이터베이스 호출을 줄여줍니다.
즉 value에서 정한 값 + :: companyName값이 키값으로 설정된다.
성능의 이점 보기
처음 데이터를 불러오는데 걸린 시간
Response code: 200; Time: 22ms (22 ms); Content length: 4094 bytes (4.09 kB) -> 22ms이다.
Select 쿼리 발생
Hibernate: select de1_0.id,de1_0.company_id,de1_0.date,de1_0.dividend from dividend_entity de1_0 where de1_0.company_id=?
캐싱된 데이터를 불러오기
Response code: 200; Time: 6ms (6 ms); Content length: 4094 bytes (4.09 kB) -> 6ms 약 2~4배 정도 빠르다.
그리고 DB에서 갖고오는게 아니기 때문에 Select 쿼리도 발생하지 않는다.
'프로젝트 이슈 및 몰랐던점 정리 > StockDividendAPI' 카테고리의 다른 글
[설정] 백엔드 API, HTTP 기본 요청 매핑 및 RestControllerAdvice예외처리 (0) | 2024.10.07 |
---|---|
[설정] Spring Security와 JWT로 로그인 기능 구현 (0) | 2024.10.07 |
[설정] 복합 유니크 키 설정 및 DB Index (0) | 2024.10.07 |
[설정] 삽입하려는 데이터의 중복 키 발생 시 레코드 무시하고 삽입하는 방법 (0) | 2024.10.07 |
[설정] 백엔드 API Pageable 사용하기 (0) | 2024.10.07 |