8. 백업 · 복구
이 장을 마치면: GritDB 데이터를 일관되게 백업하고, 백업에서 되살리고, 되살린 결과를 검증한다.
8.1 백업 단위
- 백업 단위는
datafiles/한 묶음이다. 일부만 백업한 것은 복구에 쓸 수 없다. pgdata(WAL과 복구용 복제 슬롯 포함),checkpoint,cold_file은 함께 맞아야 한다. 셋이 같은 때의 것이어야 한다.
⚠ 다른 실경로나 다른 판으로 복구하지 않는다
- 이유: 실경로가 다르면 cold file을 잃는다(1.5). cold file은 GritDB 엔진이 분석 조회용으로 열 단위로 저장한 파일이다. 판이 다르면 저장 형식이 맞지 않는다.
- 대신: 백업할 때 실경로와 판을 함께 적는다(8.2의 4번). 같은 실경로와 같은 판에만 복구한다.
datafiles/ 안 |
백업 | 메모 |
|---|---|---|
pgdata/ |
넣는다 | WAL(pg_wal), 복구용 복제 슬롯, postgresql.conf, pg_hba.conf 포함 |
checkpoint/ |
넣는다 | unify checkpoint 위치. unify checkpoint는 GritDB 엔진이 영구 반영을 마친 WAL 위치다. PostgreSQL checkpoint와 다르다 |
cold_file/ |
넣는다 | cold file |
queue/ |
넣는다 | 겉보기 크기가 크고 빈 공간이 많은 파일이므로 빈 공간을 그대로 두는 방법으로 복사한다(8.2) |
buffer_spill/ |
통째 복사에 그대로 둔다 | 정상 정지 뒤에는 비어 있다 |
query_text_archive.jsonl |
통째 복사에 함께 들어간다 | 분석 세션 조회의 SQL 원문이 들어 있으므로 백업 사본을 같은 보안 수준으로 둔다(11.7) |
함께 보관하는 것(datafiles/ 밖):
config/*.config(GritDB 엔진 설정, 5.6)share/gritdb/manifest.json(설치 판)- 데이터 볼륨 재배치 정보:
datafiles와datafiles/pgdata의 실경로(2.4, 8.2의 4번)
8.2 정지 후 백업
1.1이 지원하는 백업은 GritDB를 정상 정지하고 datafiles/를 통째로 복사하는 방법이다. PostgreSQL의 파일 시스템 수준 백업과 같은 꼴이고, GritDB는 datafiles/ 전체를 담는다. 멈춰 있는 시간은 정상 정지(4.2), 복사, 기동(4.1)에 걸리는 시간을 더한 값이다.
-
응용 프로그램, 리포트, BI 도구, CDC 도구, ETL 도구를 멈추고 남은 세션을 끊는다(4.2의 “남은 세션 끊기” 1~3번). 분석계면 정지하는 동안 운영 DB에 WAL이 쌓인다(4.7, 7.5).
-
대조할 값을 적는다(8.5 대조용).
B=<백업 자리>/gritdb_$(date +%Y%m%d_%H%M%S) mkdir -p "$B" ~/gritdb1/bin/psql -p 5432 -d <db> -Atc "SELECT schema_name, table_name FROM get_gritsurfer_tables() ORDER BY 1, 2" > "$B/tables_<db>.txt" ~/gritdb1/bin/psql -p 5432 -d <db> -Atc "SELECT count(*), sum(<숫자 열>) FROM <s>.<t>" > "$B/count_<s>.<t>.txt"<백업 자리>는 데이터 볼륨이 아닌 디스크다. 5번에서 이 자리($B)에 복사한다.- 첫 두 줄은 한 번만 실행한다. 셋째 줄은 데이터베이스마다, 넷째 줄은 표본 테이블마다 되풀이한다. 표본은 7.10의 1번 기준으로 고르고, 정수나
numeric(p, s)열을 쓴다. 더한 열 이름도 함께 적어 둔다. 8.5의 4번과 3.4 ①이 같은 열로 대조한다. - 1번 뒤에 적는다. 그러면 적은 뒤에 바뀌는 값이 없다.
-
정상 정지한다.
~/gritdb1/bin/gritdb-stop cat ~/gritdb1/run/grit_admin_clean_shutdownCLEAN_SHUTDOWN이 나오고 프로세스가 0개면 정상이다(QuickStart 4.5).- 파일이 없으면 즉시 정지로 끝났다는 뜻이다(4.2). 이때는
gritdb-start로 기동하고 4.1로 확인한다. 1번을 다시 하고, 다시 붙은 연결 풀도 멈춘다. 2번의 셋째와 넷째 줄을 같은$B로 다시 실행한다. 그다음gritdb-stop으로 다시 정지한 뒤 복사한다.
-
실경로와 판을 적는다.
readlink -f ~/gritdb1/datafiles readlink -f ~/gritdb1/datafiles/pgdata jq -r .product_version ~/gritdb1/share/gritdb/manifest.json -
2번과 같은 셸에서
$B에 복사한다. 셸이 끊겼으면B=<2 번에서 만든 자리>를 실행한다.tar --sparse -cf "$B/datafiles.tar" -C "$(readlink -f ~/gritdb1/datafiles)" . ; echo "datafiles.tar = $?" tar -cf "$B/install_meta.tar" -C ~/gritdb1 config share/gritdb/manifest.json ; echo "install_meta.tar = $?"- 두 줄 모두
= 0이면 정상이다.0이 아니면 그 사본을 쓰지 않는다. 이때는 공간이나 권한을 고치고 5번을 다시 한다. --sparse는 빈 공간이 많은 파일(queue/)을 실제 크기로 담는다.rsync를 쓰면rsync -aHS로 복사한다.-S가 같은 일을 한다. 이때도 끝 상태가0인지 본다.--pgdata로pgdata를 따로 둔 설치(2.4)에서는datafiles.tar에 그 심링크만 들어가므로pgdata실경로도 담는다. 이때는tar --sparse -cf "$B/pgdata.tar" -C "$(readlink -f ~/gritdb1/datafiles/pgdata)" . ; echo "pgdata.tar = $?"를 실행해= 0이 나오는지 확인한다.
- 두 줄 모두
-
백업을 확인한다.
tar -tf "$B/datafiles.tar" ./checkpoint/grit_unify.cp ./pgdata/PG_VERSION- 두 이름이 그대로 나오면 정상이다.
pgdata를 따로 둔 설치에서는 첫 이름만 나온다. 이때pgdata쪽은tar -tf "$B/pgdata.tar" ./PG_VERSION을 실행해 이름이 나오는지 확인한다. - 사본 전체를 원본과 견주려면 7번(기동) 전에
tar -df "$B/datafiles.tar" -C "$(readlink -f ~/gritdb1/datafiles)"를 실행해 출력이 없는지 확인한다.pgdata.tar도 같은 방법으로 견준다. 이때는 멈춰 있는 시간이 복사 시간만큼 는다.
- 두 이름이 그대로 나오면 정상이다.
-
~/gritdb1/bin/gritdb-start로 기동하고 4.1로 확인한다.
- 복사 시간은
datafiles/의 실제 크기(du -sh ~/gritdb1/datafiles/)를 백업 자리의 쓰기 속도로 나눈 값이다. - 백업 사본에는 SQL 원문과 데이터 값이 들어 있으므로 서비스 계정만 읽게 둔다(11.7).
⚠ 실행 중인 GritDB의
datafiles/를 복사하지 않는다
- 이유: 1.1은 실행 중 백업을 지원하지 않는다. 복사하는 동안
pgdata,checkpoint,cold_file이 서로 다른 때의 것이 된다.- 대신: 위 3번에서 정상 정지를 확인한 뒤 복사한다.
8.3 PostgreSQL 백업 도구와 GritDB
| 도구 | GritDB 데이터 | 쓰임 |
|---|---|---|
pg_basebackup과 PITR |
담지 않는다. cold file과 복구용 복제 슬롯이 빠진다 | GritDB 백업으로 쓰지 않는다 |
pg_dump와 pg_dumpall |
테이블 데이터만 담는다. 등록 상태는 담지 않는다 | 다른 곳으로 옮길 때(스키마 → 등록 → 데이터 순서로 복원) |
- 1.1은 실행 중 백업을 지원하지 않는다. 파일시스템이나 스토리지 스냅샷(LVM, ZFS 등)으로 만든 사본도 지원하지 않는다. 백업은 정지 후 백업(8.2)으로 한다.
- 되살릴 수 있는 시점은 마지막 정지 후 백업이다. WAL 보관(
archive_mode)으로 그 뒤 시점까지 되살리는 복구(PITR)는 1.1에서 되지 않는다. 그래서 한 데이터베이스 구성에서는 백업 주기를 잃어도 되는 데이터의 기간으로 정한다(1.9의 12번). 분석계는 운영 DB에서 다시 받는다(8.6).
⚠
postgres데이터베이스의 덤프를 다른 GritDB에 복원하지 않는다
- 이유:
postgres데이터베이스에는 GritDB 내부 테이블(gritdb스키마)이 들어 있다.pg_dumpall전체 덤프에도 들어간다.- 대신: 계정과 역할은
pg_dumpall --globals-only를 쓴다. 데이터는 데이터베이스마다pg_dump를 쓰고,postgres는 뺀다.
다른 GritDB로 옮길 때(논리 백업, 원래 서버에서):
~/gritdb1/bin/pg_dumpall -p 5432 --globals-only -f globals.sql
~/gritdb1/bin/pg_dump -p 5432 -d <db> --schema-only -f <db>_schema.sql
~/gritdb1/bin/pg_dump -p 5432 -d <db> --data-only --exclude-table-data=<s>.<t> -f <db>_data.sql
~/gritdb1/bin/psql -p 5432 -d <db> -c "\copy <s>.<t> TO '<t>.csv' (FORMAT csv)"
- 셋째와 넷째 줄의
<s>.<t>는 큰 테이블이다. 큰 테이블은 행 수가 한 트랜잭션 상한(6.8)의 절반을 넘는 테이블이다. 행 수는 원래 서버에서 잰 6번 대조 값이다. 큰 테이블마다--exclude-table-data하나와\copy줄 하나를 둔다. 큰 테이블이 없으면--exclude-table-data를 빼고 넷째 줄은 하지 않는다. --exclude-table-data는 테이블 정의는 두고 데이터만 뺀다.
새 GritDB에서 복원한다(데이터베이스마다 2~5번).
- 계정과 역할은
~/gritdb1/bin/psql -p 5432 -d postgres -f globals.sql로 복원한다. CREATE DATABASE<db>;를 실행한다. 확장이 함께 생긴다(6.1).- 테이블 정의와 기본 키는
~/gritdb1/bin/psql -p 5432 -d <db> -f <db>_schema.sql로 복원한다. - 등록한다(6.3). 기본 키가 생긴 뒤, 테이블이 비어 있을 때 한다.
- 데이터는
~/gritdb1/bin/psql -p 5432 -d <db> -f <db>_data.sql로 넣는다. 그다음 큰 테이블은 6.8의 3번으로 넣는다(적재용 테이블 → 나눠 넣기,\copy <s>.<t>_load FROM '<t>.csv' (FORMAT csv)). - 8.5의 4번으로 원래 서버에서 잰 값과 대조한다.
- 5번의
-f는 테이블마다 한 트랜잭션으로 넣는다. 그래서 큰 테이블은 셋째 줄로 덤프에서 빼고 6.8의 3번으로 나눠 넣는다. 나눌 수 없으면 지원 문의(0장)를 한다. <db>_data.sql과<t>.csv는 데이터 사본이므로 서비스 계정만 읽게 두고, 다 옮기면 지운다(11.7).- 6번의 대조 값이 같은지, 등록 목록(6.5)에 옮긴 테이블이 모두 있는지 확인한다.
- PostgreSQL 쪽 논리 백업과 복원: SQL 덤프
8.4 복구
-
~/gritdb1/bin/gritdb-stop으로 정지한 뒤 프로세스가 0개인지 확인한다(QuickStart 4.5). -
실경로와 판이 백업 때와 같은지 본다.
readlink -f ~/gritdb1/datafiles readlink -f ~/gritdb1/datafiles/pgdata jq -r .product_version ~/gritdb1/share/gritdb/manifest.json- 8.2의 4번에 적은 값과 같으면 정상이다. 다르면 멈춘다(8.1 경고).
-
지금 데이터를 보존한다(이름을 바꾼다).
- 먼저 데이터 볼륨의 빈 공간을 본다.
df -h "$(readlink -f ~/gritdb1/datafiles)"의Avail이 백업의datafiles/실제 크기(du -sh, 8.2) 이상인지 확인한다. 보관본이 같은 볼륨에 남아 4번에서 그만큼이 더 든다.pgdata를 따로 둔 설치는pgdata볼륨도 본다. 모자라면 보관본을 다른 볼륨으로 옮긴다. 보관본은 복구가 실패하면 되돌릴 자료이므로 지우지 않는다.
D=$(readlink -f ~/gritdb1/datafiles) P=$(readlink -f ~/gritdb1/datafiles/pgdata) T=$(date +%Y%m%d_%H%M%S) mv "$D" "$D.before_restore_$T" mkdir "$D" chmod 700 "$D"datafiles/(또는 아래$P)가 mount 지점이면 디렉토리째 옮길 수 없다. 이때는 안의 파일을 다른 자리로 옮기고 빈 디렉토리를 남긴다(3.1).pgdata를 따로 둔 설치(2.4)에서는$P도 보존한다. 이때는mv "$P" "$P.before_restore_$T",mkdir "$P",chmod 700 "$P"를 차례로 실행한다.P는datafiles를 옮기기 전에 구한다. 옮긴 뒤에는datafiles/pgdata링크로 찾을 수 없기 때문이다.
- 먼저 데이터 볼륨의 빈 공간을 본다.
-
백업을 같은 실경로에 푼다.
tar -xf <백업 자리>/<백업 이름>/datafiles.tar -C "$D"pgdata를 따로 둔 설치에서는 3번과 같은 셸에서tar -xf <백업 자리>/<백업 이름>/pgdata.tar -C "$P"를 실행한다.readlink -f ~/gritdb1/datafiles/pgdata가$P와 같은지 확인한다.- GritDB 엔진 설정까지 백업 때 값으로 되돌릴 때만
tar -xf <백업 자리>/<백업 이름>/install_meta.tar -C ~/gritdb1 config를 실행한다.
-
~/gritdb1/bin/gritdb-start로 기동하고 4.1로 확인한다. GritDB 엔진 복구가 끝날 때까지 출력 없이 기다릴 수 있다(4.1). -
8.5로 검증한다.
-
검증이 끝나면 3번에서 보존한 데이터를 지운다.
⚠ 분석계(6.4)는 백업으로 복원하지 않는다
- 이유: 운영 DB 슬롯은 백업 뒤로 이미 나아가 있어서, 백업 때부터의 운영 DB 변경을 다시 보내지 않는다. 그 변경이 분석 데이터에서 조용히 빠진다.
- 대신: 분석계는 8.6의 다시 받기로 복구한다. 이미 복원했으면 8.6의 전체 다시 받기를 한다.
8.5 복구 검증
-
4.1로 기동을 확인한다.
started successfully가 나오는지 보고, 20초 뒤pg_isready를 한 번 더 실행한다. -
데이터베이스마다 등록 테이블 목록을 본다.
~/gritdb1/bin/psql -p 5432 -d <db> -Atc "SELECT schema_name, table_name FROM get_gritsurfer_tables() ORDER BY 1, 2" | diff - <백업 자리>/<백업 이름>/tables_<db>.txt- 출력이 없으면 정상이다. 백업 때 적은 목록(8.2의 2번)과 같다는 뜻이다.
-
반영을 확인한다(6.6.1).
-
건수와 합계를 대조한다.
일반 세션:
SELECT count(*), sum(<숫자 열>) FROM <s>.<t>;분석 세션(6.6, GritDB 엔진 강제):
/*+ engine=burst, fallback=false */ SELECT count(*), sum(<숫자 열>) FROM <s>.<t>;- 두 값이 같고 8.2의 2번에 적은 값(
count_<s>.<t>.txt)과 같으면 정상이다.
- 두 값이 같고 8.2의 2번에 적은 값(
-
자주 쓰는 리포트 조회 하나를 두 세션에서 실행해 결과를 비교한다.
- 1~5번이 모두 맞는지 확인한다. 하나라도 다르면 8.4의 3번에서 보존한 데이터를 지우지 않는다. 이때는 QuickStart 7.4로 자료를 모아 지원 문의(0장)를 한다.
8.6 분석계 다시 받기
분석계 구성의 복구는 백업 복원이 아니라 운영 DB에서 다시 받기가 기본이다(8.4 경고).
| 상황 | 할 일 |
|---|---|
| 테이블 하나가 어긋났다 | 6.4.2로 그 테이블을 다시 받는다. 다른 테이블은 계속 받는다 |
분석계 전체. 운영 DB 슬롯이 무효(wal_status가 lost)일 때, 또는 GritDB를 백업으로 되살리는 대신 |
아래 “전체 다시 받기” |
| GritDB 서버를 잃었다 | 아래 “새 서버로 다시 받기” |
- 다시 받기는 초기 복사를 다시 하므로, 테이블 행 수가 한 트랜잭션 상한(6.8)의 절반을 넘으면 하기 전에 지원 문의(0장)를 한다. 6.4.1의 8번 경고도 본다.
- 같은 테이블을 비우고 바로 다시 등록하지 않는다. 지우고 새로 만든 테이블로 등록한다(6.4.2의 5번).
전체 다시 받기:
- 6.4.4의 1~3번으로 subscription과 운영 DB 슬롯을 치운다. publication은 그대로 둔다.
- 반영을 확인한다(6.6.1).
- GritDB 테이블을 해제하고 지운다(6.3).
- 같은 정의로 새로 만들고 등록한다(6.4.1의 6~7번).
- subscription을 다시 만들고 초기 복사를 확인한다(6.4.1의 8~9번).
새 서버로 다시 받기(GritDB 서버를 잃었을 때):
- 운영 DB에서 6.4.4의 2번과 3번으로 옛 subscription 슬롯을 지운다. 슬롯은 6.4.1의 8번에서 적어 둔
oid로 가린다. - 새 서버에 설치한다(QuickStart 2장과 3장).
- 새 서버의 주소가 다르면 운영 DB에서 접속 허용을 고친다(6.4.1의 4번).
- 6.4.1의 5~9번을 따른다.
- 6.4.1의 9번에서 세 값이 같은지 확인한다.
8.7 다른 서버로 옮기기 · 대기 서버
다른 서버로 옮기기:
-
새 서버에 같은 판을 같은 설치 경로, 같은 옵션(
--datafiles와--pgdata, 2장), 같은 이름의 서비스 계정으로 설치한다. -
원래 서버에서 정지 후 백업을 한다(8.2).
-
새 서버에서 8.4의 1~6번을 따른다. 같은 실경로에 풀고, 4번 둘째 줄로 옛 서버의 GritDB 엔진 설정인
config도 푼다.diff -r <백업의 config> ~/gritdb1/config를 실행해 출력이 없는지 확인한다. 새 서버의config/는 처음에 설치 기본값이기 때문이다(3.4 ③).
- 분석계는 백업을 옮기지 않고 새 서버에서 다시 받는다(8.6의 “새 서버로 다시 받기”).
1.1에서 대기 서버와 재해 복구 서버는 수동이다. 자동 전환이 없다(10.6).
| 구성 | 대기 서버를 만드는 법 | 주의 |
|---|---|---|
| 분석계 | 두 번째 GritDB가 같은 운영 DB에 subscription을 따로 만든다(6.4.1) | 운영 DB에 슬롯이 하나 더 생기고 부하가 는다(6.4.3). 두 subscription을 모두 감시한다(7.5) |
| 한 데이터베이스 | 정지 후 백업(8.2)을 같은 실경로와 같은 판의 다른 서버에 정한 주기로 복원한다(8.4) | 마지막 백업 뒤의 변경은 대기 서버에 없다 |
- 전환할 때는 운영자가 응용 프로그램과 BI 도구의 접속 주소를 대기 서버로 바꾼다.
- 대기 서버를 꾸리기 전에 지원 문의(0장)를 한다.
문제가 생기면
- TroubleShooting의 RECOVERY 계열을 본다.
더 알아보기
- 재초기화와 원복은 3장을, 분석계는 6.4를 본다.
- PostgreSQL 17 문서: 백업과 복원, 파일 시스템 수준 백업, SQL 덤프