[항해 플러스 백엔드 6기] "대용량 트래픽 경험"

Uicheon·2024년 10월 20일
0

항해

목록 보기
5/6
post-thumbnail

대용량 트래픽..

사실상 어딜가든 빠지지 않는 키워드! 🤬

(근데 본인은 애초에 트래픽 자체를 받고 있지도 않음)

아주 잠깐 시간을 되돌려 1주차부터 생각해보면

왜 동시성 처리에 관하여 고민했을까?
왜 테스트 코드를 작성했을까?
왜 클린 아키텍쳐를 배울까?

이런 질문들을 곰곰히 생각해봤다.

답은 이직하려면.. 좋은 개발자가 되기 위해서!

그럼 좋은 개발자란?

  • 가독성/유지보수성이 높은 코드를 작성할 줄 아는!
  • 다양한 비지니스 요구사항에 맞는 코드를 재빠르게 작성하는!
  • 많은 트래픽에서도 견고한 시스템을 만들 줄 아는!

그런 개발자가 시장에서 매력적인 좋은 개발자인 것 같다.

[들어가기 전]
다음 용어가 무엇인지 알고, 설명할 수 있나요?

  • 대용량 트래픽 시스템 설계
  • 대기열 시스템

1. 기술 회고

대기열 시스템

예를 들어보자,

우이천블러디 프라이데이(줄여서 블프)라는 이벤트를 기획하는 이커머스 회사에 다니고 있다.

블프는 엄청나게 유명한 이벤트이다.
블프 좌석을 예약하기 위해 사람들이 서로 실제로 피를 본다
당일 이벤트가 열리면 사람들이 마구마구 쏟아져서 모두 예약하려고 한다.
간단하게 DB 락을 이용하여 블프 이벤트 좌석을 예약하는 시스템을 만들어보니...

한 번에 너무나도 많은 요청이 쏟아져 어플리케이션/DB가 죽는다

어떻게 해결할까?

사실 이 문제의 해결 방법은 굉장히 다양하지만,

우리는 대기열 시스템에 대하여 먼저 얘기해 보려고 한다.

왜 대기열 시스템이 필요한가?

아래와 같이 작고 귀여운 시스템 아키텍쳐가 있다고 해보자.

12시 떙! 블프 이벤트가 시작됐다. 무슨 일이 일어날까?

일단 블프 이벤트와 좌석에 대한 조회 요청이 엄청나게 올 것이다.
그럼 우리가 할 수 있는 방법은, 블프 이벤트/좌석 조회시스템, Slave DB를 스케일 아웃 하는 것이다.

휴! 다행히도, 모든 요청을 어찌저찌 잘 처리했다. (그렇다 치자!)

자! 이제 모든 조회 요청을 끝난 이용자들이 다음으로 할 행동은 무엇일까?

예약이다!

예약이 오면 아래와 같이 어플리케이션과 DB가 힘들어한다.

심지어, 예약은 Write 요청이기 때문에 Master를 스케일 아웃 하는 전략도 가져가지 못한다.

예약 이후 결제도 마찬가지일 것이다!

(길었지만) 위와 같은 이유로, 시스템 내 트래픽을 조절할 수 있는 "무언가"가 필요하다.

"무언가"는 대기열 시스템이고, 이를 고급지게 유량 제어라고 표현한다.

물론 마스터를 미리 스케일 업 하는 방법, 샤딩, 파티셔닝, 이벤트 소싱 등등이 있을 수 있다.
그러나 굉장히 많은 공수/시스템 리소스가 필요하게 된다.
또한 기술적 성숙도가 부족한 조직에서는 시도 자체가 어려울 수도 있다.

어떻게 구현할 것인가?

먼저, 방식부터 얘기해보자.
유량제어는 크게 두 가지 방식이 있다.

1. 은행 창구식

  • 항상 총 N명 이하의 이용자가 시스템을 이용할 수 있도록 한다.

2. 놀이 공원식

  • 주기적인 시간마다 추가적으로 N명에게 시스템을 이용할 수 있도록 한다.

자. 그러면 실제로 DB로 구현은 어떻게 해야할 까?

이런 테이블 하나를 만들고, userId값을 가진 요청을 받으면 waitId라는 특정한 고유 Id를 클라이언트에게 헤더에 담아 반환한다.

