속도를 위한 설계: 스키마 없는 이벤트 수집을 위한 근거

SchemaBridge Team · 2025-12-08 · Event Ingestion, JSON, DX

이벤트 기반 시스템에서 속도 대 엄격한 타입. 우리가 엄격한 타입 정의 대신 원시 JSON을 선택한 이유.

스키마의 역설: 친구인가 적인가?

전통적인 엔터프라이즈 소프트웨어에서 엄격한 스키마(SQL, Protobuf, WSDL)는 신뢰성의 초석입니다. 계약은 단순합니다: 나는 데이터의 형태를 정의하고, 당신은 그것을 준수하며, 컴파일러는 우리가 크래시하지 않을 것을 보장합니다. 이 접근 방식은 파이프의 양쪽을 모두 소유하는 통제된 환경에서 수십 년간 우리에게 훌륭히 봉사해 왔습니다. 이는 컴파일 시점 안전성, 효율적인 바이너리 직렬화, 개발자를 위한 명확한 "진실의 원천"을 제공합니다.

하지만 SaaS 벤더가 매주 페이로드를 바꾸고, 레거시 ERP가 "유연한" CSV를 뱉어내며, 내부 마이크로서비스가 매달 생겨났다 사라지는 현대의 고속 통합 환경에서는, 경직된 스키마가 구속복(Straitjacket)이 됩니다. 이들은 관성(Inertia)이라는 대가를 치르고 안전을 제공합니다. 주변 세계가 유동적일 때, 경직된 계약은 토대가 아니라 장애 지점입니다. 스키마의 역설은 이것입니다: 엄격한 타입으로 시스템을 보호하려 할수록, 외부 세계가 변할 때 시스템은 더 취약해집니다.

역사적 진화: COBOL에서 JSON까지

스키마 없는 시스템에 대한 요구를 이해하려면, 데이터 교환의 진화 과정을 살펴봐야 합니다. 메인프레임 컴퓨팅 초창기에는 데이터가 고정 길이 레코드(COBOL COPYBOOK)로 저장되었습니다. 필드를 추가하려면 해당 레코드를 읽는 모든 프로그램을 다시 컴파일해야 했습니다. 궁극의 경직된 스키마였습니다. 이는 "단일 머신 사고방식"의 시대였고, 데이터 저장 비용이 너무 높아 모든 바이트가 고정된 위치에서 설명되어야 했습니다. 계층 구조를 위한 여지도, 선택성을 위한 여지도, 그리고 확실히 진화를 위한 여지도 없었습니다. 레코드의 모든 문자는 소중한 자원이었고, 어떤 변경이든 몇 주간의 계획과 테스트를 필요로 하는 지각변동급 사건이었습니다.

1980~90년대에는 관계형 데이터베이스와 SQL로 옮겨갔습니다. 구조화된 관계라는 개념을 도입한 거대한 진전이었습니다. 하지만 이는 동시에 데이터베이스 마이그레이션이라는 문제를 가져왔습니다. 컬럼을 추가하는 것은 다운타임, 테이블 락, DBA와 개발자 간의 세심한 조율을 의미했습니다. 스키마는 여전히 개발자가 혁신을 원할 때마다 넘어야 하는 벽이었습니다. Hibernate 같은 ORM이 등장한 이후에도, 테이블 구조의 근본적인 경직성은 무엇이 가능한지를 결정하는 최종 심판자로 남아 있었습니다.

이후 90년대 후반에 XMLSOAP이 등장했습니다. 이는 "태그"라는 개념을 도입해 어느 정도의 유연성을 허용했습니다. 파서를 반드시 깨뜨리지 않고도 XML 태그를 추가할 수 있었습니다. 하지만 업계는 곧 XSD(XML Schema Definition)WSDL을 추가했고, 이는 경직성을 다시 불러왔습니다. 우리는 네임스페이스와 씨름하고, 메시지의 문자 하나만 잘못되어도 거부하는 복잡한 엔터프라이즈 서비스 버스와 씨름하며 몇 년을 보냈습니다. 스키마의 오버헤드가 실제 데이터보다 더 많은 대역폭을 소모하던 "XML의 암흑기"였습니다.

오늘날 우리는 JSONREST를 가지고 있습니다. JSON은 본질적으로 유연합니다. 그저 키와 값의 맵일 뿐입니다. 그럼에도 우리의 엔지니어링 본능은 여전히 그 유연성을 엄격한 타입(TypeScript 인터페이스, Java DTO, Avro 스키마)으로 감싸도록 몰아붙입니다. 우리는 1970년대 메인프레임의 경직성을 2020년대 클라우드 이벤트에 강요하려 하고 있습니다. 왜일까요? 미지의 것을 두려워하기 때문입니다. 누락된 필드가 서비스를 크래시시킬까 봐 두려운 것입니다. 하지만 앞으로 살펴보겠지만, 이 두려움은 잘못된 도구로 다뤄지고 있습니다.

재무 분석: 통합 유지보수의 "숨겨진 세금"

