레이블이 Netflix인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Netflix인 게시물을 표시합니다. 모든 게시물 표시

2/27/2021

넷플릭스의 확장 가능한 플랫폼 만들기

본 글은 Netflix Tech 블로그의 을 의역하여 작성한 글입니다.

배경

Netflix는 지난 10년 간 주문형 스트리밍 비디오 서비스를 제공하고 있습니다. 서비스를 제공하는 기간동아 Netflix는 전 세계 고객 확보를 위해 30일간 무료 평가판과 결합된 3가지 요금제(기본, 표준, 프리미엄)에 의존했습니다. 하지만 지금 세상은 과거에 비해 많이 변했습니다. 사람들의 여가 시간을 채울 경쟁이 증가하고 있고 디바이스 생태계가 경이적으로 성장했으며 소비자는 언제 어디서나 원하는 디바이스로 콘텐츠를 시청하기를 원하고 있습니다.

Netflix의 Growth 엔지니어링 팀은 이런 변화를 예상하고 적응하는데 도움이 되는 Growth Initiatives를 실행하는 역할을 담당합니다. 전 세계 고객에게 가장 적합한 요금제 플랜과 인센티브로 Netflix에 가입 할 수 있도록 하는 시스템과 프로토콜을 설계하고 구축하는 것이 Growth 엔지니어링 팀의 역할입니다.


사용자 가입 경로

Netflix의 가입 경로는 3단계가 있습니다. Netflix에서는 “Signup Flow”라고 부릅니다.

1. 소개 및 계정 생성

Netflix의 가치를 소개하고, 고객이 가입을 할 수 있도록 유도합니다.

2. Plans & offers

다양한 유형의 Netflix 요금제를 offering 합니다.

3. Payment

고객이 자신의 요구에 가장 잘 맞는 것을 선택할 수 있도록 다양한 결제 옵션을 제공합니다.

서비스 소개 및 계정 생성 부분은 어느 서비스나 비슷하기에 2,3번에 대해 Netflix가 시장에 어떻게 대응하고 있는지 설명을 하려 합니다.

Plans & offers

Definitions

Netflix에서 Plan과 Offer가 무엇인지 정의 해 보겠습니다. Plan은 기본적으로 가격이 있는 기능 세트입니다.


Offer는 제한된 시간 동안 요금 할인 또는 우수한 기능을 포함하는 Incentive입니다. 일반적으로 Offer는 하나 이상의 Incentive와 속성 세트로 구성됩니다.

제안은 일반적으로 제한된 시간 동안 금전적 할인 또는 우수한 제품 기능을 포함하는 인센티브입니다. 일반적으로 오퍼는 하나 이상의 인센티브와 속성 세트로 구성됩니다.


Plan과 Offer를 병합하여 고객에게 제시하면 Plan 선택 페이지에 표시됩니다. 여기서는 선택한 Plan에 관계없이 3개의 Plan과 30일 무료 평가판이 있음을 확인할 수 있습니다.

지금까지 Netflix의 요금제 관련한 비즈니스적인 설명을 하였고, 이제 연관된 아키텍처, 프로토콜 및 시스템에 대해서 살펴 보도록 하겠습니다. 일반적으로 사람들은 비즈니스와 기술을 분리하는 경향이 있는데., 모든 기술은 비즈니스를 위해 고려되어야 하며, 이를 근간으로 아키텍처가 확립 됩니다.

Legacy 아키텍처

위에서 설명했듯이 Netflix는 스트리밍 서비스를 시작한 후 정적인 Plan과 Offer를 가지고 있었습니다. 따라서 아키텍처 또한 매우 간단했습니다. 기술적으로는 런타임에 로드되고 로컬 메모리에 저장된 작은 XML 파일 세트로 구성했습니다. 수년 동안에는 완벽하게 최적화된 디자인이었습니다. 그러나 Netflix가 계속 성장하고 서비스가 발전함에 따라 몇 가지 문제점이 생겼습니다.

  • XML 파일 업데이트는 본질적으로 오류가 발생하기 쉽고 수동적이다.
  • XML 파일이 업데이트 될 때마다 서비스 전체 배포가 필요하다.
  • XML 파일을 업데이트하려면 이 파일을 소유한 Backend 엔지니어팀의 참여가 필요하다. 타 팀의 지원을 받아야 하기에 독립적으로 업무를 수행하기가 어렵다.
  • UI를 렌더링하기 위한 클라이언트 로직이 필요하다. (아래는 30일 무료 평가판에 대한 데이터 구조입니다.)

{
“offerId”: 123,
“planId”: 111,
“price”: “$ 8.99”,
“hasSD”: true,
“hasHD”: false,
“hasFreeTrial”: true
…
}

  • 전 세계 고객에게 서비스가 제공됨에 따라 위의 모든 문제가 더욱 악화된다.

다음은 Plan & Offer 데이터 검색과 관련된 다양한 시스템을 표현한 그림입니다.


새로운 아키텍처

