Skip to content
isdnetworks
Go back

이미지 처리가 요청을 붙잡았다

상품 등록이 느리다는 얘기를 들었다. INSERT 자체는 금방인데 응답이 늦었다.

Table of contents

Open Table of contents

이미지 처리가 요청 안에 있었다

단계마다 microtime 을 찍어 보니 입력 검사와 DB 저장은 빠르고 이미지 처리가 느렸다. 코드를 보니 한 장마다 크기 셋을 만들고 있었다.

foreach ($images as $img) {
    move_uploaded_file(...);
    resize($img, 800);
    resize($img, 300);
    resize($img, 100);
}

상품 하나에 열 장까지 올릴 수 있으니 서른 번을 만든다. 그걸 요청 안에서 다 하므로 사용자는 서른 개가 만들어질 때까지 기다린다. 장수가 많으면 max_execution_time 에 걸려 등록 자체가 실패하기도 했다.

set_time_limit 으로 늘릴까 했는데 그러면 기다리는 시간은 그대로다. 실패를 성공으로 바꿀 뿐 느린 것은 안 고쳐진다.

덧붙이면 이 한도는 재는 대상이 좁다. PHP 는 시스템 호출로 밖에서 기다리는 시간을 여기에 안 넣는다. 이미지 변환은 CPU 를 쓰는 일이라 그대로 세어져서 걸린 것이다.

뒤로 미뤘다

요청 안에서는 move_uploaded_file 로 원본만 저장하고 응답을 준 뒤 변환은 뒤에서 하기로 했다. 할 일을 image_jobs 에 넣고 crontab 에 건 배치가 주기적으로 꺼내 처리한다.

INSERT INTO image_jobs (image_id, status) VALUES (?, 'wait');

저장하고 바로 응답하니 등록이 즉시 끝난다. 만드는 시간은 그대로지만 사용자가 그걸 기다리지 않는다.

아직 안 만들어진 것과 실패한 것

대신 새 문제가 생겼다. 등록 직후에는 변환된 이미지가 없어서 목록에 이미지가 안 나온다. 변환본이 없으면 원본을 보여 주게 했다.

$url = $thumb_exists ? $thumb : $original;

file_existsthumb 이 있는지 보고 없으면 원본을 준다. 크기가 크지만 보이기는 한다. 변환이 몇 초면 끝나서 그 사이만 원본이고 대부분은 티가 안 났다.

변환이 실패하면 statuswait 로 남아 계속 다시 시도하는 것도 있었다. try_count 를 세어 몇 번을 넘으면 fail 로 표시하고 그만두게 했다. 그러면 실패한 것을 누가 봐야 하므로 COUNT(*) 를 매일 세는 조회를 뒀다.

실패한 것들을 보니 이미지가 아닌 파일과 너무 커서 메모리가 모자란 이미지였다. 앞의 것은 getimagesize 로, 뒤의 것은 픽셀 수를 재서 올릴 때 거를 수 있었다. 뒤에서 실패하면 사용자는 올린 줄 알고 나갔다가 나중에 없는 것을 보게 된다.

원본을 남기기로 했다

변환이 끝나면 원본을 unlink 할지 고민했다. 지우면 du 로 재는 공간이 절약되고 남기면 나중에 다른 크기가 필요할 때 다시 만들 수 있다.

크기 규격이 바뀔 수 있다고 보고 남기기로 했다. 원본이 없으면 다시 만들 방법이 없다.

나중에 실제로 목록 이미지 크기가 바뀌었고 원본이 있어서 image_jobs 에 전부 다시 넣어 만들었다. 지웠으면 올린 사람들에게 다시 올려 달라고 해야 했을 것이다.

정리


Share this post on:

Previous Post
소수점 여덟 자리
Next Post
설정이 도중에 바뀌어 있었다