추천 서비스에서 광고/비광고 노출 정책과 크롤링 안정성 고민

송현진·2025년 8월 27일
0

트러블슈팅

목록 보기
7/7

1. 광고 개수 고정 이슈

이번 회의에서 논의된 핵심 요구사항은 결과 상품에서 광고(쿠팡 파트너스 링크) 개수를 고정하는 것이다.

예: 결과 8개 중 광고 2개 + 비광고 6개.

방식별 검토

[방식1] 광고 상품과 비광고 상품 풀을 분리

장점
광고와 비광고를 각각 분리해서 관리하기 때문에 개수를 정확히 강제할 수 있고 동일 상품이 광고와 비광고로 섞여서 노출되는 문제를 막을 수 있다. 정책적으로 가장 깔끔하다.

단점
광고 상품은 비광고 풀에서 제외되므로 동일한 추천 품질을 유지하려면 상품 확보량을 두 배로 늘려야 한다. 결과적으로 유사한 상품이 중복 노출될 가능성도 높아지고 운영 관리 비용이 커진다.

구현 난이도는 높지 않지만 운영 부담이 큰 방식이다.

[방식2] 동일 상품에 광고/비광고 링크를 모두 저장

장점
동일 상품에 쿠팡 파트너스 링크와 일반 링크를 동시에 저장해두고 광고는 2개까지만 파트너스 링크로 노출하면 된다. 쿼리할 때는 광고 여부를 따로 고려하지 않아도 되므로 로직이 단순해지고 상품 풀을 더 확보할 필요도 없다.

단점
문제는 동일한 상품이 어떤 경우는 광고로, 또 다른 경우는 비광고로 노출될 수 있다는 점이다. 사용자 입장에서 보면 “이거 광고 맞아? 왜 똑같은 상품이 어떤 건 광고고 어떤 건 아니지?”라는 의심을 살 수 있다. 비즈니스 신뢰성 차원에서 좋지 않다.

구현 난이도는 가장 낮지만 UX 혼란 가능성이 크다.

[방식3] 광고 상품에 대체 비광고 상품 등록

장점
광고 상품에 대해 미리 동일하거나 유사한 대체 비광고 상품을 매칭해두고 필요 시 그걸 노출하면 사용자 입장에서는 광고와 비광고가 자연스럽게 구분된다. 광고 중복 노출도 막을 수 있다.

단점
문제는 유사 상품을 찾고 매칭하는 로직을 따로 구현해야 한다는 점이다. 상품 데이터 관리 공수가 커지고 유사 상품이 아예 존재하지 않는 경우도 있어서 예외 처리가 필요하다.

품질과 신뢰성 측면에서는 가장 이상적이지만 구현 및 운영 공수가 크다.

내 의견

빠른 구현과 단순함을 원한다면 방식2가 적합하다. 하지만 장기적으로는 사용자 신뢰성과 품질을 우선해야 하므로 방식1이나 방식3이 더 바람직하다. 현재 팀 내부 논의 결과는 방식1을 선호하는 쪽으로 방향이 잡혔다. 따라서 네이버와 쿠팡을 주력 소스로 활용해 상품 풀을 안정적으로 확보하는 방식으로 진행할 가능성이 높다.

2. 크롤링 이슈

이 부분은 내가 직접 담당하는 영역은 아니고 프론트엔드 쪽에서 Puppeteer 기반 크롤링을 진행하고 있다. 다만 광고 개수 고정 이슈와 함께 의논되는 주제라서 백엔드 개발자 입장에서 사전에 이해하고 의견을 나누기 위해 정리했다.

원인

최근 Puppeteer 기반 크롤링을 반복적으로 실행하다 보니 사이트 측에서 접속 자체를 차단한 상황이 발생했다. 원인은 크게 두 가지로 보인다.

반복된 동일 IP/헤더 요청 → 동일한 클라이언트에서 일정 패턴으로 요청이 들어오면 봇으로 탐지된다.

짧은 주기의 반복 실행 → 요청 빈도가 지나치게 높으면 정상 사용자가 아닌 것으로 판단해 차단된다.

헤드리스 브라우저 탐지 → Puppeteer가 기본 설정으로 실행되면 사이트에서 ‘자동화 도구’임을 식별할 수 있다.

대응 방법

User-Agent 회전

매 요청마다 브라우저의 User-Agent 값을 바꿔주는 방식이다. 예를 들어 크롬, 사파리, 모바일 크롬 등 다양한 User-Agent를 랜덤으로 적용하면 탐지를 피하기 쉽다.

Proxy IP 풀 사용

여러 개의 IP 주소를 가진 프록시 서버를 사용해 요청을 분산하면 단일 IP가 차단당하는 것을 방지할 수 있다. 무료 프록시보다는 안정성과 속도가 보장되는 유료 프록시 풀을 사용하는 것이 현실적이다.

요청 패턴 무작위화

사람처럼 보이도록 요청 사이에 랜덤한 딜레이를 두는 방식이다. 예를 들어 매 요청마다 1~5초 랜덤 sleep을 주면 일정한 주기로 반복되는 패턴을 피할 수 있다.

헤드리스 탐지 회피

Puppeteer-extra-plugin-stealth 같은 라이브러리를 적용하면 브라우저가 자동화 도구라는 흔적을 지워준다. 또한 headless=false 옵션을 사용하면 실제 브라우저처럼 동작해 탐지를 피할 수 있다.

스케줄링 분산

크롤링 작업을 한 번에 몰아서 실행하지 않고 여러 시간대에 분산 실행한다. 예를 들어 1시간마다 1,000건씩 분산해서 가져오면 서버에 과부하를 주지 않고 탐지도 피할 수 있다.

📝 배운점

이번 논의를 통해 단순히 광고 개수를 고정하는 문제는 기술적인 쿼리 난이도의 문제가 아니라 운영 비용·추천 품질·사용자 신뢰성과 직결된 이슈라는 점을 다시 확인할 수 있었다. 빠른 구현을 택할지, 장기적으로 안정적인 구조를 택할지는 팀의 우선순위 결정에 달려 있으며 백엔드 입장에서는 단순한 기능 구현보다 운영 과정에서 발생할 수 있는 문제들을 미리 고려하는 것이 중요하다.

또한 크롤링 이슈는 내가 직접 담당하지는 않지만 서비스 전체의 데이터 확보와 품질 관리에 영향을 주는 중요한 영역이기 때문에 기본적인 차단 원인과 회피 방법을 이해하고 있어야 한다. Puppeteer 같은 도구는 반복된 접속 패턴이나 헤드리스 탐지에 의해 쉽게 막힐 수 있기 때문에, User-Agent 회전, Proxy IP 풀 활용, 요청 패턴 무작위화, Stealth 플러그인 적용, 크롤링 스케줄 분산 같은 기법이 필수적이다. 결국 크롤링은 항상 차단 리스크를 안고 가야 하므로 안정성을 높이려면 이러한 방식을 조합해 탐지를 최소화해야 한다.

이번 이슈를 통해 백엔드 개발자로서 배운 점은 비즈니스 요구사항과 기술적 선택 사이의 균형을 고민하는 것이 중요하다는 것이다. 단순히 동작하는 코드를 만드는 것이 아니라 운영 가능성과 데이터 신뢰성을 고려해 서비스 품질을 유지할 수 있는 구조를 설계해야 한다는 점을 다시금 느꼈다.

profile
개발자가 되고 싶은 취준생

0개의 댓글