Photoruction工事中!

Photoructionの開発ブログです!

AWS Lambdaを変えてしまったかもしれないお話

PhotoructionのWebエンジニアの下川原です。

今回は、AWS Lambdaについて語ろうと思います!

 

関連ワード

  • Lambda
  • nodejs
  • sharp
  • 画像処理
  • 雑談

 

もくじ

 

1.AWS Lambdaが変わったこと

参考:https://aws.amazon.com/jp/blogs/aws/aws-lambda-now-supports-up-to-10-gb-ephemeral-storage/

Lambdaはもともと512MBのtmpが提供されていた。

しかし、2022/3/24にアップデートがされた。要約すると

Lambdaが提供するtmpを512MBから10GBまで増やせるよ!

※ただし512MB以上の容量追加は追加料金あるよ!

やったね!

2.Lambdaに何をしてしまったのか

'use strict';
const sharp = require('sharp');

exports.mainHandler = async (event, context, callback) => {
    let work_folder = createWorkDirectoryStructure();
    //画像をDLしてくる処理
    let src = getSourceData(event.data.bucket, event.data.image_path, work_folder);
    toProcessImage(src, work_folder, event.data.image_name);
    CleanupTempDirectory(work_folder);

    return true;
};

const toProcessImage = async (src, output_base_path, slice_file_base_name) => {
    let src_img = sharp(src);
    let tmp_path = path.join(output_base_path, slice_file_base_name);

    //切り取り処理 数字は適当
    await src_img.extract({
        left: 100,
        top: 200,
        width: 500,
        height: 500,
    })
        .toFile(tmp_path);//加工した画像を配置する処理
}

const createWorkDirectoryStructure = () => {
    let work_folder = path.join('/', 'tmp', 'work-' + shortid.generate());
    if (!fs.existsSync(work_folder)) {
        fs.mkdirSync(work_folder);
    }
    return work_folder;
}

const getSourceData = (bucket, key, directory) => {
    let file_extension = path.extname(key);
    let dst = path.join(directory, `src${file_extension}`);
    return downloadFile(bucket, key, dst);
}
//ディレクトリを削除する処理
const CleanupTempDirectory = (dir) => {
    if (fs.existsSync(dir)) {
        fs.rmdir(dir, {"recursive": true}, (error) => {
            if (error) {
                console.log("clean up progress: " + error);
            }
        });
        console.log("Cleanup complete");
    }
}

こんなように、適当に画像を切り出す処理があったとする。

AWSコンソールから、

テスト実行・・・成功

テスト実行・・・成功

テスト実行・・・失敗

エラー:No space left on device

短い期間、ほぼ連続で実行するとエラーになる

なぜ?

容量不足と出ているなら、この処理のどれかが悪さをしているのだろう。

・画像をDLしてくる処理

・加工した画像を配置する処理

ディレクトリを削除する処理

Lambdaコンテナの中で何がおきてるか、確認するのが早いだろう(Linuxのコマンドが使えてよかった・・)

処理のはじめと終わりに以下のコードを追加

console.log(execSync("df -h").toString());
console.log(execSync("du -h /tmp").toString());

コード挿入後の実行ログ

1回目テスト実行・・・成功

INFO	Filesystem                                                       Size  Used Avail Use% Mounted on
/mnt/root-rw/opt/amazon/asc/worker/tasks/rtfs/nodejs14.x-amzn-2  9.8G  8.8G  947M  91% /
/dev/vdb                                                         1.5G   14M  1.4G   1% /dev
/dev/vdd                                                         526M  872K  514M   1% /tmp
/dev/root                                                        9.8G  8.8G  947M  91% /etc/passwd
/dev/vdc                                                         9.5M  9.5M     0 100% /opt
INFO 4.0K	/tmp
INFO Cleanup complete
INFO Filesystem                                                       Size  Used Avail Use% Mounted on
/mnt/root-rw/opt/amazon/asc/worker/tasks/rtfs/nodejs14.x-amzn-2  9.8G  8.8G  947M  91% /
/dev/vdb                                                         1.5G   14M  1.4G   1% /dev
/dev/vdd                                                         526M  178M  337M  35% /tmp
/dev/root                                                        9.8G  8.8G  947M  91% /etc/passwd
/dev/vdc  
INFO 4.0K	/tmp
2.7M	/tmp

2回目テスト実行・・・成功

