Skip to content

[Test] 동기 권한 회수와 독립 쓰기의 on/local 혼합 부하 비교 - #546

Merged
Gimini-3 merged 3 commits into
developfrom
feature/543
Oct 17, 2026
Merged

Gimini-3 merged 3 commits into
developfrom
feature/543

Conversation

@Gimini-3

@Gimini-3 Gimini-3 commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

목적

Closes #543

권한 회수는 항상 동기로 확정하면서, 별도의 독립 쓰기만 on 또는 local로 바꿨을 때 장애 중 업무 진행과 공유 DB 풀 대기가 어떻게 달라지는지 비교했습니다. 실제 인증 HTTP 차단은 #544에서 확인했고, 이 PR은 커밋 정책의 차이를 같은 부하에서 관측하는 시험입니다.

비교한 정책은 다음 두 가지입니다.

조건 권한 회수 시험용 독립 쓰기 비교 목적
전체 동기 on on 동기 Standby의 확인을 기다리는 기준 조건
선택적 동기 on local 독립 쓰기에서 원격 복제 확인 대기를 줄였을 때의 효과와 한계

이 환경에서 on은 strict 동기 구성을 전제로 Primary와 지정 동기 Standby의 기록 확인을 기다립니다. local은 Primary의 로컬 WAL 기록을 기다리지만 원격 복제 확인을 기다리지 않습니다. local을 off와 같은 설정으로 취급하지 않습니다.

대표 비교 4조건의 최초 요청 192건 중 204 79건은 새 Primary/복구 DB에서 모두 확인됐고, 나머지 결과 불명 113건은 같은 키로 재확정했습니다. 중단 구간의 독립 쓰기 완료는 ACK 비교에서 on 0건·local 5건이었지만, 공유 풀 대기는 두 조건 모두 최대 8개였습니다. 이번 시험에서 local 성공 데이터의 유실은 관측되지 않았습니다.

상세 결과·실행별 원장 · 전체 집계 · 설계

테스트 환경

실행일은 **2026-10-17, 시각 기준은 KST(UTC+09:00)**입니다. 공개 설정과 운영 Worker 계정 정책은 변경하지 않았으며, backend/src/main/의 업무 코드 변경도 없습니다.

구성 실제 조건과 역할
애플리케이션 로컬 JVM, 실제 PermissionController → DocumentPermissionRevocationFacade → JPA/DB
요청 방식 standalone MockMvc. 시험용 소유자 인증 정보를 주입. 실제 TCP HTTP·로그인·JWT 시험은 #544의 별도 결과
독립 쓰기 테스트 소스에만 있는 Controller와 별도 UUID 테이블. 권한 데이터와 FK·행 잠금을 공유하지 않음
DB·HA 격리 OpenSQL 3노드, PostgreSQL 17.8·Patroni 4.0.5, 지정 동기 strict·동기 Standby 수 1
연결 별도 시험 OpenProxy → 역할 어댑터 → 격리 DB. 공개 컨테이너·데이터·포트·DCS와 분리
공유 자원 두 요청 종류가 같은 Hikari 풀 사용. 최대 커넥션 5개, 동시 요청 작업자 8개
부하 조건별 권한 회수 24건 + 독립 쓰기 24건 = 최초 요청 48건
커밋 확인 회수는 항상 on. 독립 쓰기만 SET LOCAL on/local. 독립 204 응답에서 실제 current_setting 확인
시간·수집 커밋 확인 경계 5초, Hikari 상태 100ms 간격 수집. UUID별 최초 응답·재확정 응답·제어 이벤트를 별도 원장에 즉시 기록
그림 1 — 바뀌는 설정과 고정한 자원

로컬 요청 작업자 8개
  ├─ 권한 회수 24건
  │   → PermissionController
  │   → DocumentPermissionRevocationFacade.revoke()
  │   → SET LOCAL synchronous_commit=on
  │   → 권한 삭제·회수 원장 갱신 → COMMIT 확인
  │
  └─ 합성 독립 쓰기 24건
      → 시험 전용 IndependentWriteController
      → 별도 UUID·별도 테이블 갱신
      → SET LOCAL synchronous_commit=on 또는 local
      → COMMIT 확인
                     │
              공유 Hikari 풀 최대 5개
                     │
          시험 Proxy → 역할 어댑터 → 격리 Primary
                                      ├─ Standby 1
                                      └─ Standby 2

