Pub/Sub의 아키텍처 개요

Pub/Sub는 안정성과 확장성이 뛰어난 비동기 메시징 서비스입니다. 이 서비스는 지난 10여 년간 수많은 Google 제품에 활용된 Google 인프라 핵심 구성요소를 바탕으로 개발되었습니다. Google Ads, Google 검색, Gmail 같은 Google 제품은 이 인프라를 이용해 초당 5억 건이 넘는 메시지를 전송하며, 이는 초당 1TB의 데이터에 해당합니다. 이 문서에서는 Pub/Sub가 이러한 규모의 서비스를 안정적으로 제공할 수 있도록 하는 설계상의 핵심적인 특징을 설명합니다.

메시징 서비스의 성능 판단

Pub/Sub 같은 메시징 서비스의 성능은 확장성, 가용성, 지연 시간이라는 3가지 요소로 판단합니다. 이 3가지 요소는 종종 상충하므로 두 요소를 개선하려면 다른 하나를 희생해야 합니다.

'확장성', '가용성', '지연 시간'이라는 용어가 시스템의 서로 다른 속성을 지칭하기도 합니다. 따라서 지금부터는 Pub/Sub에서 이 3가지 용어가 어떻게 정의되는지 살펴보겠습니다.

확장성

확장 가능한 서비스는 지연 시간이 크게 늘어나거나 가용성의 현저한 저하 없이 점점 증가하는 로드를 처리할 수 있어야 합니다. 여기서 '로드'는 Pub/Sub 사용과 관련한 다양한 측정기준을 의미합니다.

  • 주제 수

  • 게시자 수

  • 구독 수

  • 구독자 수

  • 메시지 수

  • 메시지 크기

  • 게시하거나 소비된 메시지 비율(처리량)

  • 특정 구독의 백로그 크기

가용성

분산 시스템에서 발생하는 문제의 유형과 심각도는 매우 다양할 수 있습니다. 시스템의 가용성은 다양한 유형의 문제를 얼마나 잘 처리해 최종 사용자가 오류 해결을 알아차리지 못하게 하는가를 기준으로 측정됩니다. 장애는 하드웨어(예: 디스크 드라이브 미작동 또는 네트워크 연결 문제)나 소프트웨어에서 발생하거나 로드로 인해 발생할 수 있습니다. 로드가 원인인 오류는 서비스 내(또는 같은 하드웨어나 소프트웨어 종속 항목에서 실행되는 다른 소프트웨어 구성요소 내) 트래픽의 갑작스러운 증가 때문에 리소스가 부족해지면 발생합니다. 가용성은 소프트웨어나 구성 설정의 구축 또는 배포 시 발생하는 인적 오류로 인해 저해되기도 합니다.

지연 시간

지연 시간은 시스템 성능을 시간 기준으로 측정한 것입니다. 서비스는 일반적으로 가능한 한 지연 시간을 최소화하려고 합니다. Pub/Sub에서 가장 중요한 지연 시간 측정항목은 2가지가 있습니다.

  1. 게시된 메시지를 확인하는 데 걸리는 시간

  2. 게시된 메시지가 구독자에게 전달되는 데 걸리는 시간

Pub/Sub 기본 아키텍처

이 섹션에서는 Pub/Sub 설계에 대한 설명을 통해 서비스가 어떻게 확장성과 낮은 지연 시간을 확보하면서도 가용성을 유지하는지 설명합니다. 시스템은 수평적으로 확장하도록 설계되며, 따라서 주제, 구독 또는 메시지 수가 증가하면 실행 중인 서버의 인스턴스 수를 늘려 처리합니다.

Pub/Sub 서버는 전 세계 모든 Google Cloud 리전에서 실행됩니다. 이로 인해 서비스가 빠른 글로벌 데이터 액세스를 제공하고 사용자는 메시지가 저장되는 위치를 제어할 수 있습니다. Cloud Pub/Sub는 게시자와 구독자 클라이언트가 연결되는 서버의 위치나 서비스를 통해 데이터가 라우팅되는 방식을 인식하지 못하도록 글로벌 데이터 액세스를 제공합니다.

