← 목록

NLB 포트별 트래픽 확인이 안 된다?: VPC Flow Logs + Athena로 해결한 과정

쓰지 않는 Target Group을 지우려다 막힌 기록. NLB가 포트별 트래픽을 보여주지 않는 이유와, 계층을 내려가 VPC Flow Logs로 답을 찾은 과정

2026-04-09AWSNLBVPC Flow LogsAthenaMonitoringTroubleshooting

배경

NLB에 Target Group이 7개(9443, 8443, 9090, 8090, 4012, 2053, 8083) 붙어 있었다. 오래된 것도 섞여 있어서 쓰지 않는 게 있으면 정리하고 싶었다.

그런데 지우려면 먼저 답해야 하는 질문이 있다. "이거 지금 아무도 안 쓰는 게 맞나?" 인프라에서 삭제가 어려운 이유는 삭제 자체가 아니라 이 확인이 안 되기 때문이다. 확신이 없으면 아무도 손대지 않고, 그래서 쓰지 않는 리소스가 계속 남는다.

단순한 확인이라고 생각했는데 생각보다 쉽지 않았다.


시도한 방법과 실패

방법결과원인
CloudWatch 메트릭 (ProcessedBytes, NewFlowCount)Target Group별 데이터 없음NLB는 TG별 트래픽 메트릭을 발행하지 않음 (LB 전체 레벨만 존재)
NLB 액세스 로그 (레거시 S3)TLS 리스너만 지원해당 NLB는 전체 TCP 리스너 (TLS 없음)
NLB 액세스 로그 (CloudWatch 통합)로그 미생성TCP 리스너는 NLB_ACCESS_LOGS 미지원

왜 NLB는 이걸 안 보여주나

ALB를 쓰다가 NLB로 오면 당황하게 되는 지점이다. ALB에서는 요청 단위 액세스 로그가 당연하게 남는데, NLB에는 없다.

둘이 트래픽을 다루는 방식이 다르기 때문이다.

[ALB, L7]
클라이언트 --- 연결 ---> ALB --- 새 연결 ---> 타겟
ALB가 HTTP 요청을 해석하고 대신 전달한다
→ 경로, 상태 코드, 응답 시간 같은 요청 단위 정보가 남는다

[NLB, L4]
클라이언트 ------- 흐름 전달 -------> 타겟
NLB는 TCP 흐름을 넘길 뿐 내용을 해석하지 않는다
→ 남길 "요청"이라는 단위 자체가 없다

NLB는 내용을 보지 않는 것이 설계 목표다. 그 덕분에 빠르고 프로토콜을 가리지 않지만, 대신 관측할 수 있는 정보도 얇아진다. TLS 리스너에서만 액세스 로그가 나오는 이유도 같은 맥락이다. TLS를 종료하는 경우에만 NLB가 연결에 개입하기 때문이다.

관리형 서비스는 편한 대신, 관측 범위도 서비스가 정해준 만큼만 주어진다.

시도했다가 쓰지 않게 된 리소스는 정리했다.

리소스조치
NLB 액세스 로그 배포 (S3, CloudWatch)삭제
S3 버킷 (NLB 액세스 로그용)삭제
CloudWatch Log Group (NLB 액세스 로그용)삭제

해결: 계층을 한 칸 내려간다

NLB가 안 보여준다면, 그 트래픽이 실제로 지나가는 곳을 보면 된다. NLB도 결국 ENI를 통해 패킷을 주고받고, ENI 레벨의 기록은 VPC Flow Logs로 남길 수 있다.

NLB ENI → VPC Flow Logs → S3 (JSON 로그) → Athena (SQL 분석)

로드밸런서라는 추상화에는 포트별 트래픽이라는 개념이 없지만, 그 아래 네트워크 계층에는 "어느 목적지 포트로 몇 개의 흐름이 갔는가"가 그대로 남아 있다. 보고 싶은 정보가 상위 계층에 없으면, 같은 사실이 아래 계층에 다른 형태로 남아 있는지 찾는다.

VPC Flow Logs 설정

항목설정값
대상 ENINLB에 연결된 ENI
트래픽 유형ALL (인바운드 + 아웃바운드)
집계 간격60초
로그 대상S3

