Engineering
NOL(야놀자)에서 결제 서비스를 안정적으로 운영하는 방법
NOL Tech Blog야놀자
2025년 7월 11일
원문에서 보기 ↗
이 이미지는 생성형 AI를 활용해 제작하였습니다.
IT 서비스를 운영할 때 가장 중요한 모듈은 무엇이라고 할 수 있을까요? 많은 핵심 컴포넌트들이 있지만, 결제 서비스를 그 중에 하나로 넣는데에 이견을 표하시는 분은 없을 거라고 생각합니다.
결제 서비스의 장애는 직접적인 매출 손실은 물론, 고객의 신뢰를 잃게 만드는 치명적인 요소로 작용할 수 있는데요.
월 평균 약 2천억원(확인 시점 및 책정 방식에 따라 일부 오차가 있을 수 있습니다)의 결제가 일어나는 NOL 에서 결제 서비스를 안정적으로 운영하기 위해서 실행하고 있는 방법들을 공유 드리려고 합니다.
1. 결제 정책 조정 기능
1–1. PG 사 자체 이슈가 생기는 경우
⚫ 분배율 조정 기능
PG 사 다중화 & 분배율 조정으로 이런 상황에 대비하고 있습니다.
PG 다중화는 많은 분들이 당연하게 여기실 수 있는 부분이라고 생각합니다. PG 사는 민감한 결제 처리 특성상 신뢰성 있는 서비스를 보장하고 있으나, 서비스를 제공하는 입장에서는 PG 사만 믿고 있을 수는 없습니다.
저희는 15개의 PG 사를 연동 하고 있으며, 결제수단 역시 그만큼 많이 존재하고 있습니다. 결제수단 별로 분배율을 세팅할 수 있도록 Admin 기능을 제공하고 있으며, 결제 요청이 들어올 때 분배율 결정 로직에 따라 필요한 PG 사를 선택하고 있습니다.

PG 분배를 위한 관리자 화면
(사진은 실제 분배율과 상관없이 임의로 넣은 값이며,
상단에 노출되는 결제 수단은 중요도와 관련 없이 무작위 순서로 노출되었습니다.)
따라서 모니터링 중에 A PG 사에서 이상이 발견되면, 언제든 바로 해당 PG 의 분배율을 0%로 변경할 수 있으며, 변경이 완료되면 새롭게 정의된 분배율에 따라 더 이상 카드 결제 시 A PG 사로 요청이 가지 않도록 처리할 수 있습니다.
1–2. 결제 수단에서 문제가 생기는 경우
일반적으로 사용되는 카드, 가상계좌, 휴대폰 결제 등의 결제수단은 다양한 PG 사에서 연동을 제공하고 있습니다. 그러나 보통 간편결제(xx페이 등) 는 해당 회사에서 제공을 하고 있고 해당 서비스에 문제가 생기면 결제수단 자체가 사용 불가능해집니다.
⚫ 결제 수단 비활성화 기능
Admin 에서 각 결제수단 에 대해 공지사항을 설정할 수 있는데요.
공지사항을 게시할 수 있는 시간을 지정할 수 있으며(예약 가능) 해당 시간에 맞추어 결제수단을 비활성화 할 수 있습니다

위와 같이 Admin 에서 결제수단을 비활성화 할 수 있는 Check box 를 확인 가능합니다.
A 페이 서비스 점검으로 등록하고, A 페이를 결제수단 비활성화 했다고 가정해 보겠습니다.

비활성화 된 주문서 화면
결제수단을 비활성화 했을 때 화면입니다. 위와 같이 주문서 화면이 비활성화 된 것을 확인할 수 있습니다.
1–3. 고객 관점에서의 1–1, 1–2 가 미치는 영향
분배율 조정, 결제 수단 비활성화, 공지 등을 통해 고객에게 안내하고, 문제가 없는 결제 수단만을 노출하고 문제가 없는 PG 사로만 결제 요청을 분배합니다.
이런 기능이 없다면 어떻게 될까요? 🤔
문제가 있는 결제 수단이나 PG 로의 요청을 허용하게 되면, 이를 모르는 사용자가 해당 수단을 선택하고 실패를 경험하게 됩니다.
실패를 경험한 사용자가 다른 결제수단을 통해 다시 결제를 시도할 수도 있지만, 그렇지 않을 수도 있습니다. 그렇다면 우리는 소중한 한 건의 주문을 놓치게 되겠죠.
일반적으로 인용되는 바에 따르면, 결제 실패를 경험한 고객의 상당수가 수동으로 재시도하지 않으며 이는 즉시 매출 손실로 이어집니다.
따라서 주문서에서는 항상 현재 결제 가능한 결제 수단만 조회하도록 구성됩니다.
문제가 생긴 경우 결제 정책에서 해당 결제수단을 제외하는 것으로 간단하게 처리됩니다.
결과적으로 고객의 실패 경험 확률이 크게 줄어들게 됩니다. 😊
2. 결제 과정에 대한 가시성 확보
결제 하나가 이루어지기 위해서는 여러 과정을 거치게 됩니다. PG 사 마다 다를 수는 있지만, 일반적으로 아래와 같은 단계로 결제가 진행됩니다.

