Cold Data - 거의 이용되지않는 데이터 관리
거의 이용되지않는 데이터 관리 [오래된 데이터 저장 - append-only 데이터 처리]
서비스가 커지면서 데이터가 나날이 늘어간다. 일단은 데이터베이스 샤딩으로 해결하려고 하지만 한계가 명확하다. 그리고 제일 중요한 비용이 너무 커져버린다. 이럴 때 데이터를 어떻게 저장하고 이용할지에 대해 정리하는 글이다.
우리가 신경써야할 데이터의 종류는 크게 두가지로 나뉜다.
- 1.일년에 몇번 간간히 검색을 하긴 하는 데이터. (High-value Cold Data)
- 2.통계용으로만 쓰이고 유저들이 직접 이용하지는 않는 데이터. (Cold Data)
1번은 배달앱에서 5년전에 주문했던 데이터라고 생각하면 된다. (유저가 주문내역에서 스크롤을 엄청 내리거나 특정 연월을 검색했을 때만 나오는 데이터)
2번은 유저 행동에 관한 것들. 로그 데이터가 대표적이다.
위 두가지 데이터들을 DB에 저장하는 것은 부담이 아주 크다. 아무리 샤딩을 잘해둔다고 해도 성능적으로 악영향을 줄수 있고 가장 큰 단점으로 비용이 커진다. 그래서 S3와 같은 곳에 옮겨두고 필요할 때 불러와서 처리해야한다.
이런 데이터들을 Cold Data라고 한다.
1. 간간히 검색되는 데이터 “High-value Cold Data”
쇼핑몰 유저가 5년전에 주문한 내역을 DB에 저장해두고 최근 주문내역을 조회할 때 같이 돌리게 하는 건 성능적으로나 비용적으로 좋지않다. 자주 이용되는 데이터와 자주 이용되지않는 데이터는 분리해서 저장해야한다.
예를 들어 쇼핑몰에서 주문 데이터들은 처음 생성됐을 시 일반적인 DB(MySQL, MongoDB)에 저장된다. 그리고 이용되지 않는 시기가 오면 S3로 옮겨지며 Cold Data로 관리된다. 그리고 엄청 오래된 데이터라고 판단되면 + 법적으로 문제가 없다면 영영 지우기도 한다. (서비스마다 데이터 관리 정책에 따라 다름)
오래된 데이터들중에 유저가 간간히 조회하게 되는 데이터들이 있는데 이 데이터들을 High-value Cold Data라고 한다. 쇼핑몰에서 5년전, 10년전 주문내역을 가져올 때 간혹 응답이 느릴 때가 있다. pagination 기능을 잘못 구현해서 느린걸수도 있지만 시스템이 잘구축된 곳이라면 S3에서 데이터를 가져오기 때문에 느린 걸수도 있다.
“High-value Cold Data”가 관리되는 방식을 좀더 알아보자.
1
2
3
4
5
6
7
1. 쇼핑 주문 데이터가 생성된다.
2. 주문 데이터가 일반 DB에 저장된다.
3. 주문을 한지 몇달이 지난다. 몇달이 지나면 더이상 주문 데이터에 대해 "수정 작업이 불가"해진다.
4. 주문 전체 작업이 완료된지 몇년이 지났다.
5. 정기적으로 실행되는 cold-data 변환 프로세스에서 해당 데이터를 S3로 옮긴다.
6. 주문 데이터가 일반 DB에서 삭제된다.
7. 유저가 해당 데이터를 조회하면 S3에서 가져와서 보여준다.
“읽기 전용 데이터”
여기서 중요한점은 cold-data로 저장되는 데이터는 모두 수정작업이 불가능하다는 점이다. 서비스 기능적으로 수정을 불가능하게 막는 프로세스가 필요하다. 그후 콜드 데이터로 처리한다.
데이터 변환/저장 과정
보통 크론잡 + 메시지 큐 방식으로 변환한다. 정기적으로 특정 기간 이상된 데이터들을 조회하여 변환 큐에 넣고 처리한다.
데이터 크기에 따라 저장방식이 다르다. 데이터 하나하나의 크기가 크다면 데이터 하나하나를 파일로 저장하고 데이터 하나하나의 크기가 작다면 하루에 생기는 데이터를 하나의 파일로 저장한다. 혹은 일주일, 한달 단위로 저장할 수도 있다.
그리고 S3 사용 용량을 줄이기 위해 압축하여 저장한다. 파일 하나의 사이즈가 너무 커지면 데이터를 조회할 때 가져오는데 걸리는 시간 + 압축을 해제하는 시간 + 파싱하는 시간이 너무 오래걸린다. 적절한 사이즈로 저장될수 있는 기간의 데이터를 하나의 파일로 만들어 저장해야한다.
맵핑 테이블
S3에 저장된 파일은 파일 이름으로 조회할 수 있지만 파일 이름만으로는 조회가 어렵다. 그래서 맵핑 테이블을 만들어 파일 이름과 파일 내용을 맵핑해둔다.
기본 방식
S3에 저장됐다면 따로 맵핑 데이터를 DB에 만들어야한다. 기본 형식은 아래와 같다.
| 주문번호 | s3Key |
|---|---|
| 10004 | userId_2011_01_13.jsonl.gz |
버퍼 오프셋 + Range GET 방식
S3에 파일 갯수가 너무 많아지는게 안좋아질 때도 있다. 분석 처리할 때 파일이 너무 많으면 오래걸리기도 하고 S3에 쓰기 처리를 너무 많이하면 안좋기도 하다. (S3는 쓰기 비용이 읽기비용의 10배정도 비싸다고 한다.) 이럴 때는 하나의 파일 크기를 크게 하는 대신 맵핑 테이블에서 구획을 나눠 관리한다. offset을 추가로 저장하는 방식이다.
| 주문번호 | s3Key | byteOffsetStart | byteOffsetEnd |
|---|---|---|---|
| 10004 | userId_2011_01_13.jsonl | 1829382 | 1830123 |
| 10005 | userId_2011_01_13.jsonl | 1830123 | 1830864 |
| 10006 | userId_2011_01_13.jsonl | 1830864 | 1831605 |
위 처럼 여러 주문을 하나의 파일로 저장하고 시작점, 끝 점을 저장해둬 해당하는 부분만 S3에서 받아올 수 있다.
Range GET이라고 하는데 기존 받아오던 쿼리에 Range 파라미터만 추가하면 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
const s3 = new S3Client({ region: "ap-northeast-2" });
const command = new GetObjectCommand({
Bucket: "your-bucket-name",
Key: "your-file.jsonl",
Range: "bytes=1829382-1830123",
});
const response = await s3.send(command);
const stream = response.Body;
const data = await streamToString(stream);
~
Range 방식의 단점이 하나 있다. offset으로 필요한 데이터만 가져와야하기때문에 파일을 압축해서 저장해놓지 못한다. 압축해 놓은 파일에서 부분만 가져오는건 불가능하니말이다. 압축하지않아도 부담이 되지않는 상황에서만 이용할수 있다.
2. 통계용으로만 쓰이는 데이터 “Cold Data”
유저한테 보이지않는 데이터들 주로 유저행동 분석에 쓰이는 데이터들이다. 이 데이터들은 특별한 경우가 아니라면 디비에 저장되지않고 바로 로그 파일로 관리된다.
“일반 Cold Data”가 관리되는 방식은 간단하다.
1
2
3
4
5
6
7
1. 유저 행동 로그가 생성된다.
2. 개별 서버 인스턴스에서 로그 파일로 저장된다.
3. 적당한 버퍼 크기로 정기적으로(보통 수초 이내로) 중앙 로그 서버로 전송된다.
4. 일정기간 분석용 툴에 저장된다. (ELK, Clickhouse 등)
5. 분석 완료, 혹은 더이상 필요하지 않은 데이터는 S3로 옮겨진다.
6. 기간이 오래된 데이터라면 S3에서도 제일 저렴한 타입으로 옮겨진다.
7. 법적, 서비스 정책에 따라 데이터가 삭제된다.
일반 Cold Data는 High-value Cold Data와 다르게 수정을 불가능하게 하는 프로세스가 따로 존재하지 않는다. 어차피 로그 데이터라 수정할 일이 없다.
공통 내용
JSONL
High-value Cold Data, 일반 Cold data 모두 보통 JSONL 형식으로 저장된다. append-only 방식에서 대부분 쓰인다. 기본적으로 ,(컴마) 없이 줄바꿈으로 구분되어 한줄한줄이 하나의 json데이터다.
1
2
3
{"userId": "u1", "action": "login", "timestamp": "2025-06-01T10:00:00Z"}
{"userId": "u2", "action": "purchase", "timestamp": "2025-06-01T10:05:00Z", "item": "keyboard"}
{"userId": "u1", "action": "logout", "timestamp": "2025-06-01T10:10:00Z"}
각 줄마다 하나의 데이터이기 때문에 위에서 설명한 “버퍼 오프셋 + Range GET 방식”에 line 값을 추가해서 이용하기도 한다.
S3 수명 주기
S3도 가격이 천차만별이다.
Standard, Standard-Infrequent Access, Archive(Glacier) 등 여러가지가 있다. 링크로 한번 훑어보면 좋다.