데이터 웨어하우스가 금융 감사(Financial Audits)에 충분하지 않은 이유
요약
데이터 웨어하우스의 시점 복구 기능만으로는 금융 감사의 엄격한 규제 요구사항을 충족하기 어렵습니다. 단순한 타임 트래블을 넘어 데이터 변조 방지와 완벽한 감사 추적을 위한 아키텍처 설계의 중요성을 강조합니다.
핵심 포인트
- 데이터 웨어하우스의 시점 복구는 스키마 및 변환 코드 버전까지 보장하지 않음
- 금융 규제(FINRA, Basel III 등) 대응을 위해서는 단순 데이터 존재 이상의 감사 추적 필요
- 데이터베이스 네이티브 버전 관리와 이벤트 소싱 불변 로그 방식의 차이 이해
- Apache Iceberg나 Hudi를 활용한 불변 로그 아키텍처가 대안으로 제시됨
만약 당신의 데이터 웨어하우스(Data Warehouse)가 제공하는 "특정 시점(point-in-time)" 복구가 금융 감사(Financial Audit)에 충분하다고 생각한다면, 당신은 잘못된 조인(join) 한 번으로 규제상의 악몽을 맞이할 수 있습니다.
우리 모두가 경험해 본 상황입니다. 감사인이 지난달 14일 오후 2시 당시의 대출 포트폴리오 상태를 요구합니다. 당신은 Snowflake의 AT 절이나 Databricks의 AS OF 타임스탬프(timestamp)를 가리키며 상황을 해결했다고 생각할 것입니다. 하지만 그들은 스키마 정의(schema definition), 기반이 되는 변환 코드(transformation code) 버전, 그리고 스냅샷(snapshot)이 찍히기 전에 데이터가 잘못된 UPDATE 문에 의해 변조되지 않았다는 증거를 요구합니다. 갑자기 당신의 "타임 트래블(Time Travel)" 기능은 만능 해결책이 아니라, 그 역사 자체가 조작되었는지 알지 못한 채 과거의 한 지점을 바라보는 수단일 뿐이라는 사실을 깨닫게 됩니다.
FINRA, HIPAA 또는 바젤 III(Basel III) 규정을 다룰 때, "데이터베이스에 있습니다"라는 말은 감사 추적(audit trail)이 아닙니다. 그것은 부채(liability)입니다.
대안들
당신은 근본적으로 다른 두 가지 아키텍처 사이에서 선택해야 합니다. 첫 번째는 Snowflake(Time Travel)나 Databricks(Delta Lake Time Travel)와 같은 현대적인 클라우드 데이터 웨어하우스의 내장된 시계열 기능(temporal capabilities)에 의존하는 **데이터베이스 네이티브 버전 관리(Database-Native Versioning)**입니다. 이것은 "쉬운" 경로입니다.
두 번째는 데이터 레이크(data lake)를 원장(ledger)처럼 취급하는 **이벤트 소싱 불변 로그(Event-Sourced Immutable Logs)**입니다. 행(row)을 절대 업데이트하지 않고 변경 사항만 추가(append)합니다. 이것은 "어려운" 경로로, 보통 S3 위에 Apache Iceberg 또는 Hudi를 배치하고 엄격하게 강제되는 불변 스키마 레지스트리(immutable schema registry)를 결합하는 방식을 포함합니다.
Photo by Kelly Sikkema on Unsplash
운영 유지보수의 부담 (The burden of operational maintenance)
데이터베이스 네이티브 버전 관리(Database-native versioning)는 스토리지 비용을 직면할 때까지는 자유로워 보입니다. 만약 높은 변경 빈도(high-churn)를 가진 테이블, 예를 들어 일일 이자 계산 엔진이 있고 Snowflake의 DATA_RETENTION_TIME_IN_DAYS를 90일로 설정한다면, 현재 상태에 대해서만 비용을 지불하는 것이 아닙니다. 모든 MERGE 구문으로 생성되는 모든 블록 변경(block change)에 대해 비용을 지불하고 있는 것입니다. 대용량 금융 환경에서는 이 비용이 월별 스토리지 비용의 30%에서 50%를 추가합니다.
더 중요한 것은, 실패 모드가 조용하다는 점입니다. 보존 기간이 만료되면 데이터는 사라집니다. 복구할 방법이 없습니다. 감사관(auditor)이 91일 후에 찾아왔을 때, 당신은 왜
"재현 가능한 보고서 (reproducible report)"의 함정에 대해 이야기해 보겠습니다. 만약 당신이 오늘 보고서를 실행하여 1,000만 달러의 리스크 노출액 (risk exposure)을 확인했다면, 내일 동일한 쿼리를 실행했을 때 정확히 같은 숫자를 얻을 수 있습니까? 표준 데이터 웨어하우스 (standard warehouse)라면 가능할 수도 있습니다. 하지만 타임 트래블 (time travel) 기능이 있더라도, 기반이 되는 차원 테이블 (dimension tables)이 업데이트되었다면 조인 로직 (join logic)이 원래 실행 당시에는 보이지 않았던 다른 버전의 "고객 상태 (customer status)" 플래그를 가져올 수도 있습니다.
이를 해결하기 위해, 저는 규제 보고 (regulatory reporting)를 위해 표준 SQL 뷰 (SQL views)를 사용하는 방식에서 벗어났습니다. 대신, 우리는 "스냅샷 테이블 (Snapshot Tables)"을 사용합니다. 중요한 보고서가 생성될 때마다, 해당 계산에 사용된 원장 (ledger)의 정확한 하위 집합인 입력 데이터셋을 전용 audit_snapshots 스키마 (schema)에 기록합니다.
여기서 발생하는 비용은 저장 공간 (storage)이 아니라 컴퓨팅 (compute) 비용입니다. 본질적으로 ETL 파이프라인 (ETL pipeline)을 통해 이동하는 데이터의 양을 두 배로 늘리는 셈입니다. 20개의 노드로 구성된 Databricks 클러스터 (cluster)를 사용하는 운영 환경에서는 이 비용이 상당합니다. 하지만 이자 지급액이 4.3%가 아닌 4.2%로 계산된 이유를 두고 규제 기관과 논쟁할 때, 정확한 입력 상태를 스냅샷으로 저장해 두었는지 여부는 "경미한 지적 사항 (minor finding)"과 "업무 중단 명령 (cease and desist)"을 가르는 차이가 됩니다.
Photo by Marjan Blan on Unsplash
실패 모드 (Failure modes)와 "실수 (oops)" 요인
데이터베이스 네이티브 타임 트래블 (Time travel)의 가장 큰 실패 모드 (Failure mode)는 DDL 변경입니다. 만약 누군가 Snowflake에서 컬럼을 삭제하거나 테이블 이름을 변경한다면, 이전 상태로 "타임 트래블"할 수 있는 능력은 매우 취약해질 수 있습니다. 저는 한 번은 주니어 엔지니어가 금요일 오후에 운영 테이블의 컬럼 이름을 변경하는 것을 본 적이 있습니다. AS OF 쿼리는 기본 테이블 스키마 (Schema)가 더 이상 과거의 메타데이터 (Metadata)와 일치하지 않기 때문에 실패했습니다. 우리는 정보 스키마 (Information schema) 히스토리로부터 스키마를 재구축하느라 허둥대는 동안 4시간 동안 감사 가용성을 상실했습니다.
불변 로그 (Immutable logs)는 DDL 변경에 대해 이와는 다른 방식으로 대응합니다. 행 (Row)뿐만 아니라 파일 자체를 버전 관리하기 때문에, Iceberg의 add-column 또는 rename-column과 같은 스키마 진화 (Schema evolution) 도구를 사용하더라도 과거 데이터 파일을 읽는 능력을 깨뜨리지 않고 사용할 수 있습니다. 즉, _데이터_를 _쿼리 엔진의 현재 상태_로부터 분리(Decouple)할 수 있습니다.
표준 SQL 데이터베이스를 사용하고 있다면, 당신의 가장 큰 적은 UPDATE 또는 DELETE 문입니다. 타임 트래블 (Time Travel) 기능이 있더라도, 단 한 번의 TRUNCATE 명령으로 끔찍한 하루를 보낼 수 있습니다. 운영 스키마에 명시적인 RESTRICT 정책이 없다면, 누군가가 히스토리를 삭제할 것인가의 문제가 아니라, 언제 삭제할 것인가의 문제입니다.
내가 선택할 것, 그리고 그 이유
만약 당신이 스타트업이거나 규모가 작은 조직이라면, Snowflake/Databricks 샌드박스 (Sandbox) 안에 머무르십시오. 그들의 타임 트래블 (Time Travel) 기능을 사용하되, 제발 부탁이니 보관 기간 (Retention)을 해당 티어에서 허용하는 최대치로 설정하고, 예상치 못한 청구서에 당황하지 않도록 스토리지 비용에 명시적인 ALERT를 설정하십시오.
하지만 당신이 은행, 핀테크, 또는 의료와 같이 규제를 받는 분야에서 운영 중이라면, Iceberg 기반 아키텍처 (Architecture)로 이동해야 합니다.
저의 권장 사항은 다음과 같습니다: Silver 레이어가 엄격하게 추가 전용 (Append-only)인 "메달리온 아키텍처 (Medallion Architecture)"를 사용하십시오. 업데이트(Update)는 안 됩니다. 삭제(Delete)도 안 됩니다. 레코드를 수정해야 한다면, valid_from과 valid_to 타임스탬프 (Timestamp)를 가진 새로운 레코드를 삽입하십시오. 이렇게 하면 전체 데이터 플랫폼이 서서히 변하는 차원 (Slowly changing dimension, SCD Type 2) 원장 (Ledger)으로 변하게 됩니다.
주의할 점은 무엇일까요? 이는 쿼리 코드 (Query code)를 현저히 더 복잡하게 만든다는 것입니다. 개발자들은 모든 조인 (Join) 마다 WHERE CURRENT_TIMESTAMP BETWEEN valid_from AND valid_to를 작성해야 할 것입니다. 그들은 이를 매우 싫어할 것이며, 성능 (Performance)에 대해 불평할 것입니다.
의무 검토 (Mandatory review) 중에 고객의 리스크 프로필 (Risk profile) 변화를 시스템이 제대로 반영하지 못했을 때, 감사인 (Auditors)에게 자유롭게 불평하라고 그들에게 말하십시오. 성능 세금 (Performance tax)은 컴플라이언스 (Compliance, 준수)를 위한 비용입니다. 코드에서 이 비용을 지불하지 않는다면, 벌금으로 지불하게 될 것입니다.
Tags: #data #engineering #finance #audit
Cover photo by Albert Stoynov on Unsplash.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기