버즈니 AI Lab 정동호 플랫폼 엔지니어, 최광희 리서치 엔지니어

[아이티데일리]

▲ 정동호 버즈니 AI Lab 플랫폼 엔지니어

리타기팅의 정의
인터넷과 스마트폰을 사용하지 않는 사람은 찾기 힘들다. 우리 실생활에 IT는 뗄레야 뗄 수 없는 관계가 됐다. 한 사람이 여러 인터넷 기반 서비스, 예컨대 네이버, 페이스북, 유튜브 등을 동시에 쓰는 것도 자연스러운 일이 되었다. 이에 따라 서비스 회사들이 풀어야 하는 문제들이 생겨나기 시작했는데, 대표적인 문제 중 하나가 바로 리타기팅(Retargeting)이다.

리타기팅이란, 사용자가 인터넷상에서 한 행동을 기반으로 그에 맞춘 광고를 제공해주는 것이다. 이미 수많은 인터넷 기반 광고 회사에서 사용하는 방법으로 당장 구글 광고에서도 자신이 다른 곳에서 검색해보거나 살펴본 것들이 그대로 나와 신기해하는 경우가 흔하다.

이번 기고에서는 리타기팅이라는 큰 문제 중 사용자들이 행동을 분류해 적재하는 시스템적 측면과 여러 서비스에 독립적으로 남긴 사용자 행동들을 다시 모으는 추적 알고리즘 등 두 가지에 대해 살펴보려고 한다.

리타기팅의 흐름
일반적으로 리타기팅 시스템을 구축하기 위해서는 여러 온라인 쇼핑사들과 제휴를 맺어, 각 쇼핑사들로부터 사용자들의 행동 정보를 공유받는다. 각 쇼핑사에서 받은 여러 정보를 종합해 한 사용자가 서로 다른 쇼핑사들에서 어떤 행동을 했는지를 다시 모은다.

예컨대, 어떤 사용자가 쇼핑사 A에서 청바지를 계속 검색해보다가 쇼핑사 B로 넘어간 뒤 B에서 원하는 청바지를 한 번에 찾아 장바구니에 넣고, 쇼핑사 C에서 좀 더 검색해본 뒤에야 B로 돌아와 그 청바지를 샀다고 하자. 양질의 리타기팅을 하기 위해서는 해당 사용자가 어떤 쇼핑사에서 어느 시점에 어떤 행동을 했는지를 한꺼번에 볼 수 있어야 한다.

하지만, 각 쇼핑사는 사용자가 자신들의 서비스에 남긴 데이터만 살펴볼 수 있다. 쇼핑사 A나 C의 입장에서 해당 사용자는 명확한 구매 의사 없이 청바지 상품들에 대해 단순히 아이쇼핑을 하러 온 것으로 착각할 수 있다. 그에 반해 쇼핑사 B의 입장에서는, 잠깐 찾아보고 바로 선택했으니 까다롭지 않은 사용자라고 오해할지도 모른다.

▲ 고객의 행동 데이터

만약 제휴 쇼핑사들의 단편적인 정보 조각들이 아닌 여러 쇼핑사로부터의 종합적인 데이터를 한꺼번에 볼 수 있다면, 해당 사용자에 대해 좀 더 정확히 이해할 수 있게 된다. 각 사용자가 어떤 상품을 좋아하고 구매했는지 등 각 사용자 단위로 정보가 모인 후에는 그 정보를 바탕으로 각 사용자에 최적화된 광고를 보여준다거나 더 좋은 검색을 제공해주는 등 보다 나은 사용자 경험을 안겨줄 수 있다. 사용자는 원하는 것을 쉽게 찾아내고, 쇼핑사도 더 많은 상품을 판매할 수 있어 서로에게 도움이 될 수 있다.


