본문 바로가기
WIKI 기술 지식 베이스

Linkerd 502 에러 디버깅

원문 보기 위키 갱신

Linkerd 프록시가 요청을 처리하는 중 연결 오류를 만나면 보통 HTTP 502(Bad Gateway) 응답을 반환해요. 사용 가능한 정보가 부족해서 이런 오류가 왜 발생하는지 파악하기가 어려울 수 있어요.

왜 이런 오류가 Linkerd를 주입했을 때만 발생하나요?

Linkerd는 연결 오류를 HTTP 502 응답으로 바꿔요. 그래서 이전에는 감지되지 않던 문제가 갑자기 드러날 수 있어요. 이는 좋은 일이에요. 또한 Linkerd는 애플리케이션으로의 연결 관리 방식을 바꿔요. 즉, 영구 연결(persistent connection)을 재사용하고 연결 추적 계층을 하나 더 만듭니다. 이런 방식으로 연결을 관리하다 보면 잘못 구성된 연결 타임아웃 같은 근본적인 애플리케이션 또는 인프라 문제가 연결 오류로 드러날 수 있어요.

왜 Linkerd는 더 유용한 오류 메시지를 제공하지 못하나요?

Linkerd 프록시 입장에서는 애플리케이션으로의 연결이 아무 설명 없이 거부되거나 닫히는 것으로 보여요. 그래서 Linkerd가 502 응답에 어떤 오류 메시지도 실어 보내는 것은 거의 불가능해요. 하지만 이런 오류들이 Linkerd 도입과 함께 나타난다면, 그 문제는 연결 재사용이나 연결 추적과 관련된 것일 가능성이 높아요. 애플리케이션이 연결을 거부하거나 종료하는 일반적인 이유는 다음과 같아요.

연결 오류의 일반적인 원인

연결 유휴 타임아웃 (Connection Idle Timeouts)

일부 서버는 연결 유휴 타임아웃으로 구성돼요(예: Go HTTP 서버의 이 타임아웃). 이는 서버가 지정된 시간 동안 트래픽을 받지 못한 연결을 모두 닫는다는 뜻이에요. 연결 종료가 시작될 때 이미 전송 중이던 요청이 있다면 그 요청은 실패하게 돼요. 이 시나리오는 규칙적인 주기의 트래픽(예: liveness 체크)과 그 주기와 같은 길이의 유휴 타임아웃이 있을 때 발생하기 쉽습니다.

이를 해결하려면 서버의 유휴 타임아웃을 충분히 길게 설정해서 실제 사용 중인 연결을 닫지 않도록 해야 해요.

반쯤 닫힌 연결 타임아웃 (Half-closed Connection Timeouts)

TCP 연결이 종료되는 동안에는 연결의 각 측면을 독립적으로 닫아야 해요. 한쪽이 닫혔는데 다른 쪽이 닫히지 않으면 그 연결을 '반쯤 닫힌(half-closed)' 상태라고 해요. 이 상태가 유효하긴 하지만, 운영 체제의 연결 추적기가 오랫동안 반쯤 닫힌 상태로 남아 있는 연결을 추적하지 못할 수 있어요. 그러면 응답이 전달되지 않거나 새 연결을 만들 때 포트 충돌이 생겨 502 응답으로 나타날 수 있어요.

Kubernetes 클러스터에서 반쯤 닫힌 연결을 감지하는 스크립트를 사용할 수 있어요. 반쯤 닫힌 연결이 많이 감지되면 상황을 해결할 수 있는 방법이 몇 가지 있어요.

한 가지 해결책은 애플리케이션이 연결을 오랫동안 반쯤 닫힌 상태로 두지 않도록 업데이트하거나, 그렇게 하는 소프트웨어 사용을 중단하는 것이에요. 안타깝게도 이것이 항상 가능한 것은 아니에요.

또 다른 방법은 반쯤 닫힌 연결에 대한 연결 추적기 타임아웃을 늘리는 것이에요. 이 타임아웃의 기본값은 플랫폼에 따라 다르지만 보통 1분 또는 1시간이에요. 현재 값을 보려면 주입된 어떤 컨테이너에서든 /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_close_wait 파일을 확인하면 돼요. 이 값을 늘리려면 linkerd inject와 함께 --close-wait-timeout 플래그를 사용할 수 있어요. 다만 이 플래그를 설정하면 프록시 init 컨테이너의 privileged 필드도 true로 설정된다는 점에 주의해 주세요. 이 타임아웃을 1시간으로 설정하는 것이 보통 충분하며 kube-proxy가 사용하는 값과도 일치해요.

