Problem

node.js를 사용하고 AWS SDK1를 이용해 S3에서 파일을 다운로드를 구현 중 아래와 같이 코드를 작성해서 서비스 하고 있었다. 비교적 작은파일 (50MB 미만)는 문제가 없었지만 대용량 파일 400MB 이상을 다운로드 시 서버 자원을 많이 사용하고 속도도 매우 느려지는 등 문제가 발생하기 시작했다.

download(bucket, folder, type, id, callback) {
    const params = {
        Bucket: (bucket || process.env.AWS_S3_BUCKET) + '/' + folder,
        Key: id
    };

    this.client.getObject(params, function(err, data) {
        let rstream = null;
        if (!err && data) {
            rstream = new stream.PassThrough();
            rstream.end(new Buffer(data.Body, 'binary'));
        }

        return callback(err, _.omit(data, ['AcceptRanges', 'Metadata', 'Body']), rstream);
    });
}

Solution

S3 링크를 직접 만들거나 권한을 부여하는 등의 방법을 사용해서 해당 링크로 redirect 시키는 방법도 있지만2, 예를들면 유료로 결제한 사용자들만 받을 수 있는 파일이어서 나는 링크를 외부에 완전히 숨기기를 원했고 따라서 권한 관리도 서버에서 온전히 통제하고 싶었기 때문에 위 방법을 적용하지는 못했다. 썸네일이나 한 페이지에 대량의 요청을 해야하는 상황이라면 redirect 방식이 더 적절할 것 같았다.

해결 방법은 아래와 같이 createReadStream을 만들고 stream을 전달하여 사용하면 된다3.

download(bucket, folder, type, id, callback) {
    const params = {
        Bucket: (bucket || process.env.AWS_S3_BUCKET) + '/' + folder,
        Key: id
    };

    const rstream = this.client.getObject(params).createReadStream();
    return callback(null, null, rstream);
}

References