Pub/Sub의 부하 분산 메커니즘은 IAM 및 관리 콘솔리소스 위치 제한 섹션에 정의된 대로 데이터 저장이 허용되는 가장 가까운 Google Cloud 데이터 센터로 게시자 트래픽을 보냅니다. 즉, 여러 리전의 게시자가 하나의 주제에 대한 메시지를 짧은 지연 시간으로 게시할 수 있습니다. 모든 개별 메시지는 단일 리전에 저장됩니다. 하지만 하나의 주제에는 여러 리전에 저장된 메시지가 있을 수 있습니다. 구독자 클라이언트가 이 주제에 게시된 메시지를 요청하면 해당 주제에 게시된 모든 메시지의 데이터를 집계하여 클라이언트에게 전달하기 위해 가장 가까운 서버에 연결합니다.

Pub/Sub는 2가지 주요 영역으로 구분되는데, 데이터 영역은 게시자와 구독자 간의 데이터 이동을 처리하고 제어 영역은 게시자와 구독자를 데이터 영역의 서버에 할당하는 작업을 처리합니다. 데이터 영역 내의 서버를 포워더라고 하고 제어 영역 내의 서버를 라우터라고 합니다. 게시자와 구독자가 자신에게 할당된 포워더에 연결되면 포워더에 액세스할 수 있는 한 라우터로부터 정보를 받을 필요가 없습니다. 따라서 기존에 연결된 클라이언트에 영향을 주거나 메시지를 송수신하지 않고도 Pub/Sub의 제어 영역을 업그레이드할 수 있습니다.

제어 영역

Pub/Sub 제어 영역은 모든 클라이언트에 확장성, 가용성, 짧은 지연 시간을 제공하는 방식으로 포워더에 클라이언트를 배포합니다. 모든 포워더는 어떤 주제나 구독도 클라이언트에 제공할 수 있습니다. 클라이언트가 Pub/Sub에 연결되면 라우터는 두 지점 간의 연결에 대한 지연 시간의 척도인 최단 네트워크 거리를 기준으로 클라이언트를 연결할 데이터 센터를 결정합니다. 특정 데이터 센터 내에서 라우터는 전체 로드를 여러 가용 포워더에 분배하려고 합니다. 라우터는 이 할당을 수행할 때 2가지 목표, 즉 (a) 로드의 균일성(모든 포워더에 로드를 균일하게 분배하는 것이 이상적임)과 (b) 작업의 안정성(로드의 변경사항이나 가용 포워더의 변경사항이 최소한의 기존 할당만 변경하게 하는 것이 이상적임) 간의 균형을 유지해야 합니다. 라우터는 Google Research가 개발한 일관된 해싱의 변형을 이용해 일관성과 균일성 간의 균형을 적절하게 조정합니다. 라우터는 연결 가능하다고 판단한 포워더의, 순서가 지정된 목록을 클라이언트에게 제공합니다. 순서가 지정된 목록은 포워더 가용성과 클라이언트의 로드 형태에 따라 변경될 수 있습니다.

클라이언트는 이 포워더 목록을 이용해 하나 이상의 포워더를 연결합니다. 클라이언트는 라우터가 먼저 권장하는 포워더와의 연결을 선호하지만, 발생한 모든 오류를 고려합니다. 예를 들어 가장 가까운 포워더에 여러 번 연결을 시도했지만 실패하는 경우 다른 데이터 센터에 있는 포워더와의 연결을 시도합니다. Pub/Sub 클라이언트에 대해 이러한 구현 세부정보를 추상화하기 위해 클라이언트와 클라이언트를 대신하여 이 연결 최적화를 수행하는 포워더 사이에 서비스 프록시가 있습니다.

데이터 영역 - 메시지의 일생

