상황

300명 이상 수신자에게 예약/대량 메일 발송 시 두 번 이상 발송되는 문제

 

문제

첫 번째 요청이 끝나기도 전에 동일한 요청이 발생됨.

그 시간이 딱 1분.

WEB Server 로그 분석 (이중화 환경)

클라이언트 요청이 중복으로 들어온 것을 확인.

그 시간 간격이 딱 1분이었다.

어떤 상황에서는 1번기에 동일하게 중복 요청이 들어왔고 어떤 상황에서는 1번기, 2번기 각각 중복 요청이 들어왔다.

해결 과정

  • 원타임토큰 문제?

처음엔 메일 중복 발송을 막기 위한 OneTimeToken 의 문제로 파악했다.

사용자가 [보내기] 버튼 혹은 네트워크 장애로 인해 두 번 이상 호출되어 중복 메일 발송되는 문제를 예방하는 역할을 한다. 그러나 로그 심어 확인해 보니, 원타임토큰은 동일했다.

  • ajax 호출 응답 시간?

메일 발송은 ajax 이용하여 비동기 처리로 응답시간 최대 timeout 1분 설정을 해 놓은 상태였다.

대량 수신자 메일 발송 처리에 대한 시간이 지연되는 것으로 생각하여 이를 최대 3분으로 늘렸다.

결과는 동일했다.

  • 예약메일 로직 쓰레드 방식으로 개선

대량 수신자의 예약메일의 경우 예약메일을 관리하는 테이블에 데이터를 넣는데 그 시간이 오래 걸려 발생되는 문제로 파악했다. 이를 개선하고자 사용자한테는 예약메일 발송 시, 바로 응답을 해주고 백단에서 멀티스레드 방식으로 큐테이블에 데이터 삽입하도록 개선하였다.

그럼에도 동일한 문제가 발생….

  • L4 로드밸런서 문제를 의심

이중화 된 웹서버 로그가 수상했다.

위에서도 말했듯이 어떤 상황에서는 1번기에 동일하게 중복 요청이 들어왔고 어떤 상황에서는 1번기, 2번기 각각 중복 요청이 들어왔다.

 

중간에 거치는 게 뭐가 있을까?

L4 의 어떤 설정 때문에 그런가?

 

원인 : 로드 밸런서 유휴 시간 초과

클라우드 인프라 L4 설정 중 Connection Idle Timeout 설정의 문제였다.

디폴트 1분(60초)으로 설정되어 있었다. ( 그래서 로그에서도 딱 1분이 걸렸었구나...)

로드밸런서가 target 에 대해 요청하는 동안 target 이 TCP 연결을 닫았다.

개발기에서 3초로 설정하고 테스트 해보았더니 이슈와 같이 동일한 요청이 들어왔다.

찾았따!!!!!

**1. Connection Idle Timeout 이 뭔가?**

Http 통신할 때, client 에서 아무런 데이터 보내지 않을 경우 idle timeout 이 지난 후 
connection 을 close 한다.

즉, http 통신 연결이 자동으로 닫힐 때까지의 시간을 말한다.
이때 502/504 에러 응답코드가 나올 수 있다.

연결 유휴 시간 제한(기본값은 60초)은 "표준" 시간 제한으로 작동한다.
따라서 Idle Timeout 경과할 때까지 데이터가 전송되거나 수신되지 않은 경우 로드 밸런서가 연결을 닫는다.
애플리케이션의 Idle Timeout 을 로드밸런서 Idle Timeout 보다 크게 설정하는 것을 권장한다.

**2. Idle Timeout 과 request timeout 의 차이가 뭔가?**

Connection Idle Timeout 은 tcp 연결이 유휴한 상태로 있을 수 있는 최대 시간이다.
요청 시간 제한과 동일하게 동작한다.

Connection Timeout 은 tcp 연결을 지속하는 최대 시간을 말한다.

여기서 Idle Timeout 과 request timeout 중 Idle Timeout 이 우선순위로 지정된다.
그래서 Idle Timeou 이 request timeout 보다 낮아도 우선순위로 적용된다.

출처 : <https://repost.aws/questions/QUqP4BHC9iQ0uIB69M7QrjSg/502-errors-with-application-load-balancer-idle-timeout-apache2-keep-alive-timeout>

해결

60 초로 설정되어 있는 idle timeout 시간을 600초(10분) 으로 늘려주었다.


그 외 원타임토큰에 대한 문제

첫 번째 요청이 들어오면 해당 토큰은 세션에서 remove 된다.

