쿠팡 검색 엔진 성능 가속화

검색 엔진 성능 가속화를 위해 쿠팡의 인덱싱 플랫폼이 변화해온 과정

쿠팡 엔지니어링
Coupang Engineering Blog
6 min readAug 3, 2022

--

By Winter Wang

검색창 이미지

본 포스트는 영문으로도 제공됩니다.

쿠팡에서 검색은 고객 여정이 시작되는 곳입니다. 검색이 쿠팡의 미션인 ‘‘Wow the customer’에 있어 핵심이 되는 이유입니다. 쿠팡 검색 엔진은 사용자의 검색 키워드 입력 시 최고의 결과를 제공하는 것을 목표로 하고 있습니다. 전통적인 검색 엔진에서는 관련성이 가장 중요한 요소이지만 쿠팡의 검색 엔진에서는 상품의 랭킹, 고객의 상품평, 가격, 브랜드 등 또한 고려되어야 합니다.

이 포스트는 먼저 쿠팡의 검색 엔진이 동작하는 방식에서 시작해 핵심 컴포넌트인 검색 인덱싱 플랫폼이 어떻게 변해왔는지를 공유해보려 합니다.

목차

검색 엔진 아키텍처
1단계: 인덱싱 플랫폼 0.1
2단계: 인덱싱 플랫폼 1.0
3단계: 인덱싱 플랫폼 2.0
향후 계획

검색 엔진 아키텍처

쿠팡 검색 엔진 아키텍처
그림 1. 쿠팡 검색 엔진 아키텍처

쿠팡 검색 엔진의 전체 아키텍처는 위와 같습니다. 검색 요청 시, 쿠팡 검색 엔진은 다음 3 단계의 과정을 거치며 해당 요청을 처리합니다.

  1. 검색어(Query) 이해: 검색어의 의도와 검색어의 주석, 즉 카테고리 혹은 브랜드 등을 이해합니다.
  2. 조회(Retrieval): 검색어와 상품의 텍스트 정보를 바탕으로 검색 결과 후보들을 찾습니다.
  3. 랭킹: 랭킹 함수나 ML 모델을 적용하여 후보들의 순위를 매깁니다. 랭킹 함수는 랭킹 시그널을 사용해 보통 각 후보에 대한 점수를 제공하고 이 루틴을 빠르게 반복 실행합니다.

랭킹 알고리즘은 검색 경험 개선하는 데 유용합니다. 랭킹 알고리즘은 신뢰할 수 있는 데이터 소스와 랭킹 시그널에 기반을 두고 있습니다. 쿠팡에는 수백만 개의 상품 데이터와 페타바이트 규모의 고객 행동 데이터가 있습니다. 그렇다면 어떻게 해야 이러한 데이터를 효율적으로 활용하여 강력한 시그널을 이끌어낼 수 있을까요? 저희가 찾은 해답은 바로 인덱싱 플랫폼이었습니다.

인덱싱 플랫폼

인덱싱 플랫폼은 쿠팡 엔지니어들이 효율적인 검색 및 랭킹 시스템을 개발하는데 필요한 모든 것을 제공하는 기반이자 공장이라고 할 수 있습니다. 인덱싱 플랫폼은 확장 가능한 플랫폼이 되기 위해, 데이터를 다양한 원본(Ground Truth) 데이터 테이블로부터 수집하고, 프로덕트 쿼리가 지정한 키로 데이터를 비정규화하고, 검색 엔진 인덱스를 구축하하는 것이 가능한 플랫폼을 목표로 하고 있습니다. 또한 인덱스 플랫폼을 통해 랭킹 엔지니어들의 생산성도 향상시키려고 합니다.

다음 섹션에서는 인덱싱 플랫폼이 상기의 목표와 확장되어가는 비즈니스 니즈를 달성하기 위하여 어떻게 성장해왔는지를 설명하려고 합니다.

1단계: 인덱싱 플랫폼 0.1

