64
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【AWS re:Invent2018】AWS Lambda で Rubyを使う(Hello worldからDynamoDBとの連携、速度計測まで)

Last updated at Posted at 2018-11-30

Ruby support for Lambda

LambdaでついにRuby Runtimeがサポートされました。

UNADJUSTEDNONRAW_thumb_34b8.jpg

現在対応しているバージョンは2.5です。
とにかく触ってみることが大事ということで、早速動かしてみました。

  • Hello world
  • DynamoDB連携
  • pythonとnodeとの速度比較

Lambda関数を作成

もうGAなので選択肢にruby2.5が表示されています。(嬉しい...!)
screenshot1.png

作成。
スクリーンショット 2018-11-30 4.37.47.png

最初のコードはこんな感じですね。

lambda_function

require 'json'
 
def lambda_handler(event:, context:)
    # TODO implement
    { statusCode: 200, body: JSON.generate('Hello from Lambda!') }
end

何はともあれとりあえずこのまま実行します。 Hello from Lambda!

screenshot2.png

色々遊んで見る

標準ライブラリ以外を利用したい場合には、NodeやPythonなどと同じように、ローカルでrubyアプリを作成してそれをまとめてsamでアップロードする形になります。 AWSブログのチュートリアルを使って解説していきます。

DynamoDBとの連携

1. 下準備

まずはローカルにアプリディレクトリを作ります。

bash
$ mkdir lambda_ruby
$ cd lambda_ruby
2. Gemfileを作成する

中身にaws用のライブラリを記述します。他のライブラリを利用したい場合は合わせて書くと良いでしょう。

Gemfile
source 'https://rubygems.org'
gem 'aws-record', '~> 2'

bundle installも忘れずに実行してください。ローカルのrubyにインストールしたい場合はbundle installだけでもいいのですが、今回はライブラリも含めてLambda側にdeployするので、--deploymentオプションを付けて実行しておきましょう

bash
$ bundle install --deployment
3. Lambdaの実行スクリプトを作成する

hello_ruby_record.rbを作成します。 put_item を今回のlambdaのhandlerメソッドとしています。(後述のtemplate.yamlの設定でhandlerの関数は自由に指定できます)

hello_ruby_record.rb
require 'aws-record'

class DemoTable
  include Aws::Record
  set_table_name ENV[DDB_TABLE]
  string_attr :id, hash_key: true
  string_attr :body
end  

def put_item(event:,context:)
  body = event["body"]
  item = DemoTable.new(id: SecureRandom.uuid, body: body)
  item.save! # raise an exception if save fails
  item.to_h  
end
4. template.yamlの作成

lambda側にアップロードするための設定ファイルを作成します。Lambda側へのアップロードは、AWS SAM を利用します。

template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: 'sample ruby application'

Resources:
  HelloRubyRecordFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: hello_ruby_record.put_item
      Runtime: ruby2.5
      Policies:
      - DynamoDBCrudPolicy:
          TableName: !Ref RubyExampleDDBTable 
      Environment:
        Variables:
          DDB_TABLE: !Ref RubyExampleDDBTable

  RubyExampleDDBTable:
    Type: AWS::Serverless::SimpleTable
    Properties:
      PrimaryKey:
        Name: id
        Type: String

Outputs:
  HelloRubyRecordFunction:
    Description: Hello Ruby Record Lambda Function ARN
    Value:
      Fn::GetAtt:
      - HelloRubyRecordFunction
      - Arn

今回はLambda関数とDynamoDBテーブルを利用するので、Serverless::FunctionとServerless::SimpleTableをリソースとして定義します。
このテンプレートファイルの詳しい解説はチュートリアルを見てください。

5. 一旦フォルダ構成を確認

今までの作業でフォルダ内はこの様になっているはずです。

$ tree -L 2 -a
.
├── .bundle
│   └── config
├── Gemfile
├── Gemfile.lock
├── hello_ruby_record.rb
└── vendor
└── bundle

あとはSAMを使ってdeployを実施するだけです。

6. SAMパッケージの作成

SAMが入っていない場合はインストールしておきます。

$ pip install aws-sam-cli

先程作成したテンプレートファイルを使ってsamパッケージを作成します。
※S3バケットは予め作成しておいてください。

