【问题标题】:How to optimize images uploaded by the user and also existing images on the server in Meteor如何在 Meteor 中优化用户上传的图像以及服务器上的现有图像
【发布时间】:2019-04-16 17:41:57
【问题描述】:

目前,我的团队运行一个流星应用程序,其中包含数十万张非常大的全尺寸图像。我们早就应该这样做了,但我们需要一种方法来优化它们以帮助加载时间。我正在寻找一种解决方案,当用户从我们的应用程序上传图像时,能够以多种尺寸保存图像(例如:全尺寸、中等、缩略图),并且还可以自动旋转并允许用户旋转。我们使用 Amazon S3 来托管我们所有的图像。我们还需要一种从服务器端将所有现有图像转换为这些尺寸格式的方法。

我前段时间尝试实现一些东西,但没有成功。我在我们的服务器上设置了 imagemagick,但无法让它在生产中工作,因为图像被临时保存在服务器内存上进行处理,但由于内存量有限,这导致了崩溃。我对这种事情没有什么经验。

我的第二个想法是使用 HTML 画布来调整图像的大小。我认为这适用于新上传的图像。但我仍在寻找一种方法来处理现有图像。

我考虑过:

  • 也许 AWS 有一种内置的方式来处理它们。我不介意那样做。
  • 某种 Meteor/node 包可以帮助解决这个问题。
  • 设置另一台服务器仅用于处理图像。
  • 使用了一些第三方图像处理。

如果有人可以给我一些建议,这样我就可以开始工作,那将非常有帮助!