리타기팅의 기술적 난관들
하지만 실제 서비스를 운영하는 과정에서는 여러 기술적 난관들이 등장한다. 먼저, 여러 쇼핑사를 이용하는 수많은 사용자의 다양한 행동 정보를 일관성 있고 안정적으로 모으고, 모인 데이터를 손쉽게 활용할 수 있도록 하는 데이터 인프라스트럭처가 필수적이다. 다음으로 어떤 정보를 바탕으로 사용자를 추적해야 할지 고민한 뒤, 모인 데이터를 효과적으로 분석해 여러 쇼핑사에 걸쳐 남겨놓은 사용자의 행동 정보를 한데 모으는 알고리즘의 성능을 높여야 한다. 이제 시스템과 알고리즘의 기반이 되는 여러 아이디어를 좀 더 자세히 살펴보도록 하자.


사용자를 식별하는 방법
앞서 나온 리타기팅을 기술적으로 구현하려면 사용자들을 식별하는 게 우선이다. 그러나 웹의 기반이 되는 HTTP는 대표적인 무상태 프로토콜(stateless protocol) 중 하나이다. 무상태 프로토콜이란 서버나 클라이언트 사이에 서로 주고받는 각 세션이 독립적이라는 특징을 갖는 프로토콜을 의미한다. 현재 세션은 이전 세션 기록들을 살펴보지 않고도, 즉 어떤 상태인지 파악하지 않아도 현재 세션의 의미를 독립적으로 이해할 수 있게 된다. 하지만, 이 특징은 웹에서 사용자를 식별하고 추적하는 데 걸림돌이 되고 있다.

이 문제를 해결하고자 1994년 ‘쿠키’라는 개념이 등장했다. 넷스케이프에서 MCI 사의 e-커머스 서비스를 개발해주던 루 몬틀리(Lou Montulli)는 장바구니 시스템을 구현하면서 서버가 모든 정보를 다 기억할 필요가 없어야 한다는 HTTP의 표준에 맞춰 ‘쿠키’란 개념을 제안하게 된다. 다시 말해 서버에서 관리되는 세션과는 달리 쿠키는 클라이언트에 저장되는 정보 조각으로 클라이언트가 상태를 관리하게 하는 방법이다.

이러한 특징은 여러 세션에 등장하는 단 하나의 사용자를 식별하는 정보를 클라이언트에 심음으로써, 여러 사이트를 오가는 사용자를 추적하는 데 유용하게 활용할 수 있다.


쿠키 활용하기
그렇다면 리타기팅에서 쿠키를 어떻게 활용할 수 있을까? 먼저, 어떤 서비스에 장바구니 기능을 구현하기 위해서는 어떤 것이 필요한지, 루 몬틀리가 했던 고민을 잠시 살펴보자.

장바구니가 어떤 사용자의 장바구니인지 알기 위해서는 각 사용자를 식별할 수 있어야 한다. 또한, 이 장바구니에 어떤 물건이 담겨 있었는지 알기 위해서는 식별된 해당 사용자가 이전에 어떤 물건을 담았는지 저장하고 있어야 한다. 이는 앞에서 언급된 리타기팅의 요구사항과 완벽하게 일치한다.

쿠키의 작동 원리를 좀 더 구체적으로 살펴보자. 서버가 클라이언트가 보낸 요청(request)에 대해 응답(response)을 보낼 때, 서버가 해당 응답의 Set-Cookie 헤더를 통해 클라이언트에게 쿠키를 넘겨준다. 그 이후에 넘겨받은 쿠키를 관리하는 책임은 해당 클라이언트의 몫이 된다. 클라이언트의 쿠키를 넘겨받았던 서버와 주고받는 다음 요청부터는, 클라이언트가 요청의 쿠키(Cookie) 헤더를 통해 이전에 설정된 쿠키를 서버로 돌려주게 된다.

또한, 서버는 익스파이어(expires)와 도메인(domain) 등과 같은 여러 속성 정보들을 통해 클라이언트에 쿠키를 얼마나 오래 남길 것인지, 나중에 쿠키 헤더를 허용할 도메인은 어디까지인지 등을 추가로 설정할 수 있다. 물론 여기서 해당 정보들을 이해하고, 그 속성에 맞춰 쿠키를 관리하는 것은 클라이언트이므로, 일정 시간이 지났을 때 쿠키를 삭제하거나, 다른 도메인 말고 쿠키를 받은 해당 도메인의 요청에만 쿠키를 담아 보내는 것도 클라이언트의 책임이다.

