3센터 A-A-A RTGS 실시간총액결제 프로토타입 최초 버전관리 시작. - backend: Kotlin/Gradle 멀티모듈(sequencer, common, 채널/센터 모듈) - frontend: Vite + TS - infra: docker-compose, prometheus/grafana, ELK 네이티브 스크립트 - loadtest(k6), sim(장애/순서/정합성 시나리오), docs(PoC 보고서/복원력방안)
5.3 KiB
5.3 KiB
RTGS 3센터 삼중화 — 이관·기동 체크리스트
대상: 고사양 PC(40코어/128GB) 이관 후 테스트 시작용. 코드(B1/B2/B3)·설정공통화·스크립트는 8코어 PC에서 구현·빌드·단위테스트 완료(2026-07-13). 이 문서대로 기동하면 3센터 실측 가능.
0. 구현 요약 (이번에 반영된 것)
| 항목 | 내용 | 파일 |
|---|---|---|
| B1 무손실 순번기 | SEQUENCE global_seq_seq + journal_outbox(durable-before-publish) + 재발행 스케줄러 |
sequencer/SequencerService.kt, louisvuitton/.../db/migration/V4__seq_outbox.sql |
| B1 리더선출 | 순번기 그룹 sequencer 단일 리더(Kafka 리밸런스). 전역 단일 인스턴스 = DC1 |
동상 |
| B2 정족수 | rtgs.result=applied-ack, QuorumAggregator가 센터 집계 → 과반(2/3) ACCC |
prada/QuorumAggregator.kt, prada/PradaService.kt |
| B3 gap 타임아웃 | GapBuffer + 스케줄러: 정체 시 phantom skip(단일 파티션 근거) + rtgs.journal.gap.timeout 지표 |
hermes/GapBuffer.kt, hermes/HermesService.kt |
| 설정공통화 | 원장/엣지 groupId 센터접미사(hermes-DC1…) 파라미터화, 순번기만 단일 그룹 |
dior/hermes/prada/chanel Service |
| 이관 스크립트 | run-dc2/dc3.cmd, infra/init-3centers-db.cmd, run-dc1.cmd(3센터 모드 지원) |
루트/infra |
- 단위테스트:
QuorumAggregatorTest(6),GapBufferTest(6) —gradlew build통과.
1. 이관 검증 (고사양 PC 도착 직후)
C:\ai-dev트리를 동일 경로로 복사(포터블 무설치 철학 — 경로만 같으면 됨).- 빌드 확인:
cd C:\ai-dev\workspace\rtgs\backend && gradlew.bat build- JDK21 고정(
gradle.properties의org.gradle.java.home)이라 별도 설정 불필요. - 기대:
BUILD SUCCESSFUL, 단위테스트 12건 통과.
- JDK21 고정(
- 단일센터 스모크(선택):
run-dc1.cmd(기본 count=1, db=rtgs) → Chanel :8091로 1건 이체 → ACCC 확인.
2. 3센터 기동 절차 (순서 중요)
1) 공유 인프라 + DC1(3센터 모드) 기동:
set CENTER_COUNT=3 & set POSTGRES_DB=rtgs_dc1 & run-dc1.cmd
→ postgres:5433, kafka:9092, 단일 순번기 :8090, DC1 원장/엣지(809x) 기동.
2) 3개 DB 생성(멱등):
infra\init-3centers-db.cmd
→ rtgs_dc1/dc2/dc3 (스키마는 각 센터 LouisVuitton의 Flyway가 생성).
※ DC1은 이미 기동 중이라 rtgs_dc1은 DC1 LouisVuitton이 마이그레이션함.
3) DC2 기동: run-dc2.cmd (원장/엣지만, 819x, db=rtgs_dc2)
4) DC3 기동: run-dc3.cmd (원장/엣지만, 829x, db=rtgs_dc3)
- 순번기는 전역 단일(DC1 :8090). DC2/DC3는 저널(rtgs.journal, 단일 파티션)을 독립 그룹으로 전량 재생 → 각자 rtgs_dc2/dc3 원장에 동일 상태 도달(결정론적 재생).
- 완결: 각 센터 Prada가
rtgs.result를 전 센터분 집계 → 서로 다른 센터 2/3 도달 시 ACCC.
3. 검증 항목 (§설계서 6장 대응)
| 시나리오 | 방법 | 기대 |
|---|---|---|
| 평상시 3센터 | Chanel(:8091 등)로 이체 N건 | 3 DB의 transfer/account 완전 일치(총액·상태·순번), 즉시 과반 ACCC |
| 1센터 강제종료 | DC3 창 닫기 → 이체 계속 | 남은 2센터 ack=2 → 과반 유지 → 완결 지속, 이중지급 0 |
| 재해센터 복구 | DC3 run-dc3 재기동 | 밀린 저널 따라잡기(earliest 재생) → 잔액 일치 수렴 |
| 2센터 종료 | DC2·DC3 종료 → 이체 | ack=1 → 과반 미달 → ACSP(완결 보류), 오처리 0 |
| 2센터 복구 | DC2·DC3 재기동 | 따라잡기 후 보류분 ACCC 재개 |
| 순서 gap | (인위적 phantom) | rtgs.journal.gap.timeout 증가 + skip 후 진행 재개 |
대사(정합성) 확인 쿼리 (psql, 각 DB 반복):
psql -h localhost -p 5433 -U rtgs -d rtgs_dc1 -c "SELECT status,count(*),sum(amount) FROM transfer GROUP BY status ORDER BY status;"
psql ... -d rtgs_dc2 -c "동일"
psql ... -d rtgs_dc3 -c "동일"
-- 3개 결과가 동일해야 함. account 총합도 세 DB 동일해야 함.
4. 포트·토폴로지 참조
| 서비스 | DC1 | DC2 | DC3 | 그룹 |
|---|---|---|---|---|
| Sequencer | 8090 | (없음) | (없음) | sequencer(단일 리더) |
| Chanel | 8091 | 8191 | 8291 | chanel-DCx |
| Dior | 8092 | 8192 | 8292 | dior-DCx |
| Hermes | 8093 | 8193 | 8293 | hermes-DCx |
| Prada | 8094 | 8194 | 8294 | prada-DCx |
| Gucci | 8095 | 8195 | 8295 | (무상태) |
| LouisVuitton | 8099 | 8199 | 8299 | (Flyway/관리) |
- 공유: PostgreSQL 5433(rtgs_dc1/dc2/dc3), Kafka 9092(단일 파티션 저널), Prometheus 9090, Grafana 3000, ELK.
5. 주의·후속 (테스트 중 확인)
- 순번기 HA(선택 검증): 리더선출 시연하려면 순번기 인스턴스를 추가 기동하되 반드시 동일 SEQUENCE DB(POSTGRES_DB=rtgs_dc1)를 바라보게 할 것. 서로 다른 DB면 순번 충돌.
- Gucci 콜백 시드:
institution_endpoint가localhost:8095(DC1 Gucci)로 시드됨. 센터별 콜백 왕복까지 볼 땐 DC2/DC3 endpoint URL 조정 필요(핵심 정족수 검증엔 무관). - phantom skip 임계:
rtgs.gap-timeout-ms(기본 5000) — 실측 부하에 맞게 조정 가능(env/프로퍼티). - 재발행 grace:
rtgs.outbox-republish-grace-ms(기본 3000) — 인라인 발행과의 경합 회피 창. - 21 JVM 동시기동은 고사양 PC 전제. 8코어에선 경량 스모크만 권장.