← 모든 글

multimodal 데이터로 만든 운영 대시보드

숫자만으로는 장애 원인을 알 수 없다. HEDVION이 결제·정산 운영 대시보드에 수치·로그·UI 캡처를 통합한 구조, 임계치 트레이드오프, 원인 파악 23분→6분 단축 실전 경험을 공유한다.

오류율이 올라갔다—그래서 "왜"는 어디에 있나

결제 시스템을 운영하면서 가장 자주 겪는 불편은 지표가 움직이는 걸 보면서도 그 이유를 바로 알 수 없다는 상황이다. 성공률이 97.3%에서 94.1%로 내려가는 건 모니터링 화면에서 즉각 보인다. 그런데 그게 PG사 API 타임아웃 때문인지, 특정 카드사 응답 지연 때문인지, 아니면 전날 밤 배포한 결제 폼 수정 때문인지는 숫자만 봐서는 알 수 없다. 문제를 발견하는 것과 원인을 파악하는 것 사이에 항상 공백이 있었다.

HEDVION은 결제·정산·자동화를 직접 운영하는 작은 팀이다. 외부 APM을 써도 우리 비즈니스 맥락에 맞춰 데이터를 해석하는 건 결국 팀 내부에서 해야 한다. 오류율이 치솟은 시각에 배포가 있었는지 Git 커밋 로그를 열고, 로그 수집 도구에서 같은 시각대를 필터링하고, 정산 배치 실패와 외부 API 상태를 따로 비교하는 작업이 장애 대응 시간의 절반 이상을 차지하고 있었다. 이 컨텍스트 스위칭 비용이 크다는 걸 체감한 뒤, 데이터 유형을 하나의 타임라인으로 통합하기로 했다.

결제·정산 현장에서 멀티모달이 특히 중요한 이유

결제와 정산 시스템에는 다른 도메인보다 데이터 유형의 이질성이 두드러진다. 수치 지표(성공률, 응답 시간, 건수)는 시계열로 자연스럽게 표현된다. 반면 정산 오류 로그는 구조화된 JSON이기도 하고 스택 트레이스가 섞인 텍스트이기도 하다. 결제 플로우에서 이탈이 늘었을 때 원인을 파악하려면 실제 UI 상태—카드 입력 화면이 그 순간 어떻게 렌더링됐는지—가 필요하다. 이 세 가지는 본질적으로 서로 다른 "언어"다.

문제는 이 언어들이 각기 다른 도구에 분산돼 있다는 점이다. 수치는 CloudWatch나 Prometheus, 로그는 S3나 Loki, 화면 캡처는 별도 스토리지. 장애 상황에서 세 개의 탭을 열고 타임스탬프를 손으로 맞춰가며 원인을 추적하는 건 사람이 하기에 느리고 실수가 잦다. 우리 팀처럼 한 명이 개발·운영·장애 대응을 동시에 담당하는 구조에서는 이 탐색 시간이 직접적인 서비스 지연으로 이어진다. 아무리 좋은 알림 시스템을 갖춰도 "무슨 일이 났는지는 알지만 왜 그런지는 모르는" 상태가 지속되면 대응 품질이 낮아진다.

타임라인 인덱스로 통합하는 구조

우리가 선택한 방식의 핵심은 스키마를 통일하는 게 아니라 타임라인 인덱스 레이어를 별도로 두는 것이다. 각 데이터 유형은 원본 형식 그대로 저장한다—수치는 float 시계열, 로그는 원본 JSON 또는 텍스트, 이미지는 파일 경로. 그 위에 공통 인덱스 레이어를 얹는다. 형태는 단순하다: { timestamp, category, source_ref, tags }. 모든 이벤트를 이 포맷으로 색인하고, 대시보드는 이 인덱스를 기준으로 타임라인을 렌더링한다.

실제 동작은 이렇다. 수치 그래프에서 이상 구간을 드래그해 선택하면, 같은 시각대에 색인된 로그 요약과 UI 캡처 썸네일이 함께 나타난다. 배포 이벤트도 category: "deploy"로 인덱스에 들어가기 때문에 수치 그래프 위에 수직선으로 표시된다. 구현 초기에는 로그와 수치 두 유형만 연결했다. 이미지 캡처는 두 달 뒤에 추가했는데, 인덱스 레이어에 새 카테고리와 source_ref 규칙을 하나 추가하는 것으로 충분했다. 기존 수치·로그 파이프라인은 전혀 건드리지 않았다. 이 확장 비용의 낮음이 이 구조를 선택한 핵심 이유 중 하나다.

트레이드오프: 저장 비용과 캡처 임계치 설정의 현실

가장 많이 조정한 부분은 UI 캡처의 트리거 임계치다. "결제 완료율이 X% 이하로 떨어지면 해당 시점의 화면을 캡처한다"는 규칙은 단순해 보이지만, X를 어디에 잡느냐에 따라 저장 비용과 실제 유용성이 크게 달라진다.

