스크래핑 파이프라인은 요란한 소리를 내며 실패하는 경우가 거의 없다. 크론은 계속 실행되고, 프로세스는 계속 종료 코드 0을 반환하며, 로그는 200 OK로 가득 차 있다. 그러다가 세 팀 정도 떨어진 누군가가 일주일 전부터 보고서의 숫자가 이상해진 것을 알아챌 때까지는 모든 게 정상으로 보인다. 그때쯤이면 며칠치 데이터를 잃은 상태이고, 페이지가 이미 바뀌었기 때문에 대부분 다시 수집할 수도 없다.
이것이 바로 대규모 수집 운영에서의 관측 가능성 영역이다. Kubernetes가 오케스트레이션을 제공하고, 응답별 검증이 개별 불량 페이지를 잡아낸다면, 모니터링은 시간에 따라 전체 플릿을 지켜보면서 대상이 나를 상대로 태도를 바꾼 시점을 데이터가 웨어하우스에 도달하기 전에 알려주는 계층이다. 여기서는 중요한 지표들, 이를 기준선으로 잡는 방법, 그리고 소음에 파묻히지 않고 알림을 설정하는 방법을 다룬다.
로그는 모니터링이 아니다
가장 먼저 받아들여야 할 사실은, 로그와 종료 코드는 스크래핑이 제대로 작동하는지에 대해 거의 아무것도 말해주지 않는다는 점이다. 종료 코드 0을 반환하고 200을 기록한 프로세스는 요청을 보내고 응답을 받았다는 것만 알려줄 뿐, 올바른 응답을 받았다는 것을 말해주지는 않는다. 차단되거나 가짜인 콘텐츠 탐지하기에서 다뤘듯이, 차단 페이지, 껍데기만 남은 응답, 그리고 실제 데이터 모두 200으로 돌아온다. 모니터링이란 지표를 의미한다. 요청마다 발생시키고, 시간에 따라 집계하고, 차원별로 분류하고, 기준선과 비교하는 숫자들이다. 이는 로깅과는 다른 규율이며, 조용한 실패를 잡아내는 것이 바로 이 규율이다.
중요한 지표들
다음 지표들을 요청마다 발생시키고, 대상 호스트와 출구 지역(geo)으로 태그를 붙여 집계하라. 머신러닝은 전혀 필요 없고, 카운터와 히스토그램만 있으면 된다.
성공률. 가장 핵심적인 지표이자, 모두가 잘못 정의하는 지표이기도 하다. 성공은 HTTP 200이 아니라 검증을 통과한 것이다. 즉 응답에 실제 페이지가 항상 가지고 있는 필드나 요소가 포함되어 있었는지를 말한다. 대상 호스트별로 콘텐츠 검증을 통과한 요청의 비율을 추적하라. 다른 호스트는 안정적인데 한 호스트만 하락한다면, 그 호스트가 여러분을 향한 태도를 바꾼 것이며, 이는 대시보드에서 가장 중요한 단일 지표다.
차단율. 탐지 계층이 소프트 차단이나 챌린지로 표시하는 응답의 비율이다. 이는 대상이 더 공격적으로 바뀌었거나 풀의 평판이 떨어졌다는 조기 경고다. 서서히 상승하는 차단율은 강제 차단(hard ban)의 전조이므로, 값 자체뿐 아니라 기울기를 지켜보고 IP 평판 및 피하고자 하는 차단과 상관관계를 살펴보라.
지연 시간 백분위수. p50, p95, p99를 추적하되 평균은 절대 사용하지 말라. 평균은 실제 문제가 숨어 있는 느린 꼬리 부분을 가려버린다. p95가 상승한다는 것은 대상이 여러분을 스로틀링하고 있거나, 풀이 저하되고 있거나, 경로가 혼잡하다는 뜻이다. 이는 요청 타임아웃과 지연 시간 튜닝의 배경이 되는 동일한 신호를 플릿 수준에서 본 것이다.
필드 채움률. 추출하는 각 필드마다, 실제로 값이 채워진 레코드의 비율이다. 이는 데이터 품질의 카나리아 역할을 한다. 어제는 98퍼센트가 채워졌던 필드가 오늘은 20퍼센트라면, 그 값이 희귀해진 것이 아니라 껍데기만 남거나 일부만 있는 페이지를 받기 시작한 것이다. 필드 채움률은 성공률이 놓칠 수 있는 저하를 잡아낸다.
처리량 대 백로그. 분당 요청 수와 레코드 수를, 작업 큐의 깊이와 함께 지켜본다. 처리량이 늘어나면서 백로그가 줄어드는 것은 건강한 상태다. 처리량은 그대로인데 백로그가 늘어난다면 뒤처지고 있는 것이며 확장이 필요하다는 신호로, 큐 깊이 기반 오토스케일링에 반영되는 신호다.
신선도(Freshness). 각 소스별로 가장 최신 레코드가 얼마나 오래되었는지를 나타낸다. 신선도가 더 이상 갱신되지 않는 소스는, 다른 모든 지표가 괜찮아 보여도 조용히 생산을 멈춘 것이다. 이는 오류 없이 죽어버린 피드를 잡아내는 유일한 지표다.
레코드당 비용. 대역폭과 지출을 수집된 사용 가능한 레코드 수로 나눈 값이다. 효율성을 넘어, 이는 이상 탐지 수단이기도 하다. 레코드당 바이트 수가 갑자기 급증한다면, 데이터 대신 차단 페이지나 부풀려진 쓰레기를 다운로드하고 있다는 뜻인 경우가 많으므로, 건강 문제가 비용 급증으로 먼저 드러난다. 또한 대역폭 비용을 정직하게 유지시켜준다.
재시도율과 오류 분류 체계. 성공한 레코드 하나당 시도 횟수를, 실패 유형별(타임아웃, 429, 연결 재설정, DNS, 탐지된 차단)로 나눈 것이다. 오류의 형태가 곧 진단이다. 429의 급증은 대상을 너무 세게 밀어붙이고 있다는 뜻이고, 연결 재설정의 급증은 네트워크나 프록시 계층을 가리키며, 탐지된 차단의 급증은 평판 문제를 가리킨다. 오류 총계 하나는 뭔가 잘못됐다는 것만 알려주지만, 분류 체계는 무엇이 잘못됐는지를 알려준다.
대상별로 기준선을 잡고, 편차에 알림을 걸어라
모니터링을 쓸모없게 만드는 실수는 절대값 임계치로 알림을 설정하는 것이다. 3퍼센트의 차단율은 어떤 사이트에서는 완전히 정상이지만 다른 사이트에서는 대형 화재 경보감이다. p95가 2초라면 무거운 페이지에서는 괜찮지만 가벼운 API에서는 끔찍한 수치다. 절대값 임계치는 실제 문제를 놓치거나 끊임없이 거짓 경보를 울리며, 알림 피로는 결국 진짜 문제가 있는 페이지 하나까지 무시하게 만든다.
모든 지표를 대상 호스트별로 기준선을 잡은 다음, 그 기준선으로부터의 편차에 알림을 걸어라. 성공률의 지속적인 하락, 정상 범위보다 빠르게 상승하는 차단율, 지난주 대비 두 배로 뛴 p95 같은 것들이다. 변화율과 대상별 편차는 정말 중요한 것들을 잡아내는 동시에, 한 사이트가 단순히 다른 사이트와 다를 뿐일 때는 조용히 있어준다. 단발성의 나쁜 1분이 아니라 지속적인 편차에 알림을 걸고, 사람을 호출하는 것은 실제로 필요한 경우로만 남겨두고, 나머지는 대시보드나 다이제스트로 처리하라.
# Emit per response; aggregate into a time series, dimensioned by host + geo.def record(metrics, host, geo, resp, validation): tags = {"host": host, "geo": geo} metrics.incr("requests", tags) metrics.incr("success" if validation.ok else "failure", tags) if validation.blocked: metrics.incr("blocked", tags) # block rate = blocked / requests metrics.observe("latency_ms", resp.elapsed_ms, tags) # histogram -> p50/p95/p99 metrics.observe("bytes", resp.size, tags) # -> cost/bytes per record for field, present in validation.fields.items(): metrics.incr(f"field.{field}." + ("filled" if present else "empty"), tags)카나리아와 프록시 차원
위 내용 전부를 더 날카롭게 만들어주는 두 가지가 있다. 첫째, 카나리아를 운영하라. 정답을 이미 알고 있는 페이지를 지역별로, 일정에 따라 가져와서 여전히 일치하는지 검증하라. 카나리아는 대상이 바뀌는 순간 즉시 정상에서 이상으로 바뀌며, 집계 지표의 완만한 하락이 눈에 띄게 될 때까지 기다릴 필요가 없다. 지역별로 이를 수행하면 특정 국가의 출구 IP만 차단하고 다른 국가는 건드리지 않는 사이트도 잡아낼 수 있다.
둘째, 모든 지표를 대상뿐 아니라 출구 지역과 풀별로도 차원을 나누어라. 문제는 흔히 국지적으로 발생한다. 한 국가의 IP만 챌린지를 받고 나머지는 무사히 통과하거나, 풀의 한 부분만 저하되는 식이다. 지역과 풀 단위 분류가 없으면, 실제로는 날카롭고 조치 가능한 신호인 것이 전체 평균에서는 흐릿하고 헷갈리는 하락으로만 나타난다. 풀 품질은 차단율의 선행 지표이므로, 풀별 성공률과 차단율을 지켜보는 것은 레지덴셜 풀이 저하되어 전체 실행을 끌어내리기 전에 알려주며, 사용자가 눈치채기 전에 부하를 옮기거나 페일오버할 수 있는 선택지를 준다.
결론
모니터링되지 않는 스크래핑 파이프라인은 조용히, 그리고 비싸게 실패하는 파이프라인이다. 성공을 HTTP 200이 아니라 검증 통과로 계측하고, 차단율, 지연 시간 백분위수, 필드 채움률, 처리량 대 백로그, 신선도, 레코드당 비용, 그리고 제대로 된 오류 분류 체계를 추적하되, 이 모두를 대상 호스트와 출구 지역별로 나누어 살펴보라. 각 지표를 대상별로 기준선을 잡고, 절대값이 아니라 그 기준선으로부터의 편차에 알림을 걸어서, 진짜 문제를 잡아내면서도 거짓 경보에 파묻히지 않도록 하라. 즉각적인 조기 경고를 위해 카나리아를 추가하라. 이렇게 하면 조용한 실패는 더 이상 조용하지 않게 된다. 몇 주 뒤 후속 보고서에서가 아니라, 몇 분 만에 파이프라인 안에서 바로 알게 된다.
차단율과 지연 시간 모두 결국 여러분이 통과하는 IP의 품질로 귀결되므로, 깨끗한 레지덴셜 풀이야말로 애초에 이러한 지표들을 건강하게 유지시켜주는 요소이며, GB당 가격 정책은 지금 여러분이 지켜보고 있는 레코드당 비용을 실제로 최적화할 수 있는 대상으로 만들어준다.