Growth 엔지니어링팀은 거의 모든 플랫폼에 대해 가볍고 유연한 애플리케이션을 구축 할 수 있는 비즈니스 로직과 프로토콜을 담당하고 있습니다. 이는 Presentation Layer에 비즈니스 로직이 없어야 하며 전달되는 데이터를 렌더링하는 책임을 지니고 있음을 의미합니다. 이를 달성하기 위해 Netflix는 우려 사항 및 분리 설계 원칙을 강조하는 마이크로 서비스 아키텍처를 채택하고 설계했습니다. 아래는 Legacy 아키텍처에서 업데이트된 신규 아키텍처입니다.


위 아키텍처를 보면 두 가지 변경 사항이 있습니다.

첫째, SKU Domain Services입니다. 이 서비스에는 오케스트레이션 서비스의 일부였던 특수 비즈니스 로직이 포함되어 있습니다. 이 로직을 새로운 마이크로 서비스로 마이그레이션함으로써 오케스트레이션 서비스를 단순화하고, 도메인에 대한 소유권을 명확히합니다. 이렇게 함으로써 다른 서비스도 SKU 데이터를 사용할 수 있습니다.

둘째, SKU 서비스가 이제는 Rule Engine과 SKU Catalog DB를 활용하는 플랫폼으로 확장 되었습니다. 이 플랫폼은 Growth 엔지니어링팀이 코드 변경 겅의 없이 전 세계 고객을 위해 다양한 서비스 제공을 실험할 수 있기 때문에 엄청난 비즈니스 가치를 제공합니다. 이는 엔지니어가 지루한 작업을 수행하는데 소요되는 시간을 줄이고 미래의 요구에 잘 대응할 수 있는 조금더 창의적인 작업에 더 많은 시간을 할애 할 수 있음을 의미합니다.

1단계: 디바이스가 Plan 선택 페이지에 대한 요청을 보냅니다.

과거에는 클라이언트 UI와 중간 계층 오케스트레이션 서비스간에 사용자 지정 JSON 프로토콜을 사용했었습니다. Plan 선택 페이지를 검색하기 위한 브라우저 요청에 대한 프로토콜의 예는 아래와 같습니다.


GET /plans
{
“flow”: “browser”,
“mode”: “planSelection”
}

이 요청에는 두 가지 중요한 정보가 존재합니다.

  • flow: flow는 플랫폼을 식별하는 정보입니다. 이를 통해 오케스트레이션 서비스는 해당 요청을 적절한 플랫폼에 라우팅 할 수 있습니다.
  • mode: 요청되는 페이지의 이름입니다.

flow와 mode 정보에 의해 오케스트레이션 서비스가 요청을 처리하게 됩니다.

2단계: 요청 처리를 위해 오케스트레이션 서비스로 라우팅합니다.

오케스트레이션 서비스는 upstream 요청의 유효성을 검사하고, downstream 서비스에 대한 호출을 오케스트레이션하고, JSON 응답을 작성합니다. 특정 요청의 경우 오케스트레이션 서비스를 SKU Eligibility 서비스에서 SKU 데이터를 검색하고 UI 레이어에서 사용할 수 있는 JSON 응답을 빌드합니다.

해당 요청에 대한 JSON 응답은 아래와 같습니다. 아래의 응답은 재사용률을 높이고 30일 무료 평가판 이외의 제안을 잠재적으로 지원할 수 있도록 합니다.


{
“flow”: “browser”,
“mode”: “planSelection”,
“fields”: {
“skus”: [
{
“id”: 123,
“incentives”: [“FREE_TRIAL”],
“plan”: {
“name”: “Basic”,
“quality”: “SD”,
“price” : “$8.99”,
…
}
…
},
{
“id”: 456,
“incentives”: [“FREE_TRIAL”],
“plan”: {
“name”: “Standard”,
“quality”: “HD”,
“price” : “$13.99”,
…
}
…
},
{
“id”: 789,
“incentives”: [“FREE_TRIAL”],
“plan”: {
“name”: “Premium”,
“quality”: “UHD”,
“price” : “$17.99”,
…
}
…
}
],
“selectedSku”: {
“type”: “Numeric”,
“value”: 789
}
“nextAction”: {
“type”: “Action”
“withFields”: [
“selectedSku”
]
}
}
}

위의 응답에는 SKU 목록, 선택한 SKU 정보가 포함됩니다.

3단계 및 4단계: SKU Eligibility Service에서 적격성 결정 및 SKU 검색

Netflix는 글로벌 기업이기에 지역마다 다른 SKU가 존재합니다. 즉, SKU 가용성과 SKU 적격성을 구분해야 합니다. 가용성은 국가 수준에서 적용이되며 적격은 사용자 수준에서 적용이 됩니다. SKU 플랫폼에는 글로벌 SKU 세트가 포함되어 있기에 SKU의 가용성을 제어할 수 있습니다. 그리고 SKU 적격성은 SKU Eligibility Service에 의해 결정됩니다. 이렇게 구분함으로써 명확한 경계를 만들고 Growth 엔지니어링팀이 방문자를 위해 올바른 SKU를 표현하는데 집중 할 수 있습니다.

