Pulsar 지리 복제
Pulsar 지리 복제 (Pulsar geo-replication)
지리 복제(geo-replication)는 서로 다른 지리적 지역에 배치된 여러 Pulsar 클러스터 간에 메시지를 비동기적으로 복제하는 기능이에요. 이 페이지는 네임스페이스에 지리 복제를 활성화하고, 복제를 구성하고, 복제 구독을 사용하는 방법을 안내해요.
출처: 문서
본문
네임스페이스에 지리 복제 활성화 (Enable geo-replication for a namespace)
Pulsar에서는 지리 복제를 tenant별로 활성화해야 해요. 예를 들어 특정 두 클러스터 사이에 지리 복제를 활성화하려면 tenant가 두 클러스터 모두에 접근 권한이 있어야 해요.
지리 복제는 네임스페이스 수준에서 관리돼요. 즉, 네임스페이스를 만들어 구성하기만 하면 tenant가 접근할 수 있는 두 개 이상의 프로비저닝된 클러스터 간에 메시지를 복제할 수 있어요.
네임스페이스에 지리 복제를 활성화하려면 다음 작업을 완료해요.
- 지리 복제 네임스페이스를 활성화한다
- 그 네임스페이스가 두 개 이상의 프로비저닝된 클러스터에 복제되도록 구성한다
구성 스토어와 지리 복제 설정 (Configuration store and geo-replication setup)
지리 복제 설정 — 클러스터 등록, 테넌트, 네임스페이스, 파티션 토픽 메타데이터, 그리고 그 정책 — 은 구성 스토어(configuration store)에 저장돼요. 개별 토픽 파티션과 비-파티션 토픽은 구성 스토어의 일부가 아니며, 각 클러스터에 로컬로 존재하고 클러스터의 메타데이터 스토어(metadata store)에서 추적돼요. 지리 복제에 공유 구성 스토어가 필수적이지는 않아요.
지리 복제 설정에서 구성 스토어를 관리하는 세 가지 접근 방식이 있어요.
독립 구성 스토어 (기본) (Independent configuration stores (default))
기본적으로 각 Pulsar 클러스터는 자체 메타데이터 스토어를 구성 스토어로도 사용해요. 따라서 각 클러스터가 자체 클러스터 등록, 테넌트, 네임스페이스, 파티션 토픽 메타데이터, 정책을 독립적으로 관리해요. 지리 복제를 설정하려면 모든 참여 클러스터가 서로 등록되어야 하고, 테넌트와 네임스페이스가 모든 클러스터에서 일치하는 복제 정책으로 생성되어야 해요.
공유 구성 스토어 (Shared configuration store)
클러스터들은 각 클러스터의 로컬 메타데이터 스토어와 분리된 전용 구성 스토어를 공유할 수 있어요. 공유 구성 스토어는 보통 내결함성을 위해 여러 지역 또는 영역에 걸쳐 배포돼요. 그것을 사용하는 모든 클러스터는 같은 클러스터 등록, 테넌트, 네임스페이스, 파티션 토픽 메타데이터, 정책을 공유하므로, 한 클러스터에서 한 변경은 다른 모든 클러스터에 즉시 보이게 돼요.
configurationMetadataSyncEventTopic을 통한 구성 동기화
각 클러스터에서 독립 구성 스토어를 사용할 때도, 구성 스토어 메타데이터는 configurationMetadataSyncEventTopic 설정을 사용해 클러스터 간에 동기화할 수 있어요. 이 설정을 부트스트랩하려면 각 참여 클러스터가 자체 클러스터 등록과 더불어 동기화 토픽을 담을 전용 테넌트·네임스페이스로 독립적으로 구성되어야 해요. 그 네임스페이스에 지리 복제가 활성화되면 구성 스토어 메타데이터 — 이후의 클러스터 등록, 테넌트, 네임스페이스, 그 정책을 포함 — 가 그 토픽을 통해 모든 참여 클러스터에 자동으로 동기화돼요.
토픽 정책 (Topic policies)
네임스페이스에 지리 복제가 활성화되면, 어느 구성 스토어 접근 방식이든 관계없이 토픽 정책이 지리 복제를 통해 공유돼요. 로컬(단일 클러스터)과 글로벌(전체 클러스터) 정책이 모두 지원돼요. 글로벌 토픽 정책은 특정 클러스터에서 로컬 토픽 정책으로 재정의되지 않는 한 모든 클러스터에 적용돼요. 토픽 정책은 브로커 구성에서 topicLevelPoliciesEnabled=true(기본적으로 활성화)가 필요해요.
지리 복제에서 토픽 생성 (Creation of topics in geo-replication)
비-파티션 토픽의 경우, 브로커 수준(기본값) 또는 네임스페이스 정책에서 토픽 자동 생성을 활성화하거나, 각 클러스터에서 토픽을 명시적으로 생성해야 해요.
파티션 토픽의 경우, 파티션 토픽 메타데이터(토픽 이름과 파티션 수)는 구성 스토어에 저장되지만, 개별 토픽 파티션 자체는 각 클러스터에 로컬이라는 점을 유의해요. createTopicToRemoteClusterForReplication=true(기본값)일 때는 단일 클러스터에서 토픽을 생성하면 충분해요 — Pulsar가 원격 클러스터에 일치하는 파티션 토픽 메타데이터를 자동으로 만들어요. 이름과 달리 이 설정은 파티션 토픽에만 적용돼요. createTopicToRemoteClusterForReplication을 비활성화하고 클러스터가 구성 스토어를 공유하지 않으면, 파티션 토픽은 각 클러스터에서 명시적으로 생성되어야 해요. 그 경우 파티션 토픽 메타데이터가 클라이언트가 연결되기 전에 모든 클러스터에 존재해야 해요. 없다면 컨슈머가 메타데이터가 없는 클러스터에서 비-파티션 토픽을 자동 생성해 클러스터 간 토픽 유형이 호환되지 않을 수 있어요. 또한 복제가 대상 클러스터에 대응하는 파티션 토픽 메타데이터 없이 개별 토픽 파티션을 만들어 그 파티션을 고아(orphan)로 남길 수 있어요. 이런 이유로 createTopicToRemoteClusterForReplication을 활성화해 두는 것을 권장해요.
연쇄적 토픽 삭제 (Cascading topic deletions)
구성 접근 방식은 복제 클러스터 구성 변경이 클러스터 간에 어떻게 전파되는지도 결정해요. 특히 특정 구성 변경은 원격 클러스터에서 자동 토픽 삭제를 트리거할 수 있어요. 자세한 내용은 Cascading topic deletions when modifying the replication clusters configuration을 참고해요.
복제 구성 설정 (Replication configuration settings)
메시지 복제의 대상 클러스터는 tenant, 네임스페이스, 토픽, 메시지 수준의 설정 계층으로 결정돼요.
- Tenant allowed-clusters: tenant가 복제에 사용할 수 있는 클러스터를 지정해요. 빈 값은 모든 클러스터가 허용됨을 의미해요. 이 설정은 tenant에 기존 네임스페이스가 생기면 수정할 수 없으므로, tenant 아래에 네임스페이스를 만들기 전에 구성해야 해요.
- Namespace clusters: 네임스페이스의 메시지가 복제되는 기본 클러스터 집합을 정의해요.
- Namespace allowed-clusters: 네임스페이스 수준에서 복제가 허용되는 클러스터를 추가로 제한하며, tenant 수준 설정을 재정의해요. PIP-321에서 도입됐어요.
- Topic-level policies: 특정 토픽에 대해 네임스페이스 수준 clusters 설정을 재정의할 수 있어요. 토픽 정책은 로컬(로컬 클러스터에만 적용) 또는 글로벌(지리 복제 집합의 모든 클러스터에 복제, PIP-92 참고)일 수 있어요. allowed-clusters는 토픽 수준에서 구현되지 않았어요. PIP-321은 나중에 추가될 수 있다고 언급해요.
- Message-level replication control: 프로듀서가 클라이언트 API의
replicationClusters메서드로 특정 메시지가 복제될 클러스터를 재정의하거나,disableReplication으로 메시지 복제를 완전히 비활성화할 수 있어요(Selective replication 참고). 이 설정들은 allowed-clusters 구성을 재정의할 수 없어요 — 메시지는 해석된 allowed-clusters 설정이 허용하는 클러스터로만 라우팅될 수 있어요.
clusters와 allowed-clusters 설정은 계층적으로 해석돼요. tenant 수준 allowed-clusters가 비어 있지 않으면, 네임스페이스 수준 allowed-clusters에 지정된 모든 클러스터는 그것의 부분집합이어야 해요 — 이는 네임스페이스 수준 allowed-clusters를 수정할 때 검증돼요. 네임스페이스 수준 allowed-clusters는 tenant 구성을 추가로 제한할 수 있고, 토픽 수준 정책은 특정 토픽에 대해 네임스페이스 수준 clusters 설정을 재정의할 수 있어요.
1방향(단방향) 및 2방향(양방향) 지리 복제 (1-way (unidirectional) and 2-way (bidirectional) geo-replication)
지리 복제는 1방향(단방향) 또는 2방향(양방향)으로 구성할 수 있어요. 사용 가능한 옵션은 공유 구성 스토어를 사용하는지에 따라 달라져요.
공유 구성 스토어를 사용할 때의 복제 방향
공유 구성 스토어를 사용하면 네임스페이스 구성이 모든 클러스터에서 공유되므로 지리 복제는 네임스페이스 수준에서 항상 2방향이에요. 특정 클러스터에 로컬 클러스터만 포함하는 로컬 토픽 수준 clusters 정책을 추가하면 개별 토픽을 단방향으로 만들 수 있어요. 이렇게 하면 그 클러스터에서 생산된 메시지가 다른 클러스터로 복제되는 것을 막아요. 하지만 토픽 정책에는 allowed-clusters가 없으므로 프로듀서가 메시지 수준 replicationClusters 설정으로 여전히 이를 재정의할 수 있어, 공유 구성 스토어로는 1방향 복제의 진정한 강제가 불가능해요.
별도 메타데이터 스토어를 사용할 때의 복제 방향
각 클러스터가 자체 메타데이터 스토어를 사용하면, 1방향 또는 2방향 복제는 각 클러스터의 네임스페이스 clusters와 allowed-clusters 설정으로 결정돼요.
-
2방향 복제: 두 클러스터 모두 네임스페이스 clusters와 allowed-clusters 설정에 서로를 포함하므로 메시지가 양방향으로 흘러요.
-
1방향 복제: 아웃바운드로 복제하지 않아야 하는 클러스터에서 clusters와 allowed-clusters 모두 로컬 클러스터만 포함하도록 설정해요. 원격 클러스터는 구성된 대로 이 클러스터로 인바운드 복제는 계속할 수 있어요.
-
allowed-clusters: 나열되지 않은 클러스터로의 복제를 강제로 방지해요. 프로듀서가 메시지 수준replicationClusters설정으로 재정의할 수 없어요. -
clusters: 기본 복제 대상을 설정해요. 로컬 클러스터만 나열하면 아웃바운드 복제가 기본적으로 비활성화되지만,allowed-clusters도 제한하지 않는 한 프로듀서가replicationClusters로 메시지별로 재정의할 수 있어요.
note
복제 구독(replicated subscription) 기능은 2방향 지리 복제가 필요하며, 지리 복제를 1방향으로 구성하면 사용할 수 없어요.
로컬 영속화와 전달 (Local persistence and forwarding)
Pulsar 토픽에 메시지가 생산되면 메시지는 먼저 로컬 클러스터에 영속화되고, 그다음 원격 클러스터로 비동기적으로 전달돼요.
정상적인 경우, 연결 문제가 없으면 메시지는 로컬 컨슈머에게 디스패치되는 것과 동시에 즉시 복제돼요. 일반적으로 원격 지역 간의 네트워크 왕복 시간(RTT)이 종단 간 전달 지연을 결정해요.
애플리케이션은 원격 클러스터에 연결할 수 없을 때도(네트워크 파티션 동안처럼) 어느 클러스터에서든 프로듀서와 컨슈머를 만들 수 있어요.
프로듀서와 컨슈머는 Pulsar 인스턴스의 어떤 클러스터에서든 메시지를 게시하고 소비할 수 있어요. 하지만 지리 복제는 토픽 데이터를 복제하지 구독을 복제하지는 않아요. 각 구독은 생성된 클러스터에 로컬이며, 다른 클러스터의 같은 이름의 구독은 자체 커서·컨슈머·백로그를 가진 별도의 구독이에요. 자세한 내용은 Subscriptions and consumers across clusters를 참고해요.
클러스터 간에 동기화될 수 있는 유일한 구독 관련 상태는 복제 구독(replicated subscription)의 mark-delete 위치예요. 복제 구독을 활성화하면 그 상태가 동기화 상태로 유지되므로, 컨슈머가 다른 클러스터의 실패 지점부터 다시 소비를 시작할 수 있어요. 복제 구독은 페일오버용으로 설계되었고 액티브-액티브 소비용이 아니므로, 한 번에 단일 클러스터에서 메시지를 처리해요.

