[Project] Spring Scheduler로 조회수 로직 캐싱 구현하기 (feat. Redis)

bagt13·2023년 2월 23일
4

Project

목록 보기
10/19
post-thumbnail

📘 이전 포스팅

Spring Cache 적용으로 읽기 성능 최적화하기 (2)


이번엔 게시글에 대한 캐싱이다. 게시글 캐싱의 경우 마이페이지에 비해 고려해야할 사항이 많았다.

  1. 조회수 증가
  2. 좋아요 추가

이 두가지 요청은 빈번하게 일어나며, 이에 따라 게시글의 상태는 변화되어야 한다.
특히, 조회수의 경우 읽기 요청마다 DB의 상태가 변화되기 때문에 고민이 많았으며, 떠올린 방법은 크게 두 가지였다.


1. 요청마다 DB에 반영한다.

특정 row에 접근해 데이터를 변경하기 때문에, 요청마다 테이블을 조회해서 페이징 처리까지 하는 것보단 성능이 좋을 것이다.

하지만 요청마다 여전히 DB에 접근해야 하기 때문에, 캐시 도입의 효과가 반감될 것이라고 생각했다.

2. 조회수를 별도로 캐싱한다.

이 방법을 사용하면, 요청마다 캐시 데이터만 업데이트 하고, 특정 주기마다 DB에 반영하면 될 것이다.

이를 구현하기 위해 스케줄러(scheduler)를 사용하기로 했으며, 게시글 캐시 데이터와 조회수 캐시 데이터의 만료 시간을 동일하게 설정하여 업데이트된 캐시 데이터를 주기적으로 반영하도록 했다.


📒 코드

Spring Scheduler 활성화

먼저, @EnableScheduling을 통해 스케줄러를 활성화시켜주어야 한다.

조회수 캐시 업데이트 로직

캐시 데이터가 반환되기 전에 조회수 로직이 실행되어야 하므로, service 로직에 @Cacheable을 걸고 service layer 진입 전에 조회수를 카운트한다.

유지 보수를 고려하여 캐시 관련 로직을 분리해서 관리하기로 했다. 해당 게시글에 대한 조회수 캐시 데이터가 없으면 데이터 insert, 있으면 increment를 통해 조회수를 증가시킨다.


Scheduler 작성

스케줄러가 하는 일은 다음과 같다.

  1. 조회수 데이터 DB 반영
  2. 캐시 삭제

이때 게시글도 함께 삭제하여 주기적으로 캐시 데이터가 업데이트되도록 했다.
3분 주기마다 스케줄러가 실행되도록 했지만, 서비스 상황을 고려하여 더 짧게 또는 길게 가져갈 수도 있을 것 같다.



✅ Spring Scheduler

📒 @Scheduled

다양한 옵션으로 스케줄러 동작을 setting할 수 있다.

1. cron

  • cron 표현식을 사용하여 작업 시간을 예약한다.

  • ex) cron = "* * * * * *"

  • 첫번째 부터 초/분/시/일/월/요일/년 순이며, 마지막 요소인 (년)은 생락 가능하다.

2. zone

  • ex) zone = "Asia/Seoul"

  • 미설정 시 Local 시간대 사용

3. fixedDelay

  • 작업의 종료 시점으로부터 시간을 count한다.

4. fixedRate

  • 작업의 시작부터 시간을 count한다.

  • 고정 시간 간격으로 실행되며, 이전 작업이 완료될 때까지 다음 작업이 진행되지 않는다.


📒 Spring Scheduler의 동작 방식

Scheduler는 기본적으로 하나의 쓰레드를 이용하여 동기 형식으로 처리된다. 비동기로 처리하고 싶은 경우 @Async를 사용해 처리할 수 있다.


📒 Caching + Scheduler 동작 확인

첫 조회 시, 게시글과 조회수 데이터가 잘 저장된 걸 확인할 수 있다.

이후 조회마다 캐시 데이터에 대한 조회수 증가도 잘 수행된다.

스케줄러에 설정된 시간인 3분 주기로 update 쿼리가 잘 수행되고, DB에도 반영되었다. 또한 캐시 데이터도 성공적으로 삭제된 걸 확인할 수 있다.


➕ 추가 - 캐시 적용 후 성능 비교

캐시 적용 전

  • 평균 220 TPS를 기록했다.

캐시 적용 후

  • 평균 1000 TPS를 기록했다

  • TPS가 눈에 띄게 상승했으며, 약 5배의 성능 개선을 달성했다.

추가적으로 동시성 이슈와 같은 문제를 고려할 수 있을 것 같다. 이 부분은 학습을 병행하며 리팩토링을 진행해보면 좋을 것 같다.

profile
주니어 백엔드 개발자입니다😄

4개의 댓글

comment-user-thumbnail
2023년 9월 20일

안녕하세요 글 보다가 궁금한게 생겨서 여쭤봅니다 !
캐시 데이터가 반환되기 전에 조회수 로직이 실행되어야 하므로, service 로직에 @Cacheable을 걸고 service layer 진입 전에 조회수를 카운트한다. 혹시 이 부분 무슨 뜻인지 여쭤봐도 될까요?
좋은 글 남겨주셔서 감사합니다!

1개의 답글
comment-user-thumbnail
2024년 10월 26일

좋은 글 감사합니다~ 저도 좋아요에 캐싱 로직 구현하는데 큰 도움 되었습니다

1개의 답글