node.js - 如何将 S3 扩展到每秒数千个请求?
问题描述
AWS S3 文档状态(https://docs.aws.amazon.com/AmazonS3/latest/dev/request-rate-perf-considerations.html):
Amazon S3 自动扩展到高请求率。例如,您的应用程序可以在存储桶中每个前缀每秒至少完成 3,500 个 PUT/POST/DELETE 和 5,500 个 GET 请求。
为了测试这一点,我有以下 NodeJS 代码(使用 aws-sdk),它异步启动 1000 次零字节上传(因此,只需将空条目添加到存储桶中)。有一个计时器来测量吞吐量:
var t0 = new Date().getTime()
for (var i = 0; i < 1000; i++) {
var s3 = new AWS.S3()
var id = uuid()
console.log('Uploading ' + id)
s3.upload({
Bucket: bucket,
Body : '',
Key : "test/" + id
},
function (err, data) {
if (data) console.log('Uploaded ' + id + ' ' + (new Date().getTime() - t0))
else console.log('Error')
})
}
完成所有上传请求大约需要 25 秒。这显然与声称的每秒 3500 个请求相去甚远,而是大约每秒 40 个请求。
我有大约 1MB 的网络上传速度,网络统计数据显示,在大多数情况下,带宽只有大约 25% 饱和。同样,CPU 利用率也很低。
所以问题是:
如何扩展 S3 上传吞吐量以实现接近每秒 3500 个请求的速度,而这显然可以实现?
编辑:
我修改了这样的代码:
var t0 = new Date().getTime()
for (var i = 0; i < 1000; i++) {
var s3 = new AWS.S3()
var id = String.fromCharCode('a'.charCodeAt(0) + (i % 26)) + uuid()
console.log('Uploading ' + id)
s3.upload({
Bucket: bucket,
Body: '',
Key: id
},
function (err, data) {
if (data) console.log('Uploaded ' + id + ' ' + (new Date().getTime() - t0))
else console.log('Error')
})
}
这使用了 26 个不同的前缀,AWS 文档声称它们应该将吞吐量扩大 26 倍。
“以指数方式提高读取或写入性能很简单。例如,如果您在 Amazon S3 存储桶中创建 10 个前缀以并行读取,则可以将读取性能扩展到每秒 55,000 个读取请求。”
但是,吞吐量没有明显差异。行为存在某种差异,因此请求似乎以更并行的方式完成,而不是按顺序完成 - 但完成时间几乎相同。
最后,我尝试在 x4 个单独的 bash 线程(4 个线程、4 个内核、4x1000 个请求)中运行应用程序。尽管使用多核增加了并行性,但总执行时间约为 80 秒,因此无法扩展。
for i in {0..3}; do node index.js & done
我想知道 S3 是否会限制单个客户端/IP(尽管这似乎没有记录在案)?
解决方案
在我直接回答你的问题之前,我有几件事要提一下。
首先,我在某个时间点做了一个实验,我在大约 25 分钟内达到了 200000 个PUT
/DELETE
请求,也就是每秒 130 多个请求。我上传的对象每个大约 10 kB。(我在同一时间跨度内也有大约 125000 个GET
请求,所以我敢肯定,如果我只做PUT
s,我可以实现更高的PUT
吞吐量。)我在一个m4.4xlarge
实例上实现了这一点,它有 16 个 vCPU 和 64GB RAM,与 S3 存储桶在同一 AWS 区域中运行。
要获得更高的吞吐量,请使用更强大的硬件,并尽量减少您和 S3 之间的网络跃点数和潜在瓶颈。
S3 是一个分布式系统。(他们的文档说数据被复制到多个 AZ。)它旨在同时处理来自多个客户端的请求(这就是为什么它非常适合托管静态 Web 资产)。
实际上,如果您想测试 S3 的限制,您也需要通过启动一组 EC2 实例或将您的测试作为 Lambda 函数运行来进行分布式。
编辑: S3 不保证为您的请求提供服务的延迟。造成这种情况的一个原因可能是因为每个请求可能具有不同的有效负载大小。(对 10 B 对象的 GET 请求将比 10 MB 对象快得多。)
您一直提到服务请求的时间,但这并不一定与每秒的请求数相关。S3 每秒可以处理数千个请求,但据我所知,没有一台消费类笔记本电脑或商品服务器每秒可以发出数千个单独的网络请求。
此外,总执行时间不一定表示性能,因为当您通过网络发送内容时,总是存在网络延迟和数据包丢失的风险。您可能有一个不幸的请求,其通过网络的路径较慢,或者该请求可能比其他请求经历更多的数据包丢失。
您需要仔细定义要找出的内容,然后仔细确定如何正确测试它。
推荐阅读
- python-3.x - 根据特定条件过滤掉列
- html - 为什么第一个 nth-child 选择所有这些?
- swift - 我正在尝试将变量从 UITabController 传递给 UIViewController 但没有运气?
- java - 为什么这个 Mockito.mock 对象被调用而不是被模拟?
- javascript - 1D -> 2D Array W/Normal Curve Sub-Array Lengths
- python - 如何使用参数和 --flags 调用另一个 python 文件
- android - 如何在 Android 上将向上操作图标更改为带有文本的按钮?
- c++ - log4cpp 是否处理堆碎片问题?
- python - 如何在 python Enum 中更改 auto 的基值?
- scala - 如何更改 Ammonite、coursier 缓存位置?