정책 간 차이: 독립 쓰기의 커밋 설정 하나
고정: 회수 on / 업무 코드 / 클러스터 / 부하 / 공유 풀

독립 쓰기는 실제 인덱싱 Worker·Chunk/Embedding 작업을 대신하는 분리된 합성 쓰기입니다. 운영 Worker에 local을 적용했거나 그 효과를 측정한 결과로 해석하지 않습니다.

테스트 방법

추가한 시험 구성

파일·구성 역할
PermissionMixedCommitIntegrationTest.java 동일 부하의 on/local 비교, 최초 성공 키 감사, 불명 요청 재확정, 풀 상태 수집
backend/build.gradle permissionMixedCommitTest, 별도 태그, 전용 주소·새 회차 디렉터리 검사, 시나리오 선택
설계 문서 고정 변수·장애 절차·성공/불명 판정·측정 범위 정의
결과 디렉터리 목적·회차·정책별 응답/풀/제어 원장, 집계, 보완 과정, 최종 정리

공통 준비

  1. 매 조건마다 시험 데이터와 시험 DCS만 초기화하고 같은 노드에서 Primary를 시작합니다.
  2. Standby 2대의 streaming, strict 설정, 실제 동기 후보, Proxy를 통한 Primary 도착을 확인합니다.
  3. 최초 4건(회수 2건·독립 2건)이 모두 204인지 확인합니다.
  4. 두 시험 Standby 컨테이너를 pause한 뒤 나머지 44건을 실행합니다. 공개 DB는 중단하지 않습니다.

두 장애 시나리오

시나리오 절차 확인하려는 것
ACK 중단·복구 Standby 2대 pause → 요청 실행 → 고정 12초 대기 → unpause 원격 확인이 멈춘 구간의 독립 완료·회수 대기·공유 풀 대기
복합 Primary 상실 Standby 2대 pause → 요청 실행 → 고정 10초 대기 → Primary KILL → Standby unpause → native 자동 승격 최초 성공 응답의 실제 보존 여부와 결과 불명 요청의 재확정

Standby 컨테이너 전체를 pause하므로 복제 처리뿐 아니라 SQL·Patroni·역할 API도 멈춥니다. 순수 COMMIT ACK 지연만 고립시킨 시험이나 단순 Primary 단독 장애와 구분합니다. 실제 제어 시간에는 SSH 왕복 등이 포함됩니다.

그림 2 — 성공 응답을 먼저 감사하고, 그 뒤 불명을 해소

최초 요청 → UUID·종류·응답 상태·지연을 DB 밖 원장에 기록
  │
  ├─ 최초 204
  │   → 복구/승격 뒤 현재 Primary에서 같은 UUID 조회
  │   → 회수/on 성공 키가 없으면 합격 불가
  │   → local 성공 키가 없으면 유실 관측으로 기록
  │      ※ 이미 성공한 키는 재생성해 누락을 숨기지 않음
  │
  └─ 503/599 등 결과 불명
      → 최초 204 키 감사가 끝날 때까지 재확정 금지
      → 같은 UUID로 다시 요청
      → assertion UPDATE로 새 WAL 생성 → COMMIT 재확인
      → 실제 204와 최종 키 존재 확인

조건별 최종 확인
  ├─ 회수 원장 24개 / 회수 대상 권한 0행
  ├─ 독립 키 보존과 불명 요청 재확정 확인
  └─ 풀 기본 커밋 설정 on 복귀 확인

결과 불명은 실패 응답을 받은 쓰기가 반드시 DB에 없다는 뜻이 아닙니다. 클라이언트가 확정 여부를 알 수 없는 상태이므로 같은 요청 키로 재확정합니다. 단순 재삭제 대신 원장 UPDATE를 수행해 새 WAL과 커밋 확인이 발생하도록 합니다.

