목차
파일 업로드
사용자가 파일을 입력하면 서버는 storage에 그 파일을 정리한다.
대개 AWS라면 S3 서비스, Naver의 object storage, Azure의 bucket 서비스, 아니면 서버 디스크에 바로 저장하는 경우 등 다양한 방법으로 파일을 저장한다. 파일을 저장한 후엔, file.filename 을 통해 db에 파일 명을 저장하는 방식을 많이 사용한다.
사용자가 파일을 삭제하거나 수정할 경우 db의 파일 명은 새로운 파일 이름으로 업데이트 되고, storage에도 동일하게 파일이 올라간다.
이렇게만 보면 평화로운 서버 나라이지만, 그러나 사용자가 삭제한 파일은 여전히 storage에 저장되어 있다. 따로 storage에 delete요청을 보내지 않았기 때문이다.
더미 파일을 정리하는 방법
이럴 경우 두 가지 방법이 있다.
1. 사용자가 파일을 수정하거나 삭제할 때마다 storage에 삭제 요청을 보낸다.
2. 서버 스케줄링을 작성해 특정 시간에 사용하지 않는 파일들을 한꺼번에 삭제한다.
게임 서버 같이 서버의 리소스 관리를 철저하게 관리해야할 경우 1 방법을 주로 사용한다. 특히 게임은 한 사용자가 여러 계정을 사용하며, 아이템, 길드 등 방대한 양의 데이터들이 연관되어 있기 때문이다. 게다가 실시간으로 멀티 서버를 운영하는 등 서버 비용이 상대적으로 다른 서비스에 비해 매우 크다. 바로 바로 관리하지 않으면 더미 데이터가 겉잡을 수 없게 쌓이기 때문에 바로 바로 정리해준다고 한다.
커뮤니티 등 일반적인 웹 서비스들은 관례적으로(?) 유연하게 리소스를 관리한다고 한다. 2번 방식을 주로 사용하는데, 주기적으로 코드를 돌려주는 서버 스케줄링 기능을 통해 관리한다. 일반적으로 화요일 새벽3시쯤 돌리는 것을 좋아한다고 한다. 제일 애매한 시간대... ㅋㅋㅋㅋ 애매한 시간대에 부하가 큰(?), 매일 돌릴 필요없는 코드를 돌려 안정성을 확보하는 듯 하다.
1번 방식의 문제점
1번 방식 '요청에 따라 그때 그때 리소스를 삭제한다.'
이 방식을 구현하려고 생각하면 생각보다 많은 단계와 시나리오가 예상된다.
A) 사용자가 파일을 수정했다.
→ 수정전 파일명 가져오기, 삭제
B) 사용자가 파일을 삭제했다.
→ 삭제하는 파일명 가져오기, 삭제
C) 작품 정보를 영구 삭제 했다
→ 작품 정보와 연결된 파일명 가져오기, 삭제
파일을 수정하든, 연결된 파일만 삭제하든 이전 정보를 가져와 업데이트 해야하기때문에 이전 정보를 읽어오는 코드를 추가해야하는 번거로움이 있다. 또한 지금 파일을 업로드하는 경우가 하나일 때만 가정한 것인데, 관련하여 썸네일, 이미지 리사이징이 추가된 경우 예상되는 뎁스가 n배가 된다. 때문에 나는 2번 방식을 택했다. (서버 스케줄링을 한번 도전하고 싶기도 했고!)
2번 방식의 문제점
2번 방식, '서버 스케줄링을 작성해 특정 시간에 사용하지 않는 파일들을 한꺼번에 삭제한다.'
이 방식은 스케줄링 코드를 따로 작성해야 한다는 번거로움과, 서버에 저장된 파일이 많을수록 느리다는 단점이 있다. 이외의 단점은 차차 알아보는 걸로 ㅎㅎ
사용하지 않는 파일 리스트 뽑기 (차집합)
2번 방식을 사용하려면 우선 (A)db에 저장된 현재 사용중인 파일명을 배열로 가져온다. (B) 그후 실제 서버 스토리지에 저장된 모든 파일명을 배열로 가져온다. 그후 B에서 A를 제외한 부분만 삭제하면된다. 정확히 따지면 아래 그림 같은 모양이 되겠지만, 개발 과정에선 위 그림처럼 될 수 있다. (내 경우 개발 테스트는 aws s3에서 하다가, 디스크 스토리지로 넘어온 케이스라...)
자, 아무튼 한번 차집합을 구하는 코드를 작성해보자.
const {Artwork} = require('./models');
const sequelize = require('sequelize');
const fs = require('fs');
const Op = require('sequelize').Op;
// usingArtworkFiles 현재 사용중인 모든 작품 파일 가져오기
const getUsingArtworkFiles = async() => {
try {
let resources = await Artwork.findAll({
attributes: ['ARTWORK_RESOURCE'],
where: {
ARTWORK_RESOURCE: {
[Op.not]: null
}
}
})
// sequlize는 object 형식으로 리턴하기 때문에 배열로 다시 넣어줌
let result = []
resources.forEach( resource => {
result.push(resource.ARTWORK_RESOURCE)
})
console.log('----> usingArtworkFiles ', result)
return result
} catch (error) {
console.error(error)
return []
}
}
const getDiskArtowkFiles = async() => {
let filelist = fs.readdirSync('uploads/artwork')
console.log('----> diskArtworkFiles', filelist);
return filelist
}
const startCleanUp = async() => {
// diskArtworkFiles 파일 리스트 가져오기
let usingArtworkFiles = await getUsingArtworkFiles();
let diskArtworkFiles = await getDiskArtowkFiles();
// 차집합 구하기 차집합에 든 파일 disk에서 삭제하기
let difference = diskArtworkFiles.filter(filename => !usingArtworkFiles.includes(filename));
difference.forEach(filename => {
fs.unlink(`uploads/artwork/${filename}`, (err) => {
if (err === undefined || err == null) {
console.log(`delete >>>>> uploads/artwork/${filename}`);
} else {
console.log(err);
}
})
})
}
startCleanUp()
// getDiskArtowkFiles()
// getUsingArtworkFiles()
* 주의
꼭 비동기로 디스크에 있는 파일 리스트를 읽어와야한다. 안그러면 파일 리스트를 읽어오는게 오래 걸리기 때문에 빈 배열이 리턴된다. fs.readdirSync('uploads/artwork') 꼭 비동기로 읽어오기!
개발용 로그 남기기
아무튼 차집합을 구해 사용하지 않는 파일들을 지우는 코드를 작성했다. 여기서 바로 서버 스케줄링 코드로 넘어갈 수 있지만, 개발용 로그를 남겨보자. 정해진 시간에 파일이 정리가 되었는지, 어떤 파일들이 지워졌는지 혹시나 처리중에 에러가 발생해 서버가 죽을 수 있으니 로그를 꼭 꼭 남겨보자.
서버 스케줄링 코드 작성 (node-schedule)
const schedule = require('node-schedule');
// 초 분 시 일 월 주
// 42초가 될때마다 실행
const job = schedule.scheduleJob('42 * * * * *', function(){
console.log('42초가 되었습니다.');
});
42초가 될 때마다 콘솔에 찍도록 해주었다. 42초때마다 잘 찍히는것 확인 완료!
이를 활용하여 전에 만들어둔 cleanUpResource.js를 실행시키면 끝~~
생각보다 스케줄링이 어렵지 않아서 놀랐다. 서버 운용이라고 하면 넘 어렵게만 느껴졌는데, 역시 하면 된다!
지금 상태는 node 서버가 돌아가야만 스케줄링 코드가 돌아간다.
다음엔 한번 os에서 돌아가는 cron을 도전해봐야지!
📌 참고 블로그 글
- 로그 파일 남기기
[Node.js] Logging 라이브러리 winston 적용하기
Node.js 서버에 winston으로 로그 남기기
velog.io
- 서버 스케줄링 코드 작성
https://medium.com/nodejs-server/node-schedule-pm2-8f7831ed231e
Node-schedule & PM2
매일 정기적으로 같은 시간에 같은 일을 실행시킨다.
medium.com
https://coding8.tistory.com/34
NodeJS에서 node-schedule이용한 스케쥴러 작업
NodeJS를 이용하면서, 작업을 반복적으로 특정시간에 처리할 수 있도록 해야할 때도 있는데요. 오늘은 그런경우에 node-schedule이라고 하는 라이브러리를 이용해서, 그와 같은 작업을 하는 방법에
coding8.tistory.com
'Dev > 코딩공부 이모저모' 카테고리의 다른 글
CS ) ssh, sh, bash 란 뭘까? (0) | 2021.09.25 |
---|---|
CS) 서버 OS 알아보기, CentOS, Linux, Ubuntu, Window (0) | 2021.09.05 |
CDN ) CDN 결과 비교하기, 근데 거기에 Request header 분석을 곁들인... (0) | 2021.09.04 |
Node.js ) 페이징 처리 1 - offset, limit 방식 (0) | 2021.07.24 |
React Router ) Link 기능을 함수로 빼기, history와 location (0) | 2021.07.11 |