▲ 쿠키의 작동 원리

예시를 통해 쿠키를 어떻게 사용할 수 있을지 살펴보자. 먼저, 사용자가 쇼핑사 A에 접속하면, 쇼핑사 A에 미리 심어져 있는 리타기팅 스크립트가 실행된다. 해당 스크립트를 통해 쿠키 서버에 요청을 함으로써 서버가 해당 사용자의 클라이언트, 즉 사용자가 이용하는 브라우저에 사용자 식별자를 쿠키의 형태로 남긴다.

이후 사용자가 상품을 검색하고 물건을 장바구니에 담는 등의 여러 행동을 할 경우, 클라이언트는 리타기팅 로그 서버에 해당 식별자가 담긴 쿠키와 함께 요청하므로, 서버는 해당 사용자가 동일인임을 파악할 수 있다. 다른 쇼핑사 B에 접속하는 경우에도, 쿠키는 계속 유효하기 때문에 리타기팅 로그 서버는 해당 사용자를 이전 쇼핑사 A에서 활동한 동일한 사용자임을 파악할 수 있다.


현실적인 걸림돌
하지만 현실의 쿠키 상황은 그리 녹록지 않다. 서버가 아닌 클라이언트가 관리한다는 특징 때문에, 클라이언트의 속성에 따라 쿠키의 행동 양태가 판이하다.

수많은 사용자들이 이용하는 유명한 브라우저들에서도 서로간의 표준이 다를 수 있다. 예컨대, 인터넷 익스플로러의 경우에는 P3P라는 흔치 않은 표준을 지키고 있다. P3P는 2002년에 웹 표준에 추가된 프로토콜로, 해당 웹 페이지가 사용자의 정보를 어떻게 저장하고 사용하는지에 관해 서술하는 방식을 제시하고 있다. IE의 경우, P3P 프로토콜을 지키지 않을 경우 쿠키 사용을 막고 있다. 하지만 해당 표준은 마이크로소프트 외의 회사들의 브라우저들에서는 쉽게 찾아볼 수 없어, IE만을 위한 구현이 따로 필요하다.

이처럼 디바이스, 운영체제, 브라우저 등 각 조합 간에 차이가 있어, 각 상황을 파악하고, 그에 맞춰 관리하는 꼼꼼하고 섬세한 손길이 필요하다.

이처럼, 쿠키만을 사용할 경우 한계가 있다. 클라이언트마다 그 속성이 다를 뿐만 아니라, 브라우저 시크릿 모드에서는 탭이 종료되면 쿠키도 자동으로 삭제되고, 브라우저를 청소하면 쿠키가 사라지는 경우도 흔하며, 최악의 경우 클라이언트가 의도적으로 쿠키를 수정해서 보내기도 한다.

이를 극복하기 위해 IP주소와 사용자 에이전트 식별자(User Agent String)도 같이 사용해 볼 수 있다. 다만, 두 정보 모두 쿠키보다 더 불완전한 정보라고 할 수 있다. 먼저 IP의 경우, 크게 두 가지 문제가 있는데, 대부분의 사용자는 고정 IP가 아닌 유동 IP를 사용한다는 점이다. 인터넷을 사용하는 사용자는 대부분 이통사 3사로부터 동적으로 IP를 부여받고, 주기적으로 IP가 바뀌기 때문에, 사용자를 추적하기 힘들어지게 된다. 더욱이, 공유기를 거쳐 와이파이를 사용하는 경우도 있는데 이 때문에 여러 사용자가 동일한 IP를 갖게 되는 경우도 많다.

사용자 에이전트 식별자를 사용하는 것 역시 까다롭다. 수많은 브라우저가 오랜 시간 동안 난립하며 식별자를 파악하는 것 자체도 힘들어졌을 뿐더러, 디바이스, 운영체제, 브라우저 세 정보가 한 식별자로 들어가 있기 때문에 더욱 복잡해진다. 또한, 셋 중 하나라도 업데이트를 하게 되면 문자열이 미세하게나마 바뀌기 때문에, 문자열을 있는 그대로 사용할 수도 없다. 그렇다고 해서 사용자가 독특한 식별자를 갖는 것도 아니다.