일반적인 PG 결제 프로세스
각 단계별로 여러가지 이유로 실패할 수 있습니다.
- 사용자 액션으로 취소 되는 경우 : 결제 취소
- PG 사에서 실패를 응답하는 경우 : 잔고부족, 유효시간 초과 등
- 비즈니스 로직 실패 : 결제 중 재고 확보에 실패하거나 다른 로직에서 오류가 발생한 경우
이런 모든 실패를 결제 시스템에서 확인해야 할까요? 그렇게 하기에는 너무 많은 운영 리소스가 들어갈 것입니다. 그래서 저희는 추이를 확인합니다.
2–1. 정보 수집
저희는 각 단계 별로 이벤트를 정의하여 어떤 단계에서 오류가 발생하는지를 전반적인 흐름에서 파악하려고 하고 있습니다. 그러려면 어떤 것들이 필요할까요?
- 어떤 정보들을 수집할 것인지에 대한 대상 선정
- 이 데이터를 어디에 보관하고 어떻게 볼 것인가
크게 이 두가지 관점에서 고민할 수 있을 것입니다. 두가지 관점에 대해 간략하게 소개하겠습니다.
⚫ 데이터 처리 파이프라인
데이터를 수집하는 파이프라인은 아래와 같습니다. 대량의 결제 이벤트 데이터를 안정적으로 적재하기 위해 Kafka 기반의 스트리밍 파이프라인을 구축했는데요. 결제는 Client 와 Backend 를 오가며 이루어지기 때문에 각 컴포넌트에서 정의된 이벤트를 각자 Kafka 로 발행합니다.
이렇게 발행된 이벤트를 Log Consumer(Log Stash) 가 Consume 하여 ES 로 데이터를 보내고 있고, Kibana 로 시각화 하여 대시보드 및 알림을 제공하게 됩니다.

로그 수집 아키텍처
⚫ Event 정의
각 Event 에 따라 수집하는 데이터는 다르지만, 기본적으로 아래와 같은 내용입니다.
- 이벤트 타입 : 결제가 이루어지는 과정에서 큰 단계( 결제요청, 결제 인증, 승인 )
- 상세 이벤트 타입 : 이벤트 타입의 세부적인 과정 ( 결제 요청 시작, PG 사 분배 완료, 결제 요청 종료 등 )
- 이 과정에는 Client 의 Event Type 도 들어갑니다. 예를 들면 인증 창(PG 창) 으로 이동 했는지, 결제 완료 페이지로 이동 했는지 등
- Context 정보 : 결제 수단, PG 사, 요청처, 상품명 등
- MetaData : 요청 ID, 호출한 API 정보, TimeStamp 등
물론 실제로 수집하는 데이터는 훨씬 많고 단계도 복잡하지만 모든 내용을 기재 하기에는 TMI 가 아닐까 싶어서 대략적인 방향만 제시하는 것으로 하겠습니다. 이제 이 이벤트들을 어떤 추이를 보는데 사용하고 있는지 아래에서 다루겠습니다.
2–2. 어떤 메트릭이 추이를 확인하는데 도움이 되는가?
대시 보드의 화면을 바로 보여드리도록 하겠습니다. 처음 모니터링 대시 보드에 들어가면 보이는 화면 입니다.
화면에서는 각각의 이벤트에 대한 메트릭의 추이를 볼 수 있고, 사용자들이 어느 시점에 결제를 그만두는지를 확인할 수 있습니다.

