BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ ニュース Jackson開発者のTatu Saloranta氏がJSONベンチマークに回答

Jackson開発者のTatu Saloranta氏がJSONベンチマークに回答

原文(投稿日:2014/05/08)へのリンク

InfoQでは先週,Groovy 2.3のJSONパーザが,それまでのバージョンに比べてはるかに高速になったことをレポートした。その記事の執筆中に我々は,Jackson JSONプロセッサの作者であるTatu Saloranta氏にメールを送った。GroovyとBoonの組み合わせがJVM上のJSONパーザとして最速だとするRick ightower氏の報告に対する,氏の考えを知りたかったのだ。

InfoQ: これらのベンチマークは正確だと思いますか?

Tatu Saloranta: ごく低いレベルで言えば,テスト方法については信頼できると思っています。JMHは優れたフレームワークです。繰り返し回数なども適切ですし,結果には再現性があります。

BoonとGroovyが一部,あるいは大部分のテストにおいて高速だという可能性はあると思います。しかし実際のところ,最終的な主張には,特にテスト項目やテスト方法を意図的に選択している点については,疑問があると言わざるを得ません。

私の懸念のおもな理由は3つあるのですが,それらはすべてこの次の質問項目に関連したものです。

それから念のために - 私が確認したテストは,GitHubで公開されているものです。派生版がたくさんあると思いますが,その中には,私のコメントが当てはまらないものがあるかも知れません。

InfoQ: これらのベンチマークは,現実的な動作をテストしていると思いますか?

TS: 現実的な動作ですし,現実的な使い方です。ですが,考えられる使用法のごく一部分であるかも知れません。 彼らの重点の置き方は,単刀直入に言うと"都合のよい部分"を重視しているように思うのです。先程述べた3つの懸念点ですが,
  1. 入力ソースについて。引用されているテストの大部分がJava Stringを入力としていますが,Stringが入力ソースとして使用されることはめったにありません。StringはJVMが生成するものだから - 外部からの入力は通常,バイトストリームとして与えられます。Stringが使用されるのはユニットテストか,さもなくばフレームワーク(またはプラットフォーム – Groovyもそうでしょうか?)がStringを提供する場合くらいでしょう。書き込みについても同じです。この点はおもに,2つの部分で問題となります。つまり,(a)JacksonがRESTの基盤であるバイトストリーム,あるいはファイルストレージを徹底的に最適化しているのに対して,(b)BoonではStringの操作,中でもsun.miscの利用を集中的に最適化しているのです。Stringクラスの参照公開する内部char[]をアクセスしたり,あるいは変更したりすることは,安全な操作ではありません。ですから,ユースケースとしてはマイナーでありながら,Boonが明らかに有利(Stringの操作が高速なことは否定できません)なソースを使用しているように疑われるのです。
  2. 処理/アクセススタイルについて: (POJOではなく)Mapのリストで"untyped"を扱っている点。最初の項目ほどの疑惑はありませんが,読み取りと書き込み操作が現実的なPOJOではなく,List-of-Mapsオブジェクトのみを対象としている点に言及がないのは不思議です。現代的なJVM RESTフレームワークはすべて,"untyped"の使用も可能ではありますが,中心として扱うのはPOJOです。好みはユーザそれぞれ違いますから,いずれか一方,あるいは両方をテストしたとしても間違いとは言えませんが,それでもドキュメントには明記する必要はあると思います。
  3. データのアクセスや検証を行わないテストでの遅延生成について。Boonは,入力の遅延処理を対象とする最適化に力を入れています。データのごく小さなサブセットのみをアクセスするユースケースであれば,これは有効かも知れません。しかしここで問題なのは,パフォーマンステストでデータにアクセスしていないことです。事実,パーザはObjectを返しているのですが,実際のテストではそれを無視しています。ですから,今回のテストは,たまたま遅延処理にとって都合のよい方法で動作したに過ぎず,実際のパフォーマンスを表したものではない,と私には思えるのです。

これらすべては,次のように言い換えるべきでしょう。すなわち,このテストは本当に意味のある利用パターンに基づいて行われたものではない -- つまり,作為的なものに思われるのです。JSONを読み書きしているだけで,まったく使用していません。データ操作のオーバーヘッドを排除するという観点から見れば,理に叶っていることは分かります。ですが残念なことに,それとは別のトレードオフが結果を歪めてしまっているのです。例えばJAX-RSスタイルのREST処理を使う場合,InputStreamから取得するすべてのJSONデータをPOJOに,逆方向ではPOJOからOutputStreamに,という変換を行わなければなりません。ですから,そこで体験するパフォーマンスは,このベンチマークが示しているものとはまったく違います。

それと,"untype"なオブジェクトを使用するという方針なのであれば,少なくともコードで何らかのトラバースを行うべきでしょう。同じオブジェクトをラウンドトリップに使用するならば,変更処理も必要です。

Boonのケースでは,オーバーレイ(入力データを直接インデックス処理して抽出可能にしています)とMapの遅延構築を用いることで, 実際には存在するはずのオーバーヘッドを隠ぺいしているのです。さらにStringがソースとターゲットに使用されるならば,エンコードおよびデコードのオーバーヘッド(これはJacksonとBoonで差があります – Jacksonの方がこのステップを重視しているため)が発生するため,Jacksonのエンド・ツー・エンドの相対的な効率はさらに低下します。

InfoQ: 今後,Jacksonをより高速化する計画をお持ちですか,あるいは"十分に速い"のでしょうか?

TS: 現時点で小さな変更は可能ですが,パフォーマンスを重視した大掛かりな計画は持っていません。報告された結果にはいくつか対応して (ベンチマークが役に立ちました!),Stringを読み込む場合のオーバーヘッドを軽減したいと思っています。Jackson Afterburnerモジュールでは,この手のアグレッシブな最適化をいくつも行ってきました。ただしこれらも,どちらかと言えば漸進的な改良ということになります。

1.xをリリースした頃から,パフォーマンスは必ずしも最優先の目標ではありませんでした。オーバーヘッドは適度に低く抑えたいとは思っていますが,それよりも重要なこと – 使いやすさ,他のフォーマット(XML, CSV, CBOR, Smile)のサポート,規則,データ処理ライブラリ(Joda, Guava)のモジュール化などがあるからです。

"十分に速い"と言っていいとは感じていますから,基本的にはそのような表現が適当だと思います。

InfoQ: 率直な回答をありがとうございました!

TS: どういたしまして -- 深く考える機会を頂いて,感謝しています。全体としてBoon for JSONは優れていると思います。Groovyが現代的でハイパフォーマンスなサポートを得られているのは,特に素晴らしいことです。ただし比較するのはリンゴとリンゴであるべきですし,証拠を伴った主張をして欲しいですね。:)

この記事に星をつける

おすすめ度
スタイル

BT