CA Reward

Tech Blog

Tech Blogトップに戻る

GoでXML生成を高速に行う

2017.02.02

  • このエントリーをはてなブックマークに追加
  • Pocket
junchang1031
junchang1031エンジニア

はじめに

こんにちは開発部の辻です。 弊社では動画広告配信のサービスを運営しており、その動画広告配信フォーマットとしてVast XMLを使用しています。

Vast XMLに関しては以下の弊社ブログでも取り上げていますので、よろしければ併せて御覧ください。

今回はこのVast XML生成の高速に行う方法について書きたいと思います。

ちなみに、XMLの生成と何度か記述していますが、今回はあるGoの構造体から有効なXML文書文字列 []byte を生成すること、と定義したいと思います。

いざ実践

構造体定義

まずは検証に使う構造体です。 ちょっと長いですがVast XMLをGoの構造体で表現するとこんな感じになります。 (Vastの仕様として任意の項目などは省略しています)

チューニングなし

まずはチューニング無しでこのXML構造体の初期化と、xml.Marshalを行う処理のベンチマークを取ってみます。

この数値そのものに意味はあまりありません。 相対的にどれだけこの数値をチューニングできるかを試していきたいと思います。

xml.Marshalerを実装

encoding/jsonと同じく、 encoding/xml にも Marshaler interfaceが定義されています。 このinterfaceを実装することで、型独自のMarshall処理を記述することが可能となります。

jsonの生成をこの方法で高速化するのはわりと一般的で、ffjsonなど、interfaceの実装を自動化するツールもあります。

とういことで、私はてっきりこのMarshalerの処理を最適化することで高速化が図れると思っていました。 しかし、結論から言うと、この方法では処理の高速化を実現するのは難しそうでした。

理由は interfaceがjsonのそれと全く異なるためです。

json

json.Marshalerに必要なMarshalJSONは非常にシンプルな関数であり、 jsonのバイト配列とエラーさえ返せばOKなので実装側で最適化の余地が大いにあります。

XML

対して、xml.Marshalerに必要なMarshalXMLは *Encoder StartElement を受け取り、 Encoder.EncodeTokenEncode.EncodeElement などを使ってXML文章を組み立てて行く必要があります。 そしてこれらの関数では、速度面で問題となるinterfacereflection が使用されています。

組み方をいくつか試してベンチを取ってみましたが、やはりいずれもやや劣化、という感じでした。 というわけで、いったんこの方法で高速化を実現するのは諦めました。

text/templateを使う

さて、こまりました。 ぶっちゃけて言うと、今回の記事は「xml.Marshalerを実装するとこれだけ速度改善するよ!」 という内容にしようと思っていたのですが完全に当てが外れました。

別の方法として、標準のtext/templateパッケージを使ってxml文章をテンプレート化してみました。

半ば予想できていましたが、やはり劣化しました。 xmlの生成に特化した処理であるxml.Marshal比べて、より汎用的な用途であるtext/templateパッケージの 処理なので、まあそうだろうな、という感じです。

ではなぜベンチの結果を出しているかというと、次の方法との比較になるからです。

quicktemplate を使う

テンプレート化するというアイディアから、より速いエンジンを試してみてはどうかと思いたち html/template よりも20倍早いと謳っている quicktemplate を試してみました。

quicktemplateを使うには、専用のcompilerであるqtcを使って、テンプレートをGoのプログラムとしてコンパイルする必要がりあります。

まずテンプレートを用意します。 作り方は本家のREADMEがわかりやすいので参照して下さい。 ちなみに、よりパフォーマンスをあげるためのtipsなども書いてくれているので、 ご利用の際には全体に一通り目を通すことを強くお薦めします。

これをqtcに食わせるとGoのプログラムが生成されます。

これを使ってテストコードを書き、実行します

text/template版に比べて9倍、xml.Marshalに比べても7倍の速度改善となりました。 quickの名前に偽りなし。素晴らしいですね。

ただし、注意としては、quicktemplateは処理速度向上の為 unsafeパッケージを利用しています。 本番投入して問題ないかは、慎重に判断したほうが良いかも知れません。 (そもそもGAE環境だと動かない、などもある)

unsafeの危険性に関してはこちらにまとめています。

終わりに

xml.Marshalerの実装が速度改善に使えないのは誤算でしたが、quicktemplateのお陰でタイトル詐欺にならずに済みました。 xmlに限らずjsonや、もちろん通常のhtmlのテンプレートとしても、要件にあえば積極的に使っていきたいと思います。

検証に使ったコードはこちらにUPしています。参考にして頂ければ幸いです。 今回は以上です。

junchang1031
junchang1031エンジニア