일반적인 시간대의 대시보드, 구체적 건수는 민감 정보이므로 모자이크 처리 하였습니다.
아래의 주요 3가지 지표는 이런 것들을 의미합니다.
- 결제 인증 전환율 : 사용자가 결제를 시작한 후 PG 오픈 단계로 얼마나 넘어갔는지
- 결제 승인 전환율 : PG 인증 완료 후 승인된 비율은 얼마인지
- 결제 성공률 : 요청 시점부터 결제가 실제로 얼마나 완료 되었는지
여기서 결제 성공률이 기대보다 낮다 라고 생각하실 수 있는 여지가 있는데요. 이것이 기술적 실패를 의미하는것은 아닙니다.
이 79.8% 는 고객의 결제가 이루어지기까지 고객이 결제 과정을 끝까지 진행하지 않았을 수도 있고 카드 한도초과 등 다른 이유로 실패했을 수가 있습니다.
하지만 결제 실패가 갑작스럽게 늘어나기 시작했다면 이것이 이슈의 시작인지, 아니면 일반적인 상황인지 바로 알기 어려울 것입니다.
따라서 주요한 지표 중 하나로 주문 실패 메시지를 대시보드에 포함시켜 보고 있습니다 🙂

주문 실패 메시지 대시보드
실패 메시지를 보면 알 수 있듯이 대부분은 고객의 변심에 의한 결제 취소입니다.
그리고 실제 주문 시 validation 에서 실패한 건들이 높은 순위를 차지하고 있습니다. 이벤트가 있을 때는 이런 실패가 많이 발생할 수 있고, 따라서 결제 실패율이 급증할 수 있습니다.
이럴 때 TOP10 메시지를 보고, ‘아 어떤 게 문제여서 실패율이 올랐고 우리의 결제 시스템은 정상 동작을 하고 있구나’ 하는 것을 바로 파악할 수 있습니다.
만약에 이런 지표가 없다면 갑작스런 결제 실패율의 급증에 패닉하며 혹시 무슨 이벤트가 없는지 찾게 되겠죠?
아주 유용한 지표로 만약 없으시다면 추가하시는 것을 강력히 추천드립니다.
이외에도 결제수단 별 비중이나, PG 별 결제 비중, 결제수단에 대한 PG 분배율에 대한 현황등을 도넛 차트로 구성하여 대시보드에서 확인할 수 있습니다.
다소 민감한 데이터일 수 있어 예시로만 첨부하니 양해 부탁드리며, NOL 에서는 이렇게 하고 있다 정도로만 이해해 주시면 좋겠습니다.

예시용 도넛 차트
2–3. 이것들을 어떻게 감지하는가?
⚫ 감지 방법
다양한 알림 방법이 있겠지만 현재 ES 에서 주로 Dashboard 를 만들고 사용하고 있기 때문에, Alert 도 ES 를 통해서 받고 있습니다.
Grafana 를 사용하면 더 예쁘게 시각화 하여 복잡한 대시보드를 구성할 수도 있겠지만, 당장은 그 정도의 시각화는 필수적이지는 않다고 판단하고 있습니다.
ES 에서 역시 Monitor 할 수 있는 방법을 제공하고 있는데 Define using extraction query 를 사용하고 있습니다.
수집하는 이벤트를 쿼리를 통해 조작하여 원하는 임계값이 되었을 때 알람을 보내도록 말이죠.
아래는 query 의 예시 입니다.
물론 실제로 사용되는 event type 은 아니고, 대체하였습니다.
[ Define extraction query ]
{
"size": 0,
"query": {
"bool": {
"must": [
{
"match": {
"eventType": "APPROVE"
}
},
{
"match": {
"detailEventType": "APPROVE_COMPLETE"
}
}
],
"filter": [
{
"range": {
"eventTime": {
"from": "{{period_end}}||-1m",
"to": "{{period_end}}",
"include_lower": true,
"include_upper": true,
"format": "epoch_millis"
}
}
}
]
}
},
"aggregations": {}
}
예를 들자면 이 쿼리는 최근 1분간 PG 승인 완료 이벤트 건수를 집계하는 쿼리입니다. 평소 대비 건수가 크게 떨어지면 즉시 알림을 발송하기 위함입니다. 이렇게 쿼리를 세팅하고, Trigger 를 만들면 알림을 받아 볼 수 있습니다.
[ Trigger Condition ]
ctx.results[0].hits.total.value < N건 설정
1분간 승인 완료 건수가 N건 이하라면 알림을 울리게 되었네요.
Action 도 세팅할 수 있으며, 저희는 Slack 알람을 통해서 알림을 받아보고 있습니다.
귀여운 저희의(내용은 귀엽지 않으나) Slack 알림을 첨부합니다.

