Ruby
lambda

AWS LambdaのRuby、カスタムランタイムで動作している説

AWS LambdaのRubyの実行環境が何で動いているのか気になって軽く使ってみたのでメモ

※2018-12-06追記
コメント欄でカスタムランタイムで動いていることを @JONAO33 さんに教えて頂きました。ありがとうございます!

"The Runtime API is the future of how we’ll support new languages in Lambda. For example, this is how we built support for the Ruby language."
https://aws.amazon.com/jp/blogs/aws/new-for-aws-lambda-use-any-programming-language-and-share-common-components/

Hello worldをして呼び出し時間(課金時間)を簡単にベンチマークしてみた

なお計測前に何回か実行してコールドスタートになるのを回避している

環境

  • Ruby 2.5

検証

以下のコードを使用

def lambda_handler(event:, context:)
    puts 'Hello world!'
end

10回試行しそれぞれ課金された時間(Billed duration)を測る。単位はms

32.69
10.87
39.41
3.27
20.45
14.54
38.23
23.63
7.50
27.59

image.png

結果

平均: 21.82ms
中央値: 22.04ms
最小: 3.27ms
最大: 39.41ms

かなりばらつきが大きくLambdaのランタイムとしてgolangを使用した時と似たような挙動となった。
そもそもネイティブのRubyでもHello worldしただけで何十msもかかるわけがない。

$ time ruby -e 'puts "hello"'
hello
ruby -e 'puts "hello"'  0.04s user 0.00s system 98% cpu 0.046 total

ならなぜこんなにかかるのかというとLambdaのランタイムに仕組みがある。
以前からも実は自分でRubyやPHPなどをLambdaで動かそうと思えば自前でバイナリを用意してプロセス間通信でパラメータを渡してあげれば出来たが、今回追加されたカスタムランタイムと同様にRuby 2.5ランタイムも一回OSのパイプを経由していると思われる。

やたらばらつきが大きいのも一度OSのレイヤーに降りているので他のOSリソースにスケジューリングを奪われて実行が遅れているのかもしれない。

Pythonの場合

同様にPythonのHello worldも実行してみた

環境

  • Python 3.6

検証

def lambda_handler(event, context):
    print("hello world")

    return 'ok'
0.34
0.43
0.52
0.34
0.34
0.34
0.35
0.33
0.35
0.43

image.png

平均: 0.38ms
中央値: 0.35ms
最小値: 0.33ms
最大値: 0.52ms

となった
PythonランタイムはLambdaのコンテナが一度実行されるとしばらくそのコンテナを使いまわしてキャッシュする仕組みになっているため、ランタイムの初期化をスキップ出来る。
OSを経由しないためネイティブに近い速度が出るようになっている

$ time python -c "print(1)"
1
python -c "print(1)"  0.01s user 0.00s system 98% cpu 0.013 total

まとめ

Hello worldのばらつきからLambdaのRubyはカスタムランタイムで動いてる説を推測してみた

他のカスタムランタイムでも同様のランタイム初期化のオーバーヘッドは存在するため、ターンアラウンドタイムが重要になる場合や、オーバーヘッドを超えるような処理でない場合はLambdaに既に最適化されているPythonでサクっと処理するのがいいかもしれない