당근 / gcp-dataflow

2 개의 포스트

daangn

‘로컬’ 슈퍼 앱에서 장기 유저 모델링은 어떻게 달라질까? (새 탭에서 열림)

당근(Karrot)은 유저의 장기적인 행동 패턴과 여러 버티컬을 넘나드는 관심을 포착하기 위해 Transformer 기반의 장기 유저 모델링 시스템을 구축했습니다. 대규모 행동 로그를 대조 학습(Contrastive Learning)으로 학습하여 공통 유저 임베딩을 생성하고, 이를 홈피드와 광고 등 다양한 추천 지면에 적용함으로써 서비스 전반의 온라인 지표를 개선했습니다. 특히 지역 기반 서비스의 특성을 반영한 배치 샘플링 전략과 대규모 콘텐츠 임베딩 학습 기법을 통해 기술적 한계를 극복하며 개인화 추천의 품질을 한 단계 높였습니다. ### 장기 유저 모델링의 필요성과 구조적 접근 * 단기 히스토리만으로는 파악하기 어려운 계절적 취향, 이사 등 특정 시기에 발생하는 반복적 관심사, 그리고 중고거래와 알바 등 여러 서비스를 넘나드는 유저의 통합적 의도를 파악하기 위해 장기 모델링을 도입했습니다. * 실시간 랭킹 모델의 지연 시간(Latency) 문제를 해결하기 위해, 별도의 유저 인코더가 오프라인에서 임베딩을 생성하고 다운스트림 모델들이 이를 '공통 피처'로 사용하는 디커플링 구조를 채택했습니다. * 수백억 건의 다중 버티컬 로그를 활용해 유저의 다음 액션을 예측(Next Action Prediction)하는 방식으로 학습하며, 이는 기존 모델 대비 약 150배 많은 데이터를 활용한 결과입니다. ### 콘텐츠 임베딩 전환과 인프라 최적화 * 아이템 ID 기반 임베딩의 한계인 신규 아이템 대응 불가(Cold Start) 문제와 GPU 메모리 점유 문제를 해결하기 위해, LLM 기반의 콘텐츠 임베딩으로 전환했습니다. * 임베딩 테이블이 차지하던 메모리를 Transformer 모델 스케일업에 집중하여 파라미터 수를 ID 기반 모델 대비 1,000배 확장하는 데 성공했습니다. * 수백 GB 규모의 대규모 임베딩 데이터를 처리하기 위해 `memmap`을 사용하여 필요한 시점에만 데이터를 디스크에서 읽고, `bbhash(Minimal Perfect Hash)`를 통해 ID 매핑에 필요한 메모리를 97% 절감하는 기술적 최적화를 수행했습니다. ### 지역성을 고려한 지역 제한 배치 샘플링 (RCBS) * 당근은 거래의 86%가 반경 5km 이내에서 발생하는 지역 기반 서비스로, 유저가 물리적으로 볼 수 없는 지역의 아이템은 학습 시 의미 없는 부정 샘플(Impossible Negatives)이 되어 학습 신호를 희석시켰습니다. * 이를 해결하기 위해 같은 지역 유저끼리 미니배치를 구성하는 '지역 제한 배치 샘플링(RCBS)'을 도입하여, 유효한 부정 샘플(Feasible Negatives)의 비중을 2%에서 70%로 대폭 끌어올렸습니다. * 단순히 부적절한 샘플을 제거하는 마스킹 방식 대신 배치 구성을 변경함으로써, 효과적인 배치 사이즈를 유지하면서도 유저의 세밀한 취향을 구분해야 하는 '어려운 부정 샘플(Hard Negative)' 학습 효과를 얻었습니다. ### 실전 적용 및 운영 전략 * 생성된 유저 임베딩은 홈피드와 광고 랭킹 모델의 추가 피처로 입력되어 장기 취향을 보강하거나, 추천 후보(Retrieval) 모델의 독립적인 소스로 활용되어 결과의 다양성을 높였습니다. * 유저의 최신 취향을 반영하기 위해 GCP Dataflow와 Beam 파이프라인을 활용해 24시간 주기로 임베딩을 갱신하며, 최근 활동이 있는 유저만 선별적으로 추론하여 비용과 시간을 최적화했습니다. * 온라인 A/B 테스트 결과, 임베딩의 갱신 주기가 짧을수록 성능이 향상됨을 확인했으며 향후 실시간 추론에 가까운 시스템 구축을 과제로 삼고 있습니다.

