관리 화면이 간헐적으로 응답하지 않았다. 요청이 한참 걸리다가 max_execution_time에 걸려 끝났다.
Table of contents
Open Table of contents
늘려도 그대로였던 응답
처리할 프로세스가 모자란 것으로 보고 php-fpm의 pm.max_children을 늘렸다. 그런데 늘리기 전과 후가 거의 같았다.
늘렸는데 안 나아졌다면 pm.max_children이 병목이 아니라는 뜻이다. 그러면 그 시간이 어디에 쓰이는지를 먼저 봐야 했다.
걸린 시간이 실제로 무언가를 하느라 쓴 시간인지 기다리느라 쓴 시간인지가 갈려야 한다. 이 둘은 처방이 정반대다.
가르는 방법은 간단했는데 같은 요청을 한가한 시각에 보내 보는 것이다. 그때는 몇 초 만에 끝났다. 요청 자체는 무겁지 않고 바쁜 시각에만 오래 걸리니까 기다리는 시간이었다.
대기면 늘려도 안 나아진다
기다리는 이유는 같은 자원을 여러 쪽이 함께 쓰고 있어서였다. 그 자원이 max_connections로 상한이 걸린 MySQL 연결이든 InnoDB가 잡고 있는 잠금이든 마찬가지로, 처리할 쪽을 늘려도 그것을 더 잘게 나눠 가질 뿐이다.
오히려 경쟁이 심해져서 전체가 더 느려질 수도 있다. 처음에 pm.max_children을 늘린 조치가 효과가 없었던 이유가 여기 있었다. 무엇이 잡고 있는지는 SHOW PROCESSLIST에 나오고 그것이 잠금이면 기다리는 쪽은 innodb_lock_wait_timeout에 걸린다. 무엇이 부족한지를 안 정하고 늘리면 늘리는 것 자체는 쉬우니까 그쪽으로 손이 간다.
타임아웃을 늘리는 처방
다른 안으로 max_execution_time을 늘리는 것도 나왔다. 그러면 적어도 오류로 끝나지는 않는다.
다만 max_execution_time을 늘리는 것은 화면이 죽는 것을 안 죽는 것으로 바꿀 뿐이고 기다리는 시간은 그대로다. 쓰는 사람 입장에서는 여전히 그만큼 기다린다. 증상을 미루는 것과 원인을 없애는 것을 갈라서 봐야 했다.
단발 관측으로 단정하지 않는다
이 건에 오기까지 앞서 세 번 다른 원인으로 짐작했었다. 매번 한 번 관측한 것을 근거로 삼았다.
그때 그랬다는 것과 그것 때문이라는 것은 다른 말이다. 마지막에 부하 시점만 바꿔서 다시 재 본 한 번이 앞선 세 번의 짐작을 정리했다. 변수를 하나씩 바꿔 가며 다시 재는 것이 결국 가장 빨랐다.
정리
- 처리 시간과 대기 시간을 먼저 구분한다
- 같은 요청을 한가한 시각에 보내 보면 갈린다
- 대기면
pm.max_children을 늘려도 안 나아진다 MySQL연결이든 잠금이든 더 잘게 나눠 가질 뿐이다- 무엇이 부족한지 안 정하고 늘리면 쉬운 쪽으로 손이 간다
max_execution_time을 늘리는 것은 증상만 미룬다- 단발 관측으로 원인을 단정하지 않는다
- 변수를 하나씩 바꿔 다시 재는 것이 가장 빠르다