LINE Timeline의 새로운 도전 2편 – Discover 딜리버리 시스템 소개

들어가며

지난 1편, LINE Timeline의 새로운 도전 1편 – 추천 콘텐츠 탐색을 위한 Discover와 새로운 구독 모델 Follow에 이어서 이번에는 Discover 딜리버리 시스템을 좀 더 자세하게 소개하려고 합니다. Discover 딜리버리 시스템은 크게 Discover Feed와 Discover 에이전트, Discover ML(Machine Learning) 서버로 구성됩니다. 이번 글에서는 Discover Feed와 Discover 에이전트를 중점적으로 살펴보고, 다음 글에서 Discover ML 서버를 다루겠습니다. 아래 그림은 1편에서 소개했던 Discover 딜리버리 시스템의 전체 흐름도입니다. Discover Feed는 6번과 7번, 8번, 10번의 역할을 담당하고, Discover 에이전트는 8번과 9번의 역할을 담당하고 있습니다. 

 

Discover 딜리버리 시스템

아래는 Discover Feed와 Discover 에이전트의 구조와 흐름을 나타낸 그림입니다.

 

Discover Feed

Discover Feed는 Discover API와 Discover CMS, Discover Consumer, Discover Batch 모듈로 구성되어 있습니다.

 

Discover API

Discover API는 다음과 같은 콘텐츠를 통합(aggregation)하여 클라이언트에게 전달하는 역할을 합니다.

  • Discover ML 에이전트 API로 추천된 콘텐츠
  • 운영자가 Discover CMS를 통해 설정한 콘텐츠 

각 모듈에서 생성된 콘텐츠 데이터를 모아 다음에 소개할 콜라주(collage) 화면이나 피드 형태의 뷰에 맞는 형태로 전환하며, 클라이언트에게 전달하기 전에 콘텐츠의 상태를 체크합니다.

 

Discover CMS

Discover CMS는 ML에서 추천된 콘텐츠뿐 아니라 위에서 언급한 오퍼레이터가 설정한 콘텐츠를 노출시키는 기능을 지원합니다. Discover CMS에서 설정된 콘텐츠는 Discover 콜라주 화면에 노출됩니다.

 

Discover Consumer

Discover Consumer는 로그를 수집하여 비동기로 처리하는 기능을 담당합니다. Discover CMS에서 설정한 특정 콘텐츠의 경우, 노출 수준을 설정할 수 있고 임프레션(impression) 값을 통해 노출 여부를 제어하고 있는데요. 이 임프레션 데이터를 Discover Consumer에서 수집합니다.

 

Discover Batch

Discover Batch는 Discover CMS에서 설정한 콘텐츠의 정보를 미리 수집하여 검증하는 역할을 수행합니다. Discover CMS에서는 노출될 포스트를 계정 및 해시태그 단위로 설정할 수 있는데요. 설정된 계정이나 해시태그와 관련된 콘텐츠를 선택하는 작업은 매번 콘텐츠가 존재하는지 확인해야 하고, 관련 정보를 얻기 위해서 콘텐츠를 조회하는 API를 호출해야 합니다. 이는 성능에 많은 부담을 주기 때문에 어떤 콘텐츠를 노출할지 미리 수집해서 필터링하는 단계를 거치는데 이 작업을 Discover Batch에서 수행합니다. 물론 계정 및 해시태그 단위로 설정한 콘텐츠 외에 Discover CMS에서 설정한 다른 콘텐츠도 이 작업을 거칩니다.

 

Discover 에이전트

Discover 에이전트는 ML 서버에서 전달한 추천 리스트를 전처리 혹은 후처리하는 시스템입니다. 사용자에게 양질의 콘텐츠를 안정적으로 서비스하기 위해 ML 서버는 콘텐츠를 추천하는 부분만 담당하고, 운영하면서 부가적으로 필요한 부분은 에이전트가 처리하도록 구성했습니다. 이번 글에선 Discover 에이전트의 여러 구성 요소들 중 위 상세 구조도에서 소개된 몇 가지 주요 모듈에 대해 간단하게 소개하겠습니다.

 

페일오버(failover) 스케줄러

페일오버 스케줄러는 안정적인 서비스를 위해 가장 먼저 고려한 부분 중 하나입니다. 에이전트에게 콘텐츠를 제공하는 ML 서버는 최신 데이터를 이용해 주기적으로 새로운 콘텐츠 풀(pool)을 만들고 이렇게 생성된 콘텐츠 풀을 이용하여 새로운 모델을 만듭니다. 새로운 모델이 서비스되면 새 모델에서 사용하고 있는 콘텐츠 풀과 이전 모델에서 사용했던 콘텐츠 풀이 다르기 때문에, 이전 모델에만 존재하는 콘텐츠에 대한 요청이 발생했을 때 정상적으로 응답하지 못하는 경우가 발생합니다. 이런 경우에도 정상적으로 서비스하면서 서비스의 품질을 유지하기 위해서 페일오버 모듈을 만들고 스케줄러가 페일오버 풀을 관리하도록 구성했습니다.

 