데이터 영역은 게시자로부터 메시지를 수신해 클라이언트로 전송합니다. Pub/Sub의 데이터 영역을 이해하는 가장 좋은 방법은 메시지의 일생, 즉 서비스가 메시지를 수신하는 순간부터 더 이상 서비스에 메시지가 없게 되는 순간까지를 살펴보는 것입니다. 지금부터는 메시지를 처리하는 단계를 알아보겠습니다. 이 섹션에서는 메시지가 게시되는 주제에 연결된 구독이 하나 이상 있다고 가정하겠습니다. 일반적으로 메시지는 다음과 같은 단계를 거칩니다.

  1. 게시자가 메시지를 전송합니다.

  2. 메시지를 스토리지에 기록합니다.

  3. Pub/Sub가 메시지 수신 확인을 게시자에게 전송하고 연결된 모든 구독에 대한 메시지 전송을 보장합니다.

  4. 메시지를 스토리지에 기록함과 동시에 Pub/Sub가 이를 구독자에게 전달합니다.

  5. 구독자가 메시지 처리 확인을 Pub/Sub에 전송합니다.

  6. 각 구독에 대해 하나 이상의 구독자가 메시지를 확인하면 Pub/Sub가 메시지를 스토리지에서 삭제합니다.

먼저 게시자가 주제에 대한 메시지를 Pub/Sub에 전송합니다. 이 메시지는 프록시 레이어로 암호화되어 게시자와 연결된 포워더인 게시 포워더로 전송됩니다. 확실한 전달을 위해 메시지는 즉시 스토리지에 기록됩니다. 포워더는 메시지를 먼저 클러스터 N개(N은 홀수)에 기록하며, 클러스터 ⌈N/2⌉개 이상에 기록되면 메시지가 지속되는 것으로 간주합니다. 메시지가 지속되면 게시 포워더는 메시지 수신 확인을 게시자에게 전송하며, 이때 Pub/Sub는 연결된 모든 구독에 메시지를 전달할 것을 보장합니다. 백그라운드 프로세스가 N개의 클러스터 전체에 존재하지는 않는 메시지를 메시지가 없는 클러스터에 정기적으로 기록합니다.

각 클러스터에서 메시지는 독립 디스크 M개(M개는 홀수)에 기록되며, 데이터는 디스크 ⌈M/2⌉개에 기록되어야 해당 클러스터에서 지속되는 것으로 간주됩니다. 종합하면 모든 메시지는 클러스터 ⌈N/2⌉개의 독립 디스크 ⌈M/2⌉개 이상에 기록되어야 지속되는 것으로 간주되며, 결과적으로 디스크 N*M개에 복제됩니다.

게시 포워더에는 주제에 연결된 모든 구독 목록이 있습니다. 게시 포워더는 게시된 메시지 및 각 구독이 확인한 메시지를 설명하는 메타데이터를 모두 책임집니다. 게시 포워더가 특정 주제에 대해 수신하고 저장한 메시지 모음과 확인된 메시지에 대한 이러한 추적을 합쳐서 '게시 메시지 원본'이라고 합니다. 주제의 처리량 요구사항에 따라 단일 게시자가 메시지를 다수의 게시 포워더에 전송하고 다수의 게시 메시지 원본에 저장하기도 합니다. 같은 주제를 다루는 서로 다른 게시자가 메시지를 서로 다른 게시 포워더에 전송할 수도 있습니다. 각 메시지는 단일 게시 포워더에만 전송됩니다. Pub/Sub는 처리량이 달라지면 특정 주제에 대한 메시지를 수신하는 게시 포워더 수를 동적으로 미세 조정합니다.

구독자는 메시지를 구독자로부터 게시자로 전달하는 구독 포워더를 연결해 메시지를 수신합니다. 가져오기 구독자의 경우 '연결'이란 가져오기 요청 실행을 의미합니다. 내보내기 구독자의 경우 '연결'이란 푸시 엔드포인트를 Pub/Sub에 등록함을 의미합니다. 구독이 생성되면 해당 시점 이후에 게시된 모든 메시지는 해당 구독으로 전달되도록 보장되며, 이를 동기 지점 보장이라고 합니다.

