Nối dữ liệu vào một đối tượng S3


91

Giả sử rằng tôi có một máy mà tôi muốn có thể ghi vào một tệp nhật ký nhất định được lưu trữ trên thùng S3.

Vì vậy, máy cần phải có khả năng ghi vào nhóm đó, nhưng tôi không muốn nó có khả năng ghi đè hoặc xóa bất kỳ tệp nào trong nhóm đó (bao gồm cả tệp tôi muốn nó ghi vào).

Vì vậy, về cơ bản, tôi muốn máy của mình chỉ có thể nối dữ liệu vào tệp nhật ký đó mà không cần ghi đè hoặc tải xuống.

Có cách nào để cấu hình S3 của tôi hoạt động như vậy không? Có lẽ có một số chính sách IAM tôi có thể đính kèm vào nó để nó sẽ hoạt động như tôi muốn?


Bạn không thể sửa đổi các đối tượng trong S3. Bạn có thể chỉ cần thêm một tệp nhật ký mới? Đó sẽ là một mô hình tốt hơn và sẽ hỗ trợ nhiều khách hàng đồng thời.
jarmod

@jarmod Vâng, tôi đã nghĩ về điều đó, nhưng vấn đề là nếu kẻ tấn công truy cập thành công máy chủ của tôi, hắn sẽ có khả năng xóa tệp cục bộ được lưu trữ trên đó, trước khi nó được gửi đến nhóm S3 (giả sử xảy ra vào cuối ngày).
Theodore

Bạn cũng có thể muốn xem nhật ký CloudWatch. Hãy để nó quản lý sự phức tạp của việc thu thập và lưu trữ nhật ký của bạn, cung cấp phương tiện tìm kiếm, chính sách lưu giữ và cho phép bạn tạo cảnh báo dựa trên các chỉ số mà bạn có thể tùy chỉnh cho nhật ký của mình.
jarmod

1
Bạn cũng có thể xem qua Google BigQuery. Bạn có thể sử dụng nó để giải quyết vấn đề của mình.
Daniel777

Câu trả lời:


133

Thật không may, bạn không thể.

S3 không có hoạt động "nối thêm". * Khi một đối tượng đã được tải lên, không có cách nào để sửa đổi nó tại chỗ; lựa chọn duy nhất của bạn là tải lên một đối tượng mới để thay thế nó, đối tượng này không đáp ứng yêu cầu của bạn.

*: Vâng, tôi biết bài đăng này đã được một vài năm tuổi. Tuy nhiên, nó vẫn chính xác.


Tôi có thể biết, bằng cách sử dụng Tải lên nhiều phần chúng ta có thể đạt được điều này không?
Anjali,

1
Tải lên nhiều phần sẽ cho phép bạn tải dữ liệu vào S3 mà không cần tải xuống đối tượng gốc, nhưng sẽ không cho phép bạn ghi đè trực tiếp đối tượng gốc. Xem ví dụ: docs.aws.amazon.com/AmazonS3/latest/API/… Sau đó, bạn có thể xóa đối tượng cũ / đổi tên đối tượng mới. Tuy nhiên, đây không phải là điều mà câu hỏi đang đặt ra.
MikeGM

Tôi nghĩ rằng việc sử dụng Tải lên nhiều phần có thể thực sự hiệu quả. Tất cả các phần của bạn là các phân đoạn tuần tự của cùng một tệp. Nếu phần thành công được tải lên, cuối cùng bạn có thể cam kết tải lên để có thể đọc tệp. Vì vậy, miễn là bạn không cần đọc nội dung của tệp, bạn có thể sử dụng cùng một tải lên nhiều phần.
cerebrotecnologico

@cerebrotecnologico Tôi vẫn không nghĩ rằng nó đáp ứng các yêu cầu của OP. Tôi không có cách nào để hạn chế người dùng S3 thực hiện tải lên nhiều phần nối với một đối tượng - nếu họ có thể thực hiện tải lên nhiều phần, họ có thể tải lên bất kỳ nội dung nào họ muốn.
duskwuff -inactive-

16

Như câu trả lời được chấp nhận đã nêu, bạn không thể. Giải pháp tốt nhất mà tôi biết là sử dụng:

AWS Kinesis Firehose

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

Mẫu mã của họ trông phức tạp nhưng của bạn có thể thực sự đơn giản. Bạn tiếp tục thực hiện các thao tác PUT (hoặc BATCH PUT) trên luồng phân phối Kinesis Firehose trong ứng dụng của mình (sử dụng AWS SDK) và bạn định cấu hình luồng phân phối Kinesis Firehose để gửi dữ liệu đã phát trực tuyến của mình tới nhóm AWS S3 mà bạn chọn (trong Bảng điều khiển AWS Kinesis Firehose).