실행·계측 방법

# 기본: ACK 중단·Primary 상실 × on/local, 총 4조건
./backend/gradlew -p backend permissionMixedCommitTest

# Primary 상실 비교만 선택
PERMISSION_MIXED_SCENARIO=primary-loss ./backend/gradlew -p backend permissionMixedCommitTest

전용 루프백 JDBC·migration 주소, 시험 비밀번호, 새 실행 디렉터리와 외부 격리 장애 제어기가 필요합니다. 명령만으로 클라우드 자원과 제어기가 만들어지지는 않습니다. 수동 시험 태그는 기본 CI에서 제외됩니다.

  • requests.jsonl: UUID별 최초/재확정 응답. 상태·지연·실측 커밋 모드를 기록합니다.
  • 풀 원장: 100ms마다 Hikari active/pending 등을 기록합니다.
  • 제어 원장: pause·종료 확인·native 승격·실제 Proxy 읽기 준비 시각을 기록합니다.
  • 원장·코드의 SHA-256과 집계 수치를 대조하고, 비밀·비공개 식별자는 기록·공유 전에 제외했습니다.

관측 결과

대표 비교 4조건

ACK 두 정책은 같은 mixed-run02 하네스, Primary 두 정책은 같은 mixed-run05 하네스로 비교했습니다. 두 목적 사이에는 Proxy 준비 확인·감사 읽기 재시도를 보완했으므로 모든 회차가 같은 시험 소스였다고 표현하지 않습니다. 실제 업무 코드는 동일합니다.

회차·조건 최초 회수 204 최초 독립 204 최초 불명 회수/독립 최초 성공 키 누락 회수/독립 재확정 요청 풀 최대 active/pending
run02 · on / ACK 중단 17/24 15/24 7 / 9 0 / 0 16건 5 / 8
run02 · local / ACK 중단 15/24 21/24 9 / 3 0 / 0 12건 5 / 8
run05 · local / Primary 상실 2/24 5/24 22 / 19 0 / 0 41건 5 / 8
run05 · on / Primary 상실 2/24 2/24 22 / 22 0 / 0 44건 5 / 8

합계는 최초 192건 = 최초 204 79건 + 결과 불명 113건입니다. 최초 204 키 79건의 누락은 0건이었고, 불명 113건은 각각 같은 키로 재확정했습니다. 최초·재확정을 합친 응답 원장은 305건입니다. 대표 조건 모두 최종 회수 원장 24개·대상 권한 0행·독립 키 24개를 확인했습니다.

장애 중 독립 쓰기의 진행과 공유 풀 영향

ACK 중단 조건 실제 중단 구간 구간 안 회수 204 구간 안 독립 204 독립 응답 p95
on 약 13.048초 0건 0건 9,344.1ms
local 약 12.917초 0건 5건 5,006.9ms

이번 표본에서는 local이 일부 독립 쓰기를 진행시켰습니다. 공유 Hikari 풀의 최대 pending은 두 조건 모두 8개여서, 독립 쓰기 설정 변경만으로 공유 풀 대기까지 없어진 것은 아닙니다.

p95는 종류별 표본 24건·조건별 1회이며, MVC 호출 시작부터 반환까지입니다. executor 대기·사전 준비 시간은 제외합니다. 운영 성능·SLA 또는 안정적인 개선 비율로 일반화하지 않습니다. active와 pending은 서로 다른 시점의 최대값일 수 있으므로 두 수를 합산해 동시 작업 수로 해석하지 않습니다.

Primary 상실 뒤 DB 승격과 접속 준비

그림 3 — DB가 승격된 시각과 Proxy로 읽을 수 있는 시각을 분리