SKU Eligibility 서비스는 Netflix 서비스의 여러 부분에서 혁신을 가능하게 합니다. 이제 다양한 서비스가 SKU 데이터를 검색하기 위해 SKU Eligibility 서비스와 직접 통신을 할 수 있습니다.

5단계: SKU 플랫폼에서 적격 SKU 검색

SKU 플랫폼은 Rule Engine, 데이터베이스 및 애플리케이션 로직으로 구성됩니다. 데이터 베이스에는 Plan, Pricing 및 Offer가 포함되어 있습니다. Rule Engine은 규칙내 특정 조건이 일치 할 때 사용 가능한 Plan 및 Offer를 추출할 수 있도록 합니다. 미국에서 Offer를 검색하는 아래의 예제를 참고하세요.


SKU 플랫폼에는 이제 단 하나의 책임만 존재합니다. 즉, 모든 Netflix의 SKU를 관리합니다. 고객 컨텍스트를 가져와 SKU Rule 세트와 일치 시킵니다. SKU 자격은 Upstream으로 계산되며 SKU Rule 세트에 있는 다른 조건과 같은 방식으로 처리됩니다. 자격 및 가용성 개념을 단일 서비스에 결합하지 않음으로써 각 팀이 핵심 역량에 집중할 수 있고 자격 변경이 SKU 플랫폼에 영향을 미치지 않기에 개발자 생산성을 높일 수 있습니다. Netflix의 다음 단계는 SKU UI를 통해 셀프 서비스 및 Rule 변경에 대해 더 많이 지원하는 것입니다.

결론

SKU에 대한 아키텍처 변경 작업을 통해 Netflix는 모호했던 SKU 가용성 및 자격에 대한 경계를 명확하게 정의했습니다.

새 아키텍처가 기존 아키텍처에 비해 갖는 장점은 아래와 같습니다.

  • 재사용 및 확장 가능한 “Shape”을 가진 도메인 객체 (이 형태는 서비스 계층 뿐만 아니라 UI 계층에서도 코드 재사용을 용이하게 합니다.)
  • 최소한의 엔지니어링 개입으로 제품 혁신을 가능하게 하는 SKU 플랫폼 (이는 엔지니어가 다른 문제에 대해 더 도전적이고 창의적인 작업에 집중할 수 있음을 의미합니다.)
  • SKU 데이터 업데이트를 위한 코드 변경 대신 구성을 통해 혁신 속도를 높입니다.
  • 더 적은 서비스 호출로 인해 지연 시간이 줄어들어 방문자의 오류가 줄어 듭니다.

지금 이 세상은 끊임없이 변화하고 있고, 디바이스의 기능은 계속해서 향상되고 있습니다. 사람들이 즐거움을 원하는 방법, 시기, 장소는 계속해서 진화하고 있습니다. 이러한 유형에 대해 Netflix의 Growth 엔지니어링팀은 지속적으로 견고한 기반을 구축할 수 있도록 노력하고 있습니다.

Netflix가 SKU에 대해 이정도로 고민하는지 몰랐네요. 혁신적인 기업이라고 생각됩니다.^^/

“flow”: “browser”,




12/15/2020

Mantis- 비용 효율적, 실시간, 운영 중심의 애플리케이션 구축을 위한 플랫폼

본 글은 Netflix Tech 블로그에 작성된 을 기반으로 재가공 되었습니다.


Netflix는 스트림 처리 애플리케이션을 구축하기 위한 플랫폼을 오픈 소스로 제공했습니다.

실시간 애플리케이션을 개발할 때 기반으로 사용하며 신속하게 문제를 식별하고 Alert을 Trigger하며 수정 사항을 바로 적용할 수 있는 강점이 있습니다.

Netflix는 점점 더 복잡해지는 시스템의 운영 상태를 개선하면서 Metric을 정확하게 처리하는데 오랜 시간이 걸리는 문제를 가지고 있었습니다.

Mantis는 엔지니어에게 운영에 대한 통찰력을 손상 시키지 않고 복잡한 분산 시스템(e.g. 마이크로서비스)을 관찰하고 운영하는 비용을 최소화 할 수 있는 기능을 제공합니다.

Netflix 엔지니어들은 Mantis 위에서 비용 효율적인 애플리케이션을 구축하여 문제를 신속하게 식별하고, Alert을 Trigger하고, 변경 사항을 적용하여 Netflix 서비스의 Downtime을 최소화하거나 발생하지 않게 했다고 합니다.

기존 시스템이 Metric을 처리하는데 10분이상 걸린다면, Mantis의 경우에는 몇 초로 시간을 줄였다고 합니다. 서비스가 중단 되었을 경우에는 매 초가 중요하기 때문에 이 점은 매우 매력적입니다.