nhập mô tả hình ảnh ở đây

Nó vẫn không thuận tiện như >>từ dòng lệnh Linux, vì khi bạn đã tạo một tệp trên S3, bạn lại phải xử lý việc tải xuống, bổ sung và tải lên tệp mới nhưng bạn chỉ phải thực hiện một lần cho mỗi loạt dòng chứ không phải. hơn cho mọi dòng dữ liệu, vì vậy bạn không cần phải lo lắng về các khoản phí lớn do khối lượng các hoạt động nối thêm. Có lẽ nó có thể được thực hiện nhưng tôi không thể xem cách làm điều đó từ bảng điều khiển.


8
Lưu ý rằng có thời gian tối đa (900 giây kể từ khi tạo tệp) hoặc kích thước tối đa (kích thước tệp 128mb) để thực hiện việc này - nghĩa là Kinesis firehose sẽ nối vào cùng một tệp S3 cho đến khi nó đạt đến một trong các giới hạn đó: docs.aws .amazon.com / firehose / new / dev / create-
config.html

Bạn có thể sử dụng một tệp S3 duy nhất làm đầu ra trên Firehose không? Nghe có vẻ hơi lộn xộn khi phải hợp nhất nhiều tệp trong một thùng S3.
Jón Trausti Arason

1
Tiếc là không có. Tôi cũng ước có một giải pháp tốt hơn.
Sridhar Sarnobat

Vâng, thật không may. Tôi chủ yếu lo lắng về tình trạng chủng tộc nếu tôi tải xuống và nối các bản ghi theo cách thủ công vào một đối tượng S3. Tôi đã suy nghĩ về việc thêm các bản ghi vào SQS và sau đó sử dụng một số logic với SNS + Lambda để thăm dò SQS và sau đó viết các mục mới vào đối tượng S3.
Jón Trausti Arason

6

Các đối tượng trên S3 không thể nối thêm. Bạn có 2 giải pháp trong trường hợp này:

  1. sao chép tất cả dữ liệu S3 sang một đối tượng mới, nối nội dung mới và ghi lại vào 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. Tùy chọn thứ hai là sử dụng Kinesis Firehose. Điều này khá đơn giản. Bạn cần tạo luồng phân phối firehose của mình và liên kết đích đến nhóm S3. Đó là nó!
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
    }); 
}

Bạn có thể sử dụng một tệp S3 duy nhất làm đầu ra không?
Jón Trausti Arason

1

Như những người khác đã nêu trước đây, các đối tượng S3 không thể nối thêm.
Tuy nhiên, một giải pháp khác sẽ là ghi vào nhật ký CloudWatch và sau đó xuất nhật ký bạn muốn sang S3 . Điều này cũng sẽ ngăn không cho bất kỳ kẻ tấn công nào truy cập vào máy chủ của bạn xóa khỏi nhóm S3 của bạn, vì Lambda sẽ không yêu cầu bất kỳ quyền nào của S3.


1

Trong trường hợp bất kỳ ai muốn nối dữ liệu vào một đối tượng có dịch vụ giống S3, thì Alibaba Cloud OSS (Dịch vụ lưu trữ đối tượng) sẽ hỗ trợ điều này .

OSS cung cấp tính năng tải lên nối thêm (thông qua API AppendObject), cho phép bạn nối trực tiếp nội dung vào phần cuối của một đối tượng. Các đối tượng được tải lên bằng cách sử dụng phương pháp này là các đối tượng có thể nối thêm, trong khi các đối tượng được tải lên bằng cách sử dụng các phương pháp khác là các đối tượng bình thường. Dữ liệu thêm vào có thể đọc được ngay lập tức.


-1

Tôi đã gặp vấn đề tương tự và đây là những gì tôi đã hỏi

cách Nối dữ liệu vào tệp bằng AWS Lambda

Đây là những gì tôi nghĩ ra để giải quyết vấn đề trên:

Sử dụng getObject để truy xuất từ ​​tệp hiện có

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

Viết hàm để thêm vào tệp

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

Hy vọng điều này giúp đỡ!!


13
writeToS3Hàm của bạn sẽ ghi đè một tệp chứ không phải thêm vào tệp đó.
duskwuff -inactive- 20/09/17

@ duskwuff-inactive- đã đồng ý, và nó cũng gặp phải các điều kiện về chủng tộc nếu hai phương thức cố gắng hoạt động trên cùng một đối tượng, nhưng điều này không thực sự khác với các ngôn ngữ có chuỗi hoặc kiểu bất biến - bạn mô phỏng một append bằng cách trả về / ghi đè lên một đối tượng mới.
Fat_error
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.