この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは。サービスグループの武田です。
先日、頑張ってAWS LambdaのコンテナでRustアプリケーションからS3 Selectを実行してみました。
最後に 予想より実行時間が長い結果となりました と書いたのですが、じゃあどれくらいなら満足できるのか。というわけで、Lambdaで採用されることが多いであろうPythonとJavaScriptで同様の処理を書いて比較してみました。
Rust(+ AWS CLI) vs Python vs JavaScript
実行したソースコードはそれぞれ次のものです。なおRustは先述のエントリそのままですので省略します。
handler.py
import boto3
import json
s3 = boto3.client("s3")
def lambda_handler(event, context):
params = {
"Bucket": "testdata-xxxx",
"Key": "test_data.json",
"InputSerialization": {
"JSON": {
"Type": "LINES",
}
},
"OutputSerialization": {
"JSON": {
"RecordDelimiter": "\n",
}
},
"ExpressionType": "SQL",
"Expression": "SELECT * FROM s3object s",
}
res = s3.select_object_content(**params)
text = ""
for event in res["Payload"]:
if "Records" in event:
raw = event["Records"]["Payload"].decode("UTF-8")
text += raw
for line in text.splitlines():
print(json.loads(line))
handler.js
const AWS = require('aws-sdk');
const S3 = new AWS.S3();
exports.handler = async (event) => {
const params = {
Bucket: 'testdata-xxxx',
Key: 'test_data.json',
InputSerialization: {
JSON: {
Type: 'LINES',
}
},
OutputSerialization: {
JSON: {
RecordDelimiter: '\n',
}
},
ExpressionType: 'SQL',
Expression: 'SELECT * FROM s3object s',
};
const res = await S3.selectObjectContent(params).promise();
let text = '';
const events = res.Payload;
for await (const event of events) {
if (event.Records) {
text += event.Records.Payload.toString();
}
}
for (line of text.split('\n').filter(line => line !== '')) {
console.log(JSON.parse(line));
}
};
実行結果は次のようになりました。なおいずれも2回目〜6回目の結果を採用し、イニシャルコストは含まれていません。またJavaScriptについてはKeepAliveがデフォルトで無効化されているため、有効化しました。
Rust + AWS CLIの結果。
START RequestId: c66a065d-6673-469d-9db9-d1e251e1e4fe Version: $LATEST
[2021-02-26T02:23:29Z DEBUG rust_lambda_call_aws_cli] handler start
[2021-02-26T02:23:31Z DEBUG rust_lambda_call_aws_cli] Output { status: ExitStatus(ExitStatus(0)), stdout: "", stderr: "" }
[2021-02-26T02:23:31Z INFO rust_lambda_call_aws_cli] TestData { name: "Test", code: 1939, tags: Some("Dev"), lang: Some("ja") }
[2021-02-26T02:23:31Z INFO rust_lambda_call_aws_cli] TestData { name: "IT Division", code: 1, tags: Some("Prod"), lang: Some("ja") }
[2021-02-26T02:23:31Z INFO rust_lambda_call_aws_cli] TestData { name: "Sample", code: 31, tags: None, lang: Some("en") }
[2021-02-26T02:23:31Z INFO rust_lambda_call_aws_cli] TestData { name: "Classmethod", code: 2, tags: None, lang: Some("en") }
[2021-02-26T02:23:31Z INFO rust_lambda_call_aws_cli] TestData { name: "Classmethod2", code: 19, tags: None, lang: None }
END RequestId: c66a065d-6673-469d-9db9-d1e251e1e4fe
REPORT RequestId: 8e9f49c0-6b91-40e3-81f3-f7636abb8546 Duration: 2459.43 ms Billed Duration: 2460 ms Memory Size: 512 MB Max Memory Used: 46 MB
REPORT RequestId: 848f0aa9-fca2-46e7-8942-d7a37bd2433d Duration: 2487.36 ms Billed Duration: 2488 ms Memory Size: 512 MB Max Memory Used: 47 MB
REPORT RequestId: 2b5831ad-c1a3-4df3-b50b-db600eed5af9 Duration: 2463.11 ms Billed Duration: 2464 ms Memory Size: 512 MB Max Memory Used: 47 MB
REPORT RequestId: 34fd1cdb-b7cb-4e55-8c9a-5b6c136e3b53 Duration: 2483.41 ms Billed Duration: 2484 ms Memory Size: 512 MB Max Memory Used: 47 MB
REPORT RequestId: 99f64d9c-7acb-481d-b617-e3fc9314f595 Duration: 2501.80 ms Billed Duration: 2502 ms Memory Size: 512 MB Max Memory Used: 47 MB
Pythonの結果。
START RequestId: 16797d8f-6abf-47f2-ab02-7414e89bf5d2 Version: $LATEST
{'name': 'Test', 'code': 1939, 'tags': 'Dev', 'lang': 'ja'}
{'name': 'IT Division', 'code': 1, 'tags': 'Prod', 'lang': 'ja'}
{'name': 'Sample', 'code': 31, 'lang': 'en'}
{'name': 'Classmethod', 'code': 2, 'lang': 'en'}
{'name': 'Classmethod2', 'code': 19}
END RequestId: 16797d8f-6abf-47f2-ab02-7414e89bf5d2
REPORT RequestId: cb8cb604-6153-4f51-884f-4b782122119c Duration: 179.49 ms Billed Duration: 180 ms Memory Size: 128 MB Max Memory Used: 80 MB
REPORT RequestId: 715763e4-f6dd-4bb0-8c0a-0173ccf63d2b Duration: 24.90 ms Billed Duration: 25 ms Memory Size: 128 MB Max Memory Used: 81 MB
REPORT RequestId: 3baf17be-2a6b-4e6f-b522-4aee942c43cb Duration: 37.96 ms Billed Duration: 38 ms Memory Size: 128 MB Max Memory Used: 80 MB
REPORT RequestId: 3c5aae3a-2575-4364-a7b9-927e6554d446 Duration: 42.81 ms Billed Duration: 43 ms Memory Size: 128 MB Max Memory Used: 80 MB
REPORT RequestId: 51f995a3-20a7-4251-8713-bd8f64aea187 Duration: 40.54 ms Billed Duration: 41 ms Memory Size: 128 MB Max Memory Used: 80 MB
JavaScriptの結果。
START RequestId: e75761b2-4583-4cb1-8c11-d3f2287b65aa Version: $LATEST
2021-02-26T02:37:22.180Z e75761b2-4583-4cb1-8c11-d3f2287b65aa INFO { name: 'Test', code: 1939, tags: 'Dev', lang: 'ja' }
2021-02-26T02:37:22.187Z e75761b2-4583-4cb1-8c11-d3f2287b65aa INFO { name: 'IT Division', code: 1, tags: 'Prod', lang: 'ja' }
2021-02-26T02:37:22.207Z e75761b2-4583-4cb1-8c11-d3f2287b65aa INFO { name: 'Sample', code: 31, lang: 'en' }
2021-02-26T02:37:22.207Z e75761b2-4583-4cb1-8c11-d3f2287b65aa INFO { name: 'Classmethod', code: 2, lang: 'en' }
2021-02-26T02:37:22.207Z e75761b2-4583-4cb1-8c11-d3f2287b65aa INFO { name: 'Classmethod2', code: 19 }
END RequestId: e75761b2-4583-4cb1-8c11-d3f2287b65aa
REPORT RequestId: 74d14063-63f4-4416-a991-4baf4eec444d Duration: 70.48 ms Billed Duration: 71 ms Memory Size: 128 MB Max Memory Used: 89 MB
REPORT RequestId: e4cf838f-d085-403b-952f-5f7a10e9c89e Duration: 532.37 ms Billed Duration: 533 ms Memory Size: 128 MB Max Memory Used: 90 MB
REPORT RequestId: 27896427-f6f8-4672-945a-371dfe271b73 Duration: 44.37 ms Billed Duration: 45 ms Memory Size: 128 MB Max Memory Used: 90 MB
REPORT RequestId: 8abc9ab1-6917-4e7d-8ace-681e9276ab60 Duration: 33.97 ms Billed Duration: 34 ms Memory Size: 128 MB Max Memory Used: 90 MB
REPORT RequestId: 4edaa2e8-8cbb-4bfe-b547-6837e87f731b Duration: 33.67 ms Billed Duration: 34 ms Memory Size: 128 MB Max Memory Used: 90 MB
PythonとJavaScriptは早いですね。計測回数が少ないので外れ値が目立ちますが、おそらく回数を増やせばいい具合に収束すると思われます。
一番問題なのは、Rust + AWS CLIはメモリ割り当てを512MBに上げてこの遅さなんですよね。外部コマンド呼び出しが悪いのか、一度ファイルに書き出しているのが遅さの原因なのか。そこまで調べきれていませんが、PythonやJavaScriptの最高速と比べて2桁違うのは結構な違いかと思われます。
まとめ
結構頑張ってRustからS3 Selectをやってみたものの、比較してみると採用はしにくそうです。これであれば、AWS CLI経由ではなくて、 S3 Selectを実行するPython Lambda関数 をRustから呼び出した方が早そうですね。