서비스가 성장함에 따라 시스템의 운영 상태에 대해 비용 효율적이며 신속한 통찰력을 갖는 것이 매우 중요하게 됩니다.

Mantis란 무엇인가?

Mantis는 실시간 스트림 처리를 위한 애플리케이션을 구축할 수 있는 플랫폼입니다.

클라우드에 배포 된 마이크로 서비스와 비슷하게 Mantis 애플리케이션은 Mantis 플랫폼에 배포됩니다.

Mantis 플랫폼은 작업의 수명주기(e.g 배포, 업데이트 및 종료)를 관리하는 API를 제공하고, Pool을 컨테이너화하여 리소스를 관리하며, 클라우드 기반의 마이크로 서비스와 유사하게 Job을 검색 할 수 있습니다.

Stream 프로세싱 관련 As-a-Service를 제공함으로써 Mantis는 개발자가 비즈니스 로직에 집중할 수 있도록 강력하고 비용 효율적인 스트리밍 애플리케이션을 구축할 수 있도록 도와 줍니다.

Mantis를 만든 이유는?

Mantis는 빠르게 성장하는 복잡한 마이크로 서비스 생태계에서 더 나은 운영 통찰력을 얻기 위해 Netflix에서 만들었습니다.


시스템의 복잡성이 증가함에 따라 이해도는 급격히 감소합니다. 이러한 복잡성에 대응을 하려면 운영 통찰력이 필요하고 새로운 접근 방식이 필요합니다.

즉, 운영 데이터를 생성하고 수집하는 기존의 방식을 변경해야 합니다.

  • Raw event에 Access할 수 있어야 합니다. 애플리케이션은 모든 단일 이벤트를 게시 할 수 있어야 합니다. 일반적으로 필터링 혹은 샘플링을 통해 통찰력을 얻으려고 하지만 이 경우 Raw data가 손실되었기 때문에 쉽지 않습니다.
  • 해당 데이터에 실시간으로 Access할 수 있어야 합니다. 일반적으로 서비스 운영 시 시간에 매우 민감합니다.
  • 애플리케이션에 새로운 작업 없이 해당 데이터에 대해 새로운 질의를 할 수 있어야 합니다. 문제가 발생하는 경우 해당 데이터를 통해 통찰력을 도출 하는 것이 매우 중요합니다.

그리고 새로운 타입의 실행 환경이 필요합니다.

  • 짧은 대기 시간으로 대용량 데이터 처리가 가능해야 합니다.
  • 운영 부담이 낮아야 합니다. 대부분의 운영 작업을 자동으로 처리하는 관리형 플랫폼이 필요합니다. 모니터링 시스템을 운영하는데 추가되는 오버 헤드가 필요하지 않습니다.
  • 탄력적이어야 합니다. 노드 장애시 자동으로 복구하고 데이터 볼륨에 따라 동적으로 리소스를 확장 할 수 있는 안정적인 시스템이 필요합니다.
  • 스트리밍 서비스 생태계가 필요합니다. Netflix의 사용 사례를 보면 종종 동일한 데이터가 필요하다고 합니다. 데이터와 결과를 공유하여 공동 작업을 할 수 있도록 함으로써 코드 및 데이터 재사용을 극대화해야 합니다. 이렇게 함으로써 비용 효율적인 Job을 만들 수 있습니다.

위의 모든 작업에 대해서 비용 효율적으로 수행 할 수 있어야 합니다. 비즈니스적으로 크리티컬한 시스템이 확장됨에 따라 이 시스템을 지원하는 시스템은 크리티컬한 시스템보다 더 적은 비용이 사용되어야 합니다.

Mantis는 위의 요구 사항을 충족하도록 제작되었고, Netflix에서 설계하였습니다.

Mantis를 사용하는 방법

Mantis는 이상 감지 및 Alarm과 같은 High volume, Low latency에 적합한 플랫폼을 제공합니다.

Mantis는 2014년부터 Netflix에서 제작하였고, 매일 수 조개의 Event와 Peta byte의 데이터를 처리합니다.

스트리밍 마이크로 서비스 생태계인 Mantis 플랫폼은 엔지니어에게 운영에 대한 통찰력을 손상 시키지 않으면서 복잡한 분산 시스템을 관리/운영하는데에 드는 비용을 최소화 할 수 있는 기능을 제공합니다.

엔지니어는 Mantis를 기반으로 비용 효율적인 실시간 애플리케이션을 구축하여 문제를 신속하게 식별하고 수정을 적용하여 Netflix 서비스의 Downtime을 최소화 혹은 방지하는데 활용되고 있습니다.

Mantis 사용 사례

Netflix 스트리밍 상태에 대한 실시간 모니터링

Netflix SPS(Stream Starts per Second)는 Netflix 스트리밍 서비스의 상태를 추적하는데 사용되는 지표입니다. SPS는 스트리밍이 성공적으로 Hit한 사람들의 수를 추적합니다. 이 측정 항목의 추이가 비정상적으로 변경되면 사용자의 콘텐츠 시청에 부정적인 영향을 미칩니다.