스키마 경직성의 비용을 정량화해 봅시다. 중대형 규모의 엔지니어링 조직에서 통합 유지보수는 "조용한 위기"입니다. 대차대조표에 항목으로 나타나지는 않지만, 생산성에 막대한 부담을 줍니다.

유지보수의 수학

어떤 조직이 100개의 외부 SaaS 통합을 보유하고 있다고 가정해 봅시다.

급여 기준으로 환산하면, 연간 15만 달러 이상이 오직 "배관 수리"에만 쓰이는 셈입니다. 하지만 진정한 비용은 기회비용입니다. 시니어 엔지니어들이 Stripe v2025 업데이트에 맞춰 DTO를 수정하는 동안, 그들은 회사에 수백만 달러를 절약해 줄 수 있는 새로운 자동 사기 탐지 기능을 만들고 있지 않습니다. 5년이라는 기간 동안, 이 세금은 더 민첩한 경쟁사에 비해 회사를 몇 년씩 뒤처지게 만드는 속도의 누적 손실로 이어질 수 있습니다.

데이터 유동성의 철학: 읽기 시점 스키마

SchemaBridge에서는 사고방식의 근본적인 전환을 옹호합니다: 읽기 시점 스키마(Schema-on-Read).

데이터를 진입 시점에 검증하는 대신(쓰기 시점 스키마, Schema-on-Write), 우리는 먼저 이벤트의 원시적이고 계층적인 진실을 수집합니다. 우리는 영속적 저장소에 JSON 페이로드의 모든 바이트를 보존합니다. 특정 비즈니스 프로세스에 의해 데이터가 필요해지는 순간에만 스키마—더 정확히는 변환(Transformation)—를 적용합니다.

데이터 유동성이 승리하는 이유

1. 무개입 수집: 새로운 프로바이더로부터 몇 초 만에 이벤트를 받기 시작할 수 있습니다. Webhook을 SchemaBridge 게이트웨이로 가리키면, 데이터가 즉시 영속적 저장소로 흘러 들어가기 시작합니다. 데이터가 무엇을 의미하는지는 나중에 알아낼 수 있습니다.

2. 미지의 것에 대한 보험: 오늘 프로바이더가 필요 없는 필드를 추가하더라도, 여전히 원시 JSON에 캡처됩니다. 6개월 후에 그 필드가 실제로 필요하다는 것을 깨닫는다 해도, 과거 데이터는 이미 그곳에 있습니다. 프로바이더에게 오래된 데이터를 다시 요청할 필요가 없습니다.

3. 결합되지 않은 진화: 수집 계층과 변환 계층은 서로 다른 속도로 진화할 수 있습니다. 수집 게이트웨이를 건드리지 않고도 비즈니스 로직을 하루에 10번 업데이트할 수 있습니다.

지연 바인딩(Late-Binding)에 대한 수학적 근거

컴퓨터 과학에서 지연 바인딩(Late-Binding)이란 아이덴티티나 타입의 결정을 실행 시점까지 미루는 관행입니다. 이것이 Ruby나 Python 같은 동적 언어가 특정 작업에서 그토록 강력한 이유입니다.

읽기 시점 스키마는 데이터 인프라에 적용된 지연 바인딩입니다. 매핑을 지연시킴으로써, 여러분은 모든 변경이 전체 재빌드를 요구하는 경직된 그래프에서, 경로가 이동하며 지형에 적응할 수 있는 유연한 경로로 옮겨갑니다.

수학적으로, $N$개의 생산자와 $M$개의 소비자 사이의 잠재적 매핑 수는 $N \times M$입니다. 모든 생산자와 소비자가 엄격한 스키마에 동의해야 한다면, 거대한 조율 문제가 발생합니다. 지연 바인딩을 사용하는 스키마 없는 브릿지를 사용하면, 이 문제를 $N + M$개의 매핑으로 줄일 수 있으며, 각 매핑은 로컬이고 독립적입니다. 이것이 진정한 수평적 엔지니어링 스케일을 달성하는 방법입니다.

JSONata: 함수형 이벤트 처리 마스터클래스

읽기 시점 스키마를 실용적으로 만들려면, 발견(discovery)을 위해 설계된 언어가 필요합니다. 우리는 JSONata를 선택했습니다. JSONata는 단순한 쿼리 언어가 아니라, 원시 JSON 계층 구조에 직접 작동하는 함수형 변환 엔진입니다.

JSONata 표현식의 해부

주문 목록을 반환하는 레거시 ERP의 페이로드를 생각해 보세요. 각 주문은 복잡하고 중첩된 구조를 가지고 있습니다. $500 이상이면서 현재 'SHIPPING' 상태인 주문의 모든 부품 번호를 추출하고 싶습니다.

전통적인 코드 (JavaScript):

const parts = payload.orders
  .filter(o => o.total > 500 && o.status === 'SHIPPING')
  .flatMap(o => o.items)
  .map(i => i.partNumber);

이 코드는 취약합니다. orders가 null이거나 한 주문에 items가 없으면 크래시합니다.

JSONata의 숙련도:

orders[total > 500][status = 'SHIPPING'].items.partNumber

