참고자료 : http://jeonghwan-kim.github.io/node/2017/08/12/node-stream-you-need-to-know-3.html
개발을 하는 기능중 S3 버킷의 파일을 다른 버킷으로 이동시키는 기능을 개발 했었다.
기존의 소스의 경우
- getobject 를 해서 파일을 메모리에 buffer로 가지고 있다가
- putobject로 옮길 버킷에 업로드 하고.
- deleteObject로 기존 버킷의 파일을 삭제한다
get,put,delete object
static async getObject(type, fileKey) {
try {
const config = await utils.getEnvConfig(type);
const result = await s3
.getObject({ Bucket: config.bucket.origin, Key: fileKey })
.promise()
return result;
} catch (error) {
return Promise.reject(error);
}
}
static async putObject(type, fileKey, fileBuffer) {
try {
const config = await utils.getEnvConfig(type);
const result = await s3
.putObject({
Bucket: config.bucket.target,
Key: fileKey,
Body: fileBuffer,
})
.promise()
return result;
} catch (error) {
return Promise.reject(error);
}
}
static async deleteObject(type, fileKey) {
try {
const config = await utils.getEnvConfig(type);
const result = await s3
.deleteObject({ Bucket: config.bucket.origin, Key: fileKey })
.promise()
return result;
} catch (error) {
return Promise.reject(error);
}
}
for wait 부분
for await (const fileKey of arrFilekey) {
const fileBuffer = await DAL.getObject(type, fileKey);
console.log("fileBuffer : ", fileBuffer);
const putResult = await DAL.putObject(type, fileKey, fileBuffer);
console.log("putBuffer : ", putResult);
const deleteResult = await DAL.deleteObject(type, fileKey);
console.log("deleteResult : ", deleteResult);
}
여기서 문제점은 버킷에 있는 파일을 전부 메모리에 올리기 때문에 버킷에 메모리 사용량이 너무 높아진다는 문제점이 있었다.
이 문제를 해결하기 위해 node.js Stream을 사용해서 람다의 /tmp 폴더에 다운로드한 뒤에
stream으로 업로드하는 방식을 채택했다.
람다 실행시에 /tmp 는 512MiB 까지 사용할 수 있다.
먼저 getObejct를 스트림 방식으로 바꿔보자.
static async getObject(type, fileKey) {
const config = await utils.getEnvConfig(type);
return new Promise((resolve, reject) => {
const fileStream = fs.createWriteStream("/tmp/temp", "binary");
const s3Stream = s3
.getObject({
Bucket: config.bucket.origin,
Key: fileKey,
})
.createReadStream();
s3Stream
.on("error", function (err) {
// NoSuchKey: The specified key does not exist
fileStream.end();
console.error(err);
reject(err);
})
.on("data", (data) => {
console.log("data : ", data);
})
.on("end", () => {
console.log("read end");
});
fileStream
.on("error", function (err) {
console.error(err);
fileStream.end();
reject(err);
})
.on("close", function () {
console.log("Done.");
resolve("success");
});
s3Stream.pipe(fileStream);
});
}
const fileStream = fs.createWriteStream("/tmp/temp", "binary");
fs을 사용해서 /tmp/temp 라는 이름으로 writeStream로 선언해준다.
const s3Stream = s3
.getObject({
Bucket: config.bucket.origin,
Key: fileKey,
})
.createReadStream();
그후 기존의 getObject에 .createReadStream()을 붙여서 stream방식으로 바꿔준다.
s3Stream
.on("error", function (err) {
console.error(err);
fileStream.end();
reject(err);
})
.on("end", () => {
console.log("read end");
});
fileStream
.on("error", function (err) {
console.error(err);
fileStream.end();
reject(err);
})
.on("close", function () {
console.log("Done.");
resolve("success");
});
이후 s3Stream 과 fileStream 에 on으로 이벤트에 따라서 success처리 혹은 error처리를 명시해주고
s3Stream.pipe(fileStream);
pipe 를 사용해서 읽어 들이면서 사용할 파일을 쓰도록 만들어준다.
putObject도 마찬가지 방식으로 변경해준다
static async putObject(type, fileKey) {
const config = await utils.getEnvConfig(type);
console.log("Putobject");
const fileStream = fs.createReadStream("tmp/temp");
const s3Stream = await s3
.putObject({
Bucket: config.bucket.target,
Key: fileKey,
Body: fileStream,
})
.promise();
console.log("put done : ", s3Stream);
return s3Stream;
}
이후 실행을 시켜보면 성공적으로 변경이 완료되었다!
다음엔 한번 다운로드를 쓰는 과정을 없애서
읽어 들이면서 바로 업로드 하는 방식을 시도해보려고 한다.
성공하면 또 포스팅 해보도록 하겠다
'IT,프로그래밍 > AWS' 카테고리의 다른 글
sendgrid에서 dynamic template을 쓸때 메일 제목이 안나오는 현상 (0) | 2020.08.06 |
---|---|
[Lambda + RDS] connect ETIMEDOUT ERROR 해결법 (0) | 2020.06.09 |
[Lambda + AWS SDK S3] 람다로 S3 접근가능 url 가져오는법 (0) | 2020.05.26 |
[Azure + AWS] Azure Devops 파이프라인 에서 ECR로 push하기 (0) | 2020.04.20 |
[ AWS + Serverless.js ] 3.소스 코딩 1 (0) | 2020.04.13 |