Mantis는 수천 대의 Netflix 서버(mantis-publish 라이브러리)에서 직접 가져온 데이터를 실시간으로 처리하여 SPS 추세를 모니터링합니다. DES(Souble Exponential Smoothing)를 사용하면 비정상적인 편차를 몇 초 만에 감지하고 담당팀에 알릴 수 있습니다.

Contextual Alerting

Netflix가 성장함에 따라 마이크로 서비스의 개수도 증가했습니다. 엔지니어가 문제의 원인을 신속하게 파악하기 위해 문제 범위를 좁히려면 Downstream 및 Upstream 서비스에서 발생하는 상황을 이해해야 합니다.

Contextual alerting application은 예외를 식별하기 위해 실시간으로 Netflix 마이크로서비스간 수백만건의 Interaction을 분석합니다. Mantis를 사용함으로써 평균 감지 시간을 수십 분에서 몇 초로 줄일 수 있었습니다. Netflix의 큰 규모를 생각하면 대단한 것 같습니다.

Raven

대규모 분산 시스템에서는 가끔 사용자가 문제를 제기하지만 전반적으로 시스템의 상태가 문제 없는 경우가 있습니다. 이런 경우 사용자/디바이스/서비스와 관련된 Event를 실시간으로 탐색하여 원인을 찾을 필요가 있습니다. 더군다나 사용자의 요청이 수천 대의 서버를 경유하게 된다면? 문제가 되는 서버를 찾고 Log를 분석하는 것은 매우 힘든 작업일 것입니다.

Raven 애플리케이션은 mantis-publish 라이브러리를 이용하여 실시간 Stream 매칭 결과에서 특정 기준(e.g 사용자ID/디바이스ID)에 일치하는 Event를 파악 할 수 있도록 MQL 쿼리를 작성할 수 있는 UI를 제공합니다.

Cassandra 및 Elastic Search 상태 모니터링

Netflix는 현재 수백 개의 Cassandra 및 Elastic Search 클러스터를 이용하고 있습니다.

Cassandra 와 Elastic Search의 상태 체크 애플리케이션은 Netflix내의 모든 Cassandra/Elastic Search 클러스터의 상태를 체크하기 위해 실시간으로 Event를 분석합니다. 이 시스템이 가동된 이후 False page 수가 크게 감소했습니다.

Alerting on Log

Alerting on Logs 애플리케이션을 사용하면 애플리케이션 로그에서 특정 패턴이 감지 될 때 페이지를 표시하는 Alert을 생성할 수 있습니다. 이 애플리케이션은 실시간으로 수천 대의 서버에서 로그를 분석합니다.

Chaos 테스트에 대한 모니터링

Chaos 테스트는 Netflix의 Resilience(탄력성)중 하나입니다. 다양한 애플리케이션의 탄력성을 테스트하기 위해 매일 수십 건의 Chaos 테스트가 수행됩니다.

Chaos 테스트 애플리케이션은 테스트중에 클라이언트 및 서버측 Event를 실시간으로 분석하여 사용자 경험을 추적하고 문제가 발생할 경우 Chaos 테스트를 중단합니다.

실시간 개인 식별 정보(Personally Identifiable Information, PII) 감지

매일 수조 건의 Event가 Netflix 데이터 시스템을 통해 전달되기에 민감한 데이터가 섞이지 않도록 하는 것이 중요합니다.

이 애플리케이션은 모든 Streaming 데이터에 패턴 감지 알고리즘을 적용하여 이러한 데이터의 존재를 식별합니다.

Mantis Architecture

Mantis는 공유 Pool을 생성하는데 사용되는 Apache Mesos와 Job에 리소스를 할당하는데 사용되는 Fenzo라는 오픈 소스를 사용하여 Stream 처리 작업을 실행하는 서버 클러스터를 관리합니다.

Mantis는 크게 두 개의 주요 클러스터가 존재합니다.

Master Cluster

마스터 클러스터는 모든 Job의 흐름을 관리합니다,

  • Resource Manager: Fenzo를 사용하여 Worker에게 리소스 할당
  • Job Manager: 메타 데이터, SLA, Artifact location, Job topology 및 수명 주기를 처리 및 관리합니다.

Agent Cluster

사용자가 Stream을 제출하면 에이전트 클러스터에서 하나 이상의 Job이 실행됩니다.

  • 인스턴스: 에이전트 클러스터는 Job을 실행하는 Pool을 여러 인스턴스로 구성합니다.

끝으로, 금일 발생한 구글 장애로 인해 많은 사용자들이 불편함을 겪었습니다.

Mantis를 적용하더라도 장애에 대해서 완벽하게 대응하기는 어렵지만, 원인을 빨리 찾아 Downtime을 최소화하여 서비스의 Quality를 높이려는 그들의 노력에 박수를 보내고 싶습니다.

시간이 되면, Mantis를 가지고 테스트를 해보고 조금 더 Deep-dive한 내용으로 포스팅 하도록 하겠습니다.

