[Review] 시스템 디자인 스터디 3주차 후기
안녕하세요!
K-DEVCON (이하 “데브콘”) 그로스 매니저 박종훈입니다🙋🏻♂️
이 글에서는 9/25 (목)에 진행된 스터디에서 나눈 이야기를 정리합니다.
이번 시간에는 “웹 크롤러 설계” 과 “알림 시스템 설계” 이야기를 나눴습니다.
—
[1] 웹 크롤러
크롤러 만들어본 경험 있는지, 현재 회사에서 관련되어 사용하는 부분이 있는지에 대해서 이야기를 나누며 시작 하였습니다.
커머스 도메인에 계신 한 분이 공유해주신 사례가 최저가 보상 서비스에 크롤링을 사용한다고 하셨습니다.
최저가 보상이 단순 마케팅 용어인 줄 알았는데, 실제로 크롤링 기능으로 구현되는 사례라 흥미로웠습니다.
한 사이트만 크롤링하는 것은 비교적 간단합니다. 패턴을 잘 찾아서 크롤링을 하도록 하면 되는데요.
반면에 정해지지 않은 사이트들을 크롤링 하는 것은 좀 더 많은 고민들이 필요합니다.
<1> DNS 변환기 (DNS Resolver)
책을 읽다 보면 별도의 DNS 변환기를 구축하는 부분이 나오는데요. 이 부분이 왜 필요할까에 대한 논의를 진행하였습니다.
DNS(Domain Name System)는 도메인 이름을 IP로 변환해줍니다.
반환받은 IP를 HTTP 요청시 Host header 에 Host 정보로 담아서 요청을 보내면 응답을 받을 수 있습니다. (참고: MDN - Host header)
DNS(Client Resolver)는 대부분의 OS에 포함되어 있습니다.
그렇다면 크롤러를 구현할 때 별도의 DNS 변환기를 두는 이유는 무엇일까요?
1. 운영체제 기본 Resolver의 한계
앞서 말씀드린대로 일반적으로 DNS 조회는 운영체제(OS)가 제공하는 Resolver를 통해 처리됩니다. 이 방식은 일반적인 애플리케이션 환경에서는 적합하지만, 대규모 웹 크롤러 환경에서는 몇 가지 제약이 발생합니다.
- 동기적 API 문제 : OS의 DNS Resolver는 기본적으로 동기적으로 동작하여, 요청 시 네트워크 레벨에서 블로킹이 발생할 수 있습니다. (최근에는 비동기 방식도 지원하지만 여전히 제약이 존재합니다.)
- 병렬성 저하 : 한 VM 내에서 여러 크롤러가 동시에 동작할 경우, DNS 처리 병목으로 전체 성능이 저하될 수 있습니다.
2. 캐싱 정책의 유연성 부족
OS 수준의 DNS 캐시는 일반적인 사용 시나리오를 고려해 설계되어 있습니다. 그러나 크롤러에는 다른 요구사항이 있을 수 있습니다.
- TTL(Time To Live)을 더 길게 가져가거나, 반대로 더 자주 갱신해야 할 필요가 있음
즉, 별도의 DNS Resolver를 두면 크롤러 특성에 맞는 맞춤형 캐싱 정책을 설계할 수 있습니다.
3. 중앙화와 공유 이점
별도 DNS Resolver를 구축하면, 한 번의 조회 결과를 여러 크롤러가 동시에 활용할 수 있습니다.
- 중복 DNS 요청을 줄여 네트워크 트래픽 절감
- DNS 서버 부하 완화
- 여러 VM/컨테이너 환경에서도 일관된 해석 결과를 제공
<2> 예의 (politeness)
크롤러가 얼마나 자주, 어떻게 요청을 보내야 할까요?
- 요청 빈도: 한 번에 너무 많은 요청을 보내지 않고, 간격을 두어 서버에 부담을 줄여야 합니다.
- robots.txt 준수: 사이트가 설정한 접근 규칙을 반드시 따르는 것이 기본입니다.
최근 AI 학습용 데이터 수집 과정에서 robots.txt를 무시한 크롤링 사례가 논란이 되었는데요.
예를 들어, 최근 Cloudflare에서 작성한 글에서는 Perplexity의 크롤러가 규칙을 회피한 방식에 대해 다루며 이에 대한 비판을 하고 있습니다.
기술적 구현만큼이나 윤리적 고려도 크롤링 시스템 설계에서 중요한 요소임을 알 수 있습니다.
<3> Crawler 감지
어떻게 Crawler를 감지할 수 있을까요? 뚫는 입장에서는 더 사람처럼 행동하고자 하고, 막는 입장에서는 더 나은 방식으로 봇을 찾고자 하며 함께 진화하고 있습니다.
책에서 크롤링 감지 및 감지 회피에 대한 방법이 나왔으면 더 좋았을 것 같은데, 그렇게 깊은 내용은 없었어서 아쉬웠습니다.
아래 내용에 대해서 이야기를 나눴습니다.
- 브라우저 핑거프린트 : 실제 브라우저와 크롤러 사이에 발생되는 차이점을 통해 감지를 시도합니다. 자동화 도구를 사용할 경우 일반적인 브라우저와 동작 방식이 다르거나 존재하는 객체나 함수가 없는 경우가 있습니다. 이러한 특성들을 사용하여 비정상 유저를 찾아낼 수 있습니다.
- 접속 패턴 : 요청 속도 및 간격, 마우스/키보드 움직임, 폼 필드와의 상호 작용, 페이지 탐색경로 등을 통해 비정상 유저를 찾아낼 수 있습니다.
<4> 중복 콘텐츠 탐지
크롤러가 돌아다니면서 동일한 콘텐츠를 만날 수 있습니다.
책에서는 웹 페이지의 해시 값을 비교하는 방식에 대해서 설명하는데 가만히 생각해보면 어떻게 서로 다른 두 URL이 해시 값이 동일할 수 있을까 생각이 들기도 합니다. 왜냐면 내용이 아주 살짝만 바뀌어도 해시는 다르게 나올 것이기 때문입니다.
예를들어 같은 페이지를 바라보고 있지만 Query String만 다른 경우가 이에 해당될 것입니다.
이 경우에는 HTML의 내용은 대부분 같을 것이기 때문에 해시 값으로도 비교할 수 있을 것입니다.
내용 자체를 해시 처리하여 판단 하기에는 변수가 너무 많기 때문에, 내용의 유사도를 검사해보는것이 더 좋지 않을까 하는 의견도 있었습니다.
[2] 알림 시스템 설계
종종 특정 서비스에서 ‘테스트 입니다’ 와 같은 내용의 푸시 알림을 받았다고 인터넷에 글이 올라오기도 합니다. 알림 시스템이 잘 고려되지 않았을 경우에 발생할 수 있는 이슈 중 하나입니다.
알림 시스템은 잘못 보내면 회수하는 것이 어렵거나 불가능 하기 때문에 조심이 필요한 영역입니다.
<1> 서드파티 API
알림 시스템은 서드파티 API를 사용하는 경우가 많습니다. 각 서드파티는 서로 다른 정책을 가지고 있습니다. 따라서 이 정책에 대해서 잘 파악하고 있는것이 중요합니다.
특히 Rate Limit이나 Payload Size Limit과 같은 정책에 걸릴 경우, 정상적으로 알림이 전송되지 않을 수도 있습니다.
한 스터디원의 사례에서는 20~30만 유저에게 이벤트 시작 알림을 보내야 했습니다. 그러나 서드파티 API의 Rate Limit 정책 때문에 한 번에 모든 유저에게 보낼 수 없었고, 나눠서 보내는 과정에서 일부 고객에게는 이미 이벤트가 끝난 후 알림이 도착하기도 했습니다.
유저의 토큰 단위로 보내는 것이 어렵다면 토픽 단위로 보낼 수는 없는지 체크해보는것도 좋은 전략이라고 생각됩니다. (Firebase 같은 서드파티는 지원됨)
<2> 신뢰성
분산 환경에서의 통신을 주고 받는것의 어려움은 두 장군 문제에서 알 수 있습니다.
두 장군 문제는 분산 환경에서 완전한 합의의 불가능성에 대해서 이야기 하는 사고 실험입니다.
분산 환경의 모든 통신을 100% 보장할 순 없지만, 적어도 우리가 직접 통제하는 시스템 내부에서는 최대한의 신뢰성을 확보해야 합니다.
아래와 같은 내용에 대해서 이야기를 나눴습니다.
1. 멱등성
동일한 알림이 여러 번 발송된다면 고객에게 피로감을 줄 수 있고, 발송 건수에 따라 비용이 발생한다면 불필요한 지출로 이어질 수 있습니다. 따라서 알림 발송 로직은 멱등성을 보장해야 합니다.
이를 위해 알림 요청에 고유한 식별자(idempotency key) 를 부여하거나, 중복 발송 여부를 저장소에 기록하여 재시도 시에도 동일한 알림이 중복 발송되지 않도록 하는 전략을 사용할 수 있습니다.
2. 아웃박스 패턴
아웃박스 패턴은 메시지 전달의 신뢰성을 보장하기 위해서 사용됩니다.
서비스가 데이터를 변경할 때, 변경 사항을 이벤트 형태로 아웃박스 테이블에 저장합니다. 이후 별도의 프로세스가 아웃박스 테이블을 주기적으로 읽어 메시지 브로커로 전송합니다. 이 과정을 통해 이벤트가 유실되지 않고, 메시지가 중복되거나 누락되는 상황을 방지합니다.
3. 카프카의 메시지 전달 보장 수준
카프카에서는 다음과 같은 메시지 전달 보장 수준 을 가지고 있습니다
- 최대 한 번 (At most once): 메시지가 한 번만 전송되며, 재전송은 발생하지 않는다. 그러나 이로 인해 메시지가 유실될 수 있는 가능성이 있다.
- 최소 한 번 (At least once): 메시지가 반드시 전송되며, 최소한 한 번 이상은 전송이 보장된다. 그러나 이 과정에서 메시지가 중복으로 전송될 수 있다.
- 정확히 한 번 (Exactly once): 메시지가 정확히 한 번만 전송되며, 재전송은 일어나지 않는다. 따라서, 메시지가 유실되지 않는 것이 보장된다.
여기서 정확히 한 번 이라는 것에 대해서 이야기를 나누고 넘어갔습니다.
Kafka 에서 정확히 한 번은 Kafka의 트랜잭션을 통해서 보장합니다.
마법같은 단어로 보이지만 “카프카 내부에서 한 번” 을 보장 하는 것입니다. 외부 시스템과의 통신은 보장하지 않음에 주의해야 합니다. (카프카 이벤트는 한 번 실행되지만, 그 과정에서 외부 시스템과의 통신은 여러번 실행될 수 있음)
<4> 모니터링 중요성
또 각 플랫폼에서는 알림 설정이 세분화되고 있고, 개인 정보 보호가 강조되면서 실제로 알림이 잘 도착하였는지도 점점 더 추적하기 어려워지고 있습니다.
이를 위해 로깅과 모니터링이 필요하며, 필요하다면 이벤트를 다시 수행할 수 있도록 안전장치를 갖추는 것이 중요합니다.
<5> 운영 및 법적 제약
고객의 알림 피로도와 법적인 광고 불가 시간대에 대한 이야기도 나눴습니다.
너무 많은 알림이나, 너무 늦거나 이른 시간의 알림은 고객의 피로도를 높이고, 이는 이탈률과 연결될 수 있습니다.
또 법적으로도 광고 불가 시간대가 있어, 이를 지키지 않을 경우 과태료로 이어질수도 있으니 주의가 필요하겠습니다.
오늘은 위와같은 이야기를 함께 나누어보았습니다. 이번주도 다들 열심히 참여해주셔서 더 풍성한 스터디가 될 수 있었습니다.
다양한 관점과 의견을 제시해주는 스터디원들 덕분에 재밌게 스터디 하고 있습니다.
✅ 직접 스터디를 개설해보고 싶은 분이 계시다면, K-DEVCON에서 운영을 도와드리겠습니다. 데브콘의 '랩짱'에 도전하여 커뮤니티 성장을 함께 이끌어주세요! 슬랙을 통해 운영진에게 DM 부탁드리겠습니다😉