각 구독 포워더는 주제에 대한 게시 메시지 원본이 있는 게시 포워더로부터 메시지를 요청해야 합니다. 게시자처럼 구독자도 메시지를 받으려면 하나 이상의 구독 포워더에 연결해야 할 수 있습니다. 이렇게 되면 모든 구독 포워더가 모든 게시 메시지 원본으로부터 메시지를 확인하거나 수신할 필요가 없게 됩니다. 이는 Pub/Sub의 수평 확장을 가능하게 하는 중요한 속성입니다. 구독자에게 전달되는 메시지의 처리량을 기준으로, Pub/Sub는 이 처리량이 달라지면 구독자가 특정 주제에 대한 메시지를 수신하는 구독 포워더 수를 동적으로 미세 조정합니다.

구독 포워더는 주제에 대한 게시 메시지 원본이 있는 하나 이상의 게시 포워더에게 자신이 필요한 메시지를 요청합니다. 게시 포워더는 확인하지 않은 메시지를 구독 포워더로 전송하며, 이후 해당 메시지는 구독자에게 전달됩니다.

메시지를 처리하면 구독자는 구독 포워더에게 확인을 다시 전송합니다. 구독 포워더는 이 확인을 게시 포워더에게 전달하며, 게시 포워더는 확인을 게시 메시지 원본에 저장합니다. 주제의 모든 구독이 메시지를 확인하면 메시지는 게시 메시지 원본과 스토리지에서 비동기식으로 삭제됩니다.

하나의 주제와 구독에 대한 다양한 메시지가 많은 게시자, 구독자, 게시 포워더, 구독 포워더를 통해 전달할 수 있습니다. 게시자는 여러 포워더에 동시에 게시할 수 있으며 구독자는 여러 구독 포워더에 연결하여 메시지를 수신할 수 있습니다. 따라서 게시자, 구독자, 포워더 간의 연결을 통한 메시지 흐름은 복잡할 수 있습니다. 다음 다이어그램은 단일 주제 및 구독에 대해 메시지가 흐르는 방법을 보여줍니다. 여기서 서로 다른 색상들은 메시지가 발행자로부터 구독자에게 전달될 수 있는 다른 경로들을 나타냅니다.

여러 게시자의 메시지가 게시 및 구독 포워더를 통해 구독자에게 전달됩니다.

Pub/Sub 작동 유지

Pub/Sub 같은 분산 시스템의 작동을 유지하고 모든 고객에게 효과적으로 서비스를 제공하려면 시스템을 한눈에 파악하고 제어해야 합니다. 서비스 유지는 Google의 사이트 안정성 엔지니어링(SRE)의 책임입니다. Pub/Sub를 위해 이 엔지니어들은 전 세계 여러 지역에서 연중무휴로 서비스를 제공합니다.

환경

Pub/Sub 같은 서비스를 유지하는 첫 번째 단계는 고객이 사용하기 전에 소프트웨어를 테스트하는 것입니다. 이를 위해 테스트, 스테이징, 프로덕션이라는 3가지 Pub/Sub 환경이 존재합니다. 테스트와 스테이징 단계에는 고객 트래픽이 존재하지 않습니다. 서비스 출시 관련 문제를 확인하는 데 필요한 연속 실행 테스트와 모니터링만 존재합니다. 이러한 환경은 새로운 소프트웨어를 프로덕션 전에 미리 받습니다. 스테이징이 테스트와 다른 점은 소프트웨어 버전과 명령줄 플래그를 포함한 프로덕션 환경에 존재하는(또는 곧 존재하게 될) 요소를 그대로 재현한다는 것입니다. 테스트의 경우 개발자들이 현재 작업 중인 기능과 향후 출시 계획인 기능을 사용하기도 합니다.

출시

Pub/Sub 출시 및 테스트 절차의 목적은 잠재적 영향력을 최소화하는 것입니다. Pub/Sub 새 버전 출시의 일반적인 단계를 살펴보겠습니다.

  1. 모든 단위 테스트와 통합 테스트를 통과했는지 확인합니다.

  2. 모든 서버의 새 버전을 구축합니다.

  3. 새 서버를 테스트 및 스테이징 환경에 배포합니다.

  4. 테스트 및 스테이징 환경에서 며칠 동안 서버를 가동합니다.

  5. 알려진 문제가 없다면 소량의 고객 트래픽이 존재하는 프로덕션 환경 하위 집합인 카나리아에 서버를 출시합니다.

  6. 카나리아에서 문제가 발견되지 않으면 서버가 전 영역에 출시될 때까지 며칠에 걸쳐 점진적으로 서버를 프로덕션 환경에 출시합니다.

