데이터베이스 마이그레이션 가이드
FlowKat APM의 데이터베이스 구성 및 마이그레이션 절차를 정의한다. 버전 업그레이드, 서버 이전, 데이터 정리 시나리오를 모두 다룬다.
1. 개요
DB 구성
FlowKat은 목적에 따라 두 종류의 데이터베이스를 사용한다.
| DB | 역할 | 위치 | 비고 |
|---|---|---|---|
| PostgreSQL 16 | TX-Mining 트랜잭션 데이터, XLog 정규화 데이터 | Docker 컨테이너 (flowkat-postgres) | pg_partman, pgvector, pg_trgm 확장 포함 |
| H2 (Embedded) | Dashboard 서버 설정, 사용자/역할/대시보드 구성 | 파일 시스템 (volumes/dashboard-server/META_H2/) | Spring Boot 내장, MySQL 호환 모드 |
마이그레이션이 필요한 시점
- 버전 업그레이드: 스키마 변경 DDL이 포함된 릴리즈로 업그레이드할 때
- 서버 이전: 물리 서버 또는 클라우드 환경을 변경할 때
- 대용량 데이터 정리: 파티션 보존 기간 초과 데이터를 삭제할 때
- 디스크 용량 확보: VACUUM/REINDEX로 공간을 회수할 때
2. PostgreSQL 백업/복원
2.1 전체 백업 (pg_dump)
# 전체 덤프 (SQL 형식)
docker exec flowkat-postgres pg_dump \
-U postgres \
-d postgres \
--schema=FLOWKAT \
> backup_$(date +%Y%m%d).sql
# custom 형식 (병렬 복원 지원, 권장)
docker exec flowkat-postgres pg_dump \
-U postgres \
-d postgres \
--schema=FLOWKAT \
-Fc \
-f /tmp/flowkat_$(date +%Y%m%d).dump
# 컨테이너 밖으로 복사
docker cp flowkat-postgres:/tmp/flowkat_$(date +%Y%m%d).dump ./backups/
환경변수 확인:
POSTGRES_USER는deploy/docker-compose-mining.yml기준postgres,POSTGRES_PASSWORD는.env에서POSTGRES_PASSWORD값을 사용한다.
2.2 pg_dump 주요 옵션
| 옵션 | 설명 |
|---|---|
-Fc | custom 형식. pg_restore로 병렬 복원 가능 |
-Fd | 디렉터리 형식. -j 옵션으로 병렬 덤프 |
-j N | N개 병렬 작업 (custom/directory 형식에서만 사용) |
--schema=FLOWKAT | FLOWKAT 스키마만 덤프 |
--table=FLOWKAT.XLOG_NORM | 특정 테이블만 덤프 |
--no-acl | 권한 정보 제외 |
--no-owner | 소유자 정보 제외 (다른 사용자로 복원 시 유용) |
# 병렬 덤프 (대용량 데이터베이스)
docker exec flowkat-postgres pg_dump \
-U postgres \
-d postgres \
--schema=FLOWKAT \
-Fd \
-j 4 \
-f /tmp/flowkat_parallel_$(date +%Y%m%d)
docker cp flowkat-postgres:/tmp/flowkat_parallel_$(date +%Y%m%d) ./backups/
2.3 특정 테이블 별도 백업
XLOG_NORM은 파티션 테이블이므로 파티션별로 덤프한다.
# 파티션 목록 조회
docker exec flowkat-postgres psql \
-U postgres \
-d postgres \
-c "SELECT tablename FROM pg_tables WHERE schemaname='flowkat' AND tablename LIKE 'xlog_norm_%' ORDER BY tablename;"
# 특정 파티션 덤프
docker exec flowkat-postgres pg_dump \
-U postgres \
-d postgres \
-t 'FLOWKAT.XLOG_NORM_2026_03_*' \
-Fc \
-f /tmp/xlog_norm_202603.dump
2.4 복원 (pg_restore)
# SQL 형식 복원
docker exec -i flowkat-postgres psql \
-U postgres \
-d postgres \
< backup_20260326.sql
# custom 형식 복원
docker cp ./backups/flowkat_20260326.dump flowkat-postgres:/tmp/
docker exec flowkat-postgres pg_restore \
-U postgres \
-d postgres \
--schema=FLOWKAT \
-Fc \
/tmp/flowkat_20260326.dump
# 병렬 복원 (-j 옵션은 custom/directory 형식에서만 동작)
docker exec flowkat-postgres pg_restore \
-U postgres \
-d postgres \
--schema=FLOWKAT \
-j 4 \
/tmp/flowkat_parallel_20260326
복원 전 기존 데이터를 제거하려면
--clean옵션을 추가한다.
3. H2 데이터베이스 관리
3.1 H2 파일 위치
Dashboard 서버의 H2 데이터베이스 파일은 Docker volume에 마운트된다.
volumes/dashboard-server/META_H2/
├── H2DB_PROD.mv.db # 프로덕션 설정 DB
├── H2DB_LOCAL.mv.db # 로컬/개발 환경 DB
└── H2DB_COOKIE.mv.db # 세션/쿠키 관련 DB
flowkat.nextjs/dashboard 모듈의 application.yml에서 JDBC URL을 확인한다.
# 프로덕션 프로파일 예시
spring:
datasource:
jdbc-url: jdbc:h2:file:./META_H2/H2DB_PROD;SCHEMA=PUBLIC;MODE=MySQL;TRACE_LEVEL_FILE=1;
3.2 H2 백업
H2 파일은 단순 파일 복사로 백업한다. Dashboard 서버가 실행 중일 때는 파일이 잠길 수 있으므로 서비스를 중단하고 복사한다.
# Dashboard 서버 중단
docker stop flowkat-dashboard-server
# H2 파일 백업
cp -r volumes/dashboard-server/META_H2 \
backups/META_H2_$(date +%Y%m%d_%H%M%S)
# Dashboard 서버 재시작
docker start flowkat-dashboard-server
flowkat-cli.sh의 서비스별 백업 기능(create_service_backup)도 동일하게 META_H2를 포함한다.
3.3 H2 복원
docker stop flowkat-dashboard-server
# 기존 파일 제거 후 복원
rm -rf volumes/dashboard-server/META_H2
cp -r backups/META_H2_20260326_120000 \
volumes/dashboard-server/META_H2
docker start flowkat-dashboard-server
3.4 H2 초기 데이터 (DDL/DML)
Dashboard 서버 기동 시 hbm2ddl.auto: none 설정이므로 스키마 자동 생성이 비활성화되어 있다. 초기 데이터는 flowkat.nextjs/dashboard/src/main/resources/data/ 아래 SQL 파일로 관리된다.
flowkat.nextjs/dashboard/src/main/resources/data/
├── DEFAULT_MEMBER.sql
├── DEFAULT_ROLE_LIST.sql
├── DEFAULT_ROLE_MENU.sql
├── DEFAULT_ROLE_FUNC_AUTH.sql
├── DEFAULT_DASH_BOARD.sql
├── DEFAULT_WORKGROUP.sql
├── DEFAULT_WORKGROUP_ROLE.sql
├── DEFAULT_MEMBER_WORKGROUP.sql
└── DEFAULT_TRACKING_AUTO_RULE.sql
신규 설치 시 위 파일을 순서대로 적용한다.
4. 버전 업그레이드 시 마이그레이션
4.1 스키마 변경 원칙
FlowKat은 Flyway/Liquibase를 사용하지 않는다. 스키마 변경은 수동 DDL 적용 방식이다.
init-db.sql은IF NOT EXISTS패턴으로 멱등성을 보장한다.- 신규 컬럼/인덱스는
ALTER TABLE ... ADD COLUMN IF NOT EXISTS패턴을 사용한다. - TX-Mining 스키마 파일 위치:
deploy.release/volumes/mining-server/config/init-db.sql
4.2 PostgreSQL 스키마 변경 적용 절차
# 1. 백업 선행 (필수)
docker exec flowkat-postgres pg_dump \
-U postgres -d postgres --schema=FLOWKAT -Fc \
-f /tmp/pre_upgrade_$(date +%Y%m%d).dump
docker cp flowkat-postgres:/tmp/pre_upgrade_$(date +%Y%m%d).dump ./backups/
# 2. 변경 스크립트 컨테이너에 복사
docker cp ./migrations/v5_0_28_schema.sql \
flowkat-postgres:/tmp/
# 3. DDL 적용
docker exec flowkat-postgres psql \
-U postgres \
-d postgres \
-f /tmp/v5_0_28_schema.sql
# 4. 적용 결과 확인
docker exec flowkat-postgres psql \
-U postgres \
-d postgres \
-c "\d FLOWKAT.XLOG_NORM"
4.3 H2 스키마 변경 (Dashboard 설정 DB)
Dashboard 서버의 JPA 설정은 hbm2ddl.auto: none이므로, 컬럼 추가/변경은 수동으로 진행한다.
# H2 Console 접근 (Dashboard 서버 기동 중)
# URL: http://<host>:6300/h2-console
# JDBC URL: jdbc:h2:file:./META_H2/H2DB_PROD
# User: (application.yml에서 확인)
# 또는 컨테이너 내부에서 직접 실행
docker exec -it flowkat-dashboard-server java \
-cp /app/lib/h2*.jar \
org.h2.tools.Shell \
-url "jdbc:h2:./META_H2/H2DB_PROD;MODE=MySQL" \
-user sa
4.4 pg_partman 파티션 관리
XLOG_NORM 테이블은 end_time 컬럼(BIGINT epoch ms)으로 일별 파티션을 자동 생성한다.
-- 파티션 상태 조회
SELECT * FROM public.part_config
WHERE parent_table = 'flowkat.xlog_norm';
-- 파티션 유지 관리 수동 실행 (cron 대체)
SELECT public.run_maintenance('flowkat.xlog_norm');
-- 미래 파티션 사전 생성 수 조정 (기본 7일)
UPDATE public.part_config
SET premake = 14
WHERE parent_table = 'flowkat.xlog_norm';
5. 서버 이전 절차
5.1 전체 이전 순서
1. 소스 서버: 서비스 중단
2. 소스 서버: PostgreSQL 전체 백업
3. 소스 서버: H2 및 설정 파일 백업 (volumes/ 전체)
4. 대상 서버: FlowKat 신규 설치 (docker-compose up)
5. 대상 서버: PostgreSQL 복원
6. 대상 서버: H2 파일 복원
7. 대상 서버: 환경변수(.env) 복원 및 검증
8. 대상 서버: 에이전트 재설정
9. 대상 서버: 서비스 기동 및 동작 확인
5.2 Docker Volume 이전
# 소스 서버: 볼륨 전체 압축
tar -czf flowkat_volumes_$(date +%Y%m%d).tar.gz \
-C /path/to/deploy.release volumes/
# PostgreSQL 데이터는 pg_dump 방식 권장 (바이너리 포맷 호환성)
# volumes/mining-server/postgres-data/ 직접 복사는 PostgreSQL 버전이 동일할 때만 안전
# 대상 서버로 전송
scp flowkat_volumes_$(date +%Y%m%d).tar.gz user@target:/path/to/deploy.release/
# 대상 서버: 압축 해제
cd /path/to/deploy.release
tar -xzf flowkat_volumes_$(date +%Y%m%d).tar.gz
5.3 환경변수 이전
.env 파일에는 비밀번호, 도메인 URL 등 환경별 값이 포함된다. 이전 시 아래 항목을 반드시 검토한다.
# 주요 검토 항목
POSTGRES_PASSWORD # 변경 없이 이전 가능
NEXTAUTH_URL # 새 서버의 접속 URL로 변경 필수
NEXTAUTH_SECRET # 유지 권장 (세션 호환성)
CORS_ORIGINS # 새 서버 URL로 변경 필수
NETWORK_MODE_COLLECT # 서버 환경(bridge/host)에 따라 조정
5.4 에이전트 재설정
서버 이전 후 각 에이전트의 Collect Server 연결 설정을 새 서버 IP로 변경한다. 에이전트 파라미터 설정은 10.agent-java.md를 참조한다.
6. 데이터 정리
6.1 파티션 드롭 (보존 기간 초과 데이터)
init-db.sql에서 retention은 365일로 설정되어 있다. 수동으로 오래된 파티션을 삭제할 때는 아래 절차를 따른다.
-- 현재 파티션 목록 및 행 수 조회
SELECT
schemaname,
tablename,
pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) AS size
FROM pg_tables
WHERE schemaname = 'flowkat'
AND tablename LIKE 'xlog_norm_%'
ORDER BY tablename;
-- 특정 파티션 삭제 (데이터 영구 삭제)
DROP TABLE IF EXISTS FLOWKAT.XLOG_NORM_p20250101;
-- pg_partman run_maintenance로 retention 초과 파티션 자동 삭제
SELECT public.run_maintenance('flowkat.xlog_norm');
retention_keep_table = false이므로run_maintenance실행 시 보존 기간 초과 파티션은 자동 DROP된다.
6.2 VACUUM / REINDEX
파티션 드롭 또는 대량 삭제 후 디스크 공간을 회수한다.
# VACUUM ANALYZE (dead tuple 제거 + 통계 갱신)
docker exec flowkat-postgres psql \
-U postgres \
-d postgres \
-c "VACUUM ANALYZE FLOWKAT.XLOG_NORM;"
# VACUUM FULL (전체 공간 회수, 테이블 잠금 발생 — 유지보수 시간대 실행)
docker exec flowkat-postgres psql \
-U postgres \
-d postgres \
-c "VACUUM FULL FLOWKAT.XLOG_NORM;"
# REINDEX (인덱스 재구성, 성능 저하 시)
docker exec flowkat-postgres psql \
-U postgres \
-d postgres \
-c "REINDEX TABLE FLOWKAT.XLOG_NORM;"
VACUUM FULL과 REINDEX는 테이블 잠금이 발생한다. 서비스 트래픽이 없는 시간대에 실행한다.
6.3 디스크 공간 현황 확인
# PostgreSQL 전체 DB 크기
docker exec flowkat-postgres psql \
-U postgres \
-d postgres \
-c "SELECT pg_size_pretty(pg_database_size('postgres')) AS db_size;"
# FLOWKAT 스키마 테이블별 크기
docker exec flowkat-postgres psql \
-U postgres \
-d postgres \
-c "
SELECT
tablename,
pg_size_pretty(pg_total_relation_size('flowkat.'||tablename)) AS total_size,
pg_size_pretty(pg_relation_size('flowkat.'||tablename)) AS table_size
FROM pg_tables
WHERE schemaname = 'flowkat'
ORDER BY pg_total_relation_size('flowkat.'||tablename) DESC
LIMIT 20;
"
# H2 파일 크기
du -sh volumes/dashboard-server/META_H2/
7. 트러블슈팅
7.1 마이그레이션 실패 시 롤백
# 사전 백업에서 복원
docker exec flowkat-postgres psql \
-U postgres \
-d postgres \
-c "DROP SCHEMA IF EXISTS FLOWKAT CASCADE;"
docker cp ./backups/pre_upgrade_20260326.dump \
flowkat-postgres:/tmp/
docker exec flowkat-postgres pg_restore \
-U postgres \
-d postgres \
--schema=FLOWKAT \
/tmp/pre_upgrade_20260326.dump
7.2 시퀀스 불일치 복구
대용량 복원 후 SERIAL 컬럼의 시퀀스 값이 실제 데이터와 맞지 않을 때 발생한다.
-- 시퀀스 현재 값과 실제 최댓값 비교
SELECT
sequence_name,
last_value
FROM information_schema.sequences
WHERE sequence_schema = 'flowkat';
-- DIM_SERVICE 시퀀스 재설정 예시
SELECT setval(
'flowkat.dim_service_service_id_seq',
(SELECT MAX(service_id) FROM FLOWKAT.DIM_SERVICE)
);
-- 전체 테이블 시퀀스 일괄 재설정
DO $$
DECLARE
r RECORD;
BEGIN
FOR r IN
SELECT sequence_schema, sequence_name,
replace(sequence_name, '_id_seq', '') AS tbl,
replace(replace(sequence_name, '_id_seq', ''), 'dim_', 'dim_') || '_id' AS col
FROM information_schema.sequences
WHERE sequence_schema = 'flowkat'
LOOP
BEGIN
EXECUTE format(
'SELECT setval(%L, COALESCE((SELECT MAX(%I) FROM %I.%I), 1))',
r.sequence_schema || '.' || r.sequence_name,
r.col,
r.sequence_schema,
r.tbl
);
EXCEPTION WHEN OTHERS THEN
-- 테이블/컬럼 불일치 무시
END;
END LOOP;
END $$;
7.3 파티션 생성 실패
pg_partman이 새 파티션을 생성하지 못할 때 확인 사항이다.
-- pg_partman 설정 확인
SELECT * FROM public.part_config
WHERE parent_table = 'flowkat.xlog_norm';
-- 파티션 유지 관리 로그 확인
SELECT * FROM public.part_config_sub
WHERE sub_parent = 'flowkat.xlog_norm';
-- 수동으로 특정 날짜 파티션 생성
SELECT public.create_partition_time(
'flowkat.xlog_norm',
ARRAY['2026-04-01'::timestamptz]
);
7.4 H2 DB 잠금 오류 (Database may be already in use)
# Dashboard 서버 프로세스 강제 종료 후 잠금 파일 제거
docker stop flowkat-dashboard-server
# .lock.db 파일 제거
find volumes/dashboard-server/META_H2/ -name "*.lock.db" -delete
docker start flowkat-dashboard-server
관련 문서
- 16.docker-compose.md - PostgreSQL 컨테이너 환경변수 및 서비스 구성
- 28.server-capacity.md - 디스크 용량 계획 및 모니터링
- 14.collect-server.md - Collect Server와 DB 연동 설정
- 33.deploy-checklist.md - 배포 전 체크리스트