특히 모바일 시장에서는 애플이나 삼성의 플래그십 모델들은 동일한 디바이스와 운영체제에, 기본 탑재된 브라우저도 동일하고, 업데이트 주기 역시 모두 동일하게 적용되기 때문에 서로 다른 사용자임에도 불구하고 완전히 동일한 식별자가 나오는 경우도 흔하다. 이 때문에 수많은 로그를 통해 사용자 에이전트 식별자의 분포를 파악하는 것이 중요하다.


리타기팅 시스템 아키텍처
지금까지 사용자를 추적하는 데 필요한 정보를 서버로 넘기는 데에 집중했다면, 지금부터는 넘겨받은 서버에서 어떻게 분석하고 처리하는 지에 대해 살펴보도록 하겠다. 이 부분을 기술적으로 구현하고 최적화 하는 방법은 여러 가지가 있겠지만, 현실적으로 생각해볼 수 있는 선에서 일반적인 방법론을 제시해보고자 한다.

리타기팅 시스템을 크게 나눠보면 (1)사용자들의 행동을 기록하고 쿠키를 발급해주는 실시간 서버와 (2) 주기적으로 로그를 압축 · 적재 · 가공하는 로그 파이프라인으로 나눠볼 수 있다. AWS를 활용한 아키텍처를 예시로, 영역별로 어떻게 설계하고 무엇을 최적화해볼 수 있을지 알아본다.


리타기팅 실시간 서버
실시간 서버의 부하는 사람들이 얼마나 쇼핑사들을 사용하는지에 따라 결정된다. 사람들이 잠을 자는 새벽에는 적고, 아침부터 천천히 늘어나 저녁 늦게 가장 높아진다. 이러한 패턴은 짧은 시간 단위로 보면 유동적이지만, 하루 단위로 보게 되면 충분히 정확한 예상치를 추산할 수 있다.

이뿐만이 아니라, 다른 여러 특징 - 전송 계층 보안 (SSL/TLS)을 지원해야 하는 점, 새벽에는 부하가 적어지기는 하지만 항상 어디선가 누군가는 인터넷 쇼핑을 하므로 부하가 0이 되지는 않는다는 점 등등 - 을 고려했을 때, Lambda에 API 게이트웨이(Gateway)를 붙이는 것보다는 EC2에 ELB(Elastic Load Balancer)와 RI(Reserved Instance)를 붙이는 것이 더 적절한 선택이다.

구체적으로, 람다로 구현할 수 없는 것은 아니지만, HTTPS를 지원하기 위해 API 게이트웨이를 사용하고 로깅을 위해 Cloudwatch를 붙이면 EC2에 비교했을 때 이미 비용이 10배가량 차이가 난다. 리타기팅에서는 사용자의 행동마다 API 요청을 하기 때문에 실제 사용자 수보다 요청 수가 훨씬 더 많다. 이 외에도, 서비스를 일정 기간 운영하면서 지속적인 분석을 통해 부하가 어느 정도 파악이 되는 경우, RI를 사용하면 비용을 크게 줄일 수 있다.

▲ AWS를 활용한 리타기팅 로그 파이프라인 예시

리타기팅 로그 파이프라인
로그 파이프라인은 실시간 서버와는 전혀 다른 속성을 갖고 있다. 먼저, 데이터는 사용하기 위해 적재한다는 측면을 생각해보면, 몇 ms 단위의 실시간성은 필요가 없음을 알 수 있다. 때문에 로그 파이프라인은 대부분의 시간을 idle 상태로 보내게 된다. 또한, 데이터의 송수신은 내부망에서 일어나 SSL/TLS 등 서비스에 필요한 여러 안정성 및 보안 이슈에 대해 덜 고민할 수 있다.