쿠팡 인덱싱 플랫폼의 시작
그림 2. 쿠팡 인덱싱 플랫폼의 시작

초창기 쿠팡에서 판매되는 상품들은 지금처럼 아주 많지 않았습니다. 대부분의 원본 상품 데이터, 즉 가격, 브랜드, 카테고리 등을 관계형 데이터베이스에 저장했습니다. 인덱싱 플랫폼의 첫번째 버전에서는 관계형 데이터베이스의 SQL엔진을 사용해 상품 키(product key)로 복수의 테이블을 조인한 다음 비정규화된 단일 테이블로 병합했습니다. 그 다음 인덱싱 플랫폼이 비정규화된 테이블로부터 데이터를 온라인 서빙 검색 클러스터(Online Serving Search Cluster)로 보냅니다. 검색 엔진은 상품의 텍스트 정보와 일부 간단한 랭킹 시그널을 바탕으로 조회 후보군(retrieval candidates)을 제공하기 위해 인덱스를 사용합니다.

그러나 상품의 개수가 빠르게 증가하면서 이런 단순한 인덱싱 플랫폼으로는 증가하는 데이터 볼륨을 감당할 수 없었고 기존 문제들 중 다수는 상태가 더 악화되었습니다. 다음은 당시 저희가 직면했던 문제들 중 일부입니다.

  • 지나친 단순화. 이 단계에서의 인덱싱 플랫폼은 사실 플랫폼답지 못했습니다. 단지 원본 데이터 세트와 온라인 서빙 검색 클러스터 사이를 연결해주는 커넥터에 불과했습니다. 검색 엔진에 대한 각종 니즈를 충족시키기에는 너무 단순했습니다.
  • 미약한 확장성. 당시 인덱싱 플랫폼은 확장성이 없다보니 더 많은 양의 데이터가 주어졌을 때 제대로 처리할 수가 없었습니다. 예를 들어, 온라인 서빙 검색 클러스터의 복제본 구축 시, 동일한 인덱스를 처음부터 다시 연산해야 했는데 이러한 자원 낭비가 확장성에 영향을 미쳤습니다.
  • 비효율적이고 부족한 성능. 플랫폼의 여러 단계에서 에러가 자주 발생했고 처리 속도도 느렸습니다. 예를 들어, 온라인 서빙 검색 클러스터에서 인덱스를 구축하는 속도는 극도로 느렸고, 구축 과정에서 자원도 많이 소모됐습니다. 대규모 테이블을 수십 개 조인할 때, 관계형 데이터베이스의 SQL 엔진은 느려졌고 불안정해졌습니다. 랭킹 엔지니어들이 며칠 안에 조회 및 랭킹 시그널을 추가하는 작업도 거의 불가능했습니다.

2단계: 인덱싱 플랫폼 1.0

인덱싱 플랫폼1.0 아키텍처의 개요
그림 3. 인덱싱 플랫폼 1.0 아키텍처의 개요

쿠팡의 고속 성장을 뒷받침하기 위해, 인덱싱 플랫폼을 쉽게 확장가능한 분산형 서비스 플랫폼으로 재설계하기로 결정했습니다.

먼저 데이터 소스를 재정비했습니다. 신규 플랫폼은 분산 데이터 처리용 오픈 소스 플랫폼으로 널리 쓰이는 하둡(Hadoop)으로 구축했습니다. 관계형 데이터베이스가 병목 현상의 주요 원인이었기에 모든 원본 데이터를 하이브(Hive)로 복제했습니다. 또한 랭킹 시그널은 플랫폼으로 병합이 가능한 하이브 테이블로 생성했습니다. 이제 검색 인덱스를 구축하는데 필요한 데이터 모두가 하둡 플랫폼에 위치하게 되었습니다.

