将数据附加到S3对象

时间:2017-01-21 20:04:24

标签: amazon-web-services amazon-s3 aws-sdk amazon-kinesis-firehose

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

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

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

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

7 个答案:

答案 0 :(得分:85)

不幸的是,你不能。

S3 doesn't have an "append" operation. * 上传对象后,无法对其进行修改;您唯一的选择是上传一个新对象来替换它,这不符合您的要求。

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

答案 1 :(得分:8)

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

AWS Kinesis Firehose

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

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

enter image description here

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

答案 2 :(得分:3)

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

  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
                }
             });
        }
    });  
}
  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
    }); 
}

答案 3 :(得分:1)

S3 存储桶不允许您追加现有对象,可以使用的方法是先使用 get 方法从 S3 存储桶中获取数据,然后在本地添加您要追加的新数据,然后然后将其推回 S3 存储桶。

因为,无法附加到现有的 S3 对象。您将需要使用附加了数据的新对象替换它。这意味着每次添加新条目时,您都需要上传整个对象(日志文件)。这不会很有效。

您可以将日志条目发送到 SQS 队列,当队列大小达到设定数量时,您可以将日志消息一起批处理并作为对象添加到 S3 存储桶中。这仍然不能满足您附加到单个对象的要求

答案 4 :(得分:0)

我有类似的问题,这就是我的要求

how to Append data in file using AWS Lambda

以下是解决上述问题的方法:

使用getObject从现有文件中恢复

   s3.getObject(getParams, function(err, data) {
   if (err) console.log(err, err.stack); // an error occurred
   else{
       console.log(data);           // successful response
       var s3Projects = JSON.parse(data.Body);
       console.log('s3 data==>', s3Projects);
       if(s3Projects.length > 0) {
           projects = s3Projects;
       }   
   }
   projects.push(event);
   writeToS3(); // Calling function to append the data
});

写入要附加在文件中的函数

   function writeToS3() {
    var putParams = {
      Body: JSON.stringify(projects),
      Bucket: bucketPath, 
      Key: "projects.json",
      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
        callback(null, 'Hello from Lambda');
     });
}

希望这有帮助!!

答案 5 :(得分:0)

正如其他人之前所说,S3对象不可追加。
但是,另一个解决方案是先写出CloudWatch日志,然后写出export the logs you want to S3。这也可以防止任何访问您服务器的攻击者从S3存储桶中删除,因为Lambda不需要任何S3权限。

答案 6 :(得分:0)

万一有人想通过类似S3的服务将数据附加到对象上,则使用阿里云OSS(对象存储服务)supports this natively

  

OSS提供了附加上传(通过AppendObject API),它允许您直接将内容附加到对象的末尾。使用此方法上载的对象是可附加对象,而使用其他方法上载的对象是普通对象。附加的数据可立即读取。