ソモサン

私rohkiによる活動や読書の記録をつらつらと書くページです

Kinesis Firehose のデータ変換を Rust でやってみて速度向上が見込めた話

概要

Rust コードを Lambda 上で動かせたーと喜んだんですが、活用どころあるんだろうかと考えてみて検証してみました。
結果として Python 比較で1秒当たりで 15 倍ほど多く処理できました。
以下でつらつらと書いていってます。

前提: Lambda の環境について

Python比で起動時間に差がない

Rust はそこそこバイナリサイズが大きくなります。
前回書いた Kinesis から S3 へ保存するコードも、Lambda のコンソール上で 1MB という数字になってました。
ライブラリ結構使っているとはいえ、やっぱりでかいです。
当然デバッグ情報の削除やならんやらで小さくはなるのですが、 Python なら500 B 程度。
結果として初期の起動速度の差がでてるのかなーと考えてます。
ので、Rust を使うなら起動してすぐ結果をかえす場面でなく、そこそこじっくりと処理する方が向いてそうです。

IO が絡むとつらい

IO が絡むと待ちが発生するので、やはりうまみが少なくなります。
Lambda のコア数もメモリを 3GB まで増やしても 2 以上にはならなかったので、どうやってもこの辺りはしんどそうです。

Rust が活躍しそうな場面でいうと、IO 絡まないけど起動してそこそこ以上の量を処理する Lambda…

仮説: Kinesis Firehose のデータ変換がよいのでは?

Kinesis Firehose にはデータ変換用の Lambda がくっつけられたります。
そしてデータ変換したあとは Firehose 側が S3 なりなんなりに保存してくれます。 つまり

  • IO は Firehose 側で
  • かつ Lambda は起動してから大量レコードを一気に処理する

完璧だ…なんて相性のよさだ…

実装

比較対象は AWS Lambda の Blueprint にあった Apache のログを JSON に変換する Python コードです。
Blueprint のコードはっていいのかわかんないですね。権利誰にあるんだろう…掲載はやめときます。

で、そのコードをもとに Rust の実装を書いてみました。

github.com

測定

Lambda の環境

  • Runtime: Python2.7
  • メモリ: 128 MB
  • 実行時間上限: 5分

Rust と Python の環境は双方ともに上記になってます。
実をいうと Rust の実装は並列実行に対応してるんですが、メモリがこのサイズだとコア数が1であんまり意味がないという…

データ投入: Amazon Kinesis Data Generator

データの大量投入には Kinesis Data Generator を使いました。

aws.amazon.com

上記Apache っぽいログの作り方ものってたので、脳みそを使わずホイホイと利用してます。

とりあえずツールで投入できる上限の秒間 2,000 Records の流量で、100,000 Records までつっこみました。*1

補足として Python 側の実装がここから生成されるログとかみ合っていなくて少しだけ手を入れています。
正規表現タイムゾーンのところに : がなかった感じでした。ので、追加してます。

投入先として Rust を紐づけた Firehose と Python を紐づけた Firehose の2個を用意しました。

指標

Amazon CloudWatch メトリクスを使用したモニタリング - Amazon Kinesis Firehose を参考に、以下2つを比較の指標としました

  • ExecuteProcessing.Duration: 変換 Lambda の実行時間
  • SucceedProcessing.Records: 変換 Lambda が正常に変換できたレコード数

それぞれの合計値を比較します。

結果

f:id:rohki:20171219224927p:plain
Rust と Python の計測結果

左側の2つが Rust 実装の総処理時間とレコード数、右側が Python 実装の総処理時間とレコード数です。
文字で書くと

  • Rust: 55.8 k レコードを 23.4 秒で処理
    => 1 秒あたり約 2384.6 レコードを処理
  • Python: 56.7 k レコードを 397 秒で処理
    => 1 秒あたり約 142.8 レコードを処理

早い! 早いってことはお金がかからない! すぐ保存される!
いやー読みが当たってよかった…ということで、仮説はあってそう!

発展: バイナリフォーマットの変換

今回は速度面で考えましたが、言語の特性を考えるとバイナリ操作とかが合うのかなと考えてます。
IoT 機器からは電池消費量・通信容量の関連で省スペースなバイナリフォーマットでデータ送信したいけど、解析の時は JSON がいいからどこかで変換したい…!!てきな。*2

おわりに

CodeBuild でのビルドに成功してるので、CodePipeline でのデプロイまでいけそうです。
となるといろいろ回って楽にできるかも?
Lambda に Golang が来たら比較もしてみたいですねー

*1:いろいろビビりながらやってました

*2:個人の妄想です