•
인터넷 산업이 발전하며 디지털 광고가 전체 광고 매출에서 차지하는 비중이 날로 커지고 있다. 그 결과 광고 클릭 이벤트 추적 작업의 중요성도 지극히 높아지고 있는 실정이다.
•
이번 장에서는 페이스북이나 구글 규모에 걸맞는 광고 클릭 이벤트 집계 시스템을 설계해 본다.
1단계: 문제 이해 및 설계 범위 확정
기능 요구사항
•
지난 M분 동안의 ad_id 클릭 수 집계
•
매분 가장 많이 클릭된 100개 광고 아이디를 반환
•
다양한 속성에 따른 집계 필터링을 지원
•
데이터의 양은 페이스북이나 구글 규모
비기능 요구사항
•
집계 결과 정확성은 데이터가 RTB 및 광고 과금에 이용되므로 중요
•
지연되거나 중복된 이벤트를 적절히 처리할 수 있어야 함
•
부분적인 장애는 감내할 수 있는 견고성이 필요함
•
전체 처리 시간은 최대 수 분을 넘지 않아야 함
개략적 추정
•
일간 능동 사용자 수는 10억 명
•
각 사용자는 하루에 평균 1개 광고를 클릭한다고 가정하므로 대략 10억 번의 광고 클릭 이벤트가 발생
•
광고 클릭 QPS 10억 / 86400 = 대략 10,000
•
최대 광고 클릭 QPS는 평균 QPS의 다섯배로 가정
•
광고 클릭 이베늩 하나 당 0.1KB의 용량이 필요하다고 가정하면 일일 저장소 요구량은 대략 100GB, 월간은 대략 3TB
2단계: 개략적 설계안 제시 및 동의 구하기
질의 API 설계
•
지난 M분 동안 각 ad_id에 발생한 클릭 수 집계
•
지난 M분 동안 가장 많은 클릭이 발생한 상위 N개 ad_id 목록 반환
•
다양한 속성을 기준으로 집계 결과를 필터링하는 기능 지원
데이터 모델
•
원시 데이터, 집계 결과 데이터 둘로 저장해야 한다.
•
원시 데이터의 경우, 디버깅에 사용하기 적합하며 집계 데이터에 오류가 있을 경우, 수정하여 집계 결과를 다시 만들 수도 있다.
•
원시 데이터는 백업 데이터로 활용되며 그 용량자체가 거대하므로 질의에 적합하지 않아 집계 결과 데이터 조회를 통한 질의로 성능 이슈를 방지할 수 있다.
올바른 데이터베이스의 선택
•
평균 쓰기 QPS 10,000과 최대 쓰기 QPS 50,000 등의 지표들을 토대로 적절한 데이터베이스를 선택해야 한다.
•
일단 이 데이터베이스 시스템은 쓰기 연산에 집중되어 있다. 따라서 관계형 데이터베이스도 구현은 가능하나 가급적 쓰기 및 시간 범위 질의에 최적화된 카산드라나 InfluxDB를 사용하는 것이 좀 더 바람직하다.
개략적 설계안
•
비동기 처리
◦
카프카 같은 메시지 큐를 도입하여 생산자와 소비자 간의 결합을 끊을 수 있다.
◦
급격한 클릭 수의 증가 등으로 인해 소비자의 처리 용량이 초과되는 경우, 이슈가 발생할 수 있는데 이를 방지할 수 있다.
집계 서비스
•
광고 클릭 이벤트를 집계하는 좋은 아이디어 중 하나는 맵리듀스 프레임워크를 사용하는 것이다.
◦
유향 비순환 그래프가 해당 프레임워크에 적합한 모델인데, 이 모델의 핵심은 시스템을 맵/집계/리듀스 노드 등의 작은 단위로 세분화하는 것이다.
◦
각 노드는 한 작업만 처리하며 처리 결과를 다음 노드에 인계한다.
▪
맵 노드
•
데이터 출처에서 읽은 데이터를 필터링하고 변환하는 작업을 담당한다.
▪
집계 노드
•
ad_id 별 광고 클릭 이벤트 수를 매 분 메모리에서 집계한다.
▪
리듀스 노드
•
모든 집계 노드가 산출한 결과를 최종 결과로 축약한다.
3단계: 상세 설계
스트리밍 vs 일괄 처리
•
해당 시스템은 일괄 및 스트리밍 처리를 동시에 지원하며 이런 아키텍처를 람다라고 부른다.
•
스트림 처리는 데이터를 오는 대로 처리하고 거의 실시간으로 집계된 결과를 생성하는데 사용하며 일괄 처리는 이력 데이터를 백업하는 데 사용한다.
시간
•
해당 데이터에서 시점은 두 가지가 존재할 수 있다. 이벤트 시각과 처리 시각인데, 이 둘은 네트워크 지연이나 비동기적 처리 환경에 따라 차이가 발생할 수 있다.
•
어떤 데이터를 사용하느냐에 따라 장단점이 달라진다. 두 방안의 장단점을 고려하여 보다 적절한 설계를 만드는 것이 적합하다.
장점 | 단점 | |
이벤트 발생 시각 | 광고 클릭 시점을 정확히 아는 것은 클라이언트이므로 집계 결과가 보다 정확해진다. | 클라이언트가 생성한 타임스탬프에 의존하는 방식이므로 클라이언트의 시각에 문제가 있거나 조작된 경우, 문제가 발생할 수 있다. |
처리 시각 | 서버의 타임스탬프가 클라이언트보다 안정적이다. | 이벤트가 시스템에 늦게 도착하는 경우 집계 결과가 부정확해진다. |
•
앞서 기능 요구사항 가정에서 정확도가 더 중요하다 했으므로 클라이언트 시점의 타임스탬프를 사용한다는 가정을 해볼 수 있다.
집계 윈도
•
윈도에는 텀블링 윈도(고정 윈도), 호핑 윈도, 슬라이딩 윈도, 세션 윈도의 네 종류가 있다. 이 중, 본 설계안과 유관한 텀블링, 슬라이딩을 알아보자.
•
텀블링 윈도는 시간을 같은 크기의 겹치지 않는 구간으로 분할한다. 따라서 매 분 발생하는 클릭 이벤트를 집계하기에 아주 적합하다.
•
슬라이딩 윈도는 데이터 스트림을 미끄러져 나아가면서 일정한 시간 구간 안에 있는 이벤트를 집계한다. 슬라이딩 윈도우는 서로 겹칠 수 있다.
◦
이는 앞선 두 번째 요구사항인 지난 M 분간 가장 많이 클릭한 상위 N개 광고 수 기능을 구현하기에 적합하다.
전달 보장
•
집계 결과는 과금 등에 활용되므로 데이터의 정확성, 무결성이 아주 중요하다.
•
때문에 시스템은 다음 두 질문에 대답할 수 있어야 한다.
◦
이벤트의 중복 처리를 어떻게 피할 것인가?
▪
카프카와 같은 메시지 큐를 사용해 처리할 수 있다. 이때 정확히 한 번의 전달 방식을 사용한다면 좋을 것이다.
◦
모든 이벤트의 처리를 어떻게 보장할 것인가?
•
중복 데이터는 다양한 지점에서 발생할 수 있는 이번 절에서는 흔한 두 사례만을 살펴보자.
◦
클라이언트 측
▪
한 클라이언트가 같은 이벤트를 여러번 보내는 경우다. 이런 중복 이벤트를 처리하는 데는 광고 사기/위험 제어 컴포넌트 등의 계층을 하나 더 두어 처리하는 것이 적합하다.
◦
서버 장애 측
▪
집계 도중에 집계 서비스 노드에서 장애가 발생하여 업스트림 서비스가 이벤트 메시지에 응답하지 못했다면 재전송 로직을 통해 중복 집계될 가능성이 있다.
▪
이 문제의 가장 간단한 해결책은 HDFS나 S3와 같은 외부 저장소에 이벤트의 오프셋을 기록하여 처리하는 것이다.
▪
그러나 이 방법도 문제가 있는데, 저장소에 저장된 오프셋 이전의 이벤트는 전부 무시한다는 것이다. 오프셋 갱신 직후 집계 서비스 노드에 문제가 생긴다면 데이터가 유실될 가능성이 있다.
▪
따라서 데이터 손실을 막기 위해 다운스트림에서 집계 결과 수신 확인 응답을 받은 후, 오프셋을 저장해야 한다.
시스템 규모 확장
•
메시지 큐의 규모 확장
◦
생산자와 소비자는 모두 어렵지 않게 확장을 달성할 수 있다. 생산자는 그저 인스턴스를 늘리면 그만이며 소비자의 경우 재조정 메커니즘을 통해 달성할 수 있다.
◦
브로커의 경우, 해시 키와 파티션의 수, 토픽의 샤딩 등에 대한 고려가 필요하다.
▪
해시 키의 경우, 가급적 같은 이벤트는 같은 파티션에서 처리하도록 식별자를 선택하는 것이 좋다.
▪
파티션의 수의 경우, 사전에 충분한 수를 확보하여 프로덕션 환경에서 파티션의 수가 동적으로 변경되는 것을 방지하는 것이 좋다.
•
그렇지 않은 경우, 해시 키에 따른 파티션 할당이 변경되어 같은 식별자를 가졌음에도 규모 확장 후 다른 곳에 저장되거나 하는 등의 불상사가 발생할 수 있다.
▪
토픽의 물리적 샤딩의 경우, 지역이나 비즈니스 유형 등 분류에 다라 여러 토픽으로 나누어 시스템의 처리 대역폭을 향상시킬 수 있다. 그러나 복잡성이 증가하고 유지 비용이 증가한다.
•
집계 서비스의 규모 확장
◦
앞서 이 시스템은 맵리듀스 연산을 사용하는 데 이 경우, 각 노드들이 상호 연결되어 연산을 처리한다.
◦
이 서비스의 규모 확장을 달성하기 위해서는 ad_id마다 별도의 처리 스레드를 두거나 집계 서비스 노드를 아파치 하둡 YARN 같은 자원 공급자에 배포하여 다중 프로세싱을 활용할 수 있다.
•
데이터베이스의 규모 확장
◦
카산드라는 안정 해시와 유사한 방식으로 수평적 규모 확장을 기본적으로 지원하고 있다. 따라서 수동적으로 샤딩을 조정하는 과정은 필요하지 않다.
◦
하지만 어느정도 알고 있는 블랙박스로 두는 것이 좋으므로 어느정도 실행 과정 정도는 알아두는 것이 좋다.
핫스팟 문제
•
다른 서비스나 샤드보다 더 많은 데이터를 수신하거나 처리하는 샤드를 핫스팟이라 부른다.
•
이 경우, ad_id에 따라 발생할 수 있는데, 큰 회사는 더 많은 광고를 통해 클릭을 유도하기 때문에 핫스팟 문제가 발생할 수 있다.
•
이 문제는 더 많은 집계 서비스 노드를 할당하여 해결할 수 있다. 더 복잡하게는 전역-지역 집계, 분할 고유 집계 같은 방안을 사용해볼 수 있다.
결함 내성
•
집계는 메모리에서 일어나므로 집계 노드에 장애가 생기면 집계 결과도 손실된다.
•
이 경우, 카프카 브로커에서 이벤트를 재수신해야 하는데, 이렇게 되면 시간이 오래걸린다. 따라서 업스트림 오프셋 같은 시스템 상태를 스냅숏으로 저장하고 마지막으로 저장된 상태부터 복구해 나가는 것이 바람직하다.
데이터 모니터링 및 정확성
•
지속적 모니터링
◦
지연 시간, 메시지 큐 크기 지표 등의 경우에는 지속적으로 모니터링해야 한다.
•
조정
◦
매일 각 파티션에 기록된 클릭 이벤트를 이벤트 발생 시각에 따라 정렬한 결과를 일괄 처리하여 만들어 낸 다음, 실시간 집계 결과와 비교해보면 정확성을 검증한다.
대안적 설계안
•
광고 클릭 데이터를 하이브에 저장한 다음 빠른 질의는 엘라스틱 서치를 이용해 처리해볼 수 있다. 집계의 경우 클릭하우스나 드루이드와 같은 OLAP 데이터베이스를 통해 처리할 수 있을 것이다.
4단계: 마무리
•
이번 장에서는 페이스북이나 구글 규모의 광고 클릭 이벤트 집계 시스템을 설계해보며 다음과 같은 주제를 다루었다.
◦
데이터 모델 및 API 설계
◦
맵리듀스 데이터 처리 패러다임을 통해 광고 클릭 이벤트를 집계하는 방안
◦
메시지 큐, 집계 서비스, 데이터베이스의 규모 확장 방안
◦
핫스판 문제를 해결하는 방안
◦
시스템의 지속적 모니터링
◦
데이터 조정을 통한 정확성 보증 방안
◦
결함 내성
•
이 시스템은 전형적인 빅데이터 처리 시스템으로 아파치 카프카, 아파치 플링크, 아파치 스파크같은 업계 표준 솔루션에 대한 사전 지식을 구비해둔다면 구현이 용이할 것이다.