Showing posts with label lambda. Show all posts
Showing posts with label lambda. Show all posts

Wednesday, June 10, 2020

Flutter에서 AWS S3로 파일 업로드 Presigned URL과 Lambda Cold Start 문제 해결

Flutter에서 AWS S3로 파일 업로드: Pre-signed URL과 Lambda Cold Start 문제 해결

이 글에서는 Flutter에서 AWS S3로 파일을 직접 업로드하는 방법 및 Lambda Cold Start 문제 해결에 대해 설명합니다.

기존의 방식과 문제점

기존에는 앱에서 서버를 거쳐 S3로 파일을 업로드하는 방식을 사용하였습니다. 이 방식은 비효율적이므로, 앱에서 직접 S3로 파일을 업로드하는 방식을 도입하였습니다. 하지만 Flutter에서는 아직 AWS SDK가 제공되지 않아, 서버에서 Presigned URL을 받아야 했습니다.

우리 서비스는 Serverless를 지향하고 있어서 이 기능도 Lambda에 구현하였습니다. SDK를 활용해 URL을 생성 후 내려주고 테스트해보니 잘 동작하였으나, 예상치 못한 문제가 발생하였습니다.

Lambda Cold Start 문제 발생

일정 시간 동안 사용하지 않다가 Presigned URL을 담당하는 Lambda 함수를 다시 호출하면, 기존과 다른 URL을 반환하는 문제가 발생하였습니다. 이로 인해 파일 업로드가 정상적으로 이루어지지 않았습니다.

임시방편 해결방법

임시방편으로 최초 요청은 더미 요청으로 처리하고, 2번째 요청부터 반환된 URL을 사용하도록 하였습니다. 하지만 이 방법이 올바른 해결 방법인지에 대한 확신은 없었습니다.

Lambda Cold Start 문제 해결

구글링 결과 람다의 Cold Start 문제일 수 있다는 정보를 얻었습니다. 이를 해결하기 위해, 아래와 같은 IAM 정책을 Lambda 함수에 추가하였습니다:


{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::버킷명",
                "arn:aws:s3:::버킷명/*"
            ]
        }
    ]
}

이렇게 함으로써 Lambda Cold Start 문제를 해결할 수 있었습니다.

Thursday, December 26, 2019

AWS API Gateway와 Lambda를 이용한 Multipart 데이터 업로드 문제 해결

AWS API Gateway와 Lambda를 이용한 Multipart 데이터 업로드 문제 해결

AWS API Gateway와 Lambda(Node.js)를 사용하여 multipart 데이터를 업로드하는 방법에 대해 여러가지 방식을 찾아보았습니다. 제가 이전에 작성한 내용이 있으니 아래 링크를 참고하시면 도움이 될 것입니다.

AWS API Gateway + Lambda Multipart/Form-data

그런데 위에서 설명한 방식으로 설정을 하니, 일반 텍스트 필드와 이미지 파일이 함께 업로드되면 오류가 발생했습니다. 설정이나 전송 과정에서 문제가 있는 줄 알고 몇일 동안 고민하며 다양한 테스트를 진행했지만, 해결하지 못했습니다.

결국 사용하던 'parse-multipart' 패키지의 내용을 확인해보니, 해당 패키지는 파일만 지원하는 것이었습니다. 따라서 다른 패키지인 lambda-multipart-parser를 사용하여 다시 구성하기로 결정했습니다.

Lambda multipart upload example
Lambda에서의 multipart 데이터 업로드 예시

다만 대부분의 예제들은 API Gateway에서 Lambda proxy를 사용하는 경우였습니다. 그래서 Proxy를 사용하지 않는 제 경우처럼 구성해야 하는 분들을 위해 간략하게 구성 방법을 설명합니다. 우선, API Gateway 설정은 위 링크대로 하시면 되고, Lambda에서는 위 이미지와 같이 작성하면 됩니다.

Saturday, May 11, 2019

AWS Lambda와 API Gateway 활용, S3에 Multipart 이미지 업로드 시 파일 깨짐 문제 해결

AWS API Gateway와 Lambda
AWS API Gateway와 Lambda

서비스 개발 중에 클라이언트에서 multipart로 사진을 AWS Lambda로 보내고, Lambda에서 S3로 다시 사진을 업로드하는 작업이 필요했습니다. Flutter를 이용해 서비스를 개발하려 했으나 아직 Flutter용(dart) SDK가 없어서 우리쪽 서버를 거쳐서 보내기로 결정했습니다.

미디어 타입 설정

Lambda 코드 작성 전에 API gateway에서 미디어 타입을 추가해야 합니다.

API Gateway 미디어 타입 설정
API Gateway에서 미디어 타입 설정하기

코드 작성 및 팁 공유

인터넷에서 여러 자료를 참고하여 아래와 같은 코드를 작성했습니다. 이 예제는 여러 장의 사진을 받아 1장만 S3로 업로드하는 방법입니다. 한 가지 팁으로는, AWS SDK가 이미 설치되어 있으므로 별도의 설치가 필요하지 않다는 점입니다.


//const AWS = require('aws-sdk');
const multipart = require('parse-multipart');
exports.handler = (event, context, callback) => {
    const s3 = new AWS.S3({
        credentials: {
            accessKeyId: 'your accessKeyId',
            secretAccessKey: 'your secretAccessKey',
        },
        params: { Bucket: 'your Bucket' }
    });

    let bodyBuffer = Buffer.from(event['body-json'], 'base64');
    let boundary = multipart.getBoundary(event.params.header['content-type']);
    let parts = multipart.Parse(bodyBuffer, boundary);
    let data = {
        Key: 'your path',
        Body: parts[0].data,
        ContentEncoding: 'base64',
        ContentType: 'image/jpeg'
    };

    s3.putObject(data, function (err, data) {
      if (err) {
          callback(null, err);
      } else {
          callback(null, data);
      }
   });
};

테스트 및 문제 해결


<html>
<body>
<form action="https://your-url" enctype="multipart/form-data" method="post">
    <input multiple="" name="body-json" type="file" />
    <input type="submit" value="Submit" />
</form>
</body>
</html>

위와 같이 웹페이지를 만들어 테스트를 진행했지만 어떤 때는 동작하고 어떤 때는 동작하지 않는 이상한 상황이 발생했습니다. 원인을 찾기 위해 여러 가지 시도를 해봤지만 결국 문제의 원인은 웹에서 보낼 때 캐릭터셋 지정이 없어서 한글 파일의 경우 파일명이 깨지고 전송 후에 파일 자체가 깨지는 것이었습니다. 이를 해결하기위해 form 태그 안에 accept-charset="UTF-8"속성을 추가하고 다시 테스트해 보니 문제가 해결되었고, S3 업로드도 잘 실행되었습니다.


<html>
<body>
<form action="https://your-url" enctype="multipart/form-data" method="post" accept-charset="UTF-8">
    <input multiple="" name="body-json" type="file" />
    <input type="submit" value="Submit" />
</form>
</body>
</html>

사실상 코드는 큰 문제가 없었는데 캐릭터셋을 생각하지 못하고 코드 문제인 줄 알아서 이것저것 시도하느라 시간을 많이 잡아먹었습니다. 혹시 같은 작업이나 비슷한 문제를 겪는 사람들에게 조금이라도 도움이 되길 바랍니다.

참고 : 여러 형식의 파일 multipart upload 방법(https://blogdeveloperspot.blogspot.com/2019/12/aws-apigateway-lambdanodejs-multipart.html)