Skip to content
isdnetworks
Go back

타임아웃이 네 곳에 있다

원격 장비에서 자료를 받아오는데 큰 응답이 자꾸 끊겼다. 작은 요청은 되고 큰 것만 실패한다.

응답 시간이 오래 걸려서 그런 것으로 보고 소켓 타임아웃을 늘렸다.

struct timeval tv = { .tv_sec = 60 };
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));

여전히 30초쯤에 끊겼다.

Table of contents

Open Table of contents

내가 안 만진 타임아웃이 있었다

SO_RCVTIMEO 를 늘렸는데 동작이 안 바뀌면 그 값이 실제로 안 쓰이고 있다는 뜻이다. 요청이 지나가는 경로를 처음부터 그려 봤다.

웹 화면 → 웹서버 → 게이트웨이 프로그램 → 시리얼/소켓 → 장비

각 구간에 타임아웃이 있었다.

계층설정 위치
브라우저브라우저 기본
웹서버 프록시proxy_read_timeout30초
스크립트 실행max_execution_time30초
소켓SO_RCVTIMEO내가 60초로 바꾼 것
장비 자체펌웨어 상수확인 필요

proxy_read_timeoutmax_execution_time 이 30초였다. 한 요청에 여러 계층이 각자 시간을 재면 가장 짧은 것이 이긴다.

안쪽을 아무리 늘려도 바깥이 먼저 끊는다. 한 곳만 보고 고친 것이 이번 착오의 전부였다.

어디서 끊겼는지 구분했다

로그만 보면 전부 타임아웃으로 보인다. 어느 계층인지를 가를 근거가 둘 있었다.

첫째는 끊기는 시각이다. 30초에서 끊기면 그 값을 가진 계층이고 60초까지 가면 SO_RCVTIMEO 쪽이다.

둘째는 끊긴 뒤 오는 응답이다. 웹서버가 끊으면 502 쪽 화면이 오고 max_execution_time 이면 실행 시간 초과가 온다.

소켓이 끊기면 우리 코드가 오류를 만드는데 시각과 응답을 같이 보니 proxy_read_timeout 이었다.

설정 위치를 지도로 만들었다

한 곳을 고쳤다고 끝이 아니었다. 다시 겪지 않으려고 어디에 무엇이 있는지를 적어 뒀다.

[웹서버]
  /etc/httpd/conf.d/proxy.conf   ProxyTimeout
  → 전역 설정이다. 이 서버의 모든 vhost에 걸린다

[스크립트]
  php.ini                        max_execution_time
  → CLI와 웹이 다른 ini를 쓴다. 웹 쪽을 봐야 한다

[게이트웨이 프로그램]
  config.ini                     socket_timeout_sec
  → 우리 코드. 소스에도 기본값이 있어 둘 다 확인

[장비]
  펌웨어 상수                     확인 불가, 문의 필요

파일 경로와 항목 이름을 함께 적으니 다음에 찾는 시간이 없어졌다. php.ini 처럼 웹과 명령줄이 다른 파일을 쓰는 것도 적어 뒀다.

여기서 전역인지 개별인지를 함께 적은 것이 중요했다. ProxyTimeout 은 전역이라 늘리면 다른 화면도 전부 늘어난다.

조치 — 전역 대신 경로별로

특정 경로만 길게 하려면 그 경로에만 걸면 된다.

<Location /device/bulk>
    ProxyTimeout 120
</Location>

/device/bulk 만 120초로 덮어쓰고 나머지는 30초로 둔다.

이렇게 한 이유가 있다. 전역을 120초로 늘리면 원래 빨리 끊겨야 할 요청도 2분을 기다린다.

장애가 났을 때 응답이 안 오면 사용자가 2분간 흰 화면을 본다. 타임아웃은 짧을수록 좋고 길어야 하는 경로만 골라 늘리는 것이 맞았다.

늘리는 게 답이 아닌 경우

이번에는 늘려서 풀렸지만 그러면 안 되는 경우도 있었다. 응답이 오래 걸리는 이유가 양이 아니라 처리 속도면 ProxyTimeout 을 늘려도 증상만 미루는 것이다.

사용자는 여전히 오래 기다리고 응답 시간이 계속 늘어나는 구조면 언젠가 늘린 값도 넘는다.

그때는 타임아웃이 다시 문제가 되는데 이미 한 번 늘려 뒀으니 또 늘리게 된다. 그렇게 값만 커지다 보면 어느 순간 아무도 그 값이 왜 그 숫자인지 모른다.

판단 기준 — 늘리기 전에 묻는 것

그래서 늘리기 전에 셋을 묻기로 했다.

이 시간이 데이터 양에 비례하나, 아니면 고정으로 느린가
앞으로 데이터가 더 늘어나나
나눠서 받을 수 있나 (페이지네이션, 청크)

첫째가 비례가 아니면 ProxyTimeout 을 늘려도 안 풀리고 둘째가 그렇다면 지금 늘린 값도 나중에 넘는다.

이번 건은 대량 조회라 양에 비례했고 나눠 받는 것이 가능했다. 그래서 타임아웃은 안전 여유로 조금만 늘리고 요청을 쪼개는 쪽으로 바꿨다.

정리


Share this post on:

Previous Post
붙이면 사라지는 버그
Next Post
전에 실패한 이력이 처리 방식을 정했다