이 표현식은 Null 안전(Null-Safe)합니다. orders가 없으면 결과는 단순히 빈 배열입니다. 절대 예외를 던지지 않습니다. 데이터를 "단정"하는 대신 "발견"합니다.

고급 패턴: 깊은 하위 요소 선택

JSONata의 가장 강력한 기능 중 하나는 ** 연산자입니다. 이는 계층 구조 어디에 있든 상관없이 특정 키를 찾을 수 있게 해줍니다.

$**.tracking_number

다운스트림 프로바이더들이 추적 번호에 대해 서로 다른 중첩 구조를 사용한다면, 이 하나의 표현식이 모든 서로 다른 페이로드 버전에서 이들을 모두 찾아낼 것입니다. 이것이 구조적 회복력(Structural Resilience)의 정의입니다. 특정 키를 찾는 취약한 사냥을, 진실을 찾는 유연한 검색으로 바꿔줍니다.

고급 패턴: 즉석에서의 데이터 재구성

JSONata를 사용하면 전체 JSON 객체를 단 한 번의 패스로 재구성할 수 있습니다.

orders.{ "order_id": ID, "summary": $join(items.name, ', ') }

전통적인 코드에서는 이를 위해 객체 매핑, 문자열 연결, 배열 순회가 필요합니다. JSONata에서는 원하는 상태에 대한 선언적 투영일 뿐입니다. 이는 복잡한 이벤트의 단순화된 요약을 Slack 알림이나 모바일 앱에 보내야 할 때 특히 강력합니다.

테이블 없는 데이터의 운영화: 보안과 검증

비판적인 사람들은 종종 이렇게 묻습니다: "스키마를 사용하지 않는다면, 쓰레기 데이터가 시스템에 들어오는 것을 어떻게 막나요?"

답은 스키마 없음이 검증 없음을 의미하지 않는다는 것입니다. 우리는 단지 검증을 버텍스 수준으로 옮길 뿐입니다.

사례 연구: 50개 리전 데이터 수집 메시

우리는 최근 50개의 서로 다른 리전에서 원격 측정 데이터를 수집하던 글로벌 IoT 기업과 협업했습니다. 각 리전은 센서 펌웨어의 조금씩 다른 버전을 사용하고 있었습니다. 모든 리전은 자신만의 JSON "방언"을 가지고 있었습니다.

과제

그들은 엄격한 테이블 스키마를 가진 전통적인 SQL 기반 수집 시스템을 사용하려 했습니다. 한 국가에서 펌웨어 업데이트가 롤아웃될 때마다, 새 펌웨어가 데이터베이스에 컬럼이 없는 battery_health_v2 필드를 추가하면서 해당 국가 전체의 수집 파이프라인이 깨졌습니다. 데이터 팀은 50개의 프로덕션 데이터베이스에 걸쳐 ALTER TABLE 명령을 실행하며 끊임없이 "소방수" 모드에 있었습니다. 이러한 유지보수 시간 동안 수백만 개의 이벤트를 잃고 있었습니다.

SchemaBridge 솔루션

그들은 스키마 없는 전략으로 전환했습니다.

1. 범용 캡처: 50개 리전 모두 자신들의 데이터를 단일 SchemaBridge 게이트웨이 클러스터로 보냈습니다. 게이트웨이는 스키마에 관심이 없었습니다. 그저 원시 이벤트를 영속화할 뿐이었습니다.

2. 읽기 시점 매핑: 그들은 50개의 서로 다른 "정규화 버텍스"(펌웨어 버전당 하나씩)를 만들었습니다. 워크플로는 헤더에서 펌웨어 버전을 식별해 원시 JSON을 올바른 버텍스로 라우팅했습니다.

3. 노코드 업그레이드: 새 펌웨어 버전이 출시되면, 데이터베이스를 업데이트할 필요가 없었습니다. 그저 기존 버텍스를 복제하고, JSONata 매핑을 업데이트해 새 필드를 포함시킨 뒤 배포했습니다.

결과

결론: 속도는 설계상의 선택이다

엄격한 스키마는 하나의 선택입니다. 동적인 속도보다 정적인 안전을 우선시하는 선택입니다. 폐쇄된 시스템에서는 그것이 타당한 선택입니다. 연결되고 분산된 생태계에서는, 그것이 실패로 이어지는 선택입니다.

세상이 실제로 그러하듯이—예측 불가능하고, 진화하며, 계층적인—시스템을 설계하세요. 속도를 위해 설계하세요. SchemaBridge와 함께 설계하세요. 데이터의 유동성을 받아들임으로써, 경직된 DTO와 데이터베이스 마이그레이션에 갇힌 경쟁사들이 꿈만 꿀 수 있는 속도로 구축하고, 확장하고, 혁신할 수 있는 능력을 얻게 됩니다.

3부에서는 수집에서 실행으로 넘어가, "Spawner" 버텍스와 1만 개 이상 규모의 분산 팬아웃을 마스터하는 방법을 탐구합니다. 서버를 크래시시키거나 단 하나의 트랜잭션도 잃지 않고 수백만 개의 이벤트를 처리하는 방법을 함께 살펴봅니다. 분산 맥락에서 루프의 힘을 되찾는 여정입니다.

살펴보기