필터 스케줄러

필터 스케줄러는 콘텐츠의 품질을 관리합니다. ML 서버는 사용자의 요청에 따라 사용자가 관심을 가질만한 콘텐츠를 추천하기도 하고 요청한 것과 유사한 콘텐츠를 추천하기도 합니다. 이때 추천된 콘텐츠가 서비스하기 적합한지 판단하기 위해 필터링 서버가 추천 풀의 콘텐츠를 검사합니다. 필터 스케줄러는 주기적으로 필터링 정보를 갱신하여 최대한 빠른 시간에 필터링 정보가 적용될 수 있도록 작동합니다. 

이 외에도 ML 서버의 부하를 줄이고 페이징(paging)을 지원하기 위한 캐싱 기능과 A/B 테스트를 지원하는 모듈 등이 있고 이를 관리하기 위한 관리자 화면도 제공합니다. 추후 카테고리 서비스를 위한 모듈도 개발 중이며 이 모듈은 현재 유사 콘텐츠 추천에도 사용하고 있습니다. 

 

콘텐츠 딜리버리

이제 Discover에서 어떤 콘텐츠를 다루며 어떤 과정을 거쳐 사용자에게 전달하는지 살펴보겠습니다.

 

Discover에서 다루는 콘텐츠

Discover에서 다루고 있는 기본 콘텐츠는 포스트입니다. 사용자가 전체 공개 포스트를 작성하면 타임라인 탭뿐 아니라 Discover에도 추천되어 노출될 수 있습니다(Discover 서비스의 특성상 시각화가 가능해야 하기 때문에 추천되는 포스트에는 비디오 혹은 이미지가 포함되어 있어야 합니다). 그렇다면 Discover에 추천되기 위해서는 무조건 포스트로 작성해야 할까요? 그렇지 않습니다. Discover는 다양한 콘텐츠를 담을 수 있도록 유연한 구조로 개발되었습니다. 셀 뷰의 모델을 단순하게 만들었고, Discover에 연동되는 각 콘텐츠가 이 규칙을 지키도록 가이드하고 있습니다. 복잡한 로직은 서버 안으로 감추고, 클라이언트로 전달하는 데이터는 간소화하는 전략을 사용하고 있습니다. 아래는 뷰 모델 클래스 일부를 발췌한 내용입니다. 

public class DiscoverFeedView {
    //Tile View
    private GridBoxSpan span;
    private MediaView thumbnailMedia;
    private Url actionUrl;
    private DiscoverTitle DiscoverTitle;
    private DiscoverInfo DiscoverInfo;
 
    // Original Contents
    private DiscoverOriginContents contents;
...
 
}
 
public class Post implements DiscoverOriginContents
public class DiscoverAD implements DiscoverOriginContents
public class Campaign implements DiscoverOriginContents
...

Discover에서 표현되는 콘텐츠는 섬네일과 터치했을 때 이동할 URL, 이미지 위에 오버랩될 타이틀 등 기본적인 동작과 뷰를 위한 필수적인 공통 요소를 갖추도록 정의했고, 필요할 경우엔 원본 콘텐츠를 전달하도록 구현했습니다. 이를 통해 어떤 콘텐츠라도 클라이언트의 수정 없이 Discover에 노출할 수 있습니다. 또한 포스트 외에도 이벤트를 위한 콘텐츠 및 광고 콘텐츠까지 다양한 유형의 콘텐츠를 전달하고 있으며, 앞으로도 더 다양한 유형의 콘텐츠가 추가될 예정입니다.

Discover에서는 한 번에 많은 수의 콘텐츠를 볼 수 있는 타일 유형의 뷰로 다양한 유형의 콘텐츠를 제공하고 있습니다. 보통 타일이라고 하면 정사각형을 생각하실 텐데요. Discover는 세로로 긴 직사각형을 채택했습니다. 기본 콘텐츠인 포스트에 포함된 이미지의 비율을 조사한 결과 정사각형보다는 직사각형 비율의 이미지가 많았고, 여기에 조금 더 세련된 느낌을 강조하기 위해서 세로로 조금 더 긴 모양의 셀을 채택했습니다. 아래는 정사각형 셀을 사용한 모습과 직사각형 셀을 사용한 모습을 비교한 샘플입니다.

정방형Discover