그리고 나서 저희는 데이터를 효율적으로 병합하고 저장하기 위한 방법을 고안하였습니다. 인덱스 머저(Index Merger)을 스파크잡(Spark Job)으로 개발해 모든 상품 데이터를 병합할 수 있도록 만들었습니다. 데이터 병합 시, 모든 상품 데이터는 먼저 프로덕트 조인(ProductJoin)이라 불리는 프로토콜 버퍼(Protobuf)구조로 저장된 후 최종적으로 HBase에 저장되었습니다.

마지막으로 또 다른 스파크 잡인 인덱스 빌더(Index Builder)를 개발했습니다. 이 인덱스 빌더는 ProductJoin의 데이터를 사용해 검색 인덱스를 생성했습니다. 인덱스 빌더의 결과물은 서비스용 온라인 서빙 클러스터에서 직접 액세스 가능한 분산 스토리지에 저장되었습니다. 이 시스템에서 모든 복제본은 시스템이 제공하는 인덱스를 사용할 수 있었고 인덱스를 재구축할 필요도 없었습니다.

쿼리 데이터에도 동일한 파이프라인을 구축하여, 검색어 이해 부분에 대한 지원 수준을 더 높였습니다.

인덱싱 플랫폼 0.1과 인덱싱 플랫폼 1.0의 비교하는 표
표 1. 인덱싱 플랫폼 0.1과 인덱싱 플랫폼 1.0의 비교

3단계: 인덱싱 플랫폼 2.0

인덱싱 플랫폼의 또 다른 주요 역할은 랭킹 엔지니어가 시그널을 개발할 때 엔지니어의 잠재적 생산성이 더 펼쳐질 수 있도록 돕는 것입니다. 인덱싱 플랫폼 1.0이 성능과 확장성 이슈는 해결했지만 엔지니어가 시그널 개발을 더 빠르고 효율적으로 할 수 있도록 지원하는 데에는 부족했습니다.

문제점

예전에는 랭킹 엔지니어들이 데이터 소스 찾기와 워크플로우의 일정 수립에 상당히 많은 시간을 사용했습니다. 신규 시그널을 구축하기 위해 랭킹 엔지니어는 원시 로그의 파싱부터 시작해서 시그널을 구축하는 전체 파이프라인을 구성해야만 했고, 하이브 쿼리와 스파크잡 개발 등에 몇 시간이나 들여야 했습니다. 게다가 그러한 개별 파이프라인이 약 70개나 되어 관리가 거의 불가능할 정도였으며 리소스 낭비는 말할 것도 없었습니다.

아키텍처 개요

인덱싱 플랫폼 2.0 아키텍처
그림 4. 인덱싱 플랫폼 2.0 아키텍처

엔지니어링 효율성의 제고를 위해, 각 랭킹 엔지니어가 데이터 소스의 오염, 전체 데이터 파이프라인 개발, 워크플로우 일정 수립 등과 같은 일에 신경 쓰지 않고 오로지 시그널의 로직 구현에만 집중할 수 있도록, 인덱싱 플랫폼 2.0을 인덱싱 버스(Indexing Bus)로 구현하였습니다.

우선, 스파크잡인 세션 로그 파서(Session Log Parser)가 원시 로그 파싱 기능을 제공합니다. 즉 고객 행동 데이터를 파싱하고 병합하여 세션 로그 데이터세트(Session Log Dataset)를 생성합니다. 또한 마찬가지로 스파크잡인 원본 데이터 머저(Ground Truth Merger)는 모든 상품 데이터를 병합하여 엔지니어가 손쉽게 상품 원시 데이터에 액세스할 수 있게 해줍니다. 구현에 스파크잡을 사용한 이유는 확장의 용의성 때문이었습니다.

인덱싱 플랫폼 2.0에서 달라진 중요한 점 또 한가지는 인덱싱 플랫폼 1.0과 달리 외부 하이브 테이블의 병합 과정 없이도 플랫폼 상에서 직접 랭킹 시그널을 생성할 수 있다는 점입니다. 원본 상품 데이터와 세션 로그 모두에 쉽게 액세스할 수 있기 때문에 인덱싱 플랫폼에서 직접 이들 데이터 세트를 기반으로 시그널을 파생할 수 있도록 프로덕트 조이너(ProductJoiner)와 쿼리 조이너(QueryJoiner)를 개발했습니다.