Pub/Sub는 제어 영역과 데이터 영역의 분리 등을 통해 오류에 대비하도록 설계되므로, 서버의 새 버전 출시는 고객이 눈치채지 못하며 고객의 체감 성능에도 영향을 주지 않습니다.

모니터링

Pub/Sub의 작동을 유지하는 핵심 요소는 최종 사용자가 확인하기 전에 문제를 자동으로 감지해 완화하는 것입니다. 이렇게 하려면 시스템 전반을 모니터링해야 합니다. 사이트 안정성 엔지니어링팀(SRE)은 시스템 동작을 설명하는 명확하게 정의된 측정항목인 서비스 수준 지표(SLI) 집합을 관리합니다. 측정항목에는 'CreateSubscription 요청이 완료될 때까지 걸리는 시간'이나 '게시 요청에 따른 오류율' 등이 포함될 수 있습니다. 이러한 측정 항목은 다양한 방식으로 측정됩니다. 일부 측정항목은 Google의 포워더와 라우터에만 적용됩니다. 예를 들면 메시지를 디스크에 쓰는 데 걸리는 시간이 있습니다.

이러한 모든 측정항목은 SLI의 구체적 대상인 내부 서비스 수준 목표(SLO)를 정의하는 데 도움이 됩니다. SLO의 예시로는 'CreateSubscription 요청이 완료될 때까지 5초 이상 걸리지 않을 것'이 있습니다. SRE는 SLO 위반에 대한 알림을 받으며 5분 이내에 알림에 대응해야 합니다.

서비스수준계약(SLA)은 최종 사용자에 대한 Google의 성능 보장과 보장 실패에 따른 결과를 정의하는 SLO를 나열합니다. Pub/Sub의 SLA를 확인해 보세요.

Google은 예측적으로 게시 및 구독을 수행하는 클라이언트 집합을 관리합니다. 이를 프로버라고 합니다. 프로버는 데이터 영역과 제어 영역에 모두 존재합니다. 각각의 프로버는 고객처럼 활동하면서 지정된 행동을 하고 작업에 걸리는 시간을 측정합니다. 예를 들어 새 구독을 생성하거나, 메시지를 게시하거나, 구독 생성과 메시지 수신에 걸리는 시간을 확인하는 프로버가 있습니다. 프로버가 실제로 측정한 측정항목 중 예상과 다른 항목이 있다고 판단하면 SRE는 알림을 받습니다.

Google의 서버와 프로버에 대한 측정항목은 여러 내부 대시보드에 요약되며, 이 대시보드는 잠재적 문제 진단 시 SRE가 가장 먼저 살펴보는 곳입니다. 이러한 페이지를 이용하면 전체 서비스의 통계와 그래프를 빠르게 확인할 수 있습니다. 주제, 데이터 센터나 개별 작업별로 세분할 수도 있습니다.

서비스 사용자가 가장 관심을 보이는 측정항목은 Google Cloud Monitoring을 통해 노출됩니다.

제어

Google은 다양한 제어 장치를 이용해 Pub/Sub의 성능을 미세 조정합니다. 이러한 제어 장치 중 일부는 데이터 센터나 장치의 정전을 대비할 목적으로 제작되었습니다. 일부 또는 전체 주제에 라우팅 제약조건을 적용하기도 하는데, 포워더 모음에 연결할 수 있거나 연결할 수 없는 클라이언트 모음을 지정하는 규칙을 말합니다. 라우팅 제약 조건을 이용해, 예상대로 작동하지 않는 개별 포워더 작업이나 데이터 센터 전체로부터 트래픽을 분리합니다.

