Skip to content

선착순 ‐ 구현에 따른 성능 분석

mjmj edited this page Aug 26, 2024 · 2 revisions

단순 db로만 카운팅 한 경우

문제점

  • 동시 접속자가 많아짐에 따라 race condition이 발생함
    • 당첨자 1000명 뽑는 이벤트에 당첨자가 1700명 저장되고 있음
image
  • 성능
    • 최대 40 rps가 나옴
    • 시간이 지날수록 response time이 증가함
    • cpu 사용량이 낮음 (application 자원은 별로 사용하지 않음)
      • 스레드 풀 수를 늘려보는건 어떨까?
    • db 병목이 매우 심하다.
      • 히카리 풀을 늘려보는 건?
      • 결국 redis..?
    • 요청마다 당첨자 수를 increase 하며 데이터베이스 네트워크 비용이 매우 심함

시나리오

  • 동시접속자 1000명, 0 ~ 1000명까지 초당 10명씩 늘어날 때

유저 테이블에 10만 row가 있는데 JWT가 들어올 때마다 유저 정보를 이메일을 통해서 조회한다. 이 과정에서 10만 row를 fullscan을 하면서 성능이 매우 좋지 않았다.

email key에 인덱스를 걸어 이 문제를 해결하였다.

User 테이블에 인덱스 안걸었을 때.. image

image

User 테이블 인덱스 걸었을 때 image

image

동접자 800명이 넘어가는 순간부터 응답 시간이 증가함

  • threaddump 확인해보자

  • 대기 큐 확인 필요할지도..

  • db 접근이 너무 많나..?

  • 동시 접속자 0 ~ 700명, 1초에 10명씩 증가

image image

redis counter 적용 - thread pool 500 (동시 접속 1000 - 10명씩 점차 증가) - 선착순 1000명

image
  • 720명 까지는 20~38ms를 유지하며 병목이 적은 상태를 유지
  • 880명부터 점점 응답 시간이 길어짐

db만 사용했을 때 - thread pool 500 (동시 접속 1000 - 10명씩 점차 증가) - 선착순 1000명

image
  • 720명 까지 40 ~ 70ms 유지하며 병목이 적은 상태 유지

  • 720 ~ 990명까지 thread pool 병목이 생겨 300 ~ 600

  • 그 이후로는 점점 더 api 대기 시간이 길어지는 현상 발생

  • 동시 접속 600건 기준 cpu 사용량 34프로 정도 사용함

동시 접속 600 - (동시 접속 60 - 10명씩 점차 증가) - 선착순 1000명

image

예상

  • 선착순 10000명에 대한 db insert 쿼리문이 매우 느릴 수 있다.
  • 처리가 느려지면서 대기큐에 요청들이 쌓여 처리가 느려질 가능성이 존재

실제 실험 결과

  • insert문은 별로 느리지 않고 오히려 인덱스를 걸지않는 당첨자 카운팅 문제가 매우 느렸다.

  • 쓰레드 풀 테스트 1000개 쓰레드

image
  • 레디스 lua scripts & batch insert
image

cpu 사용량 65 ~ 68% db 서버 cpu 사용량 32%

분석

  1. redis와 db를 이용하여 단순히 선착순을 구현했을 때 그렇게 큰 성능차이가 나지 않는다. 왜?
  • 예측
    • 단순히 숫자만 증감 시키는 연산이라 그리 성능 차이가 크지 않으려나
    • 사실상 row를 추가하는 것이 아니기 때문에 그리 큰 성능 차이가 발생하지 않음
  1. 선착순이 끝나기 전 db에 insert하는데 매 요청마다 실행하니 성능이 매우 좋지 않았다.
  • 선착순이 끝나서 당첨자를 저장하지 않게 되자 응답시간이 매우 감소했다.
  1. db에 쓰기 작업을 최대한 줄여야 한다.
  • 우선 당첨자를 redis에 저장하고 자정에 배치 작업으로 한꺼번에 당첨자를 저장한다.
  • 이는 db에 쓰기 작업을 요청마다 하지 않기 때문에 선착순 이벤트 기간에 부하가 적다.
  1. 실제로 배치를 통해 당첨자를 관리하니 200tps에서 300tps로의 성능향상을 볼 수 있었다.