sam package --template-file template.yaml \
--output-template-file packaged-template.yaml \
--s3-bucket <bucketname>

フォルダにpackaged-template.yamlが作成されたら成功です。

7. パッケージのアップロード

SAMのdeployコマンドを利用してパッケージをアップロードします。
stack-nameはlambdaの関数名になりますので、好きな名前を入力してください。

$ sam deploy --template-file packaged-template.yaml \
--stack-name helloRubyDynamo \
--capabilities CAPABILITY_IAM

Waiting for changeset to be created...
Waiting for stack create/update to complete
Successfully created/updated stack - helloRubyRecord

注意点
CLIに紐付いているIAMにCloudFormationの権限を付けておかないとエラーになります。

An error occurred (AccessDenied) when calling the CreateChangeSet operation: 
User: arn:aws:iam::*** is not authorized to perform: 
cloudformation:CreateChangeSet on resource:
arn:aws:cloudformation:ap-northeast-1:***:stack/helloRubyDynamo/*
8. テスト

CloudFormationでデプロイしたので、DynamoDBのセットアップも含めてデプロイが完了しています。下記のようなテストイベントを送ってテストしてみましょう

テストイベントの設定
{"body": "hello lambda"}

成功しました。
screenshot3.png

DynamoDBにも同じ値が入っていますね。
スクリーンショット 2018-11-30 8.49.46.png

こんな感じです。途中からSAMの解説になってしまいましたが、Rubyのライブラリを入れたいならSAMを導入しておくとその後の手間が大いに削減されるので、設定しておいて損はないと思います。

処理時間はどうなのか計測

nodeやpythonと違い、新しく発表されたCustom Runtimeをバックエンドに利用しているとのことなので、ruby Runtimeの読み込み時間なども含めて処理時間ってどうなんだろう、と気になったので、計測しました。

初回起動
言語 バージョン 実行時間
ruby 2.5 23.31 ms
node.js 8.10 12.28 ms
python 3.7 4.62 ms

なるほど。。。Custom Runtimeの読み込み分が乗っかってる感じでしょうかね。。。

2回目以降

それぞれ100回叩いて平均値を計測しました。公平を期すためにHello worldのみのコードで100回ループで起動時間を計測します。

lambda_handler.rb
require 'json'

def lambda_handler(event:, context:)
    # TODO implement
    { statusCode: 200, body: JSON.generate('Hello from Lambda!') }
end
lambda_handler.js
exports.handler = async (event) => {
    // TODO implement
    const response = {
        statusCode: 200,
        body: JSON.stringify('Hello from Lambda!'),
    };
    return response;
};
lambda_handler.py
import json

def lambda_handler(event, context):
    # TODO implement
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

では100回回します。下記のようなスクリプトを言語ごとに回しました。

loop.rb
require 'json'
require 'base64'

duration_total_ruby = 0

100.times do |i| 

	result = `aws lambda invoke --invocation-type RequestResponse --function-name HelloworldRuby --log-type Tail --payload \'{}\' outputfile.txt`

	obj = JSON.parse(result)
	duration = Base64.decode64(obj["LogResult"])[/Duration: (.*) ms\tB/,1]
	p "#{i}, #{duration} ms."
	duration_total_ruby += duration.to_f

end

p "Invoke ruby duration total: #{duration_total_ruby} ms" 
p "Invoke ruby duration agverage: #{duration_total_ruby / 100} ms" 

result
"Invoke ruby duration total: 704.3100000000002 ms"
"Invoke ruby duration agverage: 7.043100000000002 ms"

"Invoke node duration total: 137.77000000000004 ms"
"Invoke node duration agverage: 1.3777000000000004 ms"

"Invoke python duration total: 638.43 ms"
"Invoke python duration agverage: 6.3843 ms"
言語 バージョン 総実行時間 平均実行時間
ruby 2.5 704.31 ms 7.0431 ms
node.js 8.10 137.77 ms 1.3777 ms
python 3.7 638.43 ms 6.3843 ms

なんとnode.jsが一番 早いという結果に!(当然rubyは一番遅い)

終わりに

個人的にも馴染みのあるRubyがサポートされたのは非常に嬉しかったですね。
これからどんどん使っていきたいと思います。

64
31
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
64
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?