이번엔 게시글에 대한 캐싱이다. 게시글 캐싱의 경우 마이페이지에 비해 고려해야할 사항이 많았다.
조회수 증가
좋아요 추가
이 두가지 요청은 빈번하게 일어나며, 이에 따라 게시글의 상태는 변화되어야 한다.
특히, 조회수의 경우 읽기 요청마다 DB의 상태가 변화되기 때문에 고민이 많았으며, 떠올린 방법은 크게 두 가지였다.
특정 row에 접근해 데이터를 변경하기 때문에, 요청마다 테이블을 조회해서 페이징 처리까지 하는 것보단 성능이 좋을 것이다.
하지만 요청마다 여전히 DB에 접근해야 하기 때문에, 캐시 도입의 효과가 반감될 것이라고 생각했다.
이 방법을 사용하면, 요청마다 캐시 데이터만 업데이트 하고, 특정 주기마다 DB에 반영하면 될 것이다.
이를 구현하기 위해 스케줄러(scheduler)를 사용하기로 했으며, 게시글 캐시 데이터와 조회수 캐시 데이터의 만료 시간을 동일하게 설정하여 업데이트된 캐시 데이터를 주기적으로 반영하도록 했다.
먼저, @EnableScheduling
을 통해 스케줄러를 활성화시켜주어야 한다.
캐시 데이터가 반환되기 전에 조회수 로직이 실행되어야 하므로, service 로직에 @Cacheable
을 걸고 service layer 진입 전에 조회수를 카운트한다.
유지 보수를 고려하여 캐시 관련 로직을 분리해서 관리하기로 했다. 해당 게시글에 대한 조회수 캐시 데이터가 없으면 데이터 insert, 있으면 increment를 통해 조회수를 증가시킨다.
스케줄러가 하는 일은 다음과 같다.
- 조회수 데이터 DB 반영
- 캐시 삭제
이때 게시글도 함께 삭제하여 주기적으로 캐시 데이터가 업데이트되도록 했다.
3분 주기마다 스케줄러가 실행되도록 했지만, 서비스 상황을 고려하여 더 짧게 또는 길게 가져갈 수도 있을 것 같다.
다양한 옵션으로 스케줄러 동작을 setting할 수 있다.
cron 표현식을 사용하여 작업 시간을 예약한다.
ex) cron = "* * * * * *"
첫번째 부터 초/분/시/일/월/요일/년 순이며, 마지막 요소인 (년)은 생락 가능하다.
ex) zone = "Asia/Seoul"
미설정 시 Local 시간대 사용
작업의 시작부터 시간을 count한다.
고정 시간 간격으로 실행되며, 이전 작업이 완료될 때까지 다음 작업이 진행되지 않는다.
Scheduler는 기본적으로 하나의 쓰레드를 이용하여 동기 형식으로 처리된다. 비동기로 처리하고 싶은 경우
@Async
를 사용해 처리할 수 있다.
첫 조회 시, 게시글과 조회수 데이터가 잘 저장된 걸 확인할 수 있다.
이후 조회마다 캐시 데이터에 대한 조회수 증가도 잘 수행된다.
스케줄러에 설정된 시간인 3분 주기로 update 쿼리가 잘 수행되고, DB에도 반영되었다. 또한 캐시 데이터도 성공적으로 삭제된 걸 확인할 수 있다.
평균 220 TPS
를 기록했다.평균 1000 TPS
를 기록했다
TPS가 눈에 띄게 상승했으며, 약 5배의 성능 개선을 달성했다.
추가적으로 동시성 이슈와 같은 문제를 고려할 수 있을 것 같다. 이 부분은 학습을 병행하며 리팩토링을 진행해보면 좋을 것 같다.
안녕하세요 글 보다가 궁금한게 생겨서 여쭤봅니다 !
캐시 데이터가 반환되기 전에 조회수 로직이 실행되어야 하므로, service 로직에 @Cacheable을 걸고 service layer 진입 전에 조회수를 카운트한다.
혹시 이 부분 무슨 뜻인지 여쭤봐도 될까요?좋은 글 남겨주셔서 감사합니다!