Kafka でのスキーマ管理は、データ品質と進化(schema evolution)を両立させる核心機能です。Confluent Schema Registry は Avro/JSON Schema/Protobuf をサポートしますが、JSON Schema は可視性と多言語連携に強みがある一方で、型の厳密さやデータサイズでは Avro に劣ることがあります。
本稿では、JSON Schema の採用判断、互換性モード、命名戦略、進化ルール、監視・性能の要点を、Avro との比較を交えて整理します。CCDAK(Confluent Certified Developer for Apache Kafka)受験者が押さえるべき論点も明示します。
JSON Schema は、人間が読みやすい JSON 形式のままスキーマ拘束をかけられる点が強みです。可観測性(目視デバッグ)や、HTTP 系サービスとの親和性が高く、クライアントが軽量な実装でも取り回しやすい特徴があります。一方で Avro のようなバイナリ最適化はなく、ペイロードサイズやシリアライズ CPU コストでは不利になりがちです。
Kafka で JSON Schema を使う場合、Confluent Schema Registry と Confluent の JSON Schema Serializer/Deserializer(KafkaJsonSchemaSerializer / KafkaJsonSchemaDeserializer)を利用するのが一般的です。互換性(BACKWARD/FORWARD/FULL とその transitive)やサブジェクト命名戦略(TopicNameStrategy など)は Avro と同様に運用できます。
Kafka × JSON Schema データフロー(概念)
Schema Registry は JSON Schema に対しても BACKWARD / FORWARD / FULL とそれぞれの transitive 互換性を提供します。実装は Confluent の互換性チェッカに依存し、required/optional、enum、型の変更などを中心に安全性を評価します。format や一部の拡張キーワードは互換性判定に影響しない場合がある点に注意してください。
運用では、まず BACKWARD_TRANSITIVE を既定にして、既存コンシューマの破壊を防ぐのが無難です。JSON Schema では additionalProperties の既定が true のため、予期しないフィールド流入を防ぐには false を明示し、許可する追加は properties に列挙します。
互換性モードの設定(Schema Registry REST API)
curl -s -X PUT \
-H 'Content-Type: application/json' \
--data '{"compatibility": "BACKWARD_TRANSITIVE"}' \
http://localhost:8081/config/my-topic-value
# 互換性の確認
curl -s http://localhost:8081/config/my-topic-value | jqサブジェクト名は互換性と独立展開の単位です。1 トピックに 1 種類のイベントであれば TopicNameStrategy、複数イベント型を 1 トピックに詰めるなら RecordNameStrategy か TopicRecordNameStrategy を選びます。JSON Schema でも Avro と同様に選べます。
バージョニングは“後方互換を崩さない”を原則に、破壊的変更が必要な場合は新サブジェクトや新トピックに分岐させます。JSON Schema の additionalProperties と required の扱いがバージョン間差分の主因になりやすいため、チーム規約で明文化しておくと事故を減らせます。
Java Producer(JSON Schema 利用)
import io.confluent.kafka.schemaregistry.client.CachedSchemaRegistryClient;
import io.confluent.kafka.schemaregistry.client.SchemaRegistryClient;
import io.confluent.kafka.schemaregistry.json.JsonSchema;
import io.confluent.kafka.serializers.json.KafkaJsonSchemaSerializer;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import java.util.*;
public class JsonSchemaProducerExample {
public static void main(String[] args) throws Exception {
Properties props = new Properties();
props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put("schema.registry.url", "http://localhost:8081");
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer");
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, KafkaJsonSchemaSerializer.class.getName());
// サブジェクト命名戦略(例)
props.put("value.subject.name.strategy", "io.confluent.kafka.serializers.subject.TopicNameStrategy");
String schemaStr = "{\n" +
" \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n" +
" \"title\": \"UserCreated\",\n" +
" \"type\": \"object\",\n" +
" \"additionalProperties\": false,\n" +
" \"properties\": {\n" +
" \"id\": {\"type\": \"string\"},\n" +
" \"age\": {\"type\": \"integer\"},\n" +
" \"email\": {\"type\": \"string\", \"format\": \"email\"}\n" +
" },\n" +
" \"required\": [\"id\"]\n" +
"}";
JsonSchema jsonSchema = new JsonSchema(schemaStr);
// Serializer は送信時に自動登録(auto.register.schemas=true が既定)
try (KafkaProducer<String, Object> producer = new KafkaProducer<>(props)) {
Map<String, Object> value = new HashMap<>();
value.put("id", UUID.randomUUID().toString());
value.put("age", 34);
value.put("email", "[email protected]");
ProducerRecord<String, Object> record = new ProducerRecord<>("user-events", value);
producer.send(record).get();
}
}
}JSON はテキストであるため、同等のレコードを Avro バイナリで送る場合と比べてメッセージサイズが大きくなります。ネットワークとストレージのコスト影響、Broker のスループット、クライアントの GC 圧などを事前に計測しましょう。圧縮(lz4、zstd)である程度は相殺できます。
一方で、障害時の切り分けは容易です。メッセージをそのままログや CLI で観察でき、Schema Registry の ID から該当スキーマを素早く引けます。検証コストは Producer/Consumer でのバリデーション有無に依存します。Producer 側で厳格に弾くか、Consumer 側で寛容に取り込むか、役割分担を決めておきます。
両者は Schema Registry と互換性モードの概念を共有しますが、型表現・エンコーディング・検証の性質が異なります。可読性と多言語連携を優先するなら JSON Schema、厳密な型と効率を優先するなら Avro が無難です。混在も可能ですが、トピック単位で統一する方が運用は容易です。
論理型(decimal、timestamp 等)やデフォルト値の扱いは Avro の方が枯れており、データプラットフォーム全体での長期保守を考えると Avro 優位な場面が多いのも事実です。逆に API エッジや PoC、分析前段のイベント収集など、初期のスキーマ探索段階では JSON Schema の取り回しが効きます。
| 観点 | JSON Schema | Avro |
|---|---|---|
| エンコーディング | テキスト JSON(可読) | コンパクトなバイナリ |
| 型の厳密さ | 緩め(format は互換性判定に影響しないことあり) | 厳密(論理型が豊富) |
| サイズ/性能 | 相対的に大(圧縮で緩和) | 小さく高速になりやすい |
| 互換性モード | Registry で Avro と同等のモードを利用 | Registry の第一級サポート |
| ツール/可視性 | CLI/ログで直読しやすい | デコードしないと読みにくい |
| スキーマ参照 | Registry の参照機能に対応(実装に依存) | 対応(成熟度高い) |
CCDAK では、Schema Registry の互換性モード、命名戦略、スキーマ進化の可否が頻出です。JSON Schema 固有の additionalProperties や required の解釈が Avro と異なる点を言語化できると有利です。
実運用の落とし穴は、互換性モードの過小評価とサブジェクトの乱立です。新規イベントを安易に既存サブジェクトへ追加して required を誤設定すると、突然の互換性違反で登録に失敗します。CI にスキーマ検証を組み込み、失敗を早期に検知しましょう。
CCDAK
問題 1
Kafka で JSON Schema を用いるトピックに、新しい任意フィールド address を追加したい。既存コンシューマを壊さずに進化させる安全な組み合わせはどれか。
正解: A
既存コンシューマ保護には BACKWARD(推奨は TRANSITIVE)が適切。新規フィールドは optional にし、additionalProperties は false のまま properties へ明示列挙する。required に入れると後方互換を壊す恐れがある。format の有無は互換性判定に影響しない場合がある。
JSON Schema を使うのに Schema Registry は必須ですか?
Kafka でスキーマ管理と互換性チェック、スキーマ ID によるデシリアライズを行うには Schema Registry の利用が前提です。独自埋め込みも理論上は可能ですが、運用・進化・相互運用性の面で非推奨です。
JSON Schema でもスキーマ参照($ref)は使えますか?
Schema Registry は Avro/JSON Schema/Protobuf のスキーマ参照機能を提供しています。JSON Schema の $ref もサポートされますが、互換性判定の対象や解決方法は実装に依存するため、公式ドキュメントで制約を確認してください。
デフォルト値や format は互換性判定に影響しますか?
互換性判定は主に構造的な変更(required、型、enum など)に基づきます。format や一部の注釈は互換性に影響しないことがあります。デフォルト値の扱いも Avro と異なる点があるため、変更前に Registry で事前検証(/compatibility/subjects/... API)することを推奨します。
NicheeLab編集部
データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。
Kafka Topic と Partition の基礎: 分散とスケーラビリティの要
CCDAK 対策と実務の両立を意識し、Topic/Partition/Replica/Consumer Group の役...
CCDAK 試験ガイド:出題範囲・配点・申込み・対策
Confluent Certified Developer for Apache Kafka (CCDAK) の出題範囲...
Confluent Certified Administrator (CCAAK) 対策: 出題範囲・配点の考え方・運用観点の要点
CCAAKに向けて、試験領域の押さえどころを運用目線で整理。プロダクションで通用する設定・監視・セキュリティの実践知を、...
Kafka の Replica と In-Sync Replicas を正しく設計する: 耐障害性と一貫性
レプリカとISRの仕組みを起点に、acks と min.insync.replicas、クリーン/アンクリーンリーダー選...
Kafka の Offset とコミット: ポジション管理と at-least-once の基礎
CCDAK 対策と実務の両立を意識して、Kafka コンシューマのオフセット管理とコミット戦略を整理。at-least-...