본문으로 바로가기

30

웹훅

남이 우리에게 알림을 보낼 때, 받는 쪽은 언제 어떻게 몰릴지 고를 수 없다

먼저 보면 좋은 강의: 이벤트 기반 아키텍처

단계별로 보기

스페이스바로 재생/정지, 좌우 화살표로 단계 이동, R로 처음으로 돌아갑니다.

대기 중1 / 4 단계 — 평소에는 아무 문제가 없다

결제사가 초당 40건의 알림을 보냅니다. 수신 서버는 알림을 받아 저장소에 기록하고 응답합니다. 여유가 있어 잘 돌아갑니다. 이 상태만 보고 설계가 끝났다고 판단하는 것이 웹훅에서 가장 흔한 실수입니다.

유입 요청초당 40건

이 강의를 마치면

  • 웹훅이 '남의 서버가 우리 서버를 호출하는' 구조라는 점과, 그래서 트래픽을 통제할 수 없다는 점을 설명한다.
  • 웹훅 수신 시 즉시 응답하고 나중에 처리해야 하는 이유를 재전송 동작과 연결해 설명한다.
  • 받는 쪽에서 스파이크를 흡수하는 구조를 직접 구성한다.

방향이 뒤집혔다

지금까지 우리 서버는 부르는 쪽이었습니다. 결제가 필요하면 우리가 결제사를 호출했습니다. 언제 부를지 우리가 정했습니다.

웹훅은 반대입니다. 결제사가 우리를 호출합니다.

평소:  우리 서버 ──호출──> 결제사      (우리가 시간을 고른다)
웹훅:  결제사   ──호출──> 우리 서버   (남이 시간을 고른다)

왜 이런 게 필요할까요? 결제 승인은 몇 초에서 몇 분까지 걸릴 수 있습니다. 그동안 우리가 계속 "됐나요? 됐나요?"라고 물을 수는 없습니다(폴링의 낭비를 앞 강의에서 봤습니다). 그래서 결제사에게 "끝나면 이 주소로 알려주세요"라고 주소를 남겨둡니다. 그 주소가 웹훅입니다.

통제권이 없다는 뜻

방향이 뒤집히면서 아주 중요한 것이 함께 넘어갑니다. 트래픽의 통제권입니다.

우리가 부르는 쪽일 때는 속도를 우리가 정했습니다. 부담되면 천천히 부르면 됐습니다. 받는 쪽이 되면 그럴 수 없습니다.

  • 결제사가 장애에서 복구되면서 밀려 있던 알림 10만 건을 한꺼번에 보낼 수 있습니다.
  • 우리가 준비됐는지 아무도 물어보지 않습니다.
  • 평소 초당 10건이던 것이 갑자기 초당 500건이 될 수 있습니다.

우리는 언제 몰릴지 고를 수 없습니다. 이것이 웹훅 설계의 출발점입니다.

재전송이 상황을 악화시킨다

여기에 한 가지가 더 얹힙니다. 웹훅을 보내는 쪽은 대개 이런 규칙을 갖고 있습니다.

정해진 시간 안에 응답이 없으면, 못 받은 것으로 보고 다시 보낸다.

이 규칙은 합리적입니다. 알림이 유실되면 곤란하니까요. 그런데 우리가 밀려 있을 때 무슨 일이 벌어지는지 보세요.

  1. 우리 서버가 바빠서 응답이 5초를 넘깁니다.
  2. 결제사는 실패로 판단하고 같은 알림을 다시 보냅니다.
  3. 이미 밀린 우리 서버에 일이 두 배로 들어옵니다.
  4. 더 느려집니다. 더 많이 재전송됩니다.

느려서 재전송되고, 재전송돼서 더 느려집니다. 스스로를 먹고 자라는 고리입니다. 한번 이 고리에 들어가면 트래픽이 원래대로 돌아와도 빠져나오지 못합니다.

그래서 규칙은 하나다

이 모든 것에서 나오는 결론은 단순합니다.

받자마자 접수증부터 끊어준다. 실제 처리는 그 뒤에 한다.

웹훅을 받으면 검증만 하고 큐에 넣고 즉시 200 OK를 돌려줍니다. 여기까지 몇 밀리초입니다. 결제사는 잘 전달됐다고 판단하고 재전송하지 않습니다. 재전송 고리가 시작조차 하지 않습니다.

실제 처리(주문 확정, 재고 차감, 메일)는 워커가 큐에서 꺼내 합니다. 그게 10초가 걸리든 1분이 걸리든 결제사와는 아무 상관이 없습니다.

동기로 처리받고 나서 처리
응답 시간처리가 끝나야 (수백 ms~수 초)몇 ms
스파이크가 오면응답 지연 → 재전송 → 붕괴큐에 쌓임. 응답은 그대로 빠름
우리 처리가 느리면보내는 쪽까지 망가진다우리 큐만 길어진다

200 OK가 뜻하는 것

주의할 점이 있습니다. 이 구조에서 우리가 돌려주는 200 OK는 "처리 완료"가 아니라 "잘 받았음"입니다.

이것은 후퇴가 아니라 정확한 약속입니다. 우리가 지킬 수 있는 것만 약속하는 것입니다. 받았다는 사실은 큐에 적힌 순간 확실합니다. 처리 성공은 그때 확실하지 않습니다. 확실하지 않은 것을 약속하면 거짓말이 됩니다.

대신 처리 단계에서 실패하면 그건 우리 책임입니다. 결제사는 이미 떠났고 다시 보내주지 않습니다. 그래서 큐에 남겨 재시도하고, 끝내 안 되면 따로 빼내 사람이 보게 합니다.

직접 해보세요

아래 과제는 웹훅을 동기로 처리하다가 스파이크에서 무너집니다. 받는 즉시 접수하고 뒤에서 처리하도록 바꿔 보세요.

이 강의가 단순화한 것

교육용 모형은 언제나 무언가를 생략합니다. 무엇을 생략했는지 아는 것도 학습의 일부입니다.

전제한 것

  • 이 시뮬레이터에는 웹훅 전용 컴포넌트가 없다. 그래서 보내는 쪽(결제사)을 클라이언트로, 받는 쪽을 일반 API 서버로 표현한다.
  • 보내는 쪽의 재전송은 이 시뮬레이터가 직접 수행하지 않는다. 재전송이 부하를 어떻게 키우는지는 본문에서 설명하고, 과제에서는 통제 불가능한 스파이크(갑자기 세 배로 뛰는 트래픽)로 그 상황을 표현한다.
  • 웹훅의 서명 검증과 인증은 다루지 않는다. 실제로는 남이 우리를 호출하는 구조이므로 이 검증이 보안상 필수다.
  • 각 단계의 처리 시간은 설명을 위해 고른 대표값이며 실제 측정값이 아니다.

다루지 않은 것

  • 웹훅 서명 검증(HMAC)과 재생 공격 방어
  • 보내는 쪽의 재시도 정책과 지수 백오프의 구체적 동작
  • 중복 수신 처리 — 뒤의 '멱등성' 강의에서 다룬다
  • 데드레터 큐와 수동 재처리 운영

더 읽을거리: Enterprise Integration Patterns — Event-Driven Consumer

이제 직접 만들어 보세요

읽어서 아는 것과 만들어서 아는 것은 다릅니다. 컴포넌트를 배치하고 트래픽을 흘려서 실제로 동작하는지 확인해 보세요.

실습 과제 열기

이 강의에 물어보기

하루 5번

이 강의 본문만 근거로 답합니다. 강의에 없는 내용은 지어내지 않습니다.