Discover에선 한 페이지에 노출되는 이미지의 수가 비교적 많기 때문에 이미지의 크기를 고려하지 않을 수 없습니다. 그래서 크기를 줄이기 위해 일정 비율로 노출되도록 대표 이미지를 크롭(crop) 처리하고 있습니다. 그런데 인물 이미지의 경우 크롭 작업 중 얼굴 부분이 잘릴 수 있는데요. 이를 방지하기 위해 인물 사진은 이미지 분석 기술을 보유하고 있는 LINE의 Vision AI 플랫폼 PicCell과 연동하여 얼굴이 잘리지 않도록 크롭 처리를 진행하고 있습니다. 이렇게 유용한 도구와 기술이 LINE에 많았기 때문에 더욱 빠른 속도로 개발을 진행할 수 있었다고 생각합니다.

원본결과물

 

콘텐츠 정제

앞서 Discover CMS에서 설정한 콘텐츠를 Discover Batch에서 수집한다고 말씀드렸습니다. 이때 콘텐츠를 효율적으로 수집하기 위해서 여러 콘텐츠를 수급하는 잡(job)을 각각 등록하고, 잡 매니저를 통해 프로세서들이 배치 잡을 중복으로 처리하지 않도록 관리합니다. 또한 노출할 콘텐츠를 수집할 때 콘텐츠가 정상인지 노출시켜도 괜찮은지 확인하는 단계를 거칩니다. 포스트는 Timeline 포스트 API를 통해 검증하고, 정상적인 포스트는 ‘Refined Post’라고 부르는 후보 풀에 담습니다. 위에서 언급했던 계정이나 해시태그 단위로 설정하는 것을 캠페인이라고 하는데요. 이렇게 캠페인에서 설정한 콘텐츠도 검증합니다. 예를 들어 설정이 계정(account)으로 되어 있다면 해당 계정의 최근 포스트를 조회해서 후보 풀에 포함시킵니다.

이런 작업은 매번 조회하는 경우엔 트래픽에 부담을 주기 때문에 특정 주기를 설정해서 실행합니다. 풀에 담긴 포스트는 추천 필터를 통해 최종 노출 여부를 결정합니다(이번 글에서는 지면 관계상 이와 관련된 자세한 내용은 생략하겠습니다). 포스트 이외의 콘텐츠는 콘텐츠 제공자가 제공한 API를 통해 콘텐츠를 검증하고 노출합니다.

 

캠페인 임프레션(impression)

Discovery에선 캠페인으로 등록된 콘텐츠가 너무 많이 노출되지 않도록 조정할 수 있습니다. 이 기능을 구현하기 위해서 집계 시스템이 필요했는데요. 자체적으로 간단하게 구현하는 것도 고려했으나 사용자별 임프레션 등 구현 난이도가 좀 높아서 비효율적이라고 판단했습니다. 대신 이미 만들어진 사내 솔루션을 살펴보았고, 그중에서 GCS(General pupose Counter System)란 시스템이 눈에 들어왔습니다. GCS에서는 서비스에서 필요한 수치를 정의하고 측정할 수 있도록 지원하고 있어서 GCS를 이용하기로 결정하고 연동했습니다. LINE에서 최소한으로 수집할 수 있는 사용자의 행동 정보는 LINE의 데이터 웨어하우스로 저장되며, 이 데이터가 저장되는 파이프라인은 Kafka를 사용하고 있습니다. 따라서 이 Kafka에 연결하면 필요한 정보를 얻을 수 있으며, 이 정보를 가공하여 GCS 시스템에 집계되도록 설계했습니다. 이런 방법으로 딱 필요한 비즈니스 로직만 구현하면서 리소스 낭비도 줄이고 원하는 결과도 얻을 수 있었습니다. 

 

추천 콘텐츠 풀 설계

ML 서버에서 생성하는 모델은 사용자에게 적절한 콘텐츠를 제공하기 위해 주기적으로 학습과 배포를 반복하고, 이때 사용되는 콘텐츠는 최신의 콘텐츠로 계속 갱신됩니다. 새로운 모델은 이전에 사용된 콘텐츠와 중복되는 부분도 있지만, 사라지는 콘텐츠와 새로 추가되는 콘텐츠도 있습니다. 따라서 이전 모델에서 서비스한 콘텐츠를 가지고 있는 사용자와 현재 모델에서 제공하는 콘텐츠 간에 간극이 발생할 수 있는데요. 이런 문제를 해결하기 위해 콘텐츠 풀을 설계하면서 이전 콘텐츠 풀과 새로운 콘텐츠를 중첩하는 방식을 사용했습니다. 에이전트는 항상 최신의 모델과 통신하면서 지난 콘텐츠 풀도 조회할 수 있습니다. 덕분에 이전 콘텐츠에 대한 요청에도 적절하게 응답할 수 있습니다. 아래 그림과 함께 예시를 들어보겠습니다. 

