我尝试了几个Imagemagick的包裹库和一些S3库。由于性能差异很大,我很难选择最佳概念。
我已经选定了node库“gm”,这是一个非常好用并且文档非常齐全的库。
至于S3,我尝试过亚马逊自己的AWS库以及“S3-Streams”。
编辑:我刚发现AWS库可以处理流。我想这是一个新的功能s3.upload(或者我只是错过了它?)。不管怎样,我放弃了s3-streams,因为它使用了更加复杂的s3uploadPart。在切换库之后,在我的测试用例中,流式传输等同于上传缓冲区。
我的测试用例是将一个2MB的jpg文件分成大约30个512px瓷砖,并将每个瓷砖发送到S3。Imagemagick有一种非常快速的自动方式通过裁剪命令生成瓦片。不幸的是,我没有找到任何可以捕获自动生成的瓦片的多文件输出的node库。相反,我必须通过单独调用每个瓦片的裁剪命令来循环生成瓦片。
我将在详细介绍之前提供总时间:
A:85秒(s3-streams)
A:34秒(aws.s3.upload) (编辑)
B:35秒(缓冲区)
C:25秒(并行缓冲区)
显然,在这种情况下,缓冲区比流更快。我不知道gm或s3-streams是否对流进行了糟糕的实现,或者我是否应该调整一些东西。现在我将使用B解决方案。C更快,但会占用更多内存。
我在低端Digital Ocean Ubuntu机器上运行此代码。这是我尝试过的内容:
A. 生成瓦片并逐个传输它们
我准备了一个包含每个要生成瓷砖的裁剪信息和s3Key的数组
该数组循环使用“async.eachLimit(1)”。我没有成功地一次生成超过一个瓷砖,因此限制(1)。
随着瓦片的生成,它们直接流式传输到S3
伪代码:
async.eachLimit(tiles, 1, function(tile, callback) {
gm(originalFileBuffer)
.crop(tile.width, tile.height, tile.x, tile.y)
.stream()
.pipe(s3Stream({Key: tile.key, Bucket: tile.bucket})) //using "s3-streams" package
.on('finish', callback)
});
B. 将图块生成到缓冲区,并使用AWS包直接上传每个缓冲区
- 当图块生成到缓冲区时,它们会直接上传到S3。
伪代码:
async.eachLimit(tiles, 1, function(tile, callback) {
gm(originalFileBuffer)
.crop(tile.width, tile.height, tile.x, tile.y)
.toBuffer(function(err, buffer) {
s3.upload(..
callback()
)
})
});
C. 与B相同,但将所有缓冲区存储在瓦片数组中以供后续并行上传
伪代码:
async.eachLimit(tiles, 1, function(tile, callback) {
gm(originalFileBuffer)
.crop(tile.width, tile.height, tile.x, tile.y)
.toBufer(function(err, buffer) {
tile.buffer = buffer;
callback()
})
});
在完成第一个each循环之后,进行下一步操作。我发现将限制推到超过10并没有增加速度。
async.eachLimit(tiles, 10, function(tile, callback) {
s3.upload(tile.buffer..
callback()
)
});
编辑:根据马克的要求提供一些背景信息。我最初没有提供详细信息,希望我可以清楚地了解缓冲区与流的差异。
目标是通过node/Express API以反应灵敏的方式为我们的应用程序提供图片服务。后端db是Postgres。大容量储存是S3。
传入的文件主要是照片、平面图和pdf文档。这些照片需要以多种尺寸存储,以便我可以以响应式方式向应用程序提供它们:缩略图、低分辨率、中分辨率和原始分辨率。
平面图必须是平铺的,以便我可以在应用程序中逐步加载(滚动平铺)。一个完整分辨率的A1图可以达到50 MPixels。
上传到S2的文件大小从50KB(平铺)到10MB(平面图)不等。
这些文件来自不同的方向,但总是以流的形式:
- 通过Web或其他API(SendGrid)的表单邮件
- 应用程序中的上传
- 上传的文件需要更多处理时从S3下载的流
为什么不用本地磁盘呢?
- 上传到S3之前会对图像进行加密。我不希望未经加密的文件在临时目录中逗留。
- 总是有清理临时文件的问题,可能会在意外崩溃后留下孤儿文件等问题。