将数据附加到S3对象

The*_*ore 69 amazon-s3 amazon-web-services aws-sdk amazon-kinesis-firehose

假设我有一台机器,我希望能够写入存储在S3存储桶中的某个日志文件.

因此,机器需要具有该存储桶的写入能力,但是,我不希望它能够覆盖或删除该存储桶中的任何文件(包括我想要写入的文件).

所以基本上,我希望我的机器只能将数据附加到该日志文件,而不是覆盖它或下载它.

有没有办法配置我的S3这样工作?也许我可以附加一些IAM策略,以便它可以像我想要的那样工作?

dus*_*uff 104

不幸的是,你做不到.

S3没有"附加"操作.*上传对象后,无法对其进行修改; 您唯一的选择是上传新对象以替换它,这不符合您的要求.

*:是的,我知道这篇文章已经有几年了.但它仍然准确.

  • Multipart Upload 将允许您在不下载原始对象的情况下将数据导入 S3,但它不允许您直接覆盖原始对象。参见例如 https://docs.aws.amazon.com/AmazonS3/latest/API/mpUploadUploadPartCopy.html 然后您可以删除旧对象/重命名新对象。然而,这不是问题所要问的。 (3认同)
  • 我认为使用分段上传实际上可能有效。您的所有部分都是同一文件的连续片段。如果该部分成功上传,您最终可以提交上传以便能够读取该文件。因此,只要您不需要读取文件的内容,您就可以附加使用相同的分段上传。 (3认同)
  • @cerebrotecnologico 我仍然认为它不符合OP的要求。据我所知,没有办法限制 S3 用户执行附加到对象的分段上传 - 如果他们可以执行分段上传,他们就可以上传他们想要的任何内容。 (2认同)

Sri*_*bat 12

正如接受的答案所述,你不能.我所知道的最佳解决方案是使用:

AWS Kinesis Firehose

https://aws.amazon.com/kinesis/firehose/

他们的代码示例看起来很复杂但你的代码可能非常简单.您继续在应用程序中的Kinesis Firehose传输流上执行PUT(或BATCH PUT)操作(使用AWS开发工具包),并配置Kinesis Firehose传输流以将您的流数据发送到您选择的AWS S3存储桶(在AWS Kinesis Firehose控制台).

在此输入图像描述

它仍然不如>>Linux命令行那么方便,因为一旦你在S3上创建了一个文件,你就必须再次处理下载,追加和上传新文件,但你只需要每批线路做一次而不是每一行数据,所以你不需要担心因为追加操作量而导致的巨额费用.也许它可以完成,但我无法从控制台看到如何做到这一点.

  • 请注意,执行此操作时有最长时间(文件创建后900秒)或最大大小(128mb文件大小) - 这意味着,Kinesis firehose会附加到同一个S3文件,直到达到其中任何一个限制:https:/ /docs.aws.amazon.com/firehose/latest/dev/create-configure.html (6认同)
  • 您可以使用单个 S3 文件作为 Firehose 上的输出吗?必须合并 S3 存储桶中的多个文件听起来有点混乱。 (2认同)
  • 是的,这很不幸。如果我手动下载记录并将其附加到单个 S3 对象,我最担心的是竞争条件。我一直在考虑将记录添加到 SQS,然后使用 SNS + Lambda 的一些逻辑来轮询 SQS,然后将新条目写入 S3 对象。 (2认同)

use*_*515 7

你可以:

  1. 设置分段上传
  2. UploadPartCopy现有 S3 对象指定为源的调用
  3. UploadPart使用您要附加的数据进行调用
  4. 关闭分段上传。

有许多限制,例如您现有的对象必须大于 5MB(但是,如果它较小,则在大多数情况下将其复制到客户端应该足够快)。

它不如直接追加那么好,但至少您不需要将数据从 aws 来回复制到本地计算机。


Bha*_*han 5

S3上的对象不可追加。在这种情况下,您有2个解决方案:

  1. 将所有S3数据复制到新对象,附加新内容并写回S3。
function writeToS3(input) {
    var content;
    var getParams = {
        Bucket: 'myBucket', 
        Key: "myKey"
    };

    s3.getObject(getParams, function(err, data) {
        if (err) console.log(err, err.stack);
        else {
            content = new Buffer(data.Body).toString("utf8");
            content = content + '\n' + new Date() + '\t' + input;
            var putParams = {
                Body: content,
                Bucket: 'myBucket', 
                Key: "myKey",
                ACL: "public-read"
             };

            s3.putObject(putParams, function(err, data) {
                if (err) console.log(err, err.stack); // an error occurred
                else     {
                    console.log(data);           // successful response
                }
             });
        }
    });  
}
Run Code Online (Sandbox Code Playgroud)
  1. 第二种选择是使用Kinesis Firehose。这很简单。您需要创建流水线传送流,并将目标链接到S3存储桶。而已!
function writeToS3(input) {
    var content = "\n" + new Date() + "\t" + input;
    var params = {
      DeliveryStreamName: 'myDeliveryStream', /* required */
      Record: { /* required */
        Data: new Buffer(content) || 'STRING_VALUE' /* Strings will be Base-64 encoded on your behalf */ /* required */
      }
    };

    firehose.putRecord(params, function(err, data) {
      if (err) console.log(err, err.stack); // an error occurred
      else     console.log(data);           // successful response
    }); 
}
Run Code Online (Sandbox Code Playgroud)