두 Standby pause → 고정 10초 대기 → Primary 종료 확인
                                              │
                  ┌───────────────────────────┴─────────────┐
                  ▼                                         ▼
             local 조건                                  on 조건
     19.372초: native 승격 관측                 19.191초: native 승격 관측
     25.158초: Proxy Primary 읽기 확인           20.963초: Proxy Primary 읽기 확인
                  │                                         │
                  └───────── 최초 성공 키 감사 ────────────────┘
                                │
                      감사 완료 후 불명 요청 재확정

중단창 독립 204: local 3건 / on 0건
최초 성공 키 누락: 두 조건 모두 0건
이전 Primary: 중지 상태 유지

위 시간은 Primary 종료 확인 시각 기준의 관측값이며 폴링·접속 확인 비용을 포함합니다. 전체 서비스 RTO나 정확한 Proxy 내부 처리 지연으로 해석하지 않습니다.

기본 CI 실행은 backend·frontend가 통과했습니다. 수동 장애 시험의 근거는 실행별 원장이며 기본 CI와 구분합니다. CodeRabbit은 수동 검토 요구로 리뷰를 건너뛰었습니다.

검증 과정에서 확인된 사항

준비·관측 경계 보완

회차 확인한 사항 대응과 최종 비교에서의 취급
mixed-run01 최초 성공 키 감사 뒤 전용 SSH 채널 3개가 종료되어 재확정·최종 감사를 완료하지 못함. 첫 SyncRep 조회의 DB 이름 필터도 부정확 해당 회차는 통과 집계에서 제외. 잘못된 조회는 무효로 표시하고 별도 접속 진단·복구 기록 보존
mixed-run02 네 조건은 통과했지만 짧은 2초 Primary 대기창 안에서 local 완료 표본이 0건 ACK 두 조건을 대표 비교로 사용. Primary 결과도 보존하되 완료 표본을 관측할 수 있도록 별도 10초 회차 수행
mixed-run03 10초 창에서 local 완료를 관측했으나 승격 직후 Proxy AllServersDown으로 최초 감사를 완료하지 못함 해당 회차는 미완료 판정 유지. 별도 읽기 전용 사후 감사에서 회수 2/2·독립 5/5 존재 확인. 재확정 쓰기를 하지 않았고 전체 회차 통과로 바꾸지 않음
mixed-run04 준비 점검 중 전용 채널 종료 업무 요청·장애 주입 전 종료. 비교 집계에서 제외
mixed-run05 활성 세션에서 채널을 유지하고 Proxy 읽기 준비 확인 후 Primary 두 조건 수행 두 조건 모두 합격 기준 통과. 대표 Primary 비교에 사용

DB 승격과 Proxy 읽기 준비가 다를 수 있어 실제 Primary 읽기 확인 단계를 추가했습니다. Hikari 복구 지연에는 감사 읽기만 최대 45초 재시도하며, 최초 성공 키 감사를 끝내기 전에 업무 재확정을 실행하지 않습니다. 이 보완은 시험 관측 절차이며 운영 코드 수정은 아닙니다.

전용 SSH 채널이 종료된 정확한 원인은 미확정입니다. run05의 완료를 원인 규명·제품 결함 수정으로 표현하지 않습니다. 원시 회차 기록은 덮어쓰거나 사후 재구성하지 않았습니다.

결과 해석 시 주의할 점

  • local 성공 데이터 유실은 관측되지 않았습니다. 컨테이너 pause는 커널 TCP 전송·소켓 버퍼까지 차단하지 않으므로, WAL이 미리 전달됐다가 재개 후 처리될 가능성이 있습니다. 다만 패킷·버퍼를 계측하지 않아 실제 보존 원인을 확정하지 않았습니다.
  • 따라서 local의 내구성, RPO 0, 네트워크 단절 시 무손실을 입증한 결과가 아닙니다. 수신 버퍼 폐기·네트워크 분리 시험은 실행하지 않았습니다.
  • requests.jsonl의 configured_mode는 그 회차의 독립 쓰기 정책입니다. 회수 행에 local로 표시돼도 실제 회수는 Facade에서 항상 on입니다. observed_mode는 독립 204에서 읽은 실제 설정입니다.
  • 원본 OpenProxy의 동기 역할 직접 지원·이전 Primary 자동 재합류·실제 Worker 부하·모델·GCS·공개 브라우저는 이번 검증 범위가 아닙니다.
  • 결론은 독립 local의 제한적인 진행 효과와 공유 풀 대기의 잔존을 관측했다는 것입니다. 운영 정책을 local로 바꾸기로 결정한 PR은 아닙니다.