Google의 또 다른 조정 기능은 흐름 제어입니다. 이 기능을 이용하면 처리량을 극대화하면서도 서비스 과부화를 방지할 수 있습니다. 흐름 제어를 적용하면 부하가 갑자기 치솟아도 시간이 지나면 안정화되는 형태로 트래픽이 제어되기 때문에 서비스 안정성이 대폭 상승합니다. 흐름 제어는 시스템 전체 또는 특정 주제나 특정 구독자를 기준으로 작동해, 전송되거나 대기 중인 메시지 수 또는 바이트 수를 제한합니다. 여기서 '대기'란 클라이언트에게 전달되었지만 아직 확인되지 않은 상태를 말합니다. 흐름 제어와 라우팅 제약조건을 이용하면 Pub/Sub의 성능을 최적화하면서도 고객이 이러한 세부사항을 신경 쓸 필요가 없습니다.

요약

Pub/Sub 같은 서비스의 확장성, 가용성, 지연 시간은 관리형 클라우드 서비스로의 이전을 고려 중인 고객에게 할 수 있는 가치 제안입니다. 모든 비동기 메시징 서비스는 이러한 기능을 염두에 두고 개발되어야 합니다. 10년 넘게 수많은 메시지를 빠르고 안정적으로 전달해 온 Pub/Sub팀은 가장 핵심적인 Google 제품군의 요구를 충족하는 서비스를 개발 및 관리하고 있습니다. 이제 전 세계에 메시지를 전송하고 싶은 모든 외부 고객도 같은 서비스를 이용할 수 있습니다. 메시징 시스템이 지금보다 2배, 10배 또는 100배에 달하는 로드를 처리할 수 있을지 걱정할 필요가 없습니다.

용어

용어 설명
클러스터 같은 장애 도메인(공유 로컬 네트워크와 공유 파워 등)을 공유하는 기기의 논리적 집합
제어 영역 게시자와 구독자를 데이터 영역의 서버에 할당하는 작업을 처리하는 Pub/Sub 레이어
데이터 영역 게시자와 구독자 간의 메시지 이동을 처리하는 Pub/Sub 레이어
포워더 데이터 영역에 존재하는 서버
글로벌 데이터 액세스 Pub/Sub 게시자와 구독자 클라이언트는 데이터의 위치를 알지 못합니다. 모든 라우팅 및 저장은 위치 제한 정책에 따라 서비스 자체에서 수행됩니다.
수평 확장 가능 서비스 구성요소의 인스턴스 수를 늘려 더 많은 로드를 서비스 중단 없이 처리하는 능력
메시지 Pub/Sub를 통해 이동하는 데이터
네트워크 거리 두 기점 간 연결의 지연 시간 측정 단위
프로버 클라이언트 역할을 하며 Pub/Sub 서버에서 하나 이상의 작업을 예측 가능하게 수행하는 작업
게시 메시지 원본 게시 포워더가 수신하고 저장한 메시지 모음과 연결된 모든 구독이 확인한 메시지 ID 모음
게시/수신(Pub/Sub) 서비스 메시지 전송자가 메시지 수신자와 분리되는 메시징 서비스
게시자 특정 주제에 대한 메시지를 만들고 전송(게시)하는 Pub/Sub 클라이언트
라우터 제어 영역에 존재하는 서버
라우팅 제약조건 라우터가 연결 가능한 엔드포인트 역할을 해 클라이언트로 전송할 수 있거나 전송할 수 없는 포워더를 지정하는 규칙 모음
서비스수준계약(SLA) 고객에 대한 시스템의 성능 보장을 정의하고 보장 실패에 따른 결과를 설명하는 SLO 목록
서비스 수준 지표(SLI) 시스템의 동작을 설명하는 명확히 정의된 측정항목
서비스 수준 목표(SLO) 서비스 수준 지표의 구체적인 대상
구독자 지정한 구독에 대한 메시지를 받는 Pub/Sub 클라이언트
구독 특정 주제에 대한 모든 메시지 수신 의향을 나타내는, 이름이 지정된 항목
동기 지점 보장 구독이 생성되면 이후의 모든 게시된 메시지가 구독자에게 전달됩니다.
주제 메시지 피드를 나타내는, 이름이 지정된 항목