【问题讨论】:

    标签: javascript amazon-s3 meteor


    【解决方案1】:

    libvips 可以在不使用内存或磁盘的情况下调整图像大小 --- 像素以小块的形式通过系统流式传输,同时解码和重新编码。

    例如,对于 10k x 10k 像素的 JPG 图像,我看到:

    $ vipsheader wtc.jpg 
    wtc.jpg: 9372x9372 uchar, 3 bands, srgb, jpegload
    $ /usr/bin/time -f %M:%e vipsthumbnail wtc.jpg -s 5000x5000 -o x.jpg
    98720:0.65
    

    这是一个 4 核 8 线程 i7。它使用 98MB 的内存,需要 0.65 秒的实时时间。有一个chapter in the docs introducing vipsthumbnail

    为了比较,我看到了 ImageMagick 6:

    $ /usr/bin/time -f %M:%e convert wtc.jpg -resize 5000x5000 x.jpg
    1263232:2.02
    

    1.3GB 内存,需要 2 秒的实时时间 - 内存增加约 10 倍,速度慢 3 倍。

    因为 vipsthumbnail 使用如此少的内存,您可以将它与 GNU 并行结合起来,而不需要具有许多 GB 内存的服务器。在这台 i7 上,我一次可以有效地运行四个,并获得大约 4 倍的加速,因此可能比 ImageMagick 整体快 12 倍。

    sharp is a popular node binding for libvips,这可能更方便。也有 Python、Ruby、PHP、Go、Lua 等的绑定。

    (免责声明:我是 libvips 的维护者之一,所以我不是很中立)

    【讨论】:

    • 谢谢。这看起来确实是一个不错的选择!似乎检查了所有的框。我们会试一试。在我将其标记为答案之前,我想看看可能会出现哪些其他选项。我最担心的是处理现有图像需要多长时间,尽管我不能指望它会很快与我们目前拥有的图像数量相比。 ;)
    【解决方案2】:

    我看到两种完全不同的预算有两种方法:

    1. 我不推荐这种方式,除非您只有 1-2 GB (https://transloadit.com/demos/file-importing/resize-all-images-in-an-s3-bucket/)

    2. 将您的 S3 链接到 Cloudinary 服务并使用 Cloudinary 进行转换(对于您拥有的图像数量,您不会喜欢它 ($$))。

    3. 在 AWS 中,我希望您使用 Cloudfront 来服务您的资产。无论采用哪种转换技术,您主要会做两件事:

      • 创建 1 个 Lambda 函数,用于转换 S3 中所有新创建的资产。我所做的是“监控”一个 S3 存储桶,所有新的东西都会触发我的 Lambda 函数,我在另外 2 个文件夹中创建资产,最终得到:全分辨率、半分辨率和拇指分辨率。然后,在 Meteor 中,您可以将每种尺寸与您需要的尺寸联系起来。最典型的情况是当您有一个用户个人资料图片时,您需要在聊天中将其视为完整的标题、列表或小拇指。
      • 创建 1 个 Lambda 边缘(我相信稍微多一点)并附加到您的 Cloudfront 边缘以响应所有呼叫。如果当前存储量的存储成本对您来说不是太高,您可以在请求图像时转换图像并替换旧的较大图像,而不是一次性运行它。

    您可能可以使用 Node 设置 EC2 机器并运行一个函数来循环遍历所有 S3 资产并进行转换,而不是 Lambda Edge。

    反正我觉得你想做的都是AWS,和你的Meteor无关。还有一件事要做:在上传之前优化图像。如果您将 React 与 Meteor 一起使用,我可以为您提供必要的组件,否则我可以为您提供组件,然后您编写 Blaze 视图层或您可能使用的任何其他内容。

    我有基于 ImageMagic 的生产中的 Lambda 转换函数,以防您有兴趣采用这种方式。我还计划“升级”此功能以使用 Sharp(如示例中所示),但目前它在生产中做得很好,当我有时间时会切换。 检查这个例子:

      Download the image from S3, transform, and upload to a different S3 bucket or folder.
    
      const dstKeyResizedHalf = `p-half/` + imageName
      s3.getObject({
        Bucket: srcBucket,
        Key: srcKey
      }).promise()
        .then(data => Sharp(data.Body)
          .jpeg({
            chromaSubsampling: '4:4:4',
            progressive: true
          })
          .resize(WEB_WIDTH_MAX)
          .toFormat('jpg')
          .toBuffer()
        )
        .then(buffer => s3.putObject({
          Body: buffer,
          Bucket: dstBucket,
          ContentType: 'image/jpg',
          Key: dstKeyResizedHalf,
          CacheControl: 'max-age=864000'
        }).promise())
        .catch(err => callback(err))
    }
    

    【讨论】:

    • 这非常有帮助。谢谢你。我想也许在阅读了回复并在线查看了一些页面之后,Lambda 是要走的路。针对旧图像的图像请求触发 Lambda 函数是一个绝妙的解决方案。
    • 如果您决定使用 Lambda,请告诉我,如果您需要,我会为您提供必要的信息。
    • 所以,想对此进行更新。我确实最终选择了 Lambda 路线,而且效果很好。我设置了一个 API 网关来触发 Lambda 函数。这对我来说是最好的方法,这样我就可以在我的应用程序端获得图像转换已完成并成功的反馈。我还最终设置了一个 cron 进程,以再次使用 API 网关转换现有图像。到目前为止它工作得很好。所以,谢谢你的帮助!
    【解决方案3】:

    我使用https://www.imagemagick.org/ 来调整、裁剪、旋转我的图像。它适用于流星。这将是一个很好的探索起点。 https://github.com/CollectionFS/Meteor-CollectionFS

    【讨论】:

    • Omgabee 在问题中写道,imagemagick 会导致与内存相关的问题,因为图像副本暂时保存在内存中。
    • 我的图片使用量有限,所以到目前为止我没有遇到任何问题。
    猜你喜欢
    • 2016-03-21
    • 1970-01-01
    • 1970-01-01
    • 2016-05-06
    • 2015-01-08
    • 2017-02-03
    • 1970-01-01
    • 1970-01-01
    • 2013-08-26
    相关资源
    最近更新 更多