🐈‍⬛

AWSのサポート切れをきっかけに、画像の透かし入れ機能をレガシーシステムからサーバーレスに切り替えた話

2023/07/01に公開

背景

こちらの発表のとおりAWSでは今後TLSのバージョンが1.2未満の通信を許可しなくなるため、影響を受けるシステムは修正しないと使えなくなります。

長年メンテナンスせずに放置されてきたシステムは簡単には更新できず、画像の透かし入れぐらいの機能なら、サーバーレスで完全に作り直した方が良いのでは?ということで実装してみることになりました。

切り替えることによって得られたメリット

保守性の向上

大昔から存在する古臭いJavaのアプリケーションをサーバーレスに切り替えたことにより、コードベースが大幅に削減されました。解読することが大変な状態から100行未満の簡単なスクリプトに変わったため、非常に保守しやすくなりました。

スケールアウト

サーバー上で稼働するWebアプリケーションをサーバーレスに切り替えたことにより、サーバーの負荷、適切なスペックを気にする必要がなく、全てはAWSが管理しているため、サービスクォータが許す限り、いくらでも無駄なく勝手にスケールアウトできます。

コスト削減

サーバーレスに切り替えたことにより、単位時間あたりの課金体制からアクセス毎の課金体制に変わりました。アクセス数の少ない時間帯でも無駄なコストが発生することはなく、アクセス数の急増に備えてバッファを確保する必要もないため、コストがかなり削減されました。

システム構成

下記の画像の通り非常にシンプルな構成です。API Gateway から Lambda を呼び出して、Lambda で S3 にある画像に透かしを入れてから、レスポンスを返す。

効果

https://<API Gateway のエンドポイント>/watermark/<S3にある画像のパス> にアクセスするとこのようにS3に事前にアップロードした猫ちゃんの画像に透かしが追加されて表示されます。

実装

アーキテクチャ

いろいろ調査してみたところ、Serverless Framework というものが一番良さそうでしたので、採用しました。 serverless.yml というファイル内に定義を記載することで、デプロイ&AWSの設定を行ってくれるので、IaC(Infrastructure as Code) も一緒に実現できます。

コード (必要であれば、ご自由にお使いください)

両方実現している機能は全く同じですが、最初は Node.js で実装しました。Lambda関数の実装について調べると、Node.js で実装した場合の情報が圧倒的に多かったです。またスクリプト言語であるためコーディングしやすく、コンパイルする必要もないので、一番簡単でした。

詰まったポイント

API GatewayのAPIパス定義

S3上にある画像は / を区切り文字として使用しているため、/watermark/{image_key} でAPIを定義するとS3のパスを正しく取得できません。/watermark/{image_key+} という風に + を付けることで、それ以降のURLはすべて image_key として取得できるようになります。

Node.js と Golang で同じものを2通り実装した理由

Lambda は リクエストの処理時間と設定したメモリに応じて課金が発生します。そのため処理時間が半分になれば、課金額も半分になります。

Node.js はとっても書きやすかったですが、コンパイル型の言語である Golang で実装したら処理時間とメモリ消費が減るのかどうかを実験するために、同じ機能を実装し直しました。

1MB ほどの画像でベンチマークを測ったところ下記の結果になりました。

言語 処理時間 消費メモリ
Node.js 約 2.4 秒 約 270 MB
Golang 約 1.3 秒 約 150 MB

つまりは Node.js ではなく Golang を使用すれば、Lambda の料金が半分以下になります。

まとめ

AWSのサポート切れにより、同じ問題で困っている企業や個人開発者さんも少なからずいるのではないかなと思います。

この記事が少しでもお役に立てれば幸いです。

Discussion