bluetape4k-dependencies 2.0.0 활용기 Part 4: 운영 진단과 안전한 실패

운영 중인 시스템은 항상 답을 주지 않습니다. Backend가 상태 조회를 지원하지 않을 수도 있고, 저장된 이력이 손상됐을 수도 있으며, 입력이 너무 커서 안전하게 해석할 수 없을 수도 있습니다. 이때 편리한 기본값으로 바꾸거나 일부 결과만 반환하면 장애가 정상처럼 보입니다.
bluetape4k-dependencies 2.0.0이
선택한 bluetape4k-leader 1.0.0,
bluetape4k-javers 1.0.0,
bluetape4k-image 1.0.0,
bluetape4k-text 1.0.0은
이런 상태를 서로 다른 경계로 다룹니다.
모르는 상태를 정상처럼 취급하지 않는다
섹션 제목: “모르는 상태를 정상처럼 취급하지 않는다”운영 API가 돌려줄 수 있는 상태는 단순한 성공과 실패만이 아닙니다.
| 상태 | 뜻 | 운영 동작 |
|---|---|---|
| 정상 | 현재 조건을 직접 확인했다 | 지표와 health 결과를 정상으로 해석한다 |
| 비정상 | 실패 조건을 직접 확인했다 | 경고하고 복구 절차를 실행한다 |
| 알 수 없음 | 확인할 수 없거나 확인 과정이 실패했다 | 정상으로 승격하지 않고 원인을 제한된 값으로 노출한다 |
| 손상 | 영속 자료의 불변식이 깨졌다 | 일부 결과를 반환하지 않고 처리를 중단한다 |
| 미지원 | Provider 또는 런타임이 기능을 제공하지 않는다 | 대체 경로를 명시적으로 선택하거나 기능을 끈다 |
UNKNOWN과 손상은 같은 상태가 아닙니다. 전자는 관측의 한계이고, 후자는 확인된 불변식 위반입니다. 따라서 경보, 재시도,
트래픽 라우팅도 서로 달라야 합니다.
Leader의 bounded UNKNOWN
섹션 제목: “Leader의 bounded UNKNOWN”Leader 1.0.0은 LeaderBackendDiagnosticsProbe를 공통 계약으로 두고 backend 연결 상태를 능동적으로 확인합니다.
확인할 수 없을 때는 자유 형식 예외 문자열을 메트릭 레이블로 내보내지 않고 다음과 같이 정해진 사유 코드를 사용합니다.
CLIENT_STATE_UNCONFIRMED: 클라이언트 상태만으로 연결을 확정할 수 없습니다.PROVIDER_UNSUPPORTED: 선택한 provider가 능동 진단을 지원하지 않습니다.PROVIDER_EXCEPTION: 진단 호출 자체가 실패했습니다.
이 값들은 Spring health, Ktor 관리 route, Micrometer counter, Prometheus 경보와 runbook까지 같은 의미로 이어집니다. 제한된
분류 덕분에 원인은 보존하면서도 태그 카디널리티가 예외 메시지 수만큼 늘지 않습니다. UNKNOWN을 UP으로 바꾸지 않는 것이
중요합니다. 운영자는 아직 확인되지 않은 상태와 실제 정상 상태를 구분할 수 있어야 합니다.
Javers 감사 체인은 손상되면 멈춘다
섹션 제목: “Javers 감사 체인은 손상되면 멈춘다”Javers 1.0.0은 Spring Boot 자동 구성에서 schema 소유권과 상충하는 flag 조합을 시작할 때 검증합니다. 여러 구성 요소가 같은 schema를 관리한다고 주장하면 애플리케이션을 띄운 뒤 충돌하도록 두지 않고 먼저 실패합니다.
Redis repository의 audit head도 같은 원칙을 따릅니다. Head가 손상되거나 이전 값으로 되감긴 경우, 읽을 수 있는 범위까지만 조용히 반환하면 이력이 짧아진 사실을 숨기게 됩니다. 1.0.0은 이때 감사 이력을 축소하지 않고 fail-closed로 중단합니다. 복구 담당자는 저장소 원본과 오류를 확인한 뒤 별도의 절차로 이력을 복원해야 합니다.
expected head: 418observed head: 271decision: stop and report corruptionnot: return revisions 1..271 as complete history감사 자료에서는 부분 성공보다 결손의 가시성이 더 중요합니다. Benchmark와 CI의 첫 시도 실패도 재현 가능한 JSON receipt로 남기는 이유가 같습니다.
Image 런타임 객체와 영속 데이터
섹션 제목: “Image 런타임 객체와 영속 데이터”Image 1.0.0은 privacy pipeline의 런타임 객체와 Spring storage/CDN collaborator에서 허위 Serializable 계약을
제거했습니다. 클라이언트나 서비스 객체가 직렬화 가능하다고 선언돼 있어도 실제 상태, 자격 증명, native handle까지 안전하게
복원되는 것은 아니기 때문입니다.
대신 영속해야 하는 값에는 Jackson 3 기반 schemaVersion=1 codec을 제공합니다. Decode는 입력 크기를 제한하고,
byte array와 collection은 방어적으로 복사합니다. 기존 Java serialization 사용자는 런타임 객체를 저장하지 말고
PrivacyDerivativePayload, report, batch용 영속 표현으로 이동해야 합니다.
이 구분은 향후 변경에도 중요합니다.
- 런타임 collaborator: 프로세스 안에서만 사용하고 수명주기를 명시적으로 관리합니다.
- 버전 관리 데이터: schema version, 크기 제한, 복사 정책을 가진 codec으로 저장합니다.
- 외부 입력: decode 전에 byte 수와 decoded dimension을 검증합니다.
PaddleOCR 모델 다운로드와 ONNX production backend도 기능을 구현할 수 있다는 이유만으로 활성화하지 않았습니다. 라이선스,
변경 불가능한 아티팩트, producer provenance, offline receipt가 준비될 때까지 결정은 DEFER입니다. 미지원 기능을 지원한다고
표시하는 것보다 보류 조건을 남기는 편이 안전합니다.
Text 모델 초기화 비용을 선택한다
섹션 제목: “Text 모델 초기화 비용을 선택한다”Text 1.0.0의 Lingua 혼합 언어 예제는 detector를 입력마다 만들지 않습니다. Pipeline 밖에서 한 번 생성한 뒤 여러 입력에 재사용합니다. 모델 준비 비용과 객체 수명을 호출 경계에서 분리한 것입니다.
모델 로딩 정책은 배포 환경에 따라 고릅니다.
| 정책 | 장점 | 비용과 적합한 환경 |
|---|---|---|
preload | 첫 요청의 지연을 예측하기 쉽다 | 시작 시간과 초기 메모리를 감당할 수 있는 상시 서비스 |
lazy | 시작이 빠르고 사용하지 않는 모델을 피한다 | 첫 사용 지연을 허용하는 간헐적 작업 |
두 경로가 같은 결과를 내는지는 예제 테스트로 확인합니다. 어느 쪽이든 detector 재사용이 기본이며, 요청마다 무거운 모델을 초기화하는 방식은 처리량과 tail latency를 불필요하게 흔듭니다.
운영 판단표
섹션 제목: “운영 판단표”| 질문 | 안전한 기본값 | 피해야 할 해석 |
|---|---|---|
| Backend 상태를 확인하지 못했는가? | 정해진 UNKNOWN 사유 코드를 노출한다 | 정상으로 간주한다 |
| Audit head가 손상되거나 되감겼는가? | 읽기를 중단하고 복구를 요구한다 | 남은 일부 이력을 전체처럼 반환한다 |
| 런타임 객체를 재시작 뒤 복원해야 하는가? | 필요한 값만 버전 관리 데이터로 저장한다 | collaborator 전체를 Java serialization한다 |
| 외부 이미지 페이로드를 decode하는가? | encoded size와 decoded dimension을 제한한다 | 메모리가 허용하는 만큼 읽는다 |
| 새 ML backend의 provenance가 부족한가? | 조건을 기록하고 DEFER한다 | 실험 결과만으로 production을 활성화한다 |
| 언어 detector를 반복 사용하는가? | 하나를 재사용하고 preload/lazy를 선택한다 | 요청마다 모델을 다시 만든다 |
안전한 실패는 모든 예외를 잡는 기법이 아닙니다. 정상, 확인 불가, 손상, 미지원이라는 상태를 보존하고 각 상태의 다음 행동을 호출자와 운영자에게 넘기는 계약입니다.
댓글
GitHub 계정으로 의견을 남기거나 reaction을 남길 수 있습니다.