그런 뒤, 스케쥴러(배치)를 돌려, status(WAIT, ACTIVE, EXPIRE) 값을 ACTIVE로 업데이트해, 이용 권한을 부여한다.

은행 창구식이라면 다음과 같은 로직을 이용할 수 있다.

다음 입장 인원 = (시스템에서 총 유지되어야 하는 인원 - 현재 ACTIVE 인원)

그런 뒤, 아래와 같은 스케쥴러를 돌려 ACTIVE 시킨다.

@Slf4j
@Component
@RequiredArgsConstructor
public class QueuePolicyScheduler {
    private final QueuePolicy queuePolicy;

    @Scheduled(fixedDelay = 1000)
    public void activate() {
        queuePolicy.activate();
    }

    @Scheduled(fixedDelay = 10000)
    public void expire() {
        queuePolicy.expire();
    }
}

놀이 공원식이라면, 내 입장 순서까지 시간를 계산할 수 있다.

내 입장순서 시간 = (내 번호 - 마지막에 들어간 사람 번호)/(한 번에 들어가는 사람 수)*(스케쥴러가 도는 주기)

두 방식 각각 장단이 있다.

특징

  • 은행창구

    • Active 된 지 특정 시간이 지난 유저는 Expire시킨다.
    • 스케쥴러가 돌면서 ACTIVE인원 - 최대 N명만큼 권한을 부여한다(ACTIVE)
    • 유량 제어가 타이트하게 가능하다.
    • 제한적이고, 유동적이지 못한 재원을 갖고 있다면, 은행 창구식이 유리하다.
    • 그러나 처리량은 놀이공원식보다 떨어질 수 있다.
  • 놀이공원

    • 스케쥴러가 돌면서 N명씩 Active시킨다.
    • 커넥션 풀이 터질 수도 있다.
    • 스케일러블한 재원을 갖고 있고, 처리량을 높이려면 놀이공원식이 유리하다.

마치며

물론, 실전에서는 Redis + 분산락이 국밥마냥 든든하게 사용하는 것 같다.
하지만, 김영한님 강좌처럼 차근 차근 시스템을 발전시켜보려는 것 같다!

2. KPT

Keep

  • 열심히 하셨잖아 한잔해

Problem

  • 시간 관리 ㅠㅠ

Try

  • 뽀모도로 타이머를 적극 활용해보자 ^^

이번 챕터를 시작하며 꼭 해내고 싶었던 목표

  • 와 OpenAPI Spec 저거 간편해보이는데 직접해봐야지!
  • 일단 주어진 스펙들을 잘 구현해보자! (구현이 또 ㅎㅎ..)

이번 챕터를 마무리하며 가장 기억에 남는 성취

  • 거의 모든 시스템을 작성 한뒤, 통합테스트 돌렸는데 테스트에 초록불이 뜬 그 순간!

이번 챕터에서 반드시 이뤘으면 했는데 이루지 못한 것

  • 사실.. 포인트 충전/조회와 결제 시스템은 못했다..

내가 강화해야 할 강점 중 가장 중요하다고 생각하는 한 가지

  • 조금 더 깊게 파보기
  • 조금 더 생각을 정리/정돈한 뒤 말하고, 글을 써보기

항해에 참가하려는 당신!

혹시 [들어가기전]의 답변이 궁금하신가요!?
글을 읽다보니 '아..! 나도 저거 알아야하는데!' 하진 않으신가요?!

여기까지 글을 읽으셨다면, 아마 항해 플러스 과정에 관심있으신 분이라고 생각합니다.

궁금한 점이 있으시다면 저에게 편하게 댓글 남겨주세요!
혹은 highestbright98@naver.com으로 메일을 남겨주셔도 굉장히 빨리 답변한답니다!

항해 플러스 백엔드에 관련해서 궁금하신점이 있다면 언제든 편하게 말씀주세요!

그리고 글이 도움됐다면, 등록하실때 제 추천인 코드 [9MPLfu] 입력하면,
20만원 할인의 혜택이 있답니다! (물론 저에게도 혜택이 있습니다! 😉)

profile
컨셉입니다~

0개의 댓글