그런데 두 번째 요청이 들어왔을 때 세션에 해당 토큰이 살아있었다.

테스트 해보니, 하나의 요청이 완전히 끝나기 전까지는 세션 정보가 변경되지 않았다.

그래서 두 번째 요청이 들어왔을 때 변경된 세션 정보가 아닌 기존 정보를 가지고 있었던 것이다.

원타임토큰을 세션에서 관리하는 것이 아닌 DB 에서 관리는 하는 것으로 변경하는 것이 좋을 것 같다.

개요

1. 사설 IP 사용하는 WAS  A서버에서 ssh 로 서버 B서버(WEB/WAS단일) 접근 후

2. B서버에서 다시 WAS A서버로 L4 통해 API 통신 시도

문제

사설 대역에서 접속한 B서버는 https://cmail.cloud.kr/api/xxx/xxxx/xxxx 이라는 API URL  호출한다.

이 과정이 3번 과정이다. 3번을 보면 URL 호출 후 외부로 나갔다가 다시 L4 통해 WEB1, WAS A서버로 들어온다.

 

문제는 해당 API URL 호출 시 WAS A서버까지 들어오지 않았다.

 

분석

1. B서버에서 80/443 통신이 안되나?

서버 통신할 때 확인하는 방법으로 아래와 같이 확인해봤다.

echo > /dev/tcp/cmail.cloud.kr/80

echo > /dev/tcp/cmail.cloud.kr/443

정상 통신 되는 걸 확인하였다.

-> 나가는 포트는 모두 열려있으므로 L4까지는 도달한다는 의미이다.

 

2. 그래서 그 다음으로 L4 통해 들어오는 WEB 서버 apache access 로그를 봤다.

client IP 가 찍혀 있어야 하는데 웬 사설 IP 가 찍혀있었다.

 

동일한 WEB서버를 바라보는 다른 L4 로 등록된 mail.sensmailcloud.kr URL 로 API 호출해봤떠니 얘는 정상적으로 WAS 까지 들어오더라.

apache access 로그 봤더니 얘는 사설 IP가 아닌 clientIP(=공인IP) 가 찍혀있었다. (정상)

 

핵심

모든 곳에서 https://cmail.cloud.kr 에 접속하여 아파치 access 로그를 확인한 결과  모두 동일한 사설IP 가 찍히고 있었다.

사무실 와이파이로 접속해도, LTE로 접속해도, 다른 서버에서 접속해도 모두 같은 IP 로 찍혔다.

정상적인 Client IP 설정이 되어 있다면, 사무실 와이파이로 접속하면 사무실 IP 가 찍혀야하고 다른 서버에서 접속했다면 접속한 서버 IP 가 찍혀야한다. (Client IP=요청한 곳의 IP)

 

해결

이 부분은 클라우드 콘솔에서 LB 설정 proxy protocol사용을 해야한다.

프록시 프로토콜을 사용(체크)하지 않으면 실제 Client Ip 가 아닌 L4 사설 Ip 가 찍히게 된다.

출처 : 네이버클라우드플랫폼 로드밸런서 생성화면

생각넓히기

Proxy Protocol 설정을 왜 하는가?

로드밸런서에서 TCP/SSL 프로토콜 사용 시, Proxy Protocol 을 사용하여 Client IP를 추출하고 특정 IP만 접근 허용할 수 있도록 한다.

 

그렇다.  Client IP 를 추출하기 위해 해당 설정을 해주는 것이다.

IP 기반으로 처리하기 위해서는 Client Ip가 필요하다.

Ip 추척 기능이라든가 API 기능이라든가 IP 제한 이라든가 하는 다양한 IP 기반의 기능을 처리해야한다면 Client IP가 필요하기 때문이다.

 

★ 주의할 점은 Proxy Protocol 을 사용하기 위해서는 반드시 TCP나 SSL 프로토콜선택해 주어야 한다.

Proxy Protocol  https://whyjlee.tistory.com/31

 

참고

 

L4 환경에서의 ACL 설정 — TCP 프로토콜 사용 시

로드밸런서에서 TCP/SSL 프로토콜 사용 시, Proxy Protocol을 사용하여 Client IP를 추출하고 특정 IP만 접근을 허용하는 법에 대해서 소개해드리고자 합니다.

medium.com

 

 

Proxy Protocol을 이용해 Client IP 확인하기 CentOS

Ncloud Network Proxy Load Balancer의 Proxy Protocol을 이용해 CentOS 서버에서 클라이언트 IP 주소를 확인하는 방법입니다.

docs.3rdeyesys.com

 

+ Recent posts