Link and Motivation Developers' Blog

リンクアンドモチベーションの開発者ブログです

AWS Lambdaにおける性能改善

どうも、リンクアンドモチベーションの代慶(よけい)です。モチベーションクラウドのエンジニアをしています。主に、アプリケーションをいじっていますが、今回はある処理の性能改善をするにあたって、クラウドの恩恵をあずかれたので、それについて書いていきます。

結論から述べると、AWS Lambda(以下、Lambda)を用いたpdfの作成処理の性能改善を、Lambdaのスペックを変えることで実現しました。

前提

LambdaLambdaの概要

性能改善対象の処理apiのリクエストで、pdf作成処理を依頼して、その間、定期的にpdfが作成したかを確認し、作成が完了したら、pdfがDLされるという処理です。 apiのリクエストからpdfがDLされるまでの時間が対象になります。 下記のシーケンス図の①-⑬までの処理が該当の処理です。

pdf作成処理のシーケンス図

性能測定

まずは、そもそも遅いと言われていたpdf作成処理が実際本当にそうなのかを測っていきます。 最近お世話になった『a philosophy of software desigin』の本でも述べてあるように、一旦性能改善しようと手を動かすのではなく、現状把握から始めていきます。

before making any changes, measure the system's existing behavior

測定した結果は、下記のようになっていました。

目標値:5s

実績:約11s(中央値)

目標の倍以上も遅くなっていたので、ユーザーの体験としてはかなり悪いものになってることがわかります。 この数字を5sまで縮めることを目標にやっていきます。

性能調査

処理全体として、性能が悪いことは確認できたので、どこの処理がボトルネックになってるのかを確認します。

今回は、rubyのbenchmarkを使って、それぞれの処理にかかる時間を見ていきました。 下記のように、処理の中に記述していきます。

require 'benchmark'

Benchmark.bm 10 do |r|
  r.report "test_1" do
    def method_1
      puts aaa
    end
  end
end

すると、こんな感じで結果が返ってきます。

user     system      total        real
0.842843 0.000000 0.842843 ( 7.759863)

user:子プロセスの user CPU time

system:子プロセスの system CPU time

total:total CPU time

real:実経過時間

(実際に細かくメソッドの中身見るときは、ruby-profを使ったほうが効率よさそうです。)

性能測定した結果、Lambdaでpdfを作成してる箇所で利用してるライブラリのメソッドで時間がかかっていました。

性能改善

自分は、これまで性能改善をしていた際のボトルネックがアプリケーションコードのことが多かったということもあり、性能改善の手段として、コードの改善に着手しようとしました。 しかし、コードの改善はライブラリの変更や仕様自体の変更が必要などで、工数がかなりかかりそうでした。 そこで、せっかくLambdaに切り出していた処理なので、Lambdaのスペックを上げるという選択肢を取りました。

Lambdaは、メモリが設定できて、メモリを変えることでCPUなども含めたスペックを変更することができるようです。 (参考にした記事:https://recipe.kc-cloud.jp/archives/10437

なので、メモリの設定を変更してみました。(これまでの本番環境のLambdaのメモリは192MB)

メモリごとのLambdaでの実行時間は下記のようになりました。

メモリごとのLambdaの実行時間

メモリサイズ Lambda実行時間(ms) duration(ms) init duration(ms)
192 9916.06 8562.4 1353.66
512 4421.42 3172.86 1248.56
768 3558.53 2157.54 1400.99
1024 3130.15 1661.27 1468.88
2048 2217.63 960.71 1256.92

durationが実際にLambdaの処理が動いてる時間で、init durationが起動にかかる時間のようです。 なので、実際に動く時間は、スペックに正比例して速くなってることがわかります。

そして結果的に、Lambdaのスペックを上げることでデータシート作成の性能要件を満たせそうなことがわかりました。

また、Lambdaのスペックを上げることで、変わる金額についても確認します。

メモリごとの金額(192MBの金額を1とした)

ちなみに、Lambdaは実行時間あたりでしかお金がかからないため、メモリを上げることで実行時間が短くなり、結果としてコストが抑えられることもあります。

これらを考慮して、一番コスパの高そうな768MBを選定しました。

実際に、Lambdaのスペックを上げた時の性能の結果は下記です。

目標値:5s

実績:約5s(中央値)

無事達成できました。

また、結果として、Lambdaにかかる費用は下記になりました。

変更前:111.66$/月

変更後:115.85$/月

費用は大きく変わることもなく、性能改善ができました。

Lambdaでの性能改善のポイント

Lambdaを使う際に性能改善する時には下記の3つをまず考える必要があります。

リソースのスペックの改善

クラウドだと気軽にスペックアップでき、コード変えるよりリードタイムも短く対応できるので、スペックが上げれないか・サーバー増やせないかなどを コードの改善と同時に考えられると良いです。 Lambdaは実行時間あたりでしかお金がかからないため、実行時間が短くなるとコストはむしろ安くなることもあります。

コードの改善

今回は工数などの観点で選択肢から外しましたが、まだ改善の余地はあるかもしれません。

コールドスタートの改善

今回は着手しませんでしたが、コールドスタートの時間を改善する方法もあります。 init durationがコールドスタートにかかる時間に相当し、約1sくらいの時間がかかります。ただ、スペックに伴って、大きく改善はしませんでした。

パッケージサイズを小さくすることで改善が見込めるようなので、Lambdaにアップロードするディレクトリ内の不要なライブラリの削除をすることで改善が見込めます。

※コールドスタート:コンテナを起動する時にかかる時間、利用可能なコンテナがない時などに発生する

まとめ

・性能改善するときは、まず性能測定をして、原因を突き止める。

クラウド環境下で性能改善するときは、コードだけでなく、クラウド側で解決できないかという選択肢も持つ。

クラウドの恩恵を生かして、もっとコスパ良く性能改善をやっていく。