References:

  • https://netflixtechblog.com/open-sourcing-mantis-a-platform-for-building-cost-effective-realtime-operations-focused-5b8ff387813a
  • https://netflix.github.io/mantis/

11/05/2019

Netflix내의 마이크로서비스가 데이터를 처리하는 방법 (Gutenberg)

 마이크로서비스 아키텍처에서는 단일 서비스에서 여러 목적지로 데이터 세트를 전파하는 것이 어려울 수 있다.

여기서 말하는 데이터 세트는 서비스 구성, 배치 작업 결과등의 모든 것을 의미 할 수 있다.

이러한 것들은 시간이 지남에 따라 종종 업데이트되어야 하기도 한다.

예를 들어서 Netflix에서는 수많은 A/B 테스트를 실행하고 있고 이런 테스트는 여러 서비스를 걸쳐서 수행되기에 테스트 담당자는 구성을 즉시 조정할 수 있어야 한다. 그리고 문제 발생시 이전 버전으로 롤백을 해야 한다.

다른 예는 머신 러닝 모델의 결과에 대한 배포이다. 머신 러닝 모델의 결과는 여러 팀에서 사용되지만, 모델을 담당하는 팀이 고가용성 서비스에 대한 관심이 높진 않다. 그리고 데이터 결과에 대한 활동들은 여러 팀이 활동하기에 중앙 집중화하는 것에 대해 가치가 있다고 판단된다.

하지만, 인프라 수준의 지원이 없다면 모든 팀은 성공을 위해 자체 솔루션을 구축하게 된다. 데이터 세트의 크기는 작게는 몇 바이트에서 많게는 몇 기가 바이트까지 다양한데 각 팀에서 이런 솔루션을 구축하는 것보다는 작업자가 빠르게 변경할 수 있도록 Tool을 제공하는 것이 중요하다.

Netflix에서는 Gutenberg라는 데이터 세트 Pub/Sub 시스템을 사용한다.

Gutenberg를 사용하면 특정 버전의 데이터 세트를 전파 할 수 있다. 데이터 세트의 각 버전은 변경이 불가능하며 데이터의 전체 뷰를 나타낸다. 이전 버전의 데이터에는 의존하지 않는다.

Gutenberg를 사용하면 Debugging 및 데이터를 이용한 머신 러닝 모델의 재학습과 같은 사용 사례에 이용될 수 있다.

데이터 모델


Gutenberg의 최상위 구조는 “Topic”이다. Publisher는 Topic에 게시하고 Consumer는 Topic을 기반으로 소비한다. Publisher가 게시하면 새롭게 증가된 “Version”이 생성된다. 각 Version에 대해서는 유지 개수 혹은 유지 기간을 설정할 수 있다.

각 Version에는 Meta data(Key/Value)와 데이터 포인터가 포함되어 있고, 데이터 포인터는 게시한 실제 데이터가 저장된 위치를 가리키는 특수 메타 데이터이다. 현재 Gutenberg는 직접 데이터 포인터와 S3 데이터 포인터를 지원하고 있고 직접 데이터 포인터는 일반적으로 데이터가 작을 때(약 1MB미만)에 사용되며 S3는 데이터가 클 때 백업 저장소로 사용된다.

Gutenberg는 지역, 응용 프로그램, 클러스터등 특정 Consumer 집합에 게시 범위를 지정할 수 있는 기능을 제공한다. 단일 클러스터로 데이터 변경 사항을 카나리아 방식으로 변경하거나, 변경 사항을 점진적으로 Roll-out하거나, 데이터 세트를 제한하여 어플리케이션의 서브 세트만 구독할 수 있도록 지원한다. Publisher는 특정 데이터 버전의 게시 범위를 결정하고 이전에 게시된 버전에 범위를 추가할 수 있다. 다시 말해서 최신 버전의 개념이 범위에 따라 달라진다는 의미이다. 두 응용 프로그램은 Publisher가 만든 범위에 따라 서로 다른 버전의 데이터를 최신 버전으로 바라 볼 수 있다. Gutenberg는 최신 버전으로 전파할 대상을 결정하기 전에 Consumer 어플리케이션과 Publishing된 범위를 일치시킨다.

사용 사례

Gutenberg의 사용 사례는 단일 Publisher에서 여러 Consumer에게 다양한 크기의 데이터를 전파하는 것이다. 데이터는 Consumer에 의해 메모리상에 저장되어 클라이언트 코드에 의해 Access되고 원자적으로 교환되는 “전체 Cache”로 사용된다. 이런 사용 사례는 느슨하게 그룹핑하여 구성할 수 있다.

예를 들어서 Cache 구성, 지원되는 장치 유형 ID, 지원되는 지불 방법 및 A/B 테스트 구성등

