30개 사이트를 매일 안정적으로 수집한다는 것: 스케일·복원력의 현실 | Signals EP.6
한 사이트 수집은 쉽다. 30개를 매일 돌리면 메모리가 폭주하고 Rate Limit에 막히고 매일 어딘가는 실패한다. "오류를 없애는 것"이 아닌 "멈추지 않는 시스템"의 설계. 시리즈 6편.
시리즈: 공공데이터에서 영업 시그널을 자동으로 발굴하기까지, 5편 읽기
한 사이트 수집은 쉽다, 30개는 다른 차원이다
한 사이트에서 데이터를 수집하는 건 어렵지 않다. 두세 개도 괜찮다. 하지만 30개를 매일 돌리면 완전히 다른 종류의 문제가 생긴다.
50개 브라우저를 동시에 띄우면 생기는 일
정부 사이트 중 약 30%는 JavaScript 렌더링이 필요하다. 이런 사이트를 수집하려면 실제 웹 브라우저를 프로그래밍으로 제어해야 한다.
빨리 끝내고 싶으니까 여러 사이트를 동시에 수집하고 싶어지는 게 당연하다. 그래서 병렬로 돌렸더니. 브라우저가 50개 이상 동시에 뜨면서 메모리가 폭주했다.
메모리 사용량이 1.5GB를 넘어가니 타임아웃이 연쇄적으로 터지기 시작했다. 한 사이트 수집이 실패하면 재시도가 걸리고, 재시도가 쌓이면 브라우저가 더 많이 뜨고, 악순환.
결국 도달한 결론: 동시 처리를 1~3개로 제한하고, 메모리 사용량을 실시간 감시하면서 초과 시 강제 정리. "빠르게 많이"가 아니라 "안정적으로 꾸준히"가 정답이었다.
명시되지 않은 Rate Limit
정부 사이트에 요청을 너무 빠르게 보내면 응답이 느려지거나 차단당한다. 그런데 이 기준이 어디에도 적혀 있지 않다.
어떤 사이트는 초당 2회 요청만 해도 느려지고, 어떤 사이트는 10회까지도 문제없다. 차단 방식도 제각각이다. IP를 아예 막는 곳, 에러를 돌려주는 곳, 아무 응답 없이 연결을 끊는 곳.
적정 속도를 찾는 동적 조절
수집 간격을 동적으로 조절하는 방식을 썼다. 기본 딜레이로 시작해서 응답이 느려지면 1.5배씩 늘리고, 정상화되면 다시 줄이는 식이다. 사이트마다 적정 속도가 다르니 각각의 "리듬"을 찾아야 했다.
공식 문서에 rate limit이 적혀 있다면 즉각 적용하면 되지만, 없으니까 경험적으로 찾을 수밖에 없었다. "돌려보고 에러 나면 줄이고, 되면 유지하고", 기계적으로 그 경계를 탐색하는 것.
실패는 일상, 복구가 핵심
30개 사이트를 매일 돌리면, 매일 어딘가는 실패한다. 사이트가 점검 중이거나, 서버가 느리거나, SSL 인증서가 갱신 중이거나. 100% 성공률은 환상이다.
중요한 건 실패를 예상하고 자동으로 복구하는 구조를 만드는 것이었다.
탄력적 수집 시스템의 4가지 핵심 장치
- 3회 자동 재시도 (간격을 점점 늘리면서)
- 연속 3페이지가 비어 있으면 수집 종료 (게시판 끝 자동 감지)
- 수집 결과 검증: 최소 항목 수를 못 채우면 경고
- 어떤 추출 로직이 실제로 동작했는지 로깅
"오류를 없애는 것"이 아니라 "오류가 나도 시스템이 멈추지 않는 것"이 설계 철학이었다. 이 차이는 실운영에 들어가야 비로소 체감된다.
예측 가능하게 노후화되는 정부 사이트
1년 이상 운영하면서 관찰한 패턴이 하나 있다. 정부 사이트는 예측 가능한 방식으로 노후화된다.
새로 구축된 사이트는 1~2년간 안정적이다. 담당 부서가 바뀌거나 운영 예산이 줄면서 관리가 소홀해지고, 3~4년차가 되면 인증서 만료나 서버 불안정 증상이 보이고, 5년이 지나면 리뉴얼과 함께 URL 체계가 통째로 바뀌기도 한다.
이 패턴을 알면 대비할 수 있다. 오래된 소스일수록 더 많은 예외 처리가 필요하고, 새로 생긴 소스는 당분간 자신을 갖고 돌려도 된다는 판단이 가능해진다. 사람이라면 직관으로 하는 일이지만, 시스템에 녹여내려면 경험 데이터가 필요하다.
다음 에피소드에서는 이 시스템에서 AI를 어디에 썼고, 어디에는 쓰지 않았는지 이야기한다.