이 프레임워크의 정수는 상품 데이터와 검색어 데이터 등 모든 데이터세트가 상품 혹은 쿼리 시그널의 생성 도중에 사용된다는 것입니다. 이러한 정보의 교류로 인해 매우 강력한 시그널이 만들어집니다. 예를 들어, 프로덕트 조이너의 상품 데이터인 가격을 활용해 쿼리 조이너에서 쿼리 랭킹을 구축할 수 있습니다. 엔지니어는 쿼리 혹은 상품 가격 분포를 바탕으로 상품의 순위를 높이거나 낮추는 시그널을 구축할 수 있습니다. 상품 가격처럼 단순한 무엇인가가 강력한 랭킹 시그널로 변환되는 것입니다.

시그널 생성 과정

단일 시그널 프로세서의 워크플로우
그림 5. 단일 시그널 프로세서의 워크플로우

쿼리 조이너가 시그널을 생성하는 단계는 다음과 같습니다.

  1. 상품 원본 데이터와 파싱된 세션 로그를 모두 포함하는 소스 데이터를 로드(load)
  2. 노출, 클릭, 구매 등의 기본으로 집계되는 원시 고객 행동 데이터를 쿼리 수준 및 상품 수준에서 생성
  3. 모든 시그널 프로세서를 실행해 시그널을 생성
  4. 생성된 시그널을 HBase에 저장

비용 최적화

인덱싱 플랫폼 2.0 구현 이전 및 이후의 효율성 비교하는 표
표 2. 인덱싱 플랫폼 2.0 구현 이전 및 이후의 효율성 비교

인덱싱 플랫폼 2.0이 로그 파싱 프로세스와 원시 시그널 생성 프로세스를 플랫폼으로 직접 통합하면서, 신규 시그널 구축이 마치 클래스 구현이나 데이터 처리를 위한 로직 추가 정도로 쉬워졌습니다. 표2는 신규 플랫폼으로 증가된 효율성을 보여줍니다.

전반적으로 인덱싱 플랫폼 2.0은 운영 이슈를 제거하고 단위 테스트 및 통합 테스트 방법을 제공하면서 랭킹 엔지니어는 고품질의 랭킹 시그널을 몇 시간 내에 구축할 수 있게 되었습니다. 플랫폼이 클러스터 리소스를 효율적으로 사용하게 되면서, 제고된 장점들 모두 저비용으로 구현되었습니다.

향후 계획

여기까지는 아직 시작에 불과하고 아직도 해야할 일은 많습니다. 현재 구축한 시스템은 인덱싱 플랫폼의 첫번째 단계로서 상품과 검색어의 관계를 도출합니다. 향후에는 고객, 상품, 검색어, 브랜드, 기타 데이터 간의 비슷한 관계성을 활용한 플랫폼을 구축하고자 합니다. 강력한 인덱싱 플랫폼을 구축하면 추천이나 광고 같은 쿠팡의 다른 비즈니스 영역도 마찬가지로 지원 가능하다고 생각합니다. 인덱싱 플랫폼의 궁극적인 최종 목표는 쿠팡 비즈니스를 뒷받침하는 브레인이 되는 것입니다.

빠르게 급변하는 환경 속에서 열정적인 개발자들과 함께 어려운 문제를 해결해 나가는 일에 관심이 있으시다면, 쿠팡의 채용 중인 포지션을 지금 한번 확인해보세요!

--

--

쿠팡 엔지니어링
Coupang Engineering Blog

쿠팡의 엔지니어들은 매일 쿠팡 이커머스, 이츠, 플레이 서비스를 만들고 발전시켜 나갑니다. 그 과정과 결과를 이곳에 기록하고 공유합니다.