본문으로 건너뛰기

DataTransfer-Out-Bytes 폭증으로 인한 과금 요소 분석 및 해결

3월 2일에 AWS 정산 내역을 이메일로 받았습니다.
평소라면 기본 요금인 2만 5천원정도가 떠야 되는데…

img1
7만 5천원….?
무엇인가 잘못됐다 생각하고 바로 EC2 청구 내역을 확인하러 갔습니다.

img2
열심히 찾아보니 DataTransfer-Out-Bytes 라는 녀석이 문제였습니다.
2월 11일부터 급증하였고 평균 20GB씩 전송되고 있었습니다. 그에 따라 무료 100GB 할당량이 끝나는 지점부터(2월 16일) 일 당 평균 2.5달러씩 지출되고 있었습니다.

DataTransfer-Out-Bytes는 무엇이고 원인은?
#

EC2에서 인터넷으로 데이터 전송할 때 측정되는 요소입니다. 2월 11일부터 갑자기 매일매일 비슷한 양으로 데이터가 나가는 요소가 생겼다..?
Nginx를 통해 액세스 로그(2026-02-11 ~ 02-28)를 보니 합산 sent_bytes: 약 0.08 GB 정도 밖에 되지 않았습니다. 그러면 유저에게 응답으로 나가는 트래픽이 아니라는 것을 확인하였습니다.

VPC Flow Logs를 통해 어떤 ip가 가장 많이 조회되었는지 확인이 필요했습니다.
다만 이를 기존에는 활성화하지 않았어서 기존 데이터가 없어 정확한 확인이 불가하였습니다.
그래서 활성화 후 일정 시간 지난 뒤 실측 확인을 하는 방식으로 진행했습니다.

dstArrd:dstPort 기준으로 보니 168.~~~:3306이 top이었습니다.
이는 확인해본 결과 Oracle Instance에 있는 MySQL 서버였습니다.

img3
이는 서버쪽에서 제가 로직 변경하다가 있었을 가능성이 크기에 깃허브 로그를 확인해보았습니다. 2월에 11일에 커밋을 보니
img4
30분 마다 매치 경기 동기화 하는 로직 안에 팀 메타데이터 동기화 메서드도 활성화시켰습니다. 이때 생각으로는 매치 경기 동기화 하는 김에 팀 메타데이터도 매번 진행하면 최신화가 바로바로 되니까 좋은거 아닌가 싶어서 넣었던 기억이 있습니다.
img5
병목은 팀 메타데이터 동기화 부분에서 발생했다는 것을 파악하였는데요. 현재 팀 관련 데이터는 두 개의 테이블로 분리되어 있는데, 하나는 외부 API에서, 다른 하나는 CSV 스케줄링 데이터에서 들어옵니다. 즉 서로 다른 소스에서 데이터를 제공받기에 팀 이름과 같은 부분이 미세하게 다른 부분이 있었습니다. 이 때문에 서로 매칭을 위한 과정이 필요했습니다.
당시 저는 팀명 정규화와 경기 날짜 범위를 기준으로, 해당 기간에 실제로 경기를 치른 팀인지 확인하는 방식으로 매칭을 구현했습니다. 하지만 이 과정에서 연관된 매핑 테이블까지 함께 조회해야 했고, 후보 로우도 많아지면서 결국 선형 탐색 비용이 커졌습니다. 이 부분이 성능 병목의 핵심 원인이었습니다. 또한 이를 30분마다 돌리게 되었으니 무료 할당량을 넘어서게 되었습니다.
img6
해결 방향은 명확했습니다. 일단 메타데이터 경로를 매치 경기 동기화 로직에서 분리하였습니다. (따로 관리)

외부 API와 내부 데이터 사이에 공통 식별자가 없어서 이름과 날짜를 기준으로 선형 탐색을 하고 있었기 때문에, 각 소스의 팀을 연결하는 중간 매핑 테이블을 두고 externalTeamId -> internalTeamId 형태로 직접 찾을 수 있도록 바꾸었습니다.

초기 한 번만 기존 방식으로 매핑을 채우고, 이후부터는 이 매핑 테이블을 기준으로 바로 조회하도록 변경했습니다. 그 결과 이름 정규화와 날짜 범위 기반 후보 탐색 과정이 대부분 제거되었고, 팀 메타데이터 동기화 비용도 크게 줄일 수 있었습니다.

테스트
#

이를 Before/After 측정을 해보았습니다.

  • Before: elapsedMs=11191, prepareStatementCount=8553, entityLoadCount=18160
  • After: elapsedMs=66, prepareStatementCount=11, entityLoadCount=20

이전에는 매번 후보 데이터를 넓게 읽고 선형 탐색을 수행했다면, 이후에는 ID 기반으로 바로 연결되면서 쿼리 수와 엔티티 로드 수가 모두 큰 폭으로 감소했습니다.

느낀점
#

기능이 확장되면서 새로운 비즈니스 상황이 생기면, 기존에 자연스럽게 동작하던 구조도 병목이 될 수 있다는 점을 다시 확인했습니다.
특히 테이블 설계나 데이터 연결 방식은 처음 한 번 정하고 끝나는 것이 아니라, 도메인이 확장될수록 더 적절한 식별 방식과 매핑 구조가 있는지 계속 점검해야 한다고 느꼈습니다.