Pulsar 스키마 이해하기
Pulsar 스키마 이해하기 (Understand Schema)
토픽에 어떤 형태의 데이터가 오가는지 생산자와 소비자가 서로 합의하는 방법이 필요해요. Pulsar의 스키마(schema)가 그 역할을 해요. 스키마는 데이터가 어떻게 직렬화·역직렬화돼야 하는지를 정의해서, 서로 다른 언어·버전의 클라이언트가 같은 토픽 데이터를 일관되게 다루게 해줘요. 이 문서는 Pulsar 스키마의 기본 개념과 추가 참고 자료를 설명해요.
본문
스키마 정의 (Schema definition)
Pulsar 스키마는 SchemaInfo라는 데이터 구조 안에 정의돼요. 스키마는 토픽 단위로 저장되고 강제되며, 네임스페이스나 테넌트 레벨에는 저장할 수 없어요. SchemaInfo의 핵심 필드는 다음 세 가지예요.
| 필드 | 설명 |
|---|---|
name |
스키마 이름(문자열)이에요. |
type |
스키마 데이터를 직렬화·역직렬화할 방법을 결정하는 스키마 타입이에요. |
properties |
애플리케이션이 스키마 데이터와 함께 전달하려는 문자열/문자열 맵의 사용자 정의 속성이에요. |
예를 들어 문자열 스키마는 { "name": "test-string-schema", "type": "STRING", "schema": "", "properties": {} } 같은 형태의 SchemaInfo로 표현돼요.
스키마 타입 (Schema type)
Pulsar가 지원하는 스키마 타입은 크게 세 범주로 나뉘어요.
- Primitive type (원시 타입)
- Complex type (복합 타입)
- Auto schema (자동 스키마)
복합 타입(Complex type) 의 대표적인 두 종류를 살펴볼게요.
| 복합 타입 | 설명 |
|---|---|
KeyValue |
복잡한 키/값 쌍을 나타내요. |
Struct |
구조화된 데이터를 나타내며 AvroBaseStructSchema, ProtobufNativeSchema, NativeAvroBytesSchema를 포함해요. |
Struct 스키마(특히 AvroBaseStructSchema)는 Avro 명세로 스키마 정의를 선언하며 AvroSchema, JsonSchema, ProtobufSchema를 지원해요. struct 스키마는 미리 정의할 수 있는데, Java에서는 POJO, Go에서는 struct, 혹은 Avro·Protobuf 도구로 생성한 클래스를 써요. 예를 들어 struct 스키마로 프로듀서를 만들고 메시지를 보내는 코드는 다음과 같아요.
Producer<User> producer = client.newProducer(Schema.AVRO(User.class)).create();
producer.newMessage().value(new User("pulsar-user", 1)).send();
반대로 struct 스키마로 컨슈머를 만들고 메시지를 받을 수도 있어요.
자동 스키마(Auto schema) — 토픽의 스키마 타입을 미리 알 수 없을 때 AUTO 스키마로 브로커에 generic record를 생산/소비할 수 있어요. Auto schema는 두 범주로 나뉘어요.
AUTO_PRODUCE: 프로듀서의 데이터를 스키마가 있는 토픽으로 전달하고, 나가는 바이트가 그 토픽의 스키마와 호환되는지 검증해줘요.AUTO_CONSUME: 스키마가 있는 토픽에서 컨슈머로 데이터를 전달하고, 나가는 바이트가 그 컨슈머와 호환되는지 검증해줘요. 즉 브로커에서 가져온SchemaInfo로 메시지를 언어별 객체GenericRecord로 역직렬화해요.
스키마 진화 (Schema evolution)
스키마는 속성과 타입의 상세를 저장해요. 새 비즈니스 요구를 충족하려면 시간이 지나며 버전 관리(versioning) 를 통해 스키마가 진화해요.
스키마 진화는 Avro, JSON, Protobuf, ProtobufNative 스키마에만 적용된다는 점을 기억해 두세요.
스키마 버전 관리 — 토픽에 저장되는 각 SchemaInfo는 버전을 가져요. 스키마 버전은 토픽 안에서 일어나는 스키마 변경을 관리해요. 어떤 SchemaInfo로 생산된 메시지는 그 스키마 버전으로 태그되고, Pulsar 클라이언트가 그 메시지를 소비할 때 버전으로 해당 SchemaInfo를 찾아 올바른 스키마로 데이터를 역직렬화해요.
클라이언트 업그레이드 순서 — 호환성 검사 전략에 따라 프로듀서/컨슈머를 업그레이드하는 순서가 달라져요.
| 호환성 전략 | 업그레이드 순서 | 설명 |
|---|---|---|
ALWAYS_COMPATIBLE |
어떤 순서든 | 호환성 검사를 비활성화해요. 그래서 프로듀서/컨슈머를 아무 순서로 업그레이드할 수 있어요. |
ALWAYS_INCOMPATIBLE |
해당 없음 | 스키마 진화를 비활성화해요. |
BACKWARD, BACKWARD_TRANSITIVE |
컨슈머 우선 | 옛 스키마 컨슈머가 새 스키마로 생산된 데이터를 읽는다는 보장이 없어요. 그래서 컨슈머부터 모두 업그레이드한 뒤 새 데이터를 생산해야 해요. |
FORWARD, FORWARD_TRANSITIVE |
프로듀서 우선 | 새 스키마 컨슈머가 옛 스키마로 생산된 데이터를 읽는다는 보장이 없어요. 그래서 프로듀서부터 모두 업그레이드해 새 스키마로 데이터를 생산하고, 그다음 컨슈머를 업그레이드해야 해요. |
더 알아보기
- 스키마를 실제 토픽에 적용하는 절차는 Schema Get Started 문서를 보면 돼요.
- 스키마가 적용된 데이터를 누가 만들고 소비하는지는 Pulsar Clients 문서에서 다뤄요.
- 메시지가 어떤 구조를 가지는지는 Messaging 문서를 참고해요.