9
5

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 Lambda@Edge と Google Cloud Functions の画像リサイズサーバどちらが速い?

Last updated at Posted at 2018-11-18

画像リサイズ処理ってけっこう面倒くさいので最近は画像リサイズサーバを構築して URL のクエリストリングで動的にリサイズするようにしています。定番は nginx で構築するケースですが、サーバの管理をしなくてはならないので個人的にはサーバレス構成が好みです。

というわけで、AWS の CloudFront Lambda@Edge と Google の Cloud Functions でリサイズ処理をしたときのパフォーマンスの違いを計測してみました。

構成図

以下のような構成で計測しました。

AWS は CloudFront + Lambda@Edge を使いリサイズ処理、オリジンサーバは S3 にしています。Google は Cloud Functions を使いリサイズ処理、オリジンサーバは Cloud Storage にしています。どちらもプライベートネットワークなどの接続ができなそうですが、おそらく物理的には近いだろうと推測して、それぞれのストレージサービスでの組み合わせにしています。

検証コード

計測するためだけのコードなので実践的ではないですが、参考までに。

Lambda@Edge

const request = require('request-promise')
const Sharp = require('sharp')

const download = (url) => {
  return request({
    url: url,
    encoding: null
  })
}

const resize = (body, format, width, height) => {
  return Sharp(body)
    .resize(width, height)
    .toFormat(format)
    .toBuffer()
    .then(buffer => {
      return buffer
    }).catch(error => {
      console.log(error)
    })
}

module.exports.perform = (event, context, callback) => {
  let response = event.Records[0].cf.response
  const request = event.Records[0].cf.request
  download(`https://s3.amazonaws.com/example-bucket-name${request.uri}`).then(body => {
    const format = 'jpeg'
    resize(body, format, 200, 100).then(body => {
      resizeFunc.save(body, format, 'sample').then(() => {
        response.status = 200
        response.body = body.toString('base64')
        response.bodyEncoding = 'base64'
        response.headers['content-type'] = [{ key: 'Content-Type', value: 'image/' + format }]
        callback(null, response)
      })
    })
  })
}

S3 からのファイルダウンロードを S3 SDK を使ったバージョンでも比較しましたが変化はありませんでした。

参考コード

const getFile = key => {
  return S3.getObject({
    Bucket: BUCKET,
    Key: key.slice(1)
  }).promise()
}
getFile(request.uri).then(data => {
  const body = data.Body
  // snip
})

Cloud Functions

import * as functions from 'firebase-functions'
const firebaseConfig = JSON.parse(process.env.FIREBASE_CONFIG)
import * as admin from 'firebase-admin'
admin.initializeApp()
storage = admin.storage()

const sharp = require('sharp')
const fileType = require('file-type')
const os = require('os')
const path = require('path')

export const image_resize = functions.https.onRequest((req, res) => {
  const filePath = req.query.path
  const bucket = storage.bucket(firebaseConfig.storageBucket)
  const tempFilePath = path.join(os.tmpdir(), `${Math.round( Math.random() * 1000 )}`)
  bucket.file(filePath).download({
    destination: tempFilePath,
  }).then(() => {
    sharp(tempFilePath)
      .rotate()
      .resize(200, 100)
      .toBuffer()
      .then(data => {
        const type = fileType(data)
        res.set('Content-Type', type.mime)
        res.status(200).send(data)
      })
  })
})

検証結果

ab コマンドを用いてそれぞれの平均レスポンスを出しました。

項目 リクエストあたりの応答速度
Lambda@Edge 4.3 sec
Cloud Functions 2.6 sec

2018/11/18 時点では Cloud Functions の方が速そうです。

どこに時間がかかっているのかと言うと、それぞれのオリジンサーバからの画像ファイルダウンロードです。Sharp を使ったリサイズ処理自体はほぼ差はありませんでした。検証で使っているコードを改善すればもっとパフォーマンス良くできるのかも知れませんが…というか、知りたい。

実際には CDN でキャッシュするので、初回のアクセス以降は高速にレスポンスを返せますが、とはいえ初回のアクセスをどこで発生させるかはアプリケーションによって変わってくるので、どんな状況であっても高速であったほうがいいと思います。

9
5
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
9
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?