⚫ 어떤 알림들을 받아보고 있나요?
그렇다면 어떤 것들을 모니터링해서, 어느 정도의 임계치일때 Alert 를 받아야 할까요?
저희가 모니터링하는 일부🚨 Alert 🚨 를 공유합니다.
- 🔻 결제 요청 1분간 N건 미만
- 🔻 결제 승인 1분간 N건 미만
- 🔥 결제 실패 모니터링 1분당 N건 초과
- ⏰ PG사 N분간 승인 완료 N건 미만(PG사마다 다르게 설정)
이런 부분들에서 N건을 설정하는 것은 사실 상당히 어려운 부분입니다. 특히 ‘어느 정도의 임계치’ 라는 것이 참 애매모호 하면서 설정하기가 어렵습니다.
⚫ 임계값 설정의 딜레마
너무 많이 알람이 오면 개발자의 피로도가 증가 하게 되고 오히려 알림에 대한 민감도가 떨어지게 됩니다. 하지만 너무 임계치를 높여 놓는다면 이상을 빠르게 알아챌 수 없을 것입니다.
운영에 민감하게 대응할 수 있는 인원이 몇 명인지에 따라서도 임계값을 적절히 조절하는것이 필요할 수 있습니다.
⚫ 그럼 어떻게 임계값을 설정해야 하나요? 🤔
이런 문제는 사실 정답이 없고, 운영을 하면서 점차 조정해야 합니다.
처음에는 임계값을 민감하게 설정하고 지켜보다가 실제로 알람이 울려서 체크했을 때 별다른 이슈가 아닌 것을 확인하고 점진적으로 임계값을 조정해 나가는 과정이 필요합니다.
⚫ 임계값 설정 실패의 끔찍한 예시
예를 들어보자면 결제 실패 모니터링 같은 경우에는 1분당 N건 초과로 했을 때 시간대에 따라서 다를 수 있습니다.
운영 서비스 특성이 아래와 같은 조건이라고 가정해보겠습니다.
- 15:00 ~ 19:00 까지는 결제가 많이 일어남
- 나머지 시간에는 결제가 거의 없음 ( 상당히 극단적인 가정이지만 예시를 위한 것이니 이해 부탁드립니다. )
- 분당 100건 이상 실패가 넘으면 알람이 오도록 설정
02:00 에 결제 서비스에 장애가 생겨서 전체 결제건이 실패 하는 상황이 되었습니다. 하지만 전체 결제가 분당 100건이 안 되기 때문에 알람이 오지 않았고, 이슈를 알아챌 수 없었습니다.
따라서 정말 섬세하게 설정한다면 시간대에 따라서 설정해 이슈를 감지할 수 있겠죠. 이런 부분들이 모니터링을 어렵게 하는 요인이지만, 잘 설정해 두면 정말 든든한 것도 사실입니다.
마무리하며
더 추가 하고 싶은 운영 기능
결제 수단 별 PG 사 결제 지표가 현저하게 떨어졌을 때 자동으로 분배율 변경
지금은 PM 이나 개발자가 이슈를 확인하고 수동으로 분배율을 변경해주고 있는데요. 간단하게 변경할 수 있는 것은 맞지만, 이슈를 확인하고 수정하기까지 시간이 걸리는 것도 사실입니다. 즉각 대응을 할 수 없는 상황도 있을 수 있고요. 이런 상황을 대비한 자동화도 고려해 볼 사안입니다.
다음 편 예고
이 문서는 본래 1편에 모든 것을 담을 생각이었지만 생각보다 문서가 길어지며 1편과 2편으로 나뉘게 되었습니다.
1편은 보셨다시피 운영적 측면에서의 정보를 더 담게 되었고 2편에서는 아래와 같은 정보를 다뤄 볼 생각입니다.
- 결제 승인 시 타임아웃이 나면 어떻게 처리하나요? - Saga 패턴 활용 및 배치 통한 PG 서비스와의 Sync 처리 OverView
- 결제 취소가 실패하면 어떻게 하나요? - 어떤 방법을 통해 결제 취소를 처리하고 있는가 - 재시도 방법 - 취소가 되지 않는다면? ( 취소 거절 케이스 )
- 우리 결제 내역이 정확한 지 어떻게 알 수 있나요? - PG 사 결제 내역과의 Sync 및 처리 방안
1편의 반응이 좋다면 2편에서 좀더 기술적인 내용으로 돌아오겠습니다 😀
많은 성원 부탁드립니다.

누구나 마음 편히 놀 수 있는 세상을 함께 만들어갈 동료를 찾고 있어요 :)
