본문 바로가기
개인 공부용 프로젝트/crud.jpa.api

Redis queue, Spring scheduler + ratelimit 트러블슈팅

by pon9 2024. 12. 17.

원래 updateViewCount 코드의 문제: 그냥 async만 사용해서 비동기적으로 처리하고있다. 하지만 대량의 요청이 들어오면 서버 리소스가 낭비된다거나, 카운팅이 중복될 수 있다. 따라서 분산 처리를 효율적으로 할 필요가 있었다.

 

해결방법: redis queue와 spring scheduler를 이용해 요청이 있을 때 마다 redis queue에 담고, batch 처리를 통해 일정 시간마다 한번에 반영한다.

@Service
@AllArgsConstructor
public class BoardQueueService {

    private final RedisTemplate<String, Object> redisTemplate;

    public void addToQueue(Long boardId){
        redisTemplate.opsForList().rightPush("board:viewCountQueue", boardId);
    }

    public Long fetchFromQueue(){
        Object value = redisTemplate.opsForList().leftPop("board:viewCountQueue");
        if(value instanceof Integer){
            return ((Integer) value).longValue();
        }
        return (Long) value;
    }
}

@Service
@RequiredArgsConstructor
public class BoardViewCountBatch {

    private final BoardQueueService boardQueueService;
    private final BoardRepository boardRepository;
    private final BoardValidationService boardValidationService;
    private final BoardDomainService boardDomainService;

    @Scheduled(fixedDelay = 5000)
    public void processViewCountBatch(){
        Long boardId;

        while((boardId = boardQueueService.fetchFromQueue()) != null){
            Board board = boardValidationService.validateBoard(boardId);
            if(board != null){
                boardDomainService.countBoard(board);
                boardRepository.save(board);
            }
        }
    }
}

조회 요청 시 redis queue에 boardId를 저장하고, batch가 5초마다 redis queue에서 boardId를 가져온다.

가져온 boardId로 Board 엔티티를 조회해 조회수를 증가시킨다. batch로 db에 저장하기에 효율적이다.

2번게시글을 더블클릭한 뒤 redis insight를 확인해보니 queue에 요청이 두개 들어와있다.

spring batch를 사용해 redis queue에서 5초 간격으로 데이터를 가져와 처리한다.

 

 

 

트러블슈팅: 왜 비로그인 사용자에게 세션이 있을까?

비로그인 사용자로 게시글을 두번째 생성할 때 세션이 존재하는 오류가 생겼다.

이처럼 첫번째 요청에는 session 값이 null이다가 두번째 요청에는 세션이 일반 유저처럼 들어와있다.

임시방편으로 sessionUser로 null확인을 했더니

정상적으로 작동하는 걸 볼수있었다. 그렇다면 왜 비로그인 사용자에게 session이 있을까?

 

그 이유는 Tomcat과 같은 웹 어플리케이션 서버가 기본적으로 세션을 생성하는 방식과 관련이 있다.

세션이란 서버가 클라이언트를 구분하기 위해 유지하는 상태 정보로, 로그인 여부와 관계없이 세션은 클라이언트와의 연결 상태를 유지하기 위해 생성될 수 있다. 예를들어 사용자가 웹 페이지에 방문하면 Tomcat이 세션ID를 생성하고 브라우저에 쿠키로 전달한다.

 

request.getSession()메서드가 호출되면 세션이 존재하지 않을 경우 자동으로 생성되고, 나의 경우 request.getSession(false)로 호출했기에 이것이 문제는 아니었다.

또다른 경우 JSP페이지에서는 기본적으로 세션을 자동으로 생성하고(디폴트 설정이 true임. 이것도 내 문제는 아님),

Tomcat은 세션을 쿠키(JSESSIONID)로 브라우저에 저장하고 "클라이언트 요청과 함께 서버로 전달된다". << 이것이 아마 내 문제인 듯 하다!

'개인 공부용 프로젝트 > crud.jpa.api' 카테고리의 다른 글

튜터님의 피드백2  (2) 2024.12.17
튜터님의 피드백  (0) 2024.12.17
Redis Insight  (0) 2024.12.16