如何将S3扩展到每秒数千个请求?

时间:2019-03-30 22:55:06

标签: node.js amazon-web-services amazon-s3

AWS S3文档状态 (https://docs.aws.amazon.com/AmazonS3/latest/dev/request-rate-perf-considerations.html):

  

Amazon S3自动扩展到高请求率。例如,您的应用程序每个存储桶中的每个前缀每秒至少可以实现3500个PUT / POST / DELETE和5500个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的速率(尽管似乎没有记录在案)?

2 个答案:

答案 0 :(得分:4)

在我直接回答你的问题之前,我有几件事要提到。

首先,我在一点上做了一个实验,我在大约25分钟内实现了200000 PUT / DELETE个请求,这相当于每秒130个请求。我上载的对象每个大约10 kB。 (我在同一时间段内还收到约125000个GET请求,因此,我可以确定,如果仅执行PUT,我可以实现更高的PUT吞吐量。 )我在一个m4.4xlarge实例上实现了该实例,该实例具有16个vCPU和64GB RAM,并且在与S3存储桶相同的AWS区域中运行。

要获得更高的吞吐量,请使用功能更强大的硬件,并最小化您和S3之间的网络跳数和潜在瓶颈。

S3是分布式系统。 (他们的文档说这些数据被复制到多个可用区。)它旨在同时处理来自许多客户端的请求(这就是为什么它非常适合托管静态网络资产的原因)。

实际上,如果要测试S3的限制,则还需要通过分散EC2实例或将测试作为Lambda函数运行来进行分发。

编辑:S3不保证服务请求的延迟。原因之一可能是因为每个请求可能具有不同的有效负载大小。 (对10 B对象的GET请求将比10 MB对象快得多。)

您经常提到服务请求的时间,但这并不一定与每秒请求的数量相关。 S3每秒可以处理数千个请求,但是据我所知,没有任何一台家用笔记本电脑或商品服务器每秒可以发出数千个独立的网络请求。

此外,总执行时间不一定表示性能,因为当您通过网络发送邮件时,始终存在网络延迟和数据包丢失的风险。您可能遇到一个不幸的请求,该请求的网络路径较慢,或者该请求可能比其他请求遭受更多的数据包丢失。

您需要仔细定义要查找的内容,然后仔细确定如何正确对其进行测试。

答案 1 :(得分:1)

您应该查看的另一件事是所使用的HTTPS代理。

AWS开发工具包使用全局代理的情况(过去可能仍然如此)。如果您使用的代理将重用连接,则可能是HTTP / 1.1,并且出于兼容性原因可能已禁用流水线操作。

使用诸如Wireshark的数据包嗅探器查看是否正在建立向外的多个连接。如果仅建立一个连接,则可以在httpOptions中指定代理。