CloudWatch Logs 전송량 증가로 NAT Gateway BytesInFromSource가 급증한 원인
このコンテンツはまだ日本語訳がありません。
Issue
섹션 제목: “Issue”4XX 에러가 증가하면서 NAT Gateway BytesInFromSource 도 증가한다.
이번 달 초에 새로운 버전의 앱을 릴리즈한 뒤부터 서버의 4XX 에러가 늘어나기 시작했다. 새 버전 설치 수가 증가할수록 4XX 에러도 같이 급증했다.
원인은 비교적 빨리 찾았다. 앱에서 API를 호출할 때 보내는 Request Body의 데이터 타입이 잘못되어 있었고, 숫자여야 하는 필드에 문자열이 들어가 validation 에러가 발생하고 있었다.
4XX 에러 증가는 원인도 빨리 찾았고 대응 방향도 정할 수 있었다. 그런데 같은 시점에 NAT Gateway의 BytesInFromSource 지표도 함께 증가하고 있었다. 이 지표가 왜 같이 오르는지는 알 수가 없었다.
BytesInFromSource: AWS 공식 문서 기준으로 NAT Gateway가 VPC 내 클라이언트로부터 받은 바이트 수 를 뜻한다.
즉, private subnet에 있는 리소스가 NAT Gateway로 밀어 넣는 트래픽 양이 늘었다는 뜻이다.
현재 백엔드 구성은 이러했다.
- 서버는 AWS ECS Fargate를 사용한다.
- ECS task는 private subnet에 있다.
- NAT Gateway를 통해 외부 AWS 서비스와 통신하고 있다.
- CloudWatch Logs용 VPC Endpoint는 따로 구성하지 않고 있다.
이 구조에서는 ECS task가 VPC 외부의 AWS 관리형 서비스인 CloudWatch Logs로 로그를 보낼 때, CloudWatch Logs VPC Endpoint가 없다면 NAT Gateway 트래픽에 포함될 수 있기에 그 점을 의심했다.
Cause
섹션 제목: “Cause”ECS(VPC 내부)에서 VPC 외부의 AWS 관리형 서비스인 CloudWatch Logs로 전송하는 에러 로그의 양이 너무 많았다.
4XX 에러 증가와 BytesInFromSource 증가가 비슷한 시점에 발생했기 때문에 둘이 연결되어 있을 가능성이 높다고 판단했다.
4XX 에러가 발생할 때 미들웨어 레이어에서 에러 로그를 남기고 있었는데, 이 로그에는 Stack Trace까지 포함되어 있었다. 에러 수 자체도 많았고, 각 에러 메시지의 길이도 길었다. 결국 에러 건수와 로그 한 건당 크기가 동시에 늘어나면서 CloudWatch Logs로 전송되는 로그 양도 급증했다.
여기서 핵심은 CloudWatch Logs로 가는 경로가 NAT Gateway를 지나고 있었다는 점이다. 현재 ECS task는 awslogs 로그 드라이버를 사용하고 있었고, 애플리케이션이 console.log, console.error로 출력한 내용은 컨테이너의 stdout/stderr를 통해 CloudWatch Logs로 전달되고 있었다.
즉 실제로 증가한 것은 애플리케이션의 정상 API 트래픽이 아니라, 에러로 인해 폭증한 로그 데이터가 NAT Gateway를 통해 CloudWatch Logs로 전송된 양이었다.
정리하면 아래와 같다.
-
- 앱 릴리즈 직후부터 4XX 에러가 급증했다.
-
- 같은 시점에 NAT Gateway
BytesInFromSource도 급증했다.
- 같은 시점에 NAT Gateway
-
- 에러 로그는 Stack Trace를 포함하고 있어 한 건당 크기가 컸다.
-
- ECS 로그는 CloudWatch Logs로 전송되고 있었고, 이 경로에 NAT Gateway가 있었다.
따라서 이번 케이스에서는 증가한 NAT 트래픽의 주원인이 CloudWatch Logs 전송량 증가라고 판단했다.
Resolution
섹션 제목: “Resolution”일단 4XX 에러를 해결하자.
이 문제를 해결하기 위해 아래의 3가지를 고려했다.
- 4XX 에러를 해결
- VPC Endpoint 설정
- 출력 로그 포맷 수정
현 상황에서는 4XX 에러를 해결하는 방법을 선택했다. 에러 로그의 수를 줄이면 CloudWatch Logs 로 전송하는 로그의 양도 줄어든다. 그러면 자연스럽게 BytesInFromSource 지표도 줄어들 것이다.
NAT Gateway를 통하지 않고 CloudWatch Logs용 VPC Endpoint를 설정하는 방법은 좀 과하다고 판단했다. 일시적으로 4XX 에러가 늘어나면서 발생한 문제이기에 이를 해결하기 위해 네트워크 구성을 바로 늘리는 건 과한 대응이라고 생각했다.
로그 출력 방식을 바꾸는 것도 검토 대상이었지만, 평상시에는 현재 수준의 로그가 크게 문제가 되지 않았다. 이번 문제는 특정 버그 때문에 비정상적으로 에러가 폭증하면서 발생한 경우였다.
그래서 가장 빠른 대응은 입력 처리 로직을 수정해 잘못된 타입의 요청이 대량 4XX로 이어지지 않도록 하는 것이었다. 앱 수정 전에 서버 쪽에서 문자열 숫자를 일시적으로 정규화해 처리하도록 보정했고, 배포 후 실제로 4XX 에러와 BytesInFromSource 지표가 같은 시점에 함께 감소했다.
Notes
섹션 제목: “Notes”- NAT Gateway 지표 이상을 볼 때는 애플리케이션 트래픽뿐 아니라 로그 전송량도 같이 의심한다.
- CloudWatch Logs VPC Endpoint가 없다면, private subnet의 ECS/EC2 로그 전송도 NAT Gateway 트래픽에 포함될 수 있다.
- 같은 현상이 다시 생기면 먼저 아래를 같이 본다.
- 릴리즈 시점
- 애플리케이션 4XX/5XX 증가 여부
- CloudWatch Logs ingestion 증가 여부
BytesInFromSource,BytesOutToSource,BytesInFromDestination,BytesOutToDestination,PacketsInFromSource
1) NAT Gateway 주요 바이트 지표
섹션 제목: “1) NAT Gateway 주요 바이트 지표”| 지표 | 의미 |
|---|---|
BytesInFromSource | source 쪽 리소스가 NAT Gateway로 보낸 바이트 수 |
BytesOutToSource | NAT Gateway가 source 쪽 리소스로 다시 돌려보낸 바이트 수 |
BytesInFromDestination | destination 쪽에서 NAT Gateway로 들어온 바이트 수 |
BytesOutToDestination | NAT Gateway가 destination 쪽으로 내보낸 바이트 수 |
- 이번 케이스에서는
BytesInFromSource뿐 아니라BytesOutToDestination도 비슷한 시점에 함께 증가했다가 함께 감소했다. 이를 통해 ECS task가 NAT Gateway로 밀어 넣은 로그 트래픽이 실제로 destination 쪽인 CloudWatch Logs로도 같이 전달됐다고 판단했다. - 용어 설명
- source: NAT Gateway에 트래픽을 보내는 ECS task
- destination: CloudWatch Logs 서비스 엔드포인트
2) NAT Gateway와 로드밸런서는 역할이 다르다.
섹션 제목: “2) NAT Gateway와 로드밸런서는 역할이 다르다.”| 항목 | NAT Gateway | 로드밸런서 |
|---|---|---|
| 역할 | private subnet 리소스가 외부 서비스로 나갈 때 쓰는 egress 경로 | 외부 요청을 내부 target으로 분산하는 ingress 경로 |
| 이 글에서는 | “나가는 통신” 관점 | “들어오는 요청” 관점 |
- 용어 설명
- private subnet 리소스: ECS Fargate task
- 로드밸런서의 내부 target: ALB 뒤에 붙어 있는 ECS task