출처: Linkerd Debugging 502s

본문

Linkerd 프록시가 요청을 처리하는 중 연결 오류를 만나면 보통 HTTP 502(Bad Gateway) 응답을 반환해요. 사용 가능한 정보가 부족해서 이런 오류가 왜 발생하는지 파악하기가 어려울 수 있어요.

왜 이런 오류가 Linkerd를 주입했을 때만 발생하나요?

Linkerd는 연결 오류를 HTTP 502 응답으로 바꿔요. 그래서 이전에는 감지되지 않던 문제가 갑자기 드러날 수 있어요. 이는 좋은 일이에요. 또한 Linkerd는 애플리케이션으로의 연결 관리 방식을 바꿔요. 즉, 영구 연결(persistent connection)을 재사용하고 연결 추적 계층을 하나 더 만듭니다. 이런 방식으로 연결을 관리하다 보면 잘못 구성된 연결 타임아웃 같은 근본적인 애플리케이션 또는 인프라 문제가 연결 오류로 드러날 수 있어요.

왜 Linkerd는 더 유용한 오류 메시지를 제공하지 못하나요?

Linkerd 프록시 입장에서는 애플리케이션으로의 연결이 아무 설명 없이 거부되거나 닫히는 것으로 보여요. 그래서 Linkerd가 502 응답에 어떤 오류 메시지도 실어 보내는 것은 거의 불가능해요. 하지만 이런 오류들이 Linkerd 도입과 함께 나타난다면, 그 문제는 연결 재사용이나 연결 추적과 관련된 것일 가능성이 높아요. 애플리케이션이 연결을 거부하거나 종료하는 일반적인 이유는 다음과 같아요.

연결 오류의 일반적인 원인

연결 유휴 타임아웃 (Connection Idle Timeouts)

일부 서버는 연결 유휴 타임아웃으로 구성돼요(예: Go HTTP 서버의 이 타임아웃). 이는 서버가 지정된 시간 동안 트래픽을 받지 못한 연결을 모두 닫는다는 뜻이에요. 연결 종료가 시작될 때 이미 전송 중이던 요청이 있다면 그 요청은 실패하게 돼요. 이 시나리오는 규칙적인 주기의 트래픽(예: liveness 체크)과 그 주기와 같은 길이의 유휴 타임아웃이 있을 때 발생하기 쉽습니다.

이를 해결하려면 서버의 유휴 타임아웃을 충분히 길게 설정해서 실제 사용 중인 연결을 닫지 않도록 해야 해요.

반쯤 닫힌 연결 타임아웃 (Half-closed Connection Timeouts)

TCP 연결이 종료되는 동안에는 연결의 각 측면을 독립적으로 닫아야 해요. 한쪽이 닫혔는데 다른 쪽이 닫히지 않으면 그 연결을 '반쯤 닫힌(half-closed)' 상태라고 해요. 이 상태가 유효하긴 하지만, 운영 체제의 연결 추적기가 오랫동안 반쯤 닫힌 상태로 남아 있는 연결을 추적하지 못할 수 있어요. 그러면 응답이 전달되지 않거나 새 연결을 만들 때 포트 충돌이 생겨 502 응답으로 나타날 수 있어요.

Kubernetes 클러스터에서 반쯤 닫힌 연결을 감지하는 스크립트를 사용할 수 있어요. 반쯤 닫힌 연결이 많이 감지되면 상황을 해결할 수 있는 방법이 몇 가지 있어요.

한 가지 해결책은 애플리케이션이 연결을 오랫동안 반쯤 닫힌 상태로 두지 않도록 업데이트하거나, 그렇게 하는 소프트웨어 사용을 중단하는 것이에요. 안타깝게도 이것이 항상 가능한 것은 아니에요.

또 다른 방법은 반쯤 닫힌 연결에 대한 연결 추적기 타임아웃을 늘리는 것이에요. 이 타임아웃의 기본값은 플랫폼에 따라 다르지만 보통 1분 또는 1시간이에요. 현재 값을 보려면 주입된 어떤 컨테이너에서든 /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_close_wait 파일을 확인하면 돼요. 이 값을 늘리려면 linkerd inject와 함께 --close-wait-timeout 플래그를 사용할 수 있어요. 다만 이 플래그를 설정하면 프록시 init 컨테이너의 privileged 필드도 true로 설정된다는 점에 주의해 주세요. 이 타임아웃을 1시간으로 설정하는 것이 보통 충분하며 kube-proxy가 사용하는 값과도 일치해요.

더 알아보기 (Learn more)