위 예시에서 T1 토픽은 세 클러스터 Cluster-A, Cluster-B, Cluster-C 간에 복제돼요.
세 클러스터 중 어느 곳에서 생산된 메시지도 모두 다른 두 클러스터로 복제된 다음 각 클러스터에 존재하는 구독으로 디스패치돼요. 이 경우 C1과 C2 컨슈머는 각각 P1, P2, P3 프로듀서가 게시하는 모든 메시지를 받아요. C1과 C2가 각 클러스터의 별도 독립 구독에 속하기 때문이에요. 순서는 프로듀서별로 여전히 보장돼요.
복제 구성 (Configure replication)
지리 복제 클러스터를 구성하려면 다음 단계를 완료해요.
Step 1: 복제 클러스터 연결 (Connect replication clusters)
클러스터 간에 데이터를 복제하려면 각 클러스터가 다른 클러스터에 연결하도록 구성해야 해요. pulsar-admin 도구로 연결을 만들 수 있어요.
예제:
3개의 복제 클러스터 us-west, us-cent, us-east가 있다고 가정해요.
- us-west에서 us-east로의 연결을 구성해요. us-west에서 다음 명령을 실행해요.
bin/pulsar-admin clusters create \
--broker-url pulsar://<DNS-OF-US-EAST>:<PORT> \
--url http://<DNS-OF-US-EAST>:<PORT> \
us-east
tip
- 클러스터에 보안 연결을 사용하려면
--broker-url-secure와--url-secure플래그를 사용할 수 있어요. 자세한 내용은 pulsar-admin clusters create를 참고해요.- 다른 클러스터가 서로 다른 인증을 가질 수 있어요.
--auth-plugin과--auth-parameters인증 플래그를 함께 사용해 클러스터 인증을 설정할 수 있어요. 이는 broker.conf와 standalone.conf에서authenticationEnabled가 true로 설정되면brokerClientAuthenticationPlugin과brokerClientAuthenticationParameters를 재정의해요. 자세한 내용은 authentication and authorization을 참고해요.
- us-west에서 us-cent로의 연결을 구성해요. us-west에서 다음 명령을 실행해요.
bin/pulsar-admin clusters create \
--broker-url pulsar://<DNS-OF-US-CENT>:<PORT> \
--url http://<DNS-OF-US-CENT>:<PORT> \
us-cent
- us-east와 us-cent에서도 유사한 명령을 실행해 클러스터 간 연결을 만들어요.
Step 2: 프로퍼티에 권한 부여 (Grant permissions to properties)
클러스터로 복제하려면 tenant가 그 클러스터를 사용할 권한이 있어야 해요. tenant를 만들 때 권한을 부여하거나 나중에 부여할 수 있어요.
tenant를 만들 때 의도한 모든 클러스터를 지정해요.
bin/pulsar-admin tenants create my-tenant \
--admin-roles my-admin-role \
--allowed-clusters us-west,us-east,us-cent
기존 tenant의 권한을 업데이트하려면 create 대신 update를 사용해요.
Step 3: 지리 복제 활성화 (Enable geo-replication)
네임스페이스 또는 토픽 수준에서 지리 복제를 활성화할 수 있어요.
네임스페이스 수준에서 지리 복제 활성화
다음 명령 샘플로 네임스페이스를 만들 수 있어요.
bin/pulsar-admin namespaces create my-tenant/my-namespace
처음에는 네임스페이스가 어떤 클러스터에도 할당되지 않아요. set-clusters 하위 명령으로 네임스페이스를 클러스터에 할당할 수 있어요.
bin/pulsar-admin namespaces set-clusters my-tenant/my-namespace \
--clusters us-west,us-east,us-cent
토픽 수준에서 지리 복제 활성화
pulsar-admin topics set-replication-clusters 명령으로 토픽 수준에서 지리 복제를 설정할 수 있어요. Pulsar admin의 최신·전체 정보(명령, 플래그, 설명 등)는 Pulsar admin docs를 참고해요.
bin/pulsar-admin topics set-replication-clusters --clusters us-west,us-east,us-cent my-tenant/my-namespace/my-topic
tip
- 네임스페이스의 복제 클러스터는 진행 중인 트래픽에 중단 없이 언제든 바꿀 수 있어요. 구성이 바뀌는 즉시 복제 채널이 모든 클러스터에서 켜지거나 꺼져요.
- 지리 복제 네임스페이스를 만들면 프로듀서나 컨슈머가 그 네임스페이스 안에 만드는 모든 토픽이 클러스터 간에 복제돼요. 보통 각 애플리케이션은 로컬 클러스터의 serviceUrl을 사용해요.
- Pulsar 2.10.x를 사용한다면 토픽 수준 지리 복제를 활성화하려면 conf/broker.conf 또는 conf/standalone.conf 파일에서 다음 구성을 변경해 토픽 정책 서비스를 활성화해야 해요.
systemTopicEnabled=true
topicLevelPoliciesEnabled=true
Step 4: 지리 복제로 토픽 사용 (Use topics with geo-replication)
선택적 복제 (Selective replication)
기본적으로 메시지는 네임스페이스에 구성된 모든 클러스터로 복제돼요. 메시지에 복제 목록을 지정해 복제를 선택적으로 제한할 수 있고, 그러면 그 메시지는 복제 목록의 부분집합으로만 복제돼요.
다음은 Java API 예시예요. Message 객체를 만들 때 replicationClusters 메서드를 사용하는 점을 유의해요.
List<String> restrictReplicationTo = Arrays.asList(
"us-west",
"us-east"
);
Producer producer = client.newProducer()
.topic("some-topic")
.create();
producer.newMessage()
.value("my-payload".getBytes())
.replicationClusters(restrictReplicationTo)
.send();
토픽 통계 (Topic stats)
지리 복제 토픽에 대한 토픽별 통계를 다음 방법 중 하나로 확인할 수 있어요.
pulsar-admin · REST API
pulsar-admin topics stats 명령을 사용해요.
bin/pulsar-admin topics stats persistent://my-tenant/my-namespace/my-topic
REST API: GET /admin/v2/persistent/{tenant}/{namespace}/{topic}/stats
각 클러스터는 인바운드·아웃바운드 복제 비율과 백로그를 포함한 자체 로컬 통계를 보고해요.
지리 복제 토픽 삭제 (Geo-replication topic deletion)
명시적 토픽 삭제 (Explicit topic deletion)
모든 클러스터에서 지리 복제 토픽을 삭제하는 권장 절차는 다음과 같아요.
- 진행하기 전에 모든 클러스터에서 토픽에 활성 프로듀서나 컨슈머가 없는지 확인해요. 다음 단계를 수행할 때 이들이 있으면 그 아래에서 토픽이 강제로 삭제돼요. 토픽 자동 생성도 활성화되어 있으면 토픽이 즉시 다시 생성될 수 있어요.
- 로컬 클러스터만 포함하는 글로벌 토픽 수준 clusters 정책을 설정해요. 이는 연쇄 삭제 메커니즘을 트리거해 제외된 모든 클러스터에서 토픽(파티션 토픽의 경우 토픽 파티션 포함)을 제거하고 스키마와 로컬 토픽 정책을 정리해요. 제외된 클러스터에 연결된 프로듀서와 컨슈머는 재연결이 거부돼요. 자세한 내용은 Cascading topic deletions when modifying the replication clusters configuration을 참고해요.
- 토픽을 삭제해요. 이제 지리 복제가 비활성화되어 삭제는 로컬 클러스터에만 영향을 줘요.
- 각 클러스터에서
pulsar-admin topicPolicies delete <topic>을 실행해 남은 토픽 수준 정책 상태를 제거해요. 이 시점에 활성 프로듀서나 컨슈머가 여전히 있다면 토픽이 다시 생성되고 지리 복제가 재활성화될 수 있어서, step 1이 전제 조건이에요.
이 절차 없이 한 클러스터에서 토픽을 강제 삭제하면 그 토픽은 고아가 돼요 — 피어 클러스터에 여전히 존재하고 그 클러스터들의 지리 복제는 계속 활성 상태예요. 토픽이 삭제된 클러스터에서 토픽 자동 생성을 활성화했다면, 자동 생성 또는 피어 클러스터에 createTopicToRemoteClusterForReplication=true가 설정되어 있어 토픽이 다시 생성될 수 있어요.
네임스페이스 또는 토픽 구성이 공유 구성 스토어를 통해 공유되거나 configurationMetadataSyncEventTopic으로 동기화되면, 토픽을 강제 삭제하면 구성을 공유하거나 받는 모든 클러스터에 삭제가 전파돼요. 하지만 복제 지연으로 인해 삭제가 모든 곳에 반영되기 전에 토픽이 다시 생성될 수 있어요. 이런 이유로 위 절차를 따르는 것을 권장해요.
특정 클러스터에서만 토픽을 제거하려면 그 클러스터를 제외하는 글로벌 토픽 수준 clusters 정책을 설정해요. 브로커는 제외된 클러스터에서 토픽(파티션 토픽의 경우 토픽 파티션 포함)을 자동으로 삭제해요. 이후 글로벌 토픽 수준 정책을 제거하지 마세요. 네임스페이스 수준 clusters 정책이 적용돼 복제가 다시 활성화될 수 있기 때문이에요. 나중에 토픽을 모든 클러스터에서 삭제하려면 위 전체 절차를 따르세요.
토픽을 유지하면서 다른 모든 클러스터에서는 제거하려면, 토픽을 유지할 클러스터에서 위 절차를 따르되 step 3과 4는 생략해요.
가비지 컬렉션에 의한 삭제 (Deletion by garbage collection)
지리 복제 토픽은 brokerDeleteInactiveTopicsEnabled=true이고 연결된 프로듀서나 컨슈머가 없을 때 가비지 컬렉션에 의해 자동으로 삭제되기도 해요. 추가 조건은 brokerDeleteInactiveTopicsMode 설정에 따라 달라져요.
delete_when_no_subscriptions: 구독이 없을 때 토픽을 삭제해요.delete_when_subscriptions_caught_up: 모든 구독이 따라잡혔고 백로그가 없을 때 토픽을 삭제해요.
brokerDeleteInactiveTopicsMode 설정은 네임스페이스 수준에서 inactive-topic-policies로 재정의할 수 있어요.
각 지역은 토픽을 로컬로 삭제하는 것이 안전한 시점을 독립적으로 결정해요. 가비지 컬렉션을 트리거하려면 모든 복제 클러스터에서 토픽의 모든 프로듀서와 컨슈머를 닫고 모든 로컬 구독을 삭제해요. Pulsar가 시스템 전체에 유효한 구독이 남지 않았다고 판단하면 토픽을 가비지 컬렉션해요.
복제 클러스터 구성 수정 시 연쇄적 토픽 삭제 (Cascading topic deletions when modifying the replication clusters configuration)
warning
네임스페이스 또는 토픽 정책 수준에서 clusters 구성을 수정하면 제외된 클러스터에서 자동 토픽 삭제를 트리거할 수 있어요. 우발적 삭제에 대한 보호가 요구된다면 항상 독립 백업을 유지하세요.
네임스페이스 수준 삭제 (Namespace-level deletions)
네임스페이스 구성이 클러스터 간에 공유되거나 동기화되면(공유 구성 스토어 또는 configurationMetadataSyncEventTopic을 통해, Configuration store and geo-replication setup 참고), 네임스페이스 clusters 구성에서 클러스터를 제거하면 제외된 클러스터에서 그 네임스페이스의 모든 토픽이 자동으로 삭제돼요. 네임스페이스 구성이 공유되거나 동기화되지 않으면 네임스페이스 수준 정책 변경은 로컬에 머물고 원격 클러스터에서 연쇄 삭제를 트리거하지 않아요.
네임스페이스 수준 allowed-clusters를 수정해 클러스터를 제외하면, clusters가 allowed-clusters의 부분집합이어야 하므로 토픽 수준 clusters 정책과 관계없이 그 클러스터의 토픽도 삭제돼요.
토픽 수준 삭제 (Topic-level deletions)
네임스페이스에 지리 복제가 활성화되어 있으면 토픽 정책은 항상 지리 복제로 공유되므로(Topic policies 참고), 클러스터를 제외하도록 글로벌 토픽 수준 clusters 정책을 업데이트하면 네임스페이스 구성이 공유되든 동기화되든 관계없이 제외된 클러스터에서 그 토픽과 모든 파티션을 삭제해요. 마지막 토픽 파티션이 삭제된 후 스키마와 로컬 토픽 정책이 정리돼요. 토픽 수준 정책 업데이트는 네임스페이스의 복제 방향을 따르는데, 1방향 복제에서는 업데이트가 대상 클러스터 방향으로만 흘러요.
특정 토픽 유지 (Retaining specific topics)
네임스페이스 clusters 구성이 바뀔 때 특정 토픽이 삭제되지 않도록 하려면, 그 토픽에 대해 유지할 클러스터를 나열하는 글로벌 토픽 수준 clusters 정책을 설정해요. 이는 그 토픽에 대해 네임스페이스 수준 clusters 정책을 재정의해요. 현재 토픽 정책에서 네임스페이스 수준 allowed-clusters를 재정의할 수 없으므로, allowed-clusters도 변경되어 클러스터를 제외하면 이 보호는 적용되지 않아요.
네임스페이스의 모든 토픽을 보호하는 단일 구성은 없어요 — 정책을 각 토픽에 개별적으로 적용해야 해요. 글로벌 토픽 수준 정책 자체가 클러스터를 제외하도록 수정되는 것에 대한 추가 보호를 위해, 그 클러스터에 로컬 클러스터만 포함하는 로컬 토픽 수준 clusters 정책을 설정할 수도 있어요.
지리 복제는 고가용성과 재해 복구를 위해 설계됐지 백업을 대체하지는 않아요. 잘못 구성된 clusters 정책은 피어 클러스터에서 연쇄 토픽 삭제를 트리거할 수 있어요.
복제 구독 (Replicated subscriptions)
Pulsar는 복제 구독을 지원해서, 비동기적으로 여러 지리적 지역에 복제되는 토픽의 맥락에서 구독 상태를 1초 미만의 시간대에 동기화 상태로 유지할 수 있어요.
페일오버 시 컨슈머는 다른 클러스터의 실패 지점부터 다시 소비를 시작할 수 있어요.
복제 구독 활성화 (Enable replicated subscription)
note
복제 구독은 모든 참여 클러스터 간에 2-way 지리 복제가 제대로 구성되어 있어야 해요. 구성 요구 사항은 1-way and 2-way geo-replication을 참고해요.
Pulsar에서 복제 구독을 사용하려면 다음을 수행해요.
broker.conf에서enableReplicatedSubscriptions가 true인지 확인해요. 기본적으로 활성화돼 있어요.- 컨슈머 쪽: 복제 구독은 기본적으로 비활성화돼 있어요. 컨슈머를 만들 때 복제 구독을 활성화할 수 있어요.
Consumer<String> consumer = client.newConsumer(Schema.STRING)
.topic("my-topic")
.subscriptionName("my-subscription")
.replicateSubscriptionState(true)
.subscribe();
장점 (Advantages)
복제 구독의 장점은 다음과 같아요.
- 로직 구현이 쉬워요.
- 복제 구독을 켜거나 끌 수 있어요.
- 켜면 오버헤드가 낮고 구성이 쉬워요.
- 끄면 오버헤드가 0이에요.
제한 사항 (Limitations)
복제 구독의 제한 사항은 다음과 같아요.
- 복제 구독은 주기적 스냅샷을 사용해 클러스터 간에 메시지 위치의 일관된 연관 관계를 만드는데, 스냅샷은
replicatedSubscriptionsSnapshotFrequencyMillis밀리초(기본 1000ms)마다 찍혀요. 하지만 원격 클러스터에서 mark-delete 위치 업데이트의 실제 세분성은 스냅샷 사이에 생산되는 메시지 수에 달려요. 자세한 내용은 Replicated subscriptions snapshot configuration and tuning을 참고해요. - mark-delete 위치(기준 커서 위치)만 복제되고 개별 승인은 복제되지 않아요. 순서가 맞지 않게 승인된 메시지는 클러스터 페일오버 후 재전달될 수 있어요.
- 복제 구독은 여러 클러스터에서 컨슈머가 동시에 활성일 때는 일관된 동작을 제공하지 않아요. 대부분의 메시지가 두 클러스터 모두에서 처리되고(중복 처리), 일부는 복제 타이밍에 따라 어느 한 클러스터에서 처리될 수 있어요. 이를 피하려면 복제 구독을 사용할 때 한 번에 단일 클러스터에서 메시지를 처리해요.
- 지연 메시지 전달은 구독 복제를 저하시켜요. 지연 메시지가 전달·승인될 때까지 mark-delete 위치가 전진하지 않으므로 복제도 그에 따라 뒤처져요.
note
- 마지막 시도 이후 새 메시지가 생산되면
replicatedSubscriptionsSnapshotFrequencyMillis마다 스냅샷 시도가 시작돼요. 각 시도는 토픽에 여러 마커 메시지를 기록해요 — 스냅샷 요청, 원격 클러스터의 응답(복제되어 돌아옴), 마지막 스냅샷 마커요. 이 마커들은 양쪽 클러스터의 비활성 구독 백로그를 늘려요.
복제 구독 스냅샷 구성과 튜닝 (Replicated subscriptions snapshot configuration and tuning)
복제 구독은 주기적 스냅샷 메커니즘을 사용해 클러스터 간에 메시지 위치의 일관된 연관 관계를 만드는데, 설계는 PIP-33: Replicated subscriptions에 설명되어 있어요.
각 스냅샷 시도는 한 라운드 또는 두 라운드로 구성되며, 각 라운드는 모든 원격 클러스터로 보내는 스냅샷 요청과 그에 이은 응답으로 이뤄져요. 두 클러스터면 한 라운드로 충분하고, 두 개보다 많으면 두 라운드가 필요해요. 스냅샷 요청과 응답 마커가 마커 메시지로 토픽에 기록되고 각 참여 클러스터의 복제기가 그것을 읽기 전에 토픽의 모든 선행 메시지를 처리해야 하므로 각 라운드에 시간이 걸려요. 높은 부하에서는 전체 스냅샷 시도 시간이 기본 replicatedSubscriptionsSnapshotTimeoutSeconds인 30초를 넘을 수 있어 완료된 스냅샷 없이 시간 초과될 수 있는데, 이는 두 라운드가 필요할 때 위험이 더 커요. 모든 라운드가 성공적으로 완료되면 일관된 교차 클러스터 위치 매핑을 포함한 최종 스냅샷이 토픽에 기록돼요.
어떤 참여 클러스터가 오프라인이면 스냅샷 시도가 시작되지 않아 스냅샷이 생성되지 않아요. 그 결과, 연결이 복원된 후에도 오프라인 기간 동안 축적된 메시지에 대한 mark-delete 위치 업데이트가 전파될 수 없는데, 그 메시지들에 연관된 스냅샷이 없기 때문이에요.
원격 클러스터에서 mark-delete 위치 업데이트의 실제 세분성은 연속 스냅샷 사이에 기록되는 메시지 수에 의해 결정되지 replicatedSubscriptionsSnapshotFrequencyMillis 단독으로는 결정되지 않아요. 버스트형 또는 고속 메시지 생산에서는 스냅샷 간격당 많은 메시지가 축적되어, mark-delete 위치 업데이트 간격이 스냅샷 주파수 설정이 시사하는 것보다 훨씬 길어져요. 이는 소비가 생산보다 훨씬 느릴 때 특히 문제가 되는데, 예를 들어 배치 작업이 30초 안에 대량의 메시지를 생산하지만 그것을 소비·승인하는 데 몇 분이나 몇 시간이 걸리는 경우예요.
잠재적 향후 개선은 복제기가 백로그를 비울 때까지 기다리는 대신 메시지 게시 시점에 스냅샷 요청과 응답을 처리하는 것이에요. 이렇게 하면 고속 메시지 생산에서 스냅샷 왕복 시간과 스냅샷 지연이 크게 줄어들 거예요.
구독의 mark-delete 위치는 구독의 스냅샷 캐시에 적절한 스냅샷이 있을 때만 원격 클러스터로 전파될 수 있어요. 스냅샷은 mark-delete 위치가 스냅샷의 로컬 위치 — 스냅샷이 생성된 로컬 클러스터 토픽의 위치 —에 도달했거나 지나갔을 때 적절해요. 완료된 스냅샷은 구독의 디스패처가 토픽에서 메시지를 읽는 대로 캐시에 추가돼요. 스냅샷 캐시는 모든 컨슈머가 연결을 끊을 때 지워져요 — 토픽 언로드, 브로커 재시작, 로드 셰딩, 명시적 연결 해제 등 그 원인이 무엇이든요. 첫 컨슈머가 다시 연결되면 디스패처가 mark-delete 위치부터 모든 미승인 메시지와 복제 마커 메시지를 다시 읽어 스냅샷 캐시를 복원하고 미승인 메시지를 재전달해요.
Pulsar 4.0.9와 4.1.3에서 PR #25044로 수정된 알려진 문제는 mark-delete 위치가 느리게 전진하는 시나리오에서 구독 상태 복제가 멈추는 것이었어요. 이는 개별 승인을 사용하는 공유(shared) 또는 키-공유(key-shared) 구독 — mark-delete 위치가 전진하려면 모든 승인 간격이 채워져야 하는 — 및 지연 메시지 전달을 사용하는 토픽에 영향을 줘요. 원래 캐시 만료 정책은 replicatedSubscriptionsSnapshotMaxCachedPerSubscription개의 가장 최근 생성된 스냅샷만 유지하고 오래된 것을 제거했어요. 그 결과, mark-delete 위치가 마지막 replicatedSubscriptionsSnapshotFrequencyMillis × replicatedSubscriptionsSnapshotMaxCachedPerSubscription 밀리초(기본 설정에서 10초) 안에 전진하지 않았다면 캐시된 모든 스냅샷이 mark-delete 위치보다 앞에 있어 적절한 스냅샷이 없게 될 수 있었어요.
PR #25044가 도입한 개선된 스냅샷 캐시 만료 정책은 캐시가 가득 찼을 때 현재 mark-delete 위치 앞에서부터 최신 스냅샷까지 전체 백로그 범위에 걸쳐 스냅샷을 유지함으로써 이를 해결해요. 첫 캐시 스냅샷은 mark-delete 위치가 그를 지나 전진할 때까지 항상 유지되어, 큰 백로그에서도 결국 전진이 이루어짐을 보장해요. 스냅샷 캐시 크기(replicatedSubscriptionsSnapshotMaxCachedPerSubscription)를 크게 하면 후속 스냅샷이 더 조밀하게 분포되어 복제가 더 자주 진행되고 페일오버 시 복제 지연과 잠재적 중복 메시지 수가 모두 줄어요.
PR #25044는 또한 각 스냅샷 엔트리의 메모리 사용량을 약 200바이트로 줄여, 큰 백로그에서 더 미세한 스냅샷 세분성이 필요할 때 replicatedSubscriptionsSnapshotMaxCachedPerSubscription을 기본 30보다 훨씬 높게 늘리는 것을 실용적으로 만들어요. 대가는 더 높은 힙 메모리 소비이며, 브로커 크기를 산정할 때 고려해야 해요. 현재 구현은 전역 메모리 예산 대신 구독별 고정 한도를 사용해요. 향후 개선은 총 캐시 메모리 소비를 상한으로 제한하고 한도에 도달하면 같은 분포 기반 축출 전략을 적용할 수 있어요.
이미 메시지를 포함하는 네임스페이스에서 지리 복제를 활성화하면 기존 백로그에 스냅샷 마커가 없어요. mark-delete 위치는 복제기가 사전 존재 메시지를 읽고 지나가고 새 스냅샷이 기록·처리될 때까지 전파될 수 없어요 — 스냅샷 캐시 크기와 무관해요. 마찬가지로 개선된 캐시 축출 정책이나 캐시 크기 증가 모두 버스트 트래픽에서의 스냅샷 사이의 긴 간격을 다루지 않으며, 이는 원격 클러스터로의 mark-delete 위치 업데이트 지연에 계속 영향을 줘요.
다음 브로커 설정이 스냅샷 동작을 제어해요.
| Setting | Default | Description |
|---|---|---|
replicatedSubscriptionsSnapshotFrequencyMillis |
1000 | 스냅샷 시도가 시작되는 빈도. 마지막 시도 완료 이후 새 메시지가 생산된 경우에만 새 시도가 시작돼요. |
replicatedSubscriptionsSnapshotTimeoutSeconds |
30 | 스냅샷 시도가 포기되기 전까지 진행될 수 있는 시간. |
replicatedSubscriptionsSnapshotMaxCachedPerSubscription |
30 (PR #25044에서 10에서 증가) | 구독당 캐시되는 최대 스냅샷 수. 각 엔트리는 약 200바이트의 메모리를 소비해요. |
튜닝 권장 사항:
- 두 개보다 많은 클러스터: 두 라운드 스냅샷 시도가 시간 초과 전에 완료되도록
replicatedSubscriptionsSnapshotTimeoutSeconds를 60으로 늘려요. - 느린 mark-delete 전진이 있는 큰 백로그(개별 승인을 사용하는 공유 또는 키-공유 구독, 또는 지연 메시지 전달):
replicatedSubscriptionsSnapshotMaxCachedPerSubscription을 최소 50으로 늘려 캐시된 스냅샷이 더 조밀하게 분포되고, 전진할 때 mark-delete 위치에 적절한 스냅샷이 가까이 있을 가능성을 높여요. 값 50에서 스냅샷 캐시는 구독당 약 10KB의 힙 메모리를 소비하고, 기본 30에서는 구독당 약 6KB의 메모리 사용량을 가져요.
복제 구독 시퀀스 다이어그램 (Replicated subscriptions sequence diagrams)
이 시퀀스 다이어그램은 두 클러스터 간에 구독 상태를 복제하는 데 관련된 상호작용을 보여줘요. 한 클러스터의 mark-delete 위치가 다른 쪽에 어떻게 전파되는지, 그리고 복제 스냅샷 캐시의 역할 — 적절한 스냅샷이 없으면 구독 업데이트가 복제되지 않을 수 있는 이유를 포함 — 이 드러나요. 스냅샷은 mark-delete 위치가 스냅샷의 로컬 위치에 도달했거나 지나갔을 때 적절해요.
관찰 가능성 (Observability)
복제 구독의 관찰 가능성은 제한적이에요. 디버깅을 위해 org.apache.pulsar.broker.service.persistent.ReplicatedSubscriptionsController에서 디버그 수준 로그를 사용할 수 있지만, 프로덕션 운영에는 적합하지 않아요.
스냅샷 상태 모니터링을 위해 다음 브로커 수준 메트릭을 사용할 수 있어요. 이 메트릭은 브로커의 모든 토픽에 걸쳐 집계되며 토픽별 라벨을 포함하지 않아요.
| Metric | OpenTelemetry name | Description |
|---|---|---|
pulsar_replicated_subscriptions_pending_snapshots |
pulsar.broker.replication.subscription.snapshot.operation.count |
현재 대기 중인 스냅샷 수 |
pulsar_replicated_subscriptions_timedout_snapshots |
pulsar.broker.replication.subscription.snapshot.operation.duration |
시간 초과된 스냅샷 수 |
토픽 통계와 내부 통계를 사용해 구독 상태를 검사할 수 있어요. 커서의 mark-delete 위치가 특히 유용한데, 구독 상태는 그 위치까지만 복제될 수 있기 때문이에요.
잠재적 향후 개선은 토픽 통계에 스냅샷 관련 토픽 수준 카운터를 포함한 대기 중인 스냅샷 시도 상태를, 구독별 통계에 스냅샷 캐시 상태를 노출하는 것이에요. 이렇게 하면 복제 구독 문제를 조사할 때 가시성이 향상돼요.
지리 복제로 클러스터 간 데이터 마이그레이션 (Migrate data between clusters using geo-replication)
지리 복제로 클러스터 간 데이터를 마이그레이션하는 것은 데이터 양이 많지 않을 때 액티브-액티브 복제 패턴의 특수한 사용 사례예요.
warning
데이터를 원격 클러스터로 복제한 다음 독립 데이터 스냅샷을 유지하려는 의도로 그 클러스터를 네임스페이스 복제 구성에서 제거하는 것은 지원되지 않는 사용 사례예요. 구성을 제거하면 특정 경우 그 클러스터의 모든 토픽의 연쇄 삭제를 트리거해, 데이터의 독립 복사본을 유지하려는 목표일 때 데이터 손실 위험이 있어요. 연쇄 삭제를 방지하는 것이 가능하지만 거기에는 주의사항이 있어요. 자세한 내용은 Cascading topic deletions when modifying the replication clusters configuration을 참고해요.
- 새 클러스터를 만들어요.
- 새 클러스터를 기존 클러스터에 추가해요.
bin/pulsar-admin clusters create new-cluster
- 새 클러스터를 tenant에 추가해요.
bin/pulsar-admin tenants update my-tenant --cluster old-cluster,new-cluster
- 네임스페이스에 클러스터를 설정해요.
bin/pulsar-admin namespaces set-clusters my-tenant/my-ns --cluster old-cluster,new-cluster
- 복제 구독을 사용하도록 애플리케이션을 업데이트해요.
- 구독 복제가 활성인지 검증해요.
bin/pulsar-admin topics stats-internal public/default/t1
- serviceURL 값을 수정해 컨슈머와 프로듀서를 새 클러스터로 이동해요.
note
- 복제는 step 4부터 시작하므로 기존 클러스터의 기존 메시지는 복제되지 않아요.
- 마이그레이션할 더 오래된 메시지가 있다면
pulsar-admin topics create-subscription -s pulsar.repl.new-cluster -m earliest <topic>으로 각 토픽의 복제 구독을 미리 만들고 earliest 위치로 설정할 수 있어요. PIP-356이 병합될 때까지는 지리 복제를 시작하려면 토픽을 언로드해야 해요.
더 알아보기 (Learn more)
- 지리 복제의 배경 개념은 지리 복제 개념 문서를 참고해요.
- 복제 구독 설계는 PIP-33 문서를 참고해요.
- 네임스페이스·토픽 정책 구성은 pulsar-admin 문서를 참고해요.
- 토픽 통계 필드에 대한 상세는 Pulsar statistics 문서를 참고해요.