Gutenburg는 데이터의 Pub/Sub을 추상화하여 Publisher가 Consumer에게 영향을 주지 않고 응용 어플리케이션을 자유롭게 반족 할 수 있게 도와준다. 경우에 따라 Gutenberg의 관리 UI를 통해 Publishing이 수행되므로 팀에서 Publisher 기능을 전혀 관리하지 않아도 된다.

Gutenberg의 또 다른 사용 사례는 Version이 지정된 데이터 저장소이다. 이것은 과거 데이터를 기반으로 모델을 구축하고 훈련하는 과정을 반복하는 머신 러닝 프로그램에 일반적인 케이스이다. Gutenberg를 사용하여 계산 결과를 별개의 버전의 데이터 세트로 저장하고 전파하고 온라인 Use-case에서는 최신 Version의 데이터 세트를 사용하여 실시간 요청을 처리하고 “오프라인” Use-case에서는 동일한 Topic의 히스토리 데이터를 사용할 수 있다.

이런 점을 보면, 다들 이렇게 생각할 수 있다. 그냥 Kafka나 Pub/Sub 구조의 이벤트 솔루션을 사용하면 되지 않나? 중요한 점은 Gutenberg가 이벤트 시스템으로 설계되지 않았고 데이터 버전 관리 및 전파를 위해서 존재한다는 점이다. 업데이트를 요청하면 현재 많은 버전이 있다고 해도 최신 버전으로만 제공된다. 전통적인 Pub/Sub 구조의 이벤트 시스템은 크기가 작고 순서대로 소비되는 메시지에 적합하다. 그러나 Gutenberg는 데이터 세트에 대한 불변의 전체뷰를 게시하고 사용하도록 설계되었다.

아키텍처

Gutenberg는 gRPC 및 REST API가 포함된 서비스와 gRPC API를 사용하는 Java Client Library로 구성되어 있다.


Client

Gutenberg 클라이언트 라이브러리는 구독 관리, S3 업로드/다운로드, Atlas metric 및 Archaius properties 를 사용하여 작업을 처리한다. 서비스 검색에 Eureka를 사용하여 gRPC를 통해 Gutenberg 서비스와 통신한다.

Publishing

Publisher는 API를 사용하여 문자열, 파일 또는 바이트 배열을 게시한다. 데이터 크기에 따라 데이터가 직접 데이터 포인터로 게시되거나 S3에 업로드 된 후 S3 데이터 포인터로 게시 될 수 있다. 클라이언트는 요청자를 대신하여 Payload를 S3에 업로드하거나 S3에 이미 존재하는 Payload에 대한 메타 데이터만 게시 할 수 있다.

직접 데이터 포인터는 자동으로 복제된다. S3에 게시된 데이터는 기본적으로 게시자가 여러 지역에 업로드 하지만 요청자가 구성 할 수 도 있다.

구독 관리

클라이언트 라이브러리는 Consumer를 위한 구독 관리 기능을 제공한다. 이 기능을 통해 사용자는 특정 Topic에 대한 구독을 작성할 수 있고, 라이브러리는 이를 기반으로 데이터를 검색한다. 구독은 Polling Model로 작동되며 30초마다 서비스에 새 업데이트를 요청하여 마지막으로 전달 받은 버전을 제공한다. 문제 발생시 재시도하는 로직은 기본으로 탑재되어 있다.

Consumption APIs

Gutenberg는 저수준 gRPC API를 Wrapping하여 추가적인 기능을 제공하는 고수준 Client API를 제공한다. 예를 들어서 특정 Topic과 Version에 대한 데이터를 다운로드한다고 할때, Netflix Hollow에 연결된 구성 요소를 광범위하게 사용할 수 있다. 또는 특정 시간에 Topic의 최신 버전을 얻는 방법도 존재한다.

Client 탄력성 및 관찰성

Gutenberg는 Comsuming 서비스를 성공적으로 하도록 설계 되었다. 이를 염두해두고 Client Library는 Gutenberg 서비스와 통신 할 수 없는 경우에 대해 대비하여 구현되었다. HTTP 요청 재시도 횟수가 소진 된 후에 Client는 S3에서 Topic에 대한 fallback cache를 다운로드 하고 이를 기반으로 작동한다. 해당 Cache에는 업데이트를 적용해야 하는지 여부와 Meta 데이터 자체 또는 S3에서 데이터를 가져와야 하는 위치를 결정하는데 필요한 모든 정보가 포함되어 있다. 이를 통해 Client는 서비스를 사용하지 않고 데이터를 Fetch할 수 있다.

Client Library 제공의 이점중 하나는 인프라 전체의 문제 또는 특정 응용 프로그램의 문제를 경고하는데 사용할 수 있는 Metric 제공하는 기능이다. 이런 측정 항목은 Gutenberg에서 게시 및 전파를 모니터링하고 광범위한 문제가 발생했을 경우 이를 경고하는데 사용된다. 또한 일부 클라이언트는 이런 측정 항목을 사용하여 개별 게시 실패 또는 특정 Topic 사용 실패와 같은 오류에 대해서도 알려준다.

Server