daangn

당근의 사용자 행동 로그 관리 플랫폼: 이벤트센터 개발기. 코드로 관리하던 사용자 행동 로그를 플랫폼으로 만든 이유 (새 탭에서 열림)

당근은 방대한 사용자 행동 로그를 보다 효율적이고 체계적으로 관리하기 위해 기존의 Git 기반 코드 관리 방식에서 벗어나 UI 중심의 로그 관리 플랫폼인 ‘이벤트센터’를 구축했습니다. 이를 통해 복잡한 JSON 스키마 작성 과정과 수동 리뷰 절차를 자동화하여 데이터 관리 비용을 획기적으로 낮추었으며, 전사적인 로그 컨벤션을 확립해 데이터의 일관성과 분석 편의성을 동시에 확보했습니다. 결과적으로 개발자와 분석가 모두가 데이터 기반의 의사결정에만 집중할 수 있는 환경을 조성하는 데 성공했습니다. **기존 Git 기반 관리 방식의 한계** * **높은 진입장벽:** 새로운 로그 스키마를 추가하기 위해 Spark의 StructType JSON 형식을 직접 코드로 작성해야 했으며, 이는 데이터 엔지니어링 지식이 부족한 구성원에게 큰 부담이 되었습니다. * **비효율적인 프로세스:** 스키마 하나를 추가할 때마다 PR 생성, 데이터 팀의 수동 리뷰, 수정 반복 과정을 거쳐야 했기에 데이터 반영 속도가 느려지는 문제가 발생했습니다. * **일관성 없는 명명 규칙:** 이벤트 이름에 대한 강제적인 컨벤션이 없어 유사한 행동이 서로 다른 이름으로 정의되거나, snake_case와 camelCase가 혼용되는 등 데이터 정합성 관리가 어려웠습니다. **사용자 행동 로그 수집 및 처리 아키텍처** * **실시간 파이프라인:** 모바일 앱 SDK에서 발생한 이벤트는 서버를 거쳐 GCP Pub/Sub으로 전달되며, Dataflow를 통해 유효성 검증, 중복 제거, 데이터 변환(Flatten)이 실시간으로 이루어집니다. * **스키마 기반 자동 테이블 생성:** 이벤트 스키마를 정의하면 BigQuery에 해당 이벤트 전용 테이블이 자동으로 생성되며, JSON 형태의 커스텀 파라미터가 일반 컬럼으로 펼쳐져 저장되어 복잡한 쿼리 없이도 즉시 분석이 가능합니다. * **데이터 신뢰성 확보:** 스트리밍 단계에서의 단기 중복 제거와 배치 단계에서의 시간 윈도우 기반 중복 제거를 병행하여 데이터의 정확도를 극대화했습니다. **이벤트센터를 통한 로그 관리 혁신** * **UI 중심의 스키마 정의:** 코드를 직접 수정하는 대신 웹 인터페이스에서 필드명, 타입, 설명, 오너십 등을 설정할 수 있어 누구나 쉽게 로그를 설계하고 관리할 수 있습니다. * **명격한 컨벤션 적용:** '행동(Action)-서비스(Service)-대상(Object)' 구조의 명명 규칙을 시스템적으로 강제하여 이벤트 검색성을 높이고 중복 정의를 방지했습니다. * **자동화된 유효성 검사:** 스키마 변경 시 발생할 수 있는 오류를 시스템이 사전에 체크하고, 변경 사항을 즉시 데이터 파이프라인에 반영하여 운영 리소스를 최소화했습니다. 데이터의 양이 늘어날수록 로그 관리의 핵심은 '자율성'과 '통제' 사이의 균형을 잡는 것입니다. 당근의 사례처럼 로그 정의 과정을 플랫폼화하고 컨벤션을 시스템으로 강제한다면, 휴먼 에러를 줄이는 동시에 전사 구성원이 데이터라는 공통 언어를 더욱 쉽고 정확하게 사용할 수 있는 환경을 만들 수 있습니다.