Skip to content
isdnetworks
Go back

크롤러를 느리게 만들었다

외부 사이트에서 자료를 모아 오는 일을 맡았다. 빨리 끝내려고 스무 개씩 동시에 요청했다. 몇 분 만에 응답이 안 왔다.

Table of contents

Open Table of contents

증상 — 막히고 나서 속도를 줄였다

연결은 되는데 응답이 없었다. 다른 곳에서 그 사이트를 열어 보니 잘 열렸다.

[우리 서버]  안 됨
[다른 곳]    됨

우리 IP 에서 나가는 요청이 통째로 차단된 상태였다. 짧은 시간에 많이 부르면 사람의 접속과 구분되고 상대는 그것을 막는다. 상대 쪽에서 보면 당연히 막아야 할 요청이었다.

foreach ($urls as $u) {
    fetch($u);
    sleep(1);
}

동시 요청을 하나로 줄이고 sleep 으로 1초 간격을 두니 안 막혔다. 대신 한 회차가 도는 시간이 크게 늘어나 정해진 주기 안에 안 끝나는 상태가 됐다.

겹쳐 도는 것을 먼저 막았다

cron 이 끝나기 전에 다음 실행이 시작돼 두 개가 같이 돌았다. 둘이 같은 대상을 동시에 부르니 요청 수가 다시 늘어 또 막힐 위험이 생겼다. 느리게 만든 것이 겹침 때문에 무의미해지고 있었다.

if (file_exists($lock)) { exit; }
touch($lock);
// 작업
unlink($lock);

돌고 있으면 시작하지 않는다. 그런데 작업이 중간에 죽으면 $lock 이 남아 영영 시작되지 않았다.

if (file_exists($lock) && time() - filemtime($lock) < 7200) { exit; }

filemtime 을 봐서 두 시간이 넘으면 죽은 것으로 봤다. 나중에 보니 flock 을 쓰면 프로세스가 죽을 때 잠금이 알아서 풀려서 시각을 넣을 일이 없었다.

일의 양을 줄였다

겹침은 막았는데 여전히 안 끝났다. 속도를 못 올리니 남은 방법은 일의 양을 줄이는 것이었다.

목록을 보니 대부분이 어제와 같았다. 바뀐 것을 어떻게 아는지 보니 목록 화면에 갱신 날짜가 있었다.

① 목록 페이지에서 날짜 확인
② 우리가 가진 것보다 새것만 상세 조회

XPath 로 목록의 날짜부터 걸러 두 단계로 나눴다.

[전]  매일 수천 건
[후]  매일 수십 건

상세 조회가 크게 줄어 몇 분 만에 끝났다. 속도를 안 올리고도 시간 안에 들어온 것이다.

처음에는 느리다는 문제를 빠르게 만드는 것으로만 풀려 했고 양을 줄이는 쪽은 안 떠올랐다. 막히고 나서야 다른 길을 찾게 됐고 막히지 않았으면 동시 요청을 늘리는 쪽으로 갔을 것이다.

표시와 규칙

요청에 누구인지 알리는 표시를 붙였다. 사이트 주소와 연락처를 User-Agent 에 넣은 것이다.

차단당했을 때 연락이 오게 하려는 것이었다. 말없이 막히면 왜 막혔는지 모른다. 우리를 막을지 말지는 상대가 정할 몫이라고 봤다.

사이트의 robots.txt 도 확인했다. 어느 경로를 수집하지 말라는 표시가 있으면 따랐다.

이걸 안 지켜도 기술적으로 막히지는 않는다. 다만 안 지키면 막힐 명분을 주는 것이라 지키는 편이 맞다고 봤다. 빨리 끝내는 것보다 계속 돌 수 있는 것이 중요했다.

정리


Share this post on:

Previous Post
돈 내고 부르던 것을 안에서 처리했다
Next Post
어느 장비에 둘지 성능과 위치로 골랐다