ソモサン

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

Kinesis Firehose のデータ変換 Lambda を Golang で作って計測してみた

概要

前回 やるといってたやつです。
AWS Lambda が Golang を公式サポートしたので、これまでやってきたのと同じような Lambda を作って計測してみました。

先に結果だけ書くと、

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

表にするとこんな感じ。

Runtime record/s
Python 142.8
Rust 2348.6
Golang 3910.0

すごい。

仮説

当初立てていた仮説では、Rust とそんなに差はでないかな、と考えていました。
というのも、風の噂でGolang の正規表現は遅い場合があると聞いていたので、ネイティブで動くにしてもそのあたりで差が詰まってトントンという見込みでした。

実装

github.com

実装が上です。これまで同様、 Apache のログを JSON に変換する Lambda です。
AWS CodeStar で作った Web サービス用のものをゴリゴリ書き換えました。

Golang は初めて書きましたが、あんまり違和感なくいけました。
C 書いてましたし、error まわりも Rust の Result と似たような意図を感じたので、そのまま書きました。
ただ、ただ日付には戸惑いました… わかるか!!
そんな僕を助けてくれた記事です。3年以上前…

Goのtimeパッケージのリファレンスタイム(2006年1月2日)は何の日? - Qiita

測定(おさらい)

Lambda の環境

  • Runtime: Go 1.x
  • メモリ: 128 MB
  • 実行時間上限: 5分

Runtime は Go、残り2つは前回と同様です。

指標

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

こちらも前回同様です。
正常に変換できたレコード数を、どれだけの実行時間でさばいたかで測ります。

結果

f:id:rohki:20180218191207p:plain

52.4k レコードを 13.4 秒で処理してます。
ので結果として、1 秒あたり約 3910.4 レコードを処理 した、ってことがわかりました。めっちゃ速いな!

予備計測

上の実装では json-iterator という速い package を使っていたためだきっとそうだ、ということで、JSON へのエンコードを標準の encoding/json でも行いました。
その結果がこちら。

f:id:rohki:20180218192010p:plain

56.2k レコードを 15.8 秒で処理してます。
1 秒あたり約 3557.0 レコードを処理 てことでやっぱり速い!

まとめ

仮説は外れ、Golang は速かったです。
くやしい… Rust の正式対応こい!

API Gateway の Kinesis Proxy で追跡性をちょこっと上げてみる

結論

本文マッピングテンプレートを以下のようにします

#set($inputRoot = $input.path('$'))
#define ($data){"requestId": "$context.requestId","data": "$inputRoot"}#end
{
    "StreamName": "STREAM_NAME",
    "Data": "$util.base64Encode($data)",
    "PartitionKey": "KEY"
}

これでリクエストの ID がとれ、後の処理の追跡がしやすくなる…はず?
設計に応じて、ステージ名とかパスとか入れるとよさそうです。

参考にさせてもらったところ

Amazon Kinesis プロキシとして API Gateway API を作成する - Amazon API Gateway

API Gatewayへの入力値にLambdaからアクセスする - Qiita

蛇足1: ちょっとめんどくさかった Json 文字列の作成

Kinesis Proxy の DataBase64エンコードされてる必要があります。よって、先に JSON 文字列を作ってやる必要がありました。
が、このやり方がひたすら謎で迷走してました。Velocity Template Language てなんやねん…
結局は #define でできました。

Apache Velocity Engine VTL Reference

ほかに試したこと

  • #set ($data = ...) でいれてみる
    -> ダブルクォート なしのやつが出来上がる
  • さらに $data.json() とかしてみる
    -> 空文字が返ってくる
  • #set ($data = ...) の際に '"" をエスケープして追加してみる
    -> いんたーなるさーばーえらー

蛇足2:本当は X-Ray の Trace Id がほしかった

API Gateway からの応答には入っていたので、$input.param('X-Amzn-Trace-Id') と書けばとれたりするかなー、と思ったりしましたがだめでした。
これが取れると X-Ray での描画ができてさらに便利になるやん、と期待してたりしました。

参考: Amazon API Gateway および AWS X-Ray - AWS X-Ray

CodeStar で AWS Lambda + Golang の雛形をサクッと作成してみた

前回 Golang サポートしたらやってみるといってたので、まずは雛形作成と調査だけ。Golang しっかり書いたことないですし。

CodeStar で雛形作成

AWS Lambda Supports Go をよむと CodeStar に対応しているぜー とかいてあったので、そちらで作りました。

f:id:rohki:20180116211837p:plain

github.com

物としては、API Gateway 経由で起動して、ローカルファイルを読み込んで返す Lambda でした。
仕組みについてはこちらをありがたく読ませていただきました。

CodeStar のよかったところ: クロスコンパイラ環境の準備と設定ができてる

CodeStar の利点としてはビルドやデプロイの設定がしてあることですね。とくにクロスコンパイラ環境。
家に帰る途中で調査の段取り考えてた時に、ビルド環境の準備面倒そうだなーとか思ってたので。
実際は $ GOOS=linux GOARCH=amd64 で行けるので手間でない模様。

雑感

バイナリサイズ: 2.4 MB

このぐらいのサイズにはなりますよね。

cold 状態からの起動による遅延: 感じられず

おそらく数ミリ秒

つづく

こちら にて紹介いただいていた sdkFirehose のイベント定義 もありました。
書くぞー計測するぞー

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

概要

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

続きを読む

AWS Lambda 上で Rust のコードを実行しようとして結構頑張った話

短く

OpenSSL はやはり鬼門
というわけでできたー。下が成果物。

github.com

続きを読む

Q. 2017/12/9 の AWS Lambda の OpenSSL のバージョンは?

import ssl

def lambda_handler(event, context):
    return ssl.OPENSSL_VERSION

チェック!

結果: "OpenSSL 1.0.0-fips 29 Mar 2010"

おし、めんどくさくなってきた。

情報元:

OpenSSL 1.0.2 Shared Library missing · Issue #855 · Miserlou/Zappa · GitHub

AWS Lambda の Traffic Shifting Using Aliases で無理やり Chaos Engineering

できんじゃねと思ったらできました。無理やり。

この間発表された AWS Lambda の更新で、エイリアスに対して割合で別バージョンを割り振ることができるようになりました。
ユースケースとしては Canary や Blue/Green が上がってたんですが、Chaos もいけんじゃねと思ってやってみたら一応できました。

正常なコードが以下です。バージョン 1 です。

import json

print('Loading function')


def lambda_handler(event, context):
    #print("Received event: " + json.dumps(event, indent=2))
    print("value1 = " + event['key1'])
    print("value2 = " + event['key2'])
    print("value3 = " + event['key3'])
    return event['key1']  # Echo back the first key value
    #raise Exception('Something went wrong')

異常なコードが以下です。バージョン 2 です。
なんも考えてません。例外はくだけ。

import json

print('Loading function')


def lambda_handler(event, context):
    raise Exception('Something went wrong')

んで、エイリアス chaos をつくり、バージョン 2 へ 5% の確率で行くよう設定します。

f:id:rohki:20171201230126p:plain

あとはひたすらポチポチ実行。

f:id:rohki:20171201230439p:plain

おー、できました。無理やり感が否めないですがw

例外パターンを最初に考えないときつそうかなー。
あとどうやって例外バージョンを指定して割り振るかってのが難しそう。

ただ形にできると発展も効きそうです。ひたすらスリープして落ちるとか。
Serverless のプラグインとかですかね?