5편에서 네이버 크롤링을 실전 스케일(타깃 21개)로 옮기자 동시 요청이 이론상 최대 20개까지 몰릴 수 있다는 걸 계산으로 확인했다. 이번엔 그 계산이 진짜인지 직접 세어보기로 했다.
실측 — 순간 최대 14개가 동시에 몰렸다
21개 타깃 전체를 다시 짧게 돌리면서, 이 프로세스가 맺은 소켓
연결을 1초 간격으로 20번 샘플링했다. 직접 IP로 가는 연결과
프록시(127.0.0.1)로 가는 연결을 구분해서.
순간 최대 동시 연결 14개(직접 3 + 프록시 11), 개별로는 직접 최대 7개, 프록시 최대 11개. 진단 규모(타깃 2개)에서는 최대 4개였던 것과 비교하면 3~5배였다. 이론상 최대치(20개)에는 못 미쳤지만 — 타깃들이 항상 정확히 같은 순간에 네트워크 요청 중은 아니라서 — 실질적으로는 그 이론치에 가깝게 몰리고 있었다.
한 가지 더 눈에 띈 게 있었다. 순간적으로는 프록시 쪽이 직접보다 더 많이 몰리는 경우도 있었다(11 vs 3). 이 프록시는 다른 프로젝트의 크롤러도 같이 쓰는 회선이었다 — 너무 몰아치면 그쪽 작업에도 영향이 갈 수 있다는 뜻이라, 더 조심해야 할 이유가 하나 늘었다.
IP당 동시 요청을 2개로 강제하다
타깃이 몇 개 동시에 처리되든, 실제 네트워크 요청만큼은 IP당 정확히 2개로 묶어두기로 했다. 각 IP로 요청을 보내는 지점에 “동시에 2개까지만” 이라는 잠금 장치를 걸었다 — 이 잠금은 실제 요청-응답 구간에만 걸려 있고, 딜레이나 403 백오프로 대기하는 동안에는 풀려 있어서, 기다리는 다른 요청이 그 자리를 바로 이어받을 수 있게 했다.
같은 방식(21타깃 실행 + 소켓 25회 샘플링)으로 다시 확인했다. 이번엔 직접/프록시 둘 다 한 번도 2를 넘지 않았다. 동시성은 확실히 잡혔다.
그런데 오히려 더 나빴다
동시성을 잡은 채로 21타깃 전체를 다시 돌렸다. 8분 만에 “직접 +프록시 둘 다 실패” 397건, 폴백 성공은 0건이었다. 분당 실패율로 계산하면, 동시성을 안 잡았던 이전 시도(16분에 764건, 분당 약 47.75건)와 사실상 같거나 오히려 살짝 더 나빴다(분당 약 49.6건).
동시 연결 수를 확실히 2개로 낮췄는데도(방금 실측으로 확인했으니) 실패율이 전혀 줄지 않았다.
열두 번째로 다시 찾은 이유 — 네이버 크롤링 IP 차단 원인
이 결과는 “동시성이 너무 높아서”라는 설명만으로는 부족하다는 뜻이었다. 대신 훨씬 유력한 설명이 하나 남았다 — 오늘 하루, 두 IP(직접, 프록시) 모두에 이미 상당한 양의 요청을 쐈다는 것. 이번 시리즈의 진단 실험들(5편부터 여기까지)과 실전 스케일 시도 두 번을 다 합치면, 오늘 하루 동안 이 두 IP로 보낸 요청은 결코 적은 양이 아니었다.
이건 2편에서 처음 세웠던 “누적 요청량 기반 시간창 rate-limit” 가설이 오늘 다시 소진 상태로 돌아온 것이었다. 특히 폴백 성공이 0건으로 떨어졌다는 게 결정적인 신호였다 — 지금까지는 직접이 막혀도 프록시는 거의 항상 뚫렸는데, 이번엔 그 프록시조차 오늘의 반복된 테스트로 지쳐 있었다는 뜻이다.
그래서 어디까지 왔나
코드 쪽 개선(요청 딜레이, 403 백오프 재시도, 프록시 폴백,
field=1로 물량 축소, 두 IP 병렬화, IP당 동시성 제한)은 전부
유효하고 필요한 변경이었다. 다만 오늘처럼 두 IP가 이미 상당히
지친 상태에서는, 그 개선들만으로 완전한 안정성을 보장할 수
없었다. 오늘은 여기서 멈추고, 두 IP를 충분히 식힌 뒤 다시
시도하기로 했다. 다음에 재개할 때 가장 먼저 확인할 것은 하나다
— 완전히 식은 상태에서 실전 스케일 전체가 한 번에 끝까지 돌아가는지.
남는 생각
열두 번의 실험 동안, “이게 원인이다”라고 생각한 게 매번 조금씩 틀렸다. 처음엔 동시성이라고 생각했고, 그다음엔 시간창이라고 생각했고, 그다음엔 순수한 물량이라고 생각했고, 다시 동시성으로 돌아갔다가, 결국 그 어느 쪽도 아니었다. 진짜 원인은 코드 안에 없었다 — 원인을 찾으려고 그날 보낸 요청들 자체가, 다음 진단을 더 어렵게 만드는 조건이 되고 있었다.
이게 이 시리즈에서 가장 크게 남는 지점이다. 문제를 진단하는 행위 자체가 그 문제의 조건을 바꿔놓을 수 있다는 것, 그리고 그 바뀐 조건이 다음 결론을 왜곡할 수 있다는 것. “고쳤다”와 “끝났다” 는 다른 말이었다. 열두 번의 실험 중 열한 번은 “무엇을 고쳐야 하는가”를 좁혀가는 과정이었지만, 마지막 한 번은 “지금 이 실험 자체가 답을 볼 수 있는 조건인가”를 먼저 물어야 했다는 걸 알려준 셈이다.