원래 'AWS 환경에서 많이 사용되는 NLB, ALB를 사이에 두고 테스트랑 패킷 분석'을 해야하지만, 백엔드 서버에서 timeout 설정도 확실히 해두면 좋을 것 같아서
timeout일 때도 패킷 분석을 해보려고 한다.
일단 아래 이미지를 사용하면 된다.
docker pull ghcr.io/kyeongjun-dev/network:dev
app/app.py에 /에 추가로 /slow 엔드포인트를 추가했다. 실제 호출할 때는 /slow?wait=5 이런 식으로 wait 매개변수를 전달한다.
from flask import Flask, request
import time
app = Flask(__name__)
@app.route('/')
def hello():
return "Hello from Flask App behind Gunicorn!"
@app.route('/slow')
def slow():
try:
wait_time = request.args.get('wait', default=10, type=int)
except ValueError:
# 쿼리 파라미터가 정수가 아닌 경우 10초를 사용합니다.
wait_time = 10
print(f"Request received. Busy waiting for {wait_time} seconds...")
# CPU를 계속 사용하는 반복문 사용
end_time = time.time() + wait_time
while time.time() < end_time:
pass # 아무것도 안 하지만 CPU는 계속 씀 (Yield 안 함)
print(f"Waited {wait_time} seconds. Sending response now.")
return f"Finally, here is your slow response..."
gunicorn을 아래와 같이 실행할 때, --timeout을 설정한다.
gunicorn --workers 1 -k gevent --bind 0.0.0.0:8000 --timeout 10 --keep-alive 10 app:app --log-level debug
이때 /slow?wait=초로 전달하는 초가 --timeout에 설정한 초보다 크면, 백엔드 서버에서 woker timeout이 발생한다.
실제로 실행시킨 후, curl로 11초를 지정해서 호출하면 WORKER TIMEOUT을 확인할 수 있다.

아래 docker-compose를 08 디렉토리에서 실행한다.
services:
server:
image: ghcr.io/kyeongjun-dev/network:dev
hostname: server
container_name: server
volumes:
- ./server_vol:/app/captures
ports:
- "8000:8000"
command: ["gunicorn", "--workers", "1", "-k", "gevent", "--bind", "0.0.0.0:8000", "--timeout", "10", "--keep-alive", "10", "app:app", "--log-level", "debug"]
client:
image: ghcr.io/kyeongjun-dev/network:dev
container_name: client
volumes:
- ./client_vol:/app/captures
command: ["sleep", "infinity"]
environment:
HOST: server
PORT: 8000
HOST_HEADER: server
USE_TLS: false
ENDPOINT: /slow?wait=11
이제 빌드해둔 이미지가 있으므로, ghcr에 올려놓은 이미지를 사용한다. (-d는 백그라운드 실행)
docker-compose up -d
tcpdump를 실행하고
docker exec -it client tcpdump -i any -n 'port 8000' -w /app/captures/client.pcap
docker exec -it server tcpdump -i any -n 'port 8000' -w /app/captures/server.pcap
client에서 server로 요청을 전송한다
docker exec -it client python client.py 11
server 로그를 확인해보면, 08:00:54에 GET 요청을 받은 후, 약 10초 뒤인 08:01:05에 WORKER TIMEOUT이 발생했다.

client가 172.19.0.3, server가 172.19.0.2

간단히 분석해보면
1. 0초 : tcp 연결 완료
2. 0초대에 /slow?wait=11로 GET 요청 전송
3. (패킷에 안보임) 10초 대에 WORKER TIMEOUT으로 워커 종료
4. 20초 : --keep-alive 10 설정에 의해 10초 뒤인 20초대에 client에 FIN 전송
client(172.19.0.3), server(172.19.0.2)--keep-alive를 20초로 변경한 후, 테스트 했을 때의 패킷은 아래와 같다. 즉, FIN 패킷을 전송할 때까지 걸리는 시간은 timeout + keep alive 타임이다.

위를 보면, 워커가 작업을 수행하는 시간은 keep alive에 포함되지 않는 것 같다.
timeout까지 고려하려니 너무 복잡해지는 거 같다. 다음 글 부터는 /slow를 이용해 timeout은 후순위로 고려하려고 한다.
다음 글에서는 AWS 환경 EKS에 nlb를 두고, 패킷 테스트를 해보자.
(이제 진짜 돈이 들겠네...)