INFO	Filesystem                                                       Size  Used Avail Use% Mounted on
/mnt/root-rw/opt/amazon/asc/worker/tasks/rtfs/nodejs14.x-amzn-2  9.8G  8.8G  947M  91% /
/dev/vdb                                                         1.5G   14M  1.4G   1% /dev
/dev/vdd                                                         526M  178M  337M  35% /tmp
/dev/root                                                        9.8G  8.8G  947M  91% /etc/passwd
/dev/vdc                                                         9.5M  9.5M     0 100% /opt
INFO 4.0K	/tmp
INFO Cleanup complete
INFO Filesystem                                                       Size  Used Avail Use% Mounted on
/mnt/root-rw/opt/amazon/asc/worker/tasks/rtfs/nodejs14.x-amzn-2  9.8G  8.8G  947M  91% /
/dev/vdb                                                         1.5G   14M  1.4G   1% /dev
/dev/vdd                                                         526M  355M  160M  70% /tmp
/dev/root                                                        9.8G  8.8G  947M  91% /etc/passwd
/dev/vdc  
INFO 4.0K	/tmp
2.7M	/tmp

3回目テスト実行・・・失敗

INFO	Filesystem                                                       Size  Used Avail Use% Mounted on
/mnt/root-rw/opt/amazon/asc/worker/tasks/rtfs/nodejs14.x-amzn-2  9.8G  8.8G  947M  91% /
/dev/vdb                                                         1.5G   14M  1.4G   1% /dev
/dev/vdd                                                         526M  355M  160M  70% /tmp
/dev/root                                                        9.8G  8.8G  947M  91% /etc/passwd
/dev/vdc                                                         9.5M  9.5M     0 100% /opt
INFO 4.0K	/tmp
INFO Cleanup complete
INFO Filesystem                                                       Size  Used Avail Use% Mounted on
/mnt/root-rw/opt/amazon/asc/worker/tasks/rtfs/nodejs14.x-amzn-2  9.8G  8.8G  947M  91% /
/dev/vdb                                                         1.5G   14M  1.4G   1% /dev
/dev/vdd                                                         526M  512M  2.4M 100% /tmp
/dev/root                                                        9.8G  8.8G  947M  91% /etc/passwd
/dev/vdc  
INFO 4.0K	/tmp
2.7M	/tmp

順調に増えてる・・・

画像はそこまでインパクトは無い・・・

作業ディレクトリはエラー無くしっかり消せている・・・

・画像をDLしてくる処理

・加工した画像を配置する処理

ディレクトリを削除する処理

    //切り取り処理 数字は適当
    await src_img.extract({
        left: 100,
        top: 200,
        width: 500,
        height: 500,
    })
        .toFile(tmp_path);//加工した画像を配置する処理

どうやら、toFile時に

関数とは違う実行ユーザーでファイルが置かれてしまうらしい

lrwx------ 1 sbx_user1051 990 64 Dec  3 01:43 24 -> /tmp/vips-0-3816661850.v (deleted)
lrwx------ 1 sbx_user1051 990 64 Dec  3 01:43 25 -> /tmp/vips-1-2724960011.v (deleted)
lrwx------ 1 sbx_user1051 990 64 Dec  3 01:43 26 -> /tmp/vips-2-485543279.v (deleted)
lrwx------ 1 sbx_user1051 990 64 Dec  3 01:43 27 -> /tmp/vips-3-930892267.v (deleted)

どおりで、/tmp配下に存在しない”ように”見えてしまっていたわけ

3.解決方法

では、上記の問題をどう解決したか?

ファイルを開く時に、メモリ経由かディスク経由かを判定するために

サイズを指定するパラメータ(VIPS_DISC_THRESHOLD)があり、

これを適切に設定しないと、ストレージが枯渇してしまう問題を見つけた。

https://github.com/lovell/sharp/issues/707

https://github.com/lovell/sharp/issues/1851

つまり、VIPS_DISC_THRESHOLDの設定を極端に少なくすれば常にメモリ経由で処理を継続してくれるというのだ。

Lambdaの環境変数に次のように追加することで設定可能

VIPS_DISC_THRESHOLD=10M

すると何回連続して実行を行っても、問題がおきることは無くなった。

4.さいごに

このような問題を発見、解決した数日後に「tmpを拡張可能にしたよ!」の記事が・・・。

さすがに数日で対応したわけは無いと思う、自由に使えるtmp容量を増やしてほしいという声は、

LambdaでAWS EFSを活用する記事をみると前々から需要があったのだろう。

気軽にtmpを拡張することができるので、ディスク上で操作する幅が広がったLambda

最後に改めて紹介しよう。

https://aws.amazon.com/jp/blogs/aws/aws-lambda-now-supports-up-to-10-gb-ephemeral-storage/

 

株式会社フォトラクションでは一緒に働く仲間を募集しています