자원 정리와 공개 환경 보존

최종 정리 원장 기준 2026-10-17 15:12:53 KST 정리 완료입니다. 시험 DB 3개·시험 Proxy 1개·로컬 Valkey 1개, 확인된 시험 이미지·데이터·시험 DCS·전용 터널·런타임 비밀을 제거했습니다.

공개 설정 해시와 동기 모드/strict는 그대로이며, 공개 클러스터 리더 1대·streaming Standby 2대를 확인했습니다. 기존 VM과 원래 터널은 유지했고 새 OS Login 키·IAM 변경은 0건입니다. 소유가 불명확한 이미지 캐시는 정리 대상에서 제외했습니다.

@Gimini-3
Gimini-3 requested a review from kangcheolung October 17, 2026 06:14
@coderabbitai

coderabbitai Bot commented Oct 17, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: Repository: DocGrid/docgrid/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 43bd5a0f-25aa-4c04-a132-2725a7f64db3
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Gimini-3 Gimini-3 left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

자체 수동 검토 기록

대상 HEAD: 777534a940783114f23a1da0a959da7d5f903655.

검토 경계 확인
범위 backend/src/main 변경0. 수동 시험·태그·문서/원장만 추가. 시험 독립 Controller는 src/test의 TestComponent
격리 전용 loopback URL과 실제 PG 포트·Primary·namespace/라벨 guard. 공개 설정 불변·공개 leader1/streaming2 최종 확인
한 변수 비교 ACK는 run02 안에서, Primary는 run05 안에서 같은 코드·풀5·동시8·종류별24. 회수는 on 고정, 독립만 on/local
감사 순서 최초 성공 UUID를 먼저 감사. 불명만 같은 키 assertion WAL로 재확정. 감사 연결 재시도는 읽기만 수행
실제 계측 원시 요청/풀/제어 원장과 집계 재대조. 최초 성공79 누락0, 불명113 재확정. 독립 중단창 on0/local5, 최대 pool pending8/8
실패 보존 run01/04 채널 실패와 run03 Proxy 준비 실패 보존. 실패 회차를 성공으로 변경하지 않음
주장 한계 MockMvc와 #544의 실제 HTTP 구분. local 유실 미재현·커널 버퍼 미차단·어댑터 경유·옛 Primary 재합류 미검증 명시
정리·민감값 시험 컨테이너/알려진 이미지/데이터/DCS/Valkey/전용 채널/비밀 파일 제거. 사전·최종 검사 발견0. 기존 VM/터널 유지

현재 검토에서 병합을 막을 코드/증거 불일치는 발견하지 않았습니다. 동료의 승인으로 대신 표현하지 않으며, 진행 중인 backend/frontend CI가 통과한 정확한 HEAD를 확인한 뒤 병합합니다.

@Gimini-3

Copy link
Copy Markdown
Contributor Author

최종 CI 확인: HEAD 777534a940783114f23a1da0a959da7d5f903655와 통과한 PR HEAD가 일치합니다.

  • CI 실행: backend·frontend 모두 성공.
  • 업로드된 backend XML 251개 suite를 메모리에서 집계: 총 1501건, 실패 0건, 오류 0건, 건너뜀 5건(실행 통과 1496건).
  • 수동 클라우드 시험 태그는 기본 CI와 분리되어 있으며 실제 실행 결과·실패·정리 원장은 PR 본문의 결과 문서에 있습니다.
  • 자체 수동 검토와 위 CI를 확인한 이 HEAD를 병합합니다.

@Gimini-3
Gimini-3 merged commit 39dbfb9 into develop Oct 17, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Test] 동기 권한 회수와 독립 쓰기의 on·local 혼합 부하 비교

1 participant