처음에 임계치를 95%로 설정했더니 하루 평균 캡처 건수가 200개를 넘었다. 결제 완료율은 트래픽이 몰리는 피크 타임에 자연스럽게 95% 아래로 내려가는 경우가 많아서, 실제 장애가 아닌 정상적인 피크 부하 상황에서도 캡처가 계속 쌓였다. 7일 보존 정책 기준으로 이미지 스토리지 비용이 월 12달러가량 추가됐고, 노이즈가 많아 진짜 이상 상황의 캡처를 찾기가 어려웠다. 임계치를 90%로 내리고 "5분 이동평균이 이 수치 이하일 때"라는 조건을 추가하자 하루 평균 캡처 건수가 15건 이하로 줄었고, 스토리지 비용은 월 1달러 수준으로 정상화됐다. 더 중요한 건 실제 이상 상황에서의 캡처 밀도가 높아졌다는 것이다—노이즈가 줄었으니 필요한 캡처가 묻히지 않는다.

로그 인덱싱도 같은 논리가 적용된다. 전체 로그를 인덱스에 넣으면 인덱스 테이블이 빠르게 커져 조회 성능이 떨어진다. 우리는 ERROR, WARN 레벨과 결제 도메인 핵심 키워드(payment_failed, settlement_error, timeout, pg_unreachable)가 포함된 로그만 인덱싱하는 필터를 적용했다. 이렇게 하면 인덱스 테이블의 일간 증가량이 전체 로그 볼륨의 약 3% 수준에서 유지된다.

HEDVION 팀의 실제 장애 대응 시나리오

구체적인 사례를 공유한다. 우리가 운영하는 정산 자동화 파이프라인은 매일 새벽 2시에 전일 결제 데이터를 집계해 파트너사에 전송한다. 어느 날 새벽 2시 17분, 배치 성공률이 평소 99.7%에서 갑자기 71%로 내려갔다. 예전 방식대로라면 배포 이력 확인, S3 로그 탐색, 외부 API 상태 페이지 확인을 순서대로 진행해야 했다. 빠르면 20분, 느리면 한 시간이 걸렸다.

멀티모달 대시보드가 있는 지금은 다르다. 타임라인에서 2시 17분 구간을 선택하면 같은 시각대에 "파트너 API 응답 시간 급증: 평균 340ms → 8.2s" 로그 요약이 뜨고, 수직선 배포 마커가 없다는 사실도 바로 보인다. 원인이 우리 코드 변경이 아닌 외부 API 지연이라는 판단을 3분 안에 내릴 수 있다. 이 구조를 도입한 후 비슷한 유형의 장애에서 원인 파악 시간이 평균 23분에서 6분으로 줄었다. 또 다른 사례: 특정 결제 플로우 완료율이 내려갔을 때 해당 시점 캡처를 확인하니 에러 메시지가 한국어가 아닌 영문 raw 오류 코드로 표시되고 있었다. i18n 누락 버그였는데, 수치만 봤다면 API 문제로 오판하고 엉뚱한 방향을 파봤을 가능성이 높다. 맥락이 해석 자체를 바꾼다.

바로 써먹을 수 있는 실행 시사점

처음 도입하는 팀을 위해 단계별로 권장 순서를 정리한다.

1단계—수치 + 배포 이벤트 오버레이부터 시작하라. 가장 빠르게 가치를 확인할 수 있는 조합이다. 배포 타임스탬프를 기존 모니터링 타임라인에 수직선으로 표시하는 것만으로도 "배포 직후 지표 변화"를 즉각 시각화할 수 있다. CI/CD 파이프라인에서 배포 완료 시각을 인덱스에 POST하는 훅 하나면 된다.

2단계—로그는 전량이 아니라 선별 인덱싱으로. ERROR/WARN + 도메인 핵심 키워드 필터를 처음부터 적용하라. 필터 기준은 보수적으로 시작해 "이 로그가 없어서 놓쳤다"는 실제 경험이 생길 때 확장하는 방식이 낫다. 전량 인덱싱은 조회 성능과 스토리지 비용을 빠르게 높인다.

3단계—UI 캡처 트리거는 이동평균 임계치로 설정하라. 순간 값 기준으로 걸면 피크 노이즈가 많다. 5분 이동평균 기준으로 설정하고, 처음 임계치는 낮게(더 드물게 캡처되도록) 잡은 뒤 실운영 데이터를 보며 조정하라. 캡처 보존 기간은 7일로 시작하면 비용과 유용성 사이의 균형을 찾기 쉽다.

4단계—인덱스 스키마의 tags 배열을 활용해 확장성을 유지하라. category는 큰 범주(metric / log / screenshot / deploy)만 구분하고, 세부 분류는 자유 형식의 tags 배열에 넣어라. 처음부터 category를 세분화하면 유형 추가 시 스키마 마이그레이션이 필요해진다. 인덱스 레이어가 가벼울수록 새 데이터 유형을 붙이는 비용이 낮다.

결제·정산·자동화 운영에서 장애 대응의 진짜 비용은 탐색 시간이다. 무슨 일이 일어났는지는 알지만 왜 그런지를 모르는 그 공백. 멀티모달 대시보드는 그 공백을 메우는 실용적인 도구다. 처음부터 완성된 형태를 만들려 하지 말고, 수치와 배포 이벤트를 연결하는 것 하나에서 시작하면 된다.

— by slecs

* 위 링크는 인프런 affiliate 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

📚 추천 강의
한 입 크기로 잘라먹는 바이브코딩 (with Claude Code)
Claude Code로 바이브코딩, 개발자라면 꼭 들어야 할 필수 강의
강의 보러가기 →

* 위 추천 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.