이러한 특성들을 생각하면, 업로드에서부터 가공과 적재까지 Lambda, S3, Cloudwatch로 구성된 이벤트 기반(Event-driven) 서버리스(Serverless) 아키텍처가 매우 유리함을 알 수 있다. 이는 AWS에서 Lambda를 소개할 때 대표적으로 다루는 유즈 케이스로, S3 trigger를 활용해 S3 버킷에 데이터가 업로드되면, Lambda가 이로부터 trigger되어 이를 가공해 다음 S3 버킷에 적재하고, 다음 프로세스가 이를 받아 가공하고 적재하는 등, 일련의 연쇄적인 데이터 흐름을 인프라스트럭처의 걱정 없이 운용할 수 있게 된다.

비용 측면에서도 idle 상태가 많아 Lambda가 더 유리하다. 한 Region 내의 AWS 내부망을 이용할 경우 서비스 간 데이터 전송 비용이 무료이기 때문에 AWS 서비스끼리 이용할 때 더욱 절약할 수 있다. 다른 여러 방식과 비교해보았을 때 비용도 비교할 수 없을 만큼 저렴해진다는 것을 알 수 있다.

추가로 S3를 데이터 레이크(Data Lake)로 사용한다는 점도 여러모로 편리하다. 먼저 S3는 Storage Class에 따라 적재 비용이 천차만별이기 때문에 적재되는 데이터의 종류와 해당 데이터에 접근하는 패턴에 맞춰 고름으로써 적재 비용을 극적으로 절약할 수 있다. 하지만 이보다 훨씬 중요한 이유는 Athena에서 찾을 수 있다. Athena를 사용하면 적재된 데이터에 대해 복잡한 처리 없이 직접 SQL 쿼리(Query)를 날려 결과를 받아볼 수 있다. 별다른 인프라 구성없이 거대한 RDB가 만들어진 셈으로, 수년 치의 데이터를 빠르고 안정적으로 받아볼 수 있다.

마지막으로, Cloudwatch를 이용한 시스템 모니터링에 대해 살펴보도록 하겠다.

앞서 리타기팅의 로그 파이프라인으로 Lambda를 활용한 서버리스 아키텍처를 소개했는데, 이런 구조에서는 시스템이 제대로 돌아가고 있는지 어떻게 모니터링할 수 있을까? 이를 위해 AWS에서는 Cloudwatch라는 서비스를 제공해 클라우드의 각종 자원을 한 곳에서 편하게 모니터링할 수 있게끔 한다.

맨 처음 클라이언트로부터 요청이 들어오는 로드밸런서에서부터 데이터 적재 과정에서 각 람다 프로세스들이 데이터를 어떻게 가공하고 있는지, 추적 알고리즘이 얼마나 많은 유저를 추적해냈는지 등등 AWS 내의 서비스라면 모두 Cloudwatch에서 확인할 수 있다. 그뿐만 아니라 시계열 데이터에서 이상 수치들에 대해 손쉽게 알람을 설정해 의심되는 정황이 감지되면 이메일이나 문자 메시지로 바로 확인해볼 수 있다는 점 역시 Cloudwatch를 사용하는 이유 중 하나다.


맺음말
성공적인 리타기팅을 위해서는 깔끔한 데이터가 필수적이다. 데이터사이언스에서 흔히 등장하듯, garbage in, garbage out이기 때문이다. 이를 위해 사용자가 남긴 다양한 힌트들을 적절히 조합해서 해당 유저를 추적할 수 있는 정교한 알고리즘과, 수많은 요청에 대해 안정적으로 처리 · 적재 · 가공을 할 수 있는 시스템이 뒷받침되어야 한다.

그럼에도, 완벽한 리타기팅은 언제나 미결의 문제로 남을 것이다. 수많은 톱니바퀴가 각자의 역할을 갖고 돌아가는 시스템이기에, 누군가는 계속 기름칠을 하고, 닳아진 톱니바퀴를 갈아끼우고, 때로는 더욱 정교하게 만들어야 한다. 인터넷 환경은 계속 진화하고, 사용자의 행동도 그에 맞춰 계속 변화해나간다. 그렇기에, 리타기팅 문제는 매력적이다.

저작권자 © 아이티데일리 무단전재 및 재배포 금지