Flow Logs는 트래픽 경로에 끼어들지 않는다. 패킷을 복사해 기록만 하므로 NLB 동작에 영향을 주지 않는다는 점이, 운영 중인 로드밸런서에 적용할 때 중요했다.

Athena 분석 환경

기존에 CloudTrail 분석용으로 구축해둔 Athena 환경(cloudtrail-analysis Workgroup)을 그대로 활용했다. VPC Flow Logs 전용 테이블만 추가로 만들었고, Partition Projection을 적용해 날짜별 파티션이 자동으로 관리되게 했다.

쿼리명용도
create-vpc-flow-logs-table테이블 생성 (최초 1회만 실행)
nlb-[lb-name]-port-traffic확인 대상 7개 포트의 트래픽 요약
nlb-[lb-name]-all-ports전체 포트 중 트래픽 상위 20개

결과는 listener_port(= Target Group 포트), connection_count, total_packets, total_bytes, unique_sources 컬럼으로 정리했다. 고유 소스 IP 수를 같이 본 이유는, 연결 수가 적어도 여러 곳에서 오고 있다면 함부로 지울 수 없기 때문이다.


확인 결과

약 1~2시간 데이터 기준이다.

포트별 연결 수와 트래픽

포트Target Group연결 수트래픽판정
8443COORD-HTTPS59,127162.41 MB활발히 사용 중
9443HTTPS-SS22,82754.38 MB활발히 사용 중
9090HTTP26013.42 MB사용 중 (소량)
8083ConnectOms3421.46 MB사용 중 (소량)
4012DB-SSH220.01 MB거의 없음
8090HTTP30.01 MB거의 없음
2053WORKER-SSH00트래픽 없음

연결 수는 세 자릿수 이상 차이가 나서, 상위와 하위의 구분은 명확했다. 흥미로운 건 9090처럼 연결 수는 적은데 트래픽은 적지 않은 경우다. 연결 하나가 오래 유지되면서 데이터를 많이 주고받는 종류라서, 연결 수만 봤으면 잘못 판단했을 것이다.

이 숫자로 지워도 되는가

여기서 한 번 멈춰야 했다. 1~2시간은 짧다.

그래서 결론을 "삭제"가 아니라 관측 기간을 늘려서 다시 보기로 잡았다. 며칠에서 한 주를 지켜보고, 그래도 0이면 바로 지우는 대신 Target Group에서 타겟을 먼저 떼거나 태그로 표시해두고 문의가 오는지 본다. 되돌리기 쉬운 순서로 밟는 편이 안전하다.


비용

항목예상 비용
VPC Flow Logs 수집 (S3)$0.089/GB
S3 저장$0.025/GB/월
Athena 쿼리스캔 1TB당 $5 (소규모 쿼리는 거의 무료)

확인이 끝나면 Flow Logs를 꺼서 비용을 줄일 수 있다. 다만 끄는 순간부터 기록이 남지 않으므로, 나중에 같은 질문이 또 나올 것 같으면 켜둔 채로 보존 기간만 짧게 잡는 쪽이 낫다.


정리


배운 점

추상화가 감춘 정보는 한 계층 아래에 있다. 로드밸런서라는 이름 위에서는 답이 없던 질문이, 네트워크 인터페이스 레벨에서는 이미 기록되어 있었다. 관리형 서비스에서 막히면 "이 서비스는 못 한다"가 아니라 "이 사실이 어디에 남는가"를 묻는 게 빠르다.

지우기 위해 필요한 건 권한이 아니라 근거였다. Target Group 삭제는 클릭 몇 번이지만, 아무도 실행하지 못한 이유는 확인 수단이 없었기 때문이다. 정리가 안 되는 인프라는 대개 게을러서가 아니라 관측이 없어서 그렇게 된다.

없다는 결론은 있다는 결론보다 더 많은 데이터를 요구한다. 트래픽이 있다는 건 한 건만 봐도 증명되지만, 없다는 건 충분히 긴 기간을 봐야 말할 수 있다. 1~2시간 데이터로 삭제까지 가지 않은 게 이 작업에서 가장 중요한 판단이었다. 같은 이유로 EDI Agent 중앙 모니터링에서도 한 번의 실패가 아니라 연속 실패를 기준으로 삼았다.

여기서 재사용한 분석 환경은 CloudTrail + Athena 감사 로그 분석 환경 구축에 정리해 뒀다.


이어 읽기