현재 시간이 T2라고 가정한다면 서비스 모델과 콘텐츠 풀, 에이전트 참조 풀은 아래와 같습니다.

  • 서비스 모델 : Model-T2(=Mt2)
  • 콘텐츠 풀 : ContentPool-T2(=CPt2)
  • 에이전트 참조 풀 : ARP(=CPt0+CPt1+CPt2) 

에이전트가 참조하는 콘텐츠 풀은 모델 Mt0~Mt2가 생성한 CPt0~CPt2 전체를 참조할 수 있도록 설계했습니다.

최근에 모델이 변경되었는데 사용자가 지난 시간에 생성된 콘텐츠 풀의 데이터를 요청했다고 가정해보겠습니다. 만약 해당 콘텐츠가 이번 모델에 포함되어 있다면 모델은 정상적으로 응답할 수 있습니다. 하지만 해당 콘텐츠가 이번 모델에 포함되어 있지 않다면 그렇지 않은데요. 이런 경우엔 페일오버를 통해 서비스합니다. 

페일오버를 통해 서비스하는 경우엔 ARP(Agent Reference Pool) 전체에 카테고리 서비스 로직을 적용하고 유사 콘텐츠를 추출하여 품질을 보장하도록 고려했습니다. 

 

추천 콘텐츠 필터링

모델이 새로 학습하여 새로운 콘텐츠를 추천 풀에 추가하고 새로운 모델이 서비스를 시작하면, ML 서버는 새로 추가된 콘텐츠를 응답에 포함시킵니다. 이때 풀에 추가된 콘텐츠는 바로 사용자에게 제공되지 않습니다. 다양한 방법으로 검증한 뒤 이 검증을 통과한 콘텐츠만이 실제 사용자에게 제공됩니다. 여러 종류의 콘텐츠 필터링이 있고, 아래 그림과 같이 각 상황에 맞는 필터와 기능이 수행됩니다.

현재 적용 중인 필터와 기능은 다음과 같습니다.

  • 필터
    • 텍스트 필터: 콘텐츠에 특정 단어들이 포함된 경우 필터링을 수행합니다.
    • 성인물(adult) 필터: 콘텐츠에 포함된 이미지에 성인물이 포함된 경우 필터링을 수행합니다.
    • 광고(AD) 필터: 콘텐츠에 포함된 이미지가 광고라고 판단되면 필터링을 수행합니다.
    • OCR(Optical character recognition) 필터: 콘텐츠에 포함된 이미지에서 글자가 일정 면적 이상을 차지할 경우 필터링을 수행합니다.
    • 안면인식 필터: 콘텐츠에 포함된 이미지에 공인이 아닌 사람이 인식될 경우 필터링을 수행합니다.
  • 기능
    • LMP(Line Monitoring Platform): 필터를 모두 통과했을 경우 직접 검수를 수행합니다.
    • 이미지 해시: 같은 이미지가 중복 노출되지 않도록 이미지 해시를 이용해서 필터링이 완료된 콘텐츠를 그룹으로 묶습니다.
    • CDN(Content Delivery Network) 캐시: 클라이언트에서 섬네일 이미지를 빠르게 볼 수 있도록 캐시 기능을 제공합니다.

 

새로운 모델을 위한 A/B 테스트

새로운 모델을 개발하면 기존 모델과 비교해 성능이 향상되었는지 평가하는 과정이 필요합니다. 그래서 요청의 일부분을 새로운 모델로 전달하여 사용자에게 제공한 뒤, 이후 발생하는 사용자 로그를 기반으로 새로운 모델의 성능을 평가하고, 이 평가를 기반으로 기존 모델을 새로운 모델로 변경할 것인지 판단합니다. 이런 평가는 실제 사용자 요청에 기반해야 보다 정확한 결과를 얻을 수 있기 때문에 서비스 중에 임의로 테스트가 가능하도록 구현했습니다.

현재 구현된 A/B 테스트 모듈의 특징은 다음과 같습니다.

  • 사용자 기반의 테스트 그룹 설정 지원
  • 국가별 혹은 모델별 테스트 설정 지원
  • 동시에 여러 개의 모델 테스트 지원
  • 서비스 무중단 테스트 지원

 

맺으며

이번 글에서는 Discover 서비스 중 딜리버리 시스템을 소개했습니다. 보통 웹 기반 서비스에서 많이 이용하는 기술들을 사용했기 때문에 기술에 대한 자세한 설명보다는 저희가 제공하는 Discover 서비스에 특화된 부분을 주로 다루었습니다. Discvoer 서비스의 핵심은 ‘어떻게 사용자가 원하는 콘텐츠를 추천하는가’ 혹은 ‘어떻게 유사한 콘텐츠를 제공하는가’라는 문제일 텐데요. 이어지는 3편에서 저희가 이런 문제를 어떻게 해결했는지 다루겠습니다. 많은 기대 바랍니다.

Related Post