Avroについて

昨日、関ジャバで喋ったのしかったよー(∩´∀`)∩

bufferings.hatenablog.com

その発表のために色々と新しいことを学んだので、ちょこちょこ気が向いたときにアウトプットしておこうと思う。数カ月後に全て忘れているであろう自分のために。

てことで、今日はAvro。余談ですが、勉強会に行くと勉強になるけど、勉強会で登壇するともっと勉強になるからおすすめです!

Avroとの出会い

同じ学年にAvroさんという人がいるのは知ってたけど、違うクラスだから喋ることもないかなーって思ってたくらいの距離感(なんの話?)

名前を初めて聞いたのは、去年のSpring Oneに行った時。Spring Cloud StreamでData Microserviceだー!って言葉が押し出されてて。Avroの名前がでてきてたのはSchema Evolutionという文脈の中だったなという印象。「メッセージング系の処理やってると悩むのは、メッセージのスキーマを変更したいときよね。この問題をどうやって扱おう?そこでAvroを使って、スキーマの進化について考えてみよう」って感じだったかな。

でも、僕はSpring Cloud Streamは別に追いかけなくていいかなーと思ってて(好き嫌いとかじゃなくて、単純に優先順位の問題ね)。なので、Avroのことも「ふーん、そんなのあるんだー」くらい。

スキーマがあると良さそう?

登壇駆動ってことで、タイトルを先に決めてから「よし!Kafkaを勉強するぞー!」って触りはじめて。

といっても、実は去年の秋のJJUG CCCで発表したときも少しKafkaを触ってたんだけど、その時はドメインイベントのオブジェクトをJSONシリアライズ・デシリアライズしてた。

今回も同じようにしたらいいかなーと思ってたんけど、去年から一歩進めて複数のサービスに分割してイベントを扱おうと思った時に「はて、これは、決めごとがあるほうが良さそう?」って思った。

同じアプリの中でメッセージのやり取りをするんだったら、そのクラスをやり取りすればいいからJSONでもいいかなーって思ってたんだけど。サービスごとに複数のチームに分かれて作業するとかを考えるとインターフェイスみたいなものを決める方が良さそうだなーって思った。「ここ、数字だと思ってたら文字列も入ってくるのか!」とか「nullの場合あるの?初期値とかは?」とかならないように。しかもプログラミング言語に依存しない形で。

だから、スキーマがある方が良さそう。ということで、Avroさんに会いに行くことにした。

Avroとは?

公式サイト: Welcome to Apache Avro!

今ぐぐってみたんだけど、日本語だとOracleのサイトの説明が分かりやすい 第7章 Avroスキーマ Oracleで使用するケースの話みたいだけどね。

スキーマ定義に従って、データをコンパクトなバイナリ形式でシリアライズ/デシリアライズする。という感じなのかな。

Javaのサンプル

Apache Avro™ 1.8.2 Getting Started (Java)

スキーマ定義ファイルを元にJavaのクラスの生成もできるみたいだけど、好みの問題で、僕はそれは使わずに、GenericRecordを使うことにした。Mapみたいなものね。

だから、上記のドキュメントの「Serializing and deserializing without code generation」の方を見てた。

シリアライズ

例えば OrderItemCreatedEvent.avsc って名前のファイルを用意して

{
  "name": "OrderItemCreatedEvent",
  "type": "record",
  "fields": [
    {"name": "orderGroupId", "type": "string"},
    {"name": "orderItemId", "type": "string"},
    {"name": "orderGuestId", "type": "int"},
    {"name": "orderGuestName", "type": "string"},
    {"name": "productId", "type": "string"},
    {"name": "quantity", "type": "int"},
    {"name": "orderedOn",  "type": "string"}
  ]
}

こんなコードを書くと

    Schema schema = new Schema.Parser().parse(new File("OrderItemCreatedEvent.avsc"));

    GenericRecord record = new GenericData.Record(schema);
    record.put("orderGroupId", "b78cbc2c-ee1b-4c03-9b8c-70abf121b0d1");
    record.put("orderItemId", "7e570f08-65bd-4b1f-be75-3d977d818023");
    record.put("orderGuestId", 123456);
    record.put("orderGuestName", "bufferings");
    record.put("productId", "1d8bcd93-2b9c-4225-a525-8f750d4c444c");
    record.put("quantity", 4);
    record.put("orderedOn", "2017-06-24T06:57:14.090");

    File outputFile = new File("data.avro");
    DatumWriter<GenericRecord> datumWriter = new GenericDatumWriter<>(schema);
    try (DataFileWriter<GenericRecord> dataFileWriter = new DataFileWriter<>(datumWriter)) {
      dataFileWriter.create(schema, outputFile);
      dataFileWriter.append(record);
    }

こうなった

f:id:bufferings:20170625133757p:plain

おぉ。スキーマも一緒に出力されるのか。されないと思ってた。そっか、これでもJSONと比べていいのは、複数レコードを保存するときにスキーマを最初に一回だけ書くところなのかな。

シリアライズ

公式サイトに書いてある通りにこんな感じ。インスタンスを再利用してるの面白いね。大量レコード対応って感じすね。僕は1レコードのシリアライズにしか今は興味がないけど。

    Schema schema = new Schema.Parser().parse(new File("OrderItemCreatedEvent.avsc"));
    File dataFile = new File("data.avro");

    DatumReader<GenericRecord> datumReader = new GenericDatumReader<>(schema);
    GenericRecord record = null;
    try (DataFileReader<GenericRecord> dataFileReader = new DataFileReader<>(dataFile, datumReader)) {
      while (dataFileReader.hasNext()) {
        record = dataFileReader.next(record);
        System.out.println(record);
      }
    }

出力はこんな感じになる。

{"orderGroupId": "b78cbc2c-ee1b-4c03-9b8c-70abf121b0d1", "orderItemId": "7e570f08-65bd-4b1f-be75-3d977d818023", "orderGuestId": 123456, "orderGuestName": "bufferings", "productId": "1d8bcd93-2b9c-4225-a525-8f750d4c444c", "quantity": 4, "orderedOn": "2017-06-24T06:57:14.090"}

んでも、スキーマ情報がデータファイルに入ってるのに、デシリアライズのときにもスキーマファイルが必要なのは不思議だ。合ってるかどうかチェックでもするのかな?

ま、気にしない。

Kafkaの場合

んで、Kafkaについて考えてみると、↑の方式でみたいに毎回スキーマ情報を書き込むのってなんかいけてない感じがする。それより、どっかにスキーマ情報を登録しといて、それを使ったほうが良くね?って思った。ら、ちゃんとあった。それがSchema Registry。

Schema Registry — Confluent Platform 3.2.2 documentation

今日はこんなとこかな。次はSchema RegistryとKafkaについて書こうかな。