Kafka 와 Confluent Schema Registry 를 사용한 스키마 관리 #1

Junghoon Song
10 min readJul 10, 2018

--

진화하는 메시지

우리는 서비스에서 특정한 이벤트가 발생되면 Kafka 를 통하여 해당 이벤트에 관한 메시지를 전달하고 있습니다.
그리고 이 메시지들은 하나이상의 소비자들에게 전달이 되고, 적절한 서비스로직이 수행되는 것을 기대할 것입니다.

예를 한가지 들어봅시다.

먼저 서비스에 사용자가 가입하거나(추가), 탈퇴하거나(삭제), 또는 사용자정보를 변경하는것도 이벤트로 보고, Kafka 와 같은 Broker 를 통해서 아래와 같은 형태로 메시지를 전달한다고 가정해봅니다.

사용자 정보에 대한 이벤트 메시지 v.1

이것은 매우 단순한 형태의 메시지인데 생산자(Producer)는 특정 사용자에게 어떤 이벤트가 발생하였고 이 사용자는 현재 어떤 상태인지를 전달하고 있습니다.
그리고 소비자(Consumer)들은 어떤 형태의 메시지를 받을것인지를 잘 알고 있고, 이 메시지 형태에 적합한 서비스로직을 각자 구현을 하게 될 것입니다.

하지만 비즈니스 요구사항은 계속 변하고 있고, 어느순간 새로운 요구사항을 만족시키기 위하여 메시지 형태가 변경이 되어야 하는 순간이 오게됩니다.
더 많은 정보를 담아야 할 필요성이 생기기도 하고, 아니면 더이상 사용하지 않는 불필요한 정보는 삭제해야 할 필요성도 있습니다.

요구사항이 변하였습니다.
앞으로는 사용자의 성과 이름을 따로 받아서 저장하게 되었고 이벤트 발생시 전달되는 메시지도 변경이 되었습니다.

사용자 정보에 대한 이벤트 메시지 v.2

기존에 사용하던 Name 이라는 필드가 사라졌고 firstName, lastName 이라는 필드가 새로 추가되었습니다.
이벤트 생산자(Producer)는 앞으로 위와 같은 형태의 메시지를 발행하게 되겠지만, 아직 소비자(Consumer)들은 변경된 메시지의 형태를 알지 못하고 있습니다.
소비자들은 firstName 이나 lastName 은 알지 못하며, 여전히 name 이라는 필드를 통해 사용자 이름에 대한 데이터를 전달받을것을 기대하고 있습니다.
결국은 적절하게 서비스로직이 수행되지 못하게되며 오류가 발생하는 상황에 이르게 됩니다.

우리는 이러한 상황(소비자들에게서 오류가 발생하는)을 피하고 싶습니다.
그러면서도 메시지의 형태를 지속적으로 안전한 방향으로 진화시켜나가기를 원하고 있습니다.
(예를 들자면 Name 이라는 필드를 삭제하지 않고 유지하면서 firstName, lastName 필드만 추가하는 방식으로 말이죠.)

지속적으로 메시지가 변경되어야 하는 상황에서는, 메시지의 스키마를 관리하고 안전한 방향으로 진화하고 있는지를 확인하는것이 중요합니다.
그렇지 못한다면 다수의 소비자(Consumer)들이 에러를 마주하게 됩니다.

Confluent Schema Regsitry

Confluent (Confluent: Apache Kafka & Streaming Platform for the Enterprise) 는 LinkedIn 에서 Apache Kafka 를 개발한 팀이 세운 회사입니다.

Apache Kafka 와 더불어 다양한 플랫폼들을 연결시켜 오픈소스로 공개하였는데, 그 중 Schema Registry 도 같이 포함되어 있으며 이것을 Confluent Schema Registry 라고 부르고 있습니다.

Confluent Schema Registry 는 RESTful 인터페이스를 사용하여 스키마(Schema)를 관리하거나 조회하는 기능을 제공합니다.
그리하여 생산자와 소비자는 Apache Avro (Welcome to Apache Avro!) 포맷의 메시지를 Kafka 를 통해서 전달하고 받을수 있도록 도와줍니다.

Confluent Schema Registry 를 사용하였을때 메시지 흐름

소비자(Consumer)는 Kafka 로부터 바이너리 데이터를 받는데 이 데이터에는 스키마 ID 가 포함되어 있습니다.
이 ID 정보를 가지고 로컬캐시 혹은 Confluent Schema Registry 에서 스키마정보를 탐색하여 가져오고, 스키마정보를 사용하여 역직렬화하여 사용하게 됩니다.

Confluent 에서 제공하는 Schema Registry 만 있는것은 아닙니다.
Hortonworks 에서도 Schema Registry 를 제공하고 있고 Spring Cloud Stream 에도 Schema Registry Server 가 포함되어 있습니다.
하지만 구글에서 검색을 해보시면 Confluent Schema Registry 가 압도적으로 많이 노출되는것을 보실 수 있습니다. (2018.07 현재)
그만큼 가장 많이 사용된다고 판단하였고 저희는 Confluent Schema Registry 를 선택했었습니다.

Introduction to Schemas in Apache Kafka with the Confluent Schema Registry 은 Confluent Schema Registry 를 이해하는데 많은 도움을 줄 것입니다. 강력하게 추천합니다.

스키마 진화 전략

