IL-0177 LINE+ · 2022-10-14 (게시일)kubernetesnetworking
messaging-hub 는 LINE+ ABC Studio 가 만든 범용 메시징 플랫폼으로, Demaecan 의 Merchant 앱과 Driver 앱에 웹소켓으로 서버 푸시를 보낸다. 클라이언트 연결은 L7 로드밸런서와 Ingress Nginx 를 거쳐 웹소켓 서버인 connection-manager 로 전달된다. 어느 날부터 웹소켓 연결이 불규칙하게 한꺼번에 끊기기 시작했다.
끊긴 동안의 메시지는 FCM 으로 넘어갔지만, 클라이언트들이 재연결하면서 커넥션 토큰 요청이 Merchant 시스템으로 몰렸다. Merchant 시스템은 토큰 발급 말고도 다른 시스템 연동과 자체 비즈니스 로직을 맡고 있어 지연이 번졌고, 결국 Merchant 사용자가 영향을 받았다. 스트레스 테스트로 Merchant 시스템의 DB 가 병목이라는 것을 찾았고, Merchant 팀이 토큰 발급 API 를 따로 떼어 배포했다. 재연결이 몰릴 때 Nginx 노드의 NF_CONNTRACK 테이블이 차서 패킷이 버려지는 문제도 나왔다. 팀은 운영체제 설정을 바꾸는 대신 Nginx 를 늘렸다. NF_CONNTRACK 는 VM 마다 하나씩이므로 파드 안티 어피니티로 Nginx 파드가 서로 다른 노드에 뜨게 했다. 그 뒤로는 웹소켓 드롭이 다시 일어나도 Nginx 패킷 드롭은 생기지 않았다.
원래 문제인 웹소켓 드롭은 connection-manager, 소켓 수를 정하는 설정, 클라이언트 종류, 통신사, Nginx 타임아웃을 차례로 봐도 풀리지 않았다. SRE 경험이 많은 다른 팀 동료가 L7 에 쓰이는 HAProxy 를 로컬에 띄워 시험하면서 원인을 찾았다. docker-compose kill -s HUP haproxy 로 HAProxy 를 재로드하면 hard-stop-after 설정 시간이 지난 뒤 이전 프로세스가 종료되면서 붙어 있던 웹소켓 연결이 끊겼다. 인프라 팀에 물으니 hard-stop-after 는 30분이었다. 사내 IaaS 인 Verda 대시보드에서 LB 를 배포하자 정확히 30분 뒤 HAProxy uptime 이 갱신되면서 웹소켓 드롭이 재현됐다.
팀은 자기들이 LB 를 거의 바꾸지 않는데도 HAProxy 가 재시작되는 이유도 찾았다. LB 를 다른 서비스와 공유하고 있어서, 다른 서비스 담당자가 자기 LB 설정을 배포하기만 해도 HAProxy 가 재시작됐다. 드롭이 불규칙했던 이유가 이것이었다. Verda 대시보드에서는 LB 를 프로젝트별로 설정하기 때문에 다른 서비스와 공유하고 있다는 생각을 하지 못했고, 이것도 원인 파악을 늦췄다. L7 LB 의 이 운영상 한계는 피할 수 없었기 때문에 팀은 L4 LB 로 바꿨고, 그 뒤 웹소켓 드롭은 사라졌다.
LINE 의 messaging-hub 는 일본 음식 배달 서비스 Demaecan 의 Merchant 앱과 Driver 앱에 웹소켓으로 메시지를 보낸다. 어느 날 최대 트래픽 시간이 아닌데도 웹소켓 연결 수 그래프가 순간적으로 크게 떨어졌다. 이 현상은 한 번으로 끝나지 않고 불규칙하게 계속 일어났다.
웹소켓이 끊겨도 messaging-hub 는 메시지를 FCM 으로 돌려 보내서 처음에는 클라이언트에 영향이 없었다. 하지만 끊긴 클라이언트들이 재연결하려고 커넥션 토큰을 한꺼번에 요청하면서 토큰을 발급하는 Merchant 시스템에 요청이 몰렸다. 처리가 지연되고 그 지연이 다른 구성 요소로 번지면서 Merchant 사용자가 직접 영향을 받았다.
같은 무렵 messaging-hub 의 Nginx 에서도 패킷이 버려졌다. 네트워크 모니터링으로 보니 트래픽이 몰릴 때 NF_CONNTRACK 모듈의 연결 추적 테이블이 가득 찼고, 테이블이 찬 뒤 들어온 패킷이 드롭되고 있었다.
여러 번 문의했지만 인프라 팀과 네트워크 팀은 문제가 없다고 답했다. 팀은 connection-manager 를 50% 늘려 봤다. 이어서 GC 영향, 서버가 연결을 끊는 로직, 3분짜리 idle 타임아웃과 PING, 약 28,000개의 가용 로컬 포트, TIME_WAIT, open files 값 1048576, Nginx 최대 접속 수를 차례로 확인했지만 이상이 없었다. 연결이 끊기는 클라이언트는 Merchant 앱이 압도적으로 많았다. 인프라 팀이 보여 준 클라이언트 쪽 리셋 지표는 원인이 아니라 결과였다. 일본 통신사 장애도 찾아봤지만 없었다. 개발 환경에서 Nginx 의 proxy-read-timeout 과 proxy-send-timeout 을 3s 로 줄이면 드롭이 재현돼서 운영 값을 3600s 로 올렸지만, 드롭은 또 일어났다.
원인 ? 설정 변경
웹소켓 연결 수 그래프에서 최대 트래픽 시간이 아닌데도 연결 수가 순간적으로 뚝 떨어지는 것을 보고 알았다. Nginx 패킷 드롭은 네트워크 모니터링으로 원인을 찾았다.
–
문제의 범위를 미리 단정해 스스로 제한하면 안 된다. 인프라 팀과 네트워크 팀이 문제없다고 답했다는 이유로 직접 다룰 수 있는 영역만 뒤지다가 공유 L7 LB 를 늦게 의심했다. LB 같은 기술 리소스를 다른 서비스와 공유하면 다른 팀의 배포가 내 서비스의 연결을 끊을 수 있다. Nginx 를 늘려 NF_CONNTRACK 부담을 나눌 때는 파드가 서로 다른 노드에 뜨게 해야 하고, 노드 수보다 많이 늘리면 Pending 상태로 남는 파드가 생긴다는 점도 알아야 한다.
같은 원인 · 공통 HAProxy, 클라우드 로드 밸런서
같은 원인 · 공통 인그레스 컨트롤러, 클라우드 로드 밸런서
같은 원인 · 공통 클라우드 로드 밸런서
같은 원인 · 공통 클라우드 로드 밸런서
같은 원인 · 공통 클라우드 로드 밸런서