Gutenberg 서비스는 gRPC 및 REST End-point를 공개하는 Governator/Tomcat 어플리케이션이다. 지속성을 위해서 글로벌하게 복제된 Cassandra Cluster를 사용아여 모든 지역에 게시 메타 데이터를 전파한다. Consumer 요청을 처리하는 인스턴스는 게시 요청을 처리하는 인스턴스와 별도로 확정된다. 일반적으로 게시 요청보다 Consuming 요청이 약 1000배 더 많기에 Publishing을 Consuming으로 부터 격리시킨다. 그 이유는 갑자기 Publishing이 급증해도 Consuming에 영향을 미치지 않기 위함이고 반대도 마찬가지이다.

Consumer 요청 클러스터의 각 인스턴스는 자체 메모리의 최신 게시에 대한 Cache를 유지 관리하여 몇 초마다 Cassandra에서 새롭게 갱신된다. 이는 트래픽을 Cassandra 클러스터로 전달하지 않고 클라이언트에서 오는 대량의 Polling 요청을 처리하기 위함이다.

여러 지역의 S3 Bucket에 데이터가 게시 된 경우에는 서버는 클라이언트의 위치에 따라 다운로드 할 클라이언트로 다시 보낼 Bucket을 결정한다. 이 경우 가장 가까운 Region에서 Bucket을 클라이언트에 제공하고 Region이 중단 된 경우 클라이언트가 다른 Region으로 fallback되도록 한다.

구독 데이터를 Consumer에게 반환하기 전에 Gutenburg는 데이터에 대한 일관성 검사를 선행한다. 검사가 실패하고 Polling 클라이언트가 일부 데이터를 사용한 경우 서비스는 아무것도 리턴하지 않으므로 사실상 사용 가능한 업데이트가 없음을 의미한다. Polling 클라이언트가 데이터를 사용하지 않은 경우에는 히스토리를 조회하고 일관성 검사를 통해 최신 데이터를 리턴한다. 클라이언트가 새로운 데이터를 Polling할 때 가장 최근에 게시된 버전과 관련된 메타 데이터가 복제된 Cassandra 계층에서 복제 지연이 발생하기 때문이다. 그리고 데이터를 가져올때 실패할 경우를 대비해 서버에서는 일관성 검사를 실행한다.

Data Resilient

Pinning

어플리케이션의 개발 환경에서는 배포가 잘못되거나 배포를 Rollback하는 정책이 필요하다. 데이터 중심의 아키텍처는 시간이 지남에 따라서 변경되는 데이터에 의해 작동되기에 이 부분은 매우 까다롭다.

Guternberg에서는 문제가 발생하면 마지막 안정버전의 데이터로 Rollback할 수 있는 방법이 필요하다. 이를 제공하기 위해서 Gutenberg는 Topic을 특정 버전에 고정하는 기능을 제공한다.

Pin은 최신 버전의 데이터를 무시하고 클라이언트가 해당 버전으로 Update하도록 도와준다.

따라서 관리자가 마지막의 안정버전을 모르더라도 빠르게 처리할 수 있다.

Incremental Rollout

새로운 코드를 배포할때는 카나리아 혹은 점진적으로 Rollout하는 방식으로 수행한다.

Gutenberg가 제공하는 기능중에 SPinnaker 파이프라인을 통해 데이터 게시를 Rollout라는 것을 제공한다. 특정 Topic의 경우 사용자는 자신이 게시 할 범위에 지연 시간을 구성하게 된다. 그리고 해당 Topic에 게시하게 되면 파이프 라인이 시작되어 동일한 데이터 버전이 각 범위에 점차적으로 게시되게 된다. 사용자는 파이프라인과 상호 작용할 수 있다.

Scale

Gutenberg는 지난 3년간 Netflix에서 사용되고 있고, 수만 가지의 Topic을 Production에 저장하고 있다. 이 중에 약 1/4이 지난 6개월 동안 한번 이상은 Publishing되었다. Topic은 1분에 수십번에서 몇달간 한번까지 다양하게 게시되었으며, 평균적으로 약 12시간 간격으로 초당 약 1~2번의 게시가 가능하다.

24시간 동안 적어도 한개의 Topic에 가입된 노드의 수는 6자리 미만이고, 이 노드중 하나가 구독하는 최대 Topic수는 200개이다.

향후 작업 계획

Polyglot 지원 (현재는 Java만 지원하지만, Node.js 및 Python을 지원할 계획을 가지고 있다.)

암호화 지원 (민감한 데이터의 경우 암호화 및 암호 해독 기능을 제공하여 사용 될 수 있도록 준비중이다.)

Topic 정리 (Topic을 게시하거나 사용하지 않는 사람이 있어도 명시적으로 삭제하지 않는한 Topic이 계속 유지되기에 Elasticsearch에서 색인화 작업을 거쳐서 Topic을 정리하는 시스템을 구축할 계획)

References:

  • https://medium.com/netflix-techblog/how-netflix-microservices-tackle-dataset-pub-sub-4a068adcc9a