Confluent Schema Registry 에선 아래와 같은 패턴으로 호환성을 유지하게 됩니다. (Data Serialization and Evolution — Confluent Platform 참고)

  • Backward : 새로운 스키마로 이전 데이터를 읽는것이 가능한것을 의미합니다.
    새로운 스키마에 필드가 추가되었는데 해당 필드에 default value 가 없다면 오류가 발생할 것이므로 스키마 등록을 허용하지 않게 됩니다.
    새로 추가되는 필드에 default value 를 지정할때에만 스키마 등록이 허용이 됩니다.
    Confluent Schema Registry 는 기본적으로 Backward 로 동작합니다. (물론 설정에서 변경할 수 있습니다.)
  • Forward : 이전 스키마에서 새로운 데이터를 읽는것이 가능한것을 의미합니다.
    새로운 스키마에서 특정 필드가 삭제된다면, 해당 필드는 이전 스키마에서 default value 를 가지고 있었어야 합니다.
  • Full : Backward 와 Forward 을 모두 만족함을 이야기합니다. 가능하다면 이것을 사용하기를 권장합니다.
  • None : Backward 와 Forward 어느한장 만족하지 못합니다. 아주 예외적인 상황을 제외한다면 사용하지 않기를 권장합니다.

만약 항상 모든 Consumer 가 먼저 배포되고 이후에 Producer 가 배포된다면 Backward 로 충분합니다.
하지만 그것을 확신할 수 없다면 Full 을 사용하는것을 권장합니다.

스키마를 설계할때는 아래와 같은 내용들을 고려하도록 합시다.

  • 삭제될 가능성이 있는 필드라면 default value 를 지정합니다. 해당 필드에 데이터가 들어오지 않더라도 에러가 발생하지 않습니다.
  • 추가되는 필드라면 default value 가 지정되어야 합니다.
  • Enum 은 변경될 가능성이 없을때에만 사용하도록 합니다.
  • 필드의 이름은 변경하지 않도록 합니다.

Schema Registry 사용의 장점과 단점

우리는 Schema Registry 를 사용하면서 메시지의 스키마를 보다 안전하게 진화해나갈 수 있습니다.
만약 잘못된 스키마를 가진 메시지를 전달하고자 한다면 Schema Registry 에 등록되는 과정에서 실패가 되고, Kafka 에 메시지가 전달되지 않게 됩니다.
소비자들은 잘못된 스키마의 메시지를 받을일이 없기 때문에 에러는 발생하지 않을것입니다.

또 한가지 장점은 Kafka 에 전달되는 바이너리 데이터에 스키마 정보가 포함되어 있지 않기 때문에, 상대적으로 적은 용량의 데이터가 전달된다는 점 입니다.
따라서 JSON 등과 비교하여 Kafka 시스템에서 더 적은 공간만 차지하게 되고 네트워크 대역폭도 절약할 수 있습니다.

물론 단점도 있습니다.

가장 큰 단점은 Schema Registry 의 역할이 굉장히 중요하고 Schema Registry 의 장애가 발생하는 경우 정상적으로 메시지를 전달하지 못하게 됩니다.
이것은 Kafka 만 운영하였을때와 비교하여 운영포인트가 증가한다는것을 의미합니다.

그 외에 Avro 포맷은 JSON등과 비교하여 직렬화과정에서 퍼포먼스가 조금 떨어진다고 알려져있습니다. (개인적으로는 큰 문제는 아니라고 생각합니다.)

Confluent Schema Registry 설치

Download — Confluent 에서 배포판을 받아서 압축을 해제하는것만으로 설치는 끝납니다.
해당 배포판에는 Kafka 를 비롯하여 Schema Registry, REST Proxy 등등이 포함되어 있습니다.
아래와 같은 방법으로 실행하시면 됩니다.

# 압축해제
$ tar xvfz confluent-oss-4.1.1-2.11.tar.gz
# Zookeeper 실행
$ ./bin/zookeeper-server-start ./etc/kafka/zookeeper.properties
# Kafka 실행
$ ./bin/kafka-server-start ./etc/kafka/server.properties
# Schema Registry 실행
$ ./bin/schema-registry-start ./etc/schema-registry/schema-registry.properties
# Schema Registry 에 등록된 스키마 조회 (기본포트 8081)
$ curl -X GET http://localhost:8081/subjects
[]
$ curl -X GET http://localhost:8081/config
{"compatibilityLevel":"BACKWARD"} # 기본적으로 BACKWARD 를 사용하고 있습니다.
$ curl --header "Content-Type: application/json" -X PUT --data '{"compatibility": "FULL"}' http://localhost:8081/config
{"compatibility":"FULL"} # FULL 로 변경되었습니다.

schema-registry.properties 의 자세한 설정은 Schema Registry Configuration Options — Confluent Platform 를 참고하시면 됩니다.

제공되는 API 는 API Reference — Confluent Platform 에서 확인이 가능합니다.

Docker (Docker Quick Start — Confluent Platform) 를 사용하는 방법도 있으니 편리한 방법으로 설치해서 사용하시길 바랍니다.

다음장에서는 Avro 를 사용하여 스키마를 설계하고, Java (특히 Spring Framework를 사용한) 어플리케이션에서 Schema Registry 를 사용하는 방법에 대해서 알아보도록 하겠습니다.

--

--