저는 거의 매일 소스별 건수만 보여주는 탭을 하나 열어둡니다. 예쁜 화면이 아니라—차트도, 필터도 없이—우리가 리스팅을 가져오는 1,375개 사이트 각각의 숫자와 마지막으로 체크인한 시각만 나열한 화면입니다. 대부분의 날은 인프라가 그래야 하듯 지루합니다. 이번 여름은 그렇지 않았고, 무엇이 잘못됐는지에 대한 이야기가 우리가 대신 쓸 수 있었을 "중고차 구매 요령" 같은 조언보다 여러분—차를 알아보는 사람—에게 더 유용하리라 생각합니다. "실시간 데이터"라는 게 실제로 무엇을 의미하는지, 그것을 먹여 살리는 게 여러분에게 아무 의무도 없는 1,375개의 개별 웹사이트일 때 어떤 모습인지에 관한 이야기니까요.
7월 중순: 자랑스러웠던 숫자
7월 중순 우리는 소스 레지스트리를 73개 지역에 걸쳐 1,190개 소스로 끌어올렸습니다—몇 주간 중복 항목과 죽은 링크를 정리하며 우리 스스로의 집계를 은근히 부풀리고 있던 것들을 바로잡은 결과였죠. 1,190개의 진짜, 체크인이 확인된 소스가 자랑할 만한 성과라고 생각했던 게 기억납니다. 개별 딜러 사이트, 중고거래 게시판, 경매 피드가 그만큼 많다는 뜻이고, 각각이 저마다 다른 HTML 구조, 저마다 다른 요청 제한, 스크래퍼를 고객으로 볼지 공격자로 볼지에 대한 저마다의 입장을 갖고 있습니다.
그러다 몇 달째 대기 상태로 방치되어 있던 683개 소스 대기열—일부는 차단됐고, 일부는 아예 구축된 적조차 없던—을 처리하던 백로그 캠페인이 성과를 내기 시작했습니다. 7월 후반부에 걸쳐 그중 274개가 구축되어 연결됐습니다. 월말이 되자 작동 중인 소스 수는 1,464개까지 올라갔습니다. 스크린샷을 찍어둘 만한 한 주였죠.
8월 초: 241개 소스가 사라지다
그리고 한 주를 망치는 숫자가 나타났습니다: 하룻밤 사이 241개 소스가 열화 상태로 떨어진 겁니다. 우리가 뭔가를 잘못해서가 아니라, 프록시 제공업체의 결제 계정이 만료됐기 때문이었습니다—우리 트래픽의 상당 부분이 로테이팅 IP를 거치는 이유는 스크래퍼를 요청 제한으로 차단하는 사이트들에 걸리지 않기 위해서인데, 프록시가 없으니 새 페이지도, 새 리스팅도 없었습니다. 소스는 자기가 고장 났다고 알려주지 않습니다. 그냥 조용히 새 데이터를 반환하지 않게 될 뿐, 기존 리스팅들은 여전히 최신인 것처럼 그 자리에 남아 있습니다.
이게 바로 여러분이 일부러 찾아보지 않는 한 어느 자동차 사이트의—우리도 예외는 아닙니다—리스팅 카운트에는 드러나지 않는 부분입니다: "실시간" 마켓플레이스라도 오래된 데이터 행이 신선한 데이터 옆에 나란히 앉아 겉보기엔 똑같아 보일 수 있다는 것. 우리는 실제 프록시 헬스 체크를 통과해야만 새 크롤 작업을 실행하도록 게이트를 걸어, 죽은 풀 때문에 품질이 조용히 더 나빠지는 일을 막았고, 상황을 더 악화시켰을 스케줄의 일부는 중단시켰습니다. 화려한 작업은 아닙니다. 여러분이 이런 일에 대해 전혀 듣지 못했다면, 그건 누군가가 자기 일을 제대로 했다는 뜻입니다.
여담이지만 분명히 짚어둘 가치가 있습니다: 매일 고정된 정수 리스팅 건수를 자랑하는 사이트가 있다면, 실제로는 실시간이 아니거나, 아니면 이번 주 같은 주에 대해 말해주지 않고 있는 겁니다.
멈춰버린 시간
프록시 갱신으로 대부분은 해결됐습니다. 예상 못 했던 건 몇 주 뒤 크롤러 자체가 멈춰버린 일이었습니다—teardown 데드락으로, 19개 워커 스레드 중 18개가 futex_wait 상태로 CPU를 전혀 태우지 않은 채 75시간 내내 그대로 멈춰 있었습니다. 크래시도, 누군가에게 소리치는 에러 로그도 없었습니다. 그냥… 아무 일도 일어나지 않는데, 대시보드는 마지막으로 성공한 실행을 마치 지금도 최신인 양 계속 보여주고 있었죠. 그 특정 호스트에는 아직 워치독을 설치해두지 않았던 겁니다—이런 문장은 그 일을 한 번 직접 겪고 나서야 쓰게 되는 종류의 문장입니다.
우리는 워치독을 구축했습니다. 그리고 프록시 갱신이 안정적으로 확인될 때까지 스케줄을 중단시켰습니다. 절반만 정상화된 크롤이 좋은 데이터 행을 나쁜 데이터로 조용히 덮어쓰게 두는 위험을 감수하기보다는요—크롤된 소스는 리스팅이 병합되는 게 아니라 교체되기 때문에, 잘못된 실행 한 번은 데이터를 추가하지 못하는 데서 그치지 않고 멀쩡한 행을 실제로 지워버리고 그 자리에 더 나쁜 것을 채워 넣을 수 있습니다. 우리가 하루쯤 데이터가 낡은 채로 운영하는 편을 열화된 채로 운영하는 것보다 택하는 이유가 바로 이 비대칭성 때문입니다.
숫자가 도착한 곳
오늘의 집계와, 여기까지 오는 6주간의 흐름은 이렇습니다:
우리는 73개 지역에 걸쳐 1,375개 소스, 실시간 리스팅 1,108,535건에 도달했고, 그중 12,823건이 현재 지역 코호트 대비 저가로 플래그되어 있습니다. 7월 정점보다 약 90개 소스가 적은 셈인데—241개 열화 소스 중 일부는 끝내 완전히 복구되지 않았고, 몇몇은 그사이 안티봇 정책을 바꿔버려서 재연결이 아니라 재구축이 필요한 사이트들이었습니다. 아직 몇 개는 작업 중입니다.
이게 여러분에게 실제로 갖는 의미
이 이야기가 여러분이 어떤 차를 사야 하는지를 바꾸진 않습니다. 하지만 어느 자동차 사이트든—우리만이 아니라—"실시간 재고" 숫자를 읽는 방식은 바꿔놓아야 합니다. 지금 이 순간 지역별 집계 1위는 프랑스로 67,569건, 그 뒤를 일본이 61,940건으로 바짝 쫓고 있는데, 이 숫자들은 움직입니다—중고차 시장 자체가 그렇게 빠르게 요동쳐서가 아니라, 그것을 지켜보는 인프라가 그렇게 요동치기 때문입니다. 소스가 열화되어서 사흘 묵은 리스팅은, 플랫폼이 그 차이에 대해 정직하지 않는 한 신선한 리스팅과 완전히 똑같아 보입니다.
우리는 숫자가 절대 흔들리지 않는 척하기보다는 75시간의 멈춤에 대해 여러분에게 말씀드리는 쪽을 택하겠습니다. 나쁜 한 주가 있었다는 사실을 절대 인정하지 않는 데이터셋이 있다면, 그건 덜 의심할 게 아니라 더 의심해봐야 할 대상입니다.



