본문으로 건너뛰기

© 2026 Molayo

Zenn헤드라인2026. 06. 30. 09:16

"Cube"를 프로덕트 측의 '시맨틱 레이어(Semantic Layer)'로 만든 이야기

요약

회계 및 운영 데이터의 정확성과 실시간성을 보장하기 위해, 분석 기반(DWH)이 아닌 프로덕트 측(Operational DB)에 Cube를 활용한 시맨틱 레이어를 구축한 사례를 소개합니다. ETL 과정을 거치지 않고 기간 DB를 직접 집계하여 데이터 정합성 문제를 해결하고 업무 담당자의 자립을 도왔습니다.

핵심 포인트

  • 분석 기반(DWH) 대신 프로덕트 측에 시맨틱 레이어를 구축하여 데이터 정합성 확보
  • ETL 지연 및 변환 과정에서 발생할 수 있는 데이터 불일치 문제 해결
  • Cube의 Query Builder와 API를 활용해 비개발자도 리포트 생성 가능하도록 구현
  • 사전 집계 및 캐싱을 통해 기간 DB의 부하를 줄이고 쿼리 성능 최적화

TL;DR

  • 회계·운영 집계 데이터를 분석 기반(DWH/BI)이 아닌 프로덕트(기간 시스템 앱) 측의 시맨틱 레이어(Semantic Layer)로서 Cube로 구현했다.
  • 회계·운영은 정확한 숫자를 지금 즉시 필요로 한다는 전제가 있어, 분석 기반에서 ETL을 거치게 되면 리포트의 값이 실제 데이터와 일치하는지 정합성 검증을 하기 어려워진다. 그렇다고 실시간 분석 기반을 별도로 구축·운영하는 것도 수고와 비용이 많이 든다. 그래서 변환 전의 기간 데이터(operational DB)를 직접 집계하는 구성으로 했다.
  • 리포트를 만들려면 필요한 컬럼을 선택하고, 조건으로 필터링하며, 축(axis)으로 묶어 피벗(Pivot)하는 등 실질적으로 SQL에 가까운 조작이 필요하다. 이를 SQL을 작성할 수 없는 업무 담당자가 스스로 해낼 수 있도록 하고 싶었다.
  • Cube는 OSS(Open Source Software)로 간편하게 서버를 배포할 수 있으며, Query Builder UI도 표준으로 제공된다. 또한, measure / dimension으로 지표를 일원 정의하는 데이터 모델과 사전 집계 및 쿼리 캐시(Cube Store)를 통한 고속화와 기간 DB의 부하 경감, REST / GraphQL / SQL 등 다양한 API를 통한 배포 기능도 갖추고 있다. 이러한 점들이 위의 요구사항에 그대로 부합했기에, Cube를 UI와 함께 기간 앱에 통합했다.
  • 처음에는 동반 지원이 필요했지만, 머지않아 업무 담당자가 자립하여 100개 이상의 리포트가 자동으로 만들어지게 되었다.

서론

회계나 운영에서 사용하는 집계 데이터를 처음에는 분석 기반으로 가져가는 방식으로 만들었습니다. 하지만 이 숫자들에 요구되는 것은 "지금·정확하게·내가 보고 싶은 형태로"입니다. 분석 기반을 한 단계 거친 집계는 정합성이 때때로 깨지며, 깨졌을 때의 원인 규명도 어려워집니다. 그래서 기간 앱의 operational DB(Aurora PostgreSQL)에 Cube를 얹어, SQL을 작성할 수 없는 회계·운영 담당자가 스스로 집계 리포트를 구성할 수 있는 메커니즘을 만들었습니다.

먼저 한 가지만 보충하자면, 이 기사는 "분석용" 시맨틱 레이어(Semantic Layer)에 관한 이야기가 아닙니다. dbt Semantic Layer나 Looker, Databricks의 Metric Views처럼 분석 기반(DWH/BI) 위에 두는 것이 아니라, 그것을 프로덕트(기간 앱) 측으로 가져온 이야기입니다. 배경부터 Cube의 위치 설정, 구현, 운용까지 차례대로 써 내려가겠습니다.

왜 분석 기반을 경유해서는 잘 되지 않았는가

당초에는 집계를 분석 기반에 집중시키는 방침으로 생각했습니다. 하지만 회계·운영 현장의 요구사항을 마주하다 보니, 분석 기반을 경유하는 구성에는 몇 가지 무리가 있다는 것을 알게 되었습니다. 이유는 크게 4가지입니다.

첫 번째는 가장 컸던 데이터의 정확성과 실시간성입니다.

회계나 운영이 다루는 숫자는 나중에 반드시 "이 값이 정말 맞는가"라는 질문을 받게 됩니다. 결산 작업이나 일일 대조 시에는 리포트에 나오는 금액이나 건수가 기간 시스템상의 실제 데이터와 1원 단위, 1건 단위로 일치하는 것이 전제 조건입니다. 그런데 분석 기반을 경유하는 구성에서는 데이터가 ETL을 통해 한 번 추출되고, 가공·정형을 거친 뒤 DWH에 쌓입니다. 이 변환 과정이 한 단계 끼어드는 것만으로도 정합성 검증이 다소 어려워집니다. 리포트의 숫자가 실제 데이터와 어긋났을 때, 그것이 원본 데이터의 문제인지 아니면 ETL의 어느 지점에서 발생한 차이인지 구분해야 하며, 결국은 기간 데이터와 대조하여 확인하는 작업이 발생합니다. 검증을 위해 기간 데이터를 참조해야 한다면, 처음부터 기간 데이터를 집계하는 것이 합리적입니다.

실시간성도 근본적으로는 같은 문제입니다. ETL은 배치(Batch) 주기나 데이터 수집 타이밍에 좌우되기 때문에 필연적으로 지연이나 결손이 발생할 수 있습니다. "지금의 실제 데이터를 지금 즉시 올바른 형태로 보고 싶다"는 회계·운영의 요구에 대해, 수십 분 전이나 수 시간 전의 데이터밖에 제공할 수 없다면 맞지 않습니다.

분석 기반 측을 실시간으로 만드는 방법도 생각할 수 있지만, 그 경우에는 CDC나 스트리밍, 정합성을 유지하기 위한 메커니즘을 별도로 구축·운영해야 하므로 수고와 비용이 그에 상응하여 발생합니다. 회계·운영의 집계를 위해 그 정도의 기반을 새로 구축하는 것은 수지타산이 맞지 않았습니다.

이상을 종합하면, 가장 적합했던 것은 가공되기 전의 기간 데이터 그 자체를 직접 집계하는 방법이었습니다. 변환 과정을 거치지 않으면 정합성 검증은 실제 데이터와의 대조로 완결되며, 최신성도 자연스럽게 보장됩니다.

두 번째는 **집계의 유연성 (Flexibility of Aggregation)**입니다. 임의의 컬럼을 조합하고, Pivot으로 가로로 확장하며, 조건으로 필터링하는 작업. 이러한 요구사항은 리포트마다 조금씩 다릅니다. 그때마다 엔지니어가 SQL을 작성하여 준비하는 운영 방식은 현실적이지 않습니다.

세 번째는 주요 사용자가 SQL을 작성할 수 없는 사람이라는 점입니다. 이용자는 회계·운영 업무 담당자이며, 코드가 아닌 화면 조작을 통해 집계를 구성할 수 있는, 이른바 Visual한 Query Builder가 요구됩니다.

네 번째는 그 Query Builder를 Cube가 처음부터 갖추고 있다는 점입니다. Cube의 스키마에는 어떤 지표를 어떻게 보여줄지, 어떤 축으로 필터링할지 등의 메타데이터 (Metadata)를 기술할 수 있으며, 이를 그대로 화면에 전달할 수 있습니다.

이러한 점들을 고려하여 선택한 방침은, "분석 기반 옆에 또 하나의 집계 메커니즘을 두는 것"이 아니라, 이미 작동 중인 핵심 애플리케이션(Core App) 내부에 시맨틱 레이어 (Semantic Layer)를 통합하는 것입니다.

시맨틱 레이어와 Cube의 위치 선정

먼저, 시맨틱 레이어란 무엇인지 정리하겠습니다. 이는 로우 데이터 (Raw Data)와 이용자(사람·BI·AI) 사이에 서서 "지표와 의미를 통일하는 계층"입니다. 매출·수수료·건수와 같은 지표의 정의를 한 곳에 고정하여, 어디서 참조하더라도 동일한 의미로 반환되도록 합니다. 이것이 시맨틱 레이어의 역할입니다.

여기서 중요한 점은, 현재 시중에 나와 있는 대부분의 시맨틱 레이어는 분석 기반 (Analytics Platform) 측에 위치하고 있다는 것입니다. dbt Semantic Layer (MetricFlow)는 YAML과 Git으로 지표를 정의하는 코드 퍼스트 (Code-first) 방식이며, Looker의 LookML은 "semantic layer as code"의 원조 격인 존재이고, Databricks의 Metric Views는 Unity Catalog에 플랫폼으로서 통합되어 있습니다. 모두 DWH(Data Warehouse)나 BI를 전제로 한 설계입니다.

이와 대조적으로 Cube는 입지가 다릅니다. BI의 UI에 의존하지 않는 헤드리스 (Headless) 구성으로, REST·GraphQL·SQL 등 API 퍼스트 (API-first) 방식으로 집계 데이터를 제공할 수 있습니다. 사전 집계와 캐시 (Cube Store)를 갖추고 있으며, 셀프 호스팅용 Cube Core도 OSS (Open Source Software)로 공개되어 있습니다. 그리고 앞서 언급했듯이, Query Builder를 그대로 구성할 수 있는 메타데이터를 다룰 수 있습니다.

정말로 Cube가 요구사항에 맞았는가

이번 요구사항(핵심 데이터를 실시간으로 확인하고, 컬럼 선택·조건 필터링·Pivot과 같은 집계 조작을 SQL을 작성할 수 없는 사람이 Visual하게 수행하며, 자사 앱에 내장할 수 있음)에 대해, 다른 선택지들은 어떠한지 나열하여 비교해 보겠습니다.

선택지핵심 DB 실시간 확인집계 조작 (선택/필터링/Pivot)비 SQL 사용자용 Query Builder자사 앱 내장 / 셀프 호스팅도입·운영의 용이성
Cube○ (Cube Core는 OSS)
dbt Semantic Layer✕ (DWH 전제)✕ (UI 없음)✕ (dbt Cloud 전제)
Looker (LookML)△ (SaaS·유료)
...

Cube도 만능은 아닙니다. 도입·운영을 △로 표시한 것처럼, 스키마 정의는 실질적으로 SQL을 작성하는 것에 가까우며, 유지보수에도 상응하는 비용이 발생합니다 (이 점은 후반부의 운영 이야기와 직결됩니다).

다른 선택지들을 차례대로 살펴보겠습니다. dbt Semantic Layer나 Databricks의 Metric Views는 분석 인프라를 전제로 하기에, 우선 실시간성 측면에서 이번 요구사항과는 맞지 않습니다. Looker는 기능적으로는 유사하지만, SaaS 형태의 유료 서비스이며 자사 앱의 한 기능으로서 깊숙이 통합하기에는 무겁습니다. 마지막까지 비교 대상으로 남은 것은 BI 툴의 임베딩(Metabase나 Superset)입니다. 도입은 빠르고 Query Builder도 갖추고 있습니다. 하지만 지표 정의를 한 곳에 고정하고 앱에서 API로 참조하는 '시맨틱 레이어(Semantic Layer)로서의 사용법'에는 적합하지 않으며, 대시보드 용도로 벗어나기 어렵다는 제약이 있습니다. 자체 구현은 자유도가 높은 반면, Cube가 기본적으로 제공하는 기능들을 처음부터 만들어야 합니다. 쿼리 캐싱(Query Cache)이나 사전 집계(Pre-aggregation), 메타 정보로부터 Visual한 Query Builder를 구동하는 UI까지 모두 직접 구현하는 것은 비용 측면에서 현실적이지 않습니다. 이를 종합하여, Cube를 채택하는 것이 타당하다고 판단했습니다.

비교 결과, 「실시간 × 유연한 집계 × 비 SQL(Non-SQL)로도 사용 가능한 Query Builder × 자사 앱으로의 통합」을 동시에 ○로 만들 수 있는 것은 Cube뿐이었습니다. 운영의 편의성 측면에서의 △는 도입 초기 단계에 인력이 동반 지원한다는 전제하에 수용하기로 했습니다.

구현: 핵심 앱 내부에 시맨틱 레이어를 배치하기

여기서부터는 실제 구성을 설명하겠습니다. 앞서 언급한 4가지 과제에 구현의 어떤 요소가 대응하는지를 매칭하며 읽으시면 이해하기 쉬울 것입니다.

전체 구성은 다음과 같습니다.

포인트는 두 가지입니다. 사용자는 Cube를 직접 호출하지 않습니다. backend가 JWT를 발행하여 쿼리를 대리 실행하고, 결과값만 UI에 반환합니다. Cube의 API는 외부에 공개하지 않는 구성입니다. 또한, Cube가 참조하는 DB는 운영용(operational) DB에 대한 **읽기 전용(read-only) 역할(Role)**입니다.

이를 AWS 상에 올릴 때는 Cube와 Cube Store를 ECS(Fargate) 상의 컨테이너로 구동하며, 외부로 노출되지 않는 내부 ALB를 경유하여 앱 backend에서만 접근할 수 있도록 설정했습니다.

DB 접속 정보와 JWT 서명 키는 Secrets Manager로부터 기동 시에 주입합니다. 내부 ALB의 보안 그룹(Security Group)은 backend 태스크로부터의 통신만 허용하며, 외부에서는 도달할 수 없습니다.

데이터 모델: 업무 테이블을 measure / dimension으로 번역하기

Cube에서는 「업무 테이블 1개 = 1 cube」로 정의하며, measures(합계나 건수 등의 집계)와 dimensions(그룹화의 축)를 선언적으로 작성해 나갑니다. 여기서 핵심적인 역할을 하는 것이 각 dimension에 부여하는 업무 메타 정보입니다. 필터링이 가능한지, 어떤 마스터와 연결되는지, 어떤 UI로 보여줄지 등의 정보를 스키마 측에 작성해 두면, 그것이 그대로 Query Builder의 사양이 됩니다.

cube("Sales", {
sql_table: `SELECT * FROM sales`,
measures: {
...

실제로는 동일한 종류의 값이 한 행 안에 가로로 나열되어 반복되는 컬럼(예를 들어 '항목 1의 금액, 항목 2의 금액, 항목 3의 금액...'과 같이 번호가 붙어 나열된 열)이 수십 개 존재하며, 그 하나하나를 measure / dimension으로 정의해야 합니다. 수작업으로 나열하면 양이 방대해지기 때문에, SQL 측에서 루프(Loop)를 생성하여 한꺼번에 전개하고 있습니다.

자체 Query Builder: Cube의 메타 정보로 UI를 구성하기

마지막으로, SQL을 작성할 수 없는 사람이 스스로 작업할 수 있는 이유에 대한 부분입니다. Cube의 cube / measure / dimension과 그 메타 정보(group / filterable / masterKey / filterUi / 날짜 프리셋 등)를 backend에서 추출하고(물론 공개해도 좋은 항목으로만 한정한 뒤), 프론트엔드의 React 기반 Query Builder가 이를 읽어 들입니다. 이후에는 「데이터 소스 선택 → 지표 선택 → 축 선택 → 필터 설정 → Excel 추출」이라는 흐름을 화면 조작만으로 구성할 수 있습니다.

SQL을 작성할 수 없는 사람이 드래그 앤 드롭(Drag & Drop) 방식으로 집계를 구성할 수 있는 것은, 바로 이 “스키마(Schema)가 그대로 UI의 사양(Specification)이 되는” 구조 덕분입니다. 앞서 언급한 「Cube는 쿼리 빌더(Query Builder)를 처음부터 갖추고 있다」는 점이 여기서 빛을 발합니다. 지표(Metric)와 축(Dimension)의 정의를 한 번 제대로 작성해 두면, UI 측은 자동으로 이에 따라갑니다. 이 구조가 이후의 운영 방식을 크게 바꾸어 놓았습니다.

운영해 보니

처음부터 스스로 자립할 수 있었던 것은 아닙니다. 쿼리 빌더(Query Builder)라고는 해도, 지표를 선택하고 축을 조합하며 조건을 중첩하는 작업은 실질적으로 SQL을 조립하는 것과 같습니다. 데이터의 의미나 테이블 구조를 이해하지 못하면 의도한 숫자를 얻을 수 없습니다. 따라서 도입 초기에는 업무 담당자들에게 난이도가 높은 작업이었습니다.

그래서 도입 초기에는 **동반 지원(伴走支援, Hands-on support)**을 실시했습니다. 자주 사용하는 리포트를 함께 만들면서, "이 지표는 이런 의미다", "이 축으로 나누면 이렇게 보인다"와 같은 지식을 하나씩 공유해 나갔습니다. 꾸준함과 수고가 필요한 공정입니다.

점차 익숙해지면서, 저희가 SQL을 작성하거나 지원에 나서지 않아도 업무 담당자들이 직접 필요한 리포트를 만들 수 있게 되었습니다. 최종적으로는 저희가 관여하지 않은 100개가 넘는 리포트가 업무 측에서만 만들어지고 있었습니다. 회계는 결산용 집계를, 운영은 일일 확인을 담당하는 등 현장에서 필요한 것을 스스로 작성하게 되었습니다.

이러한 셀프 서비스(Self-serve)가 돌아가기 시작하면서, 시맨틱 레이어(Semantic Layer)를 프로덕트 측에 배치한 효과가 명확해졌습니다. 지표의 정의를 한 곳에 고정하고, 이를 업무 담당자가 직접 만질 수 있는 곳에 배치함으로써 엔지니어를 거치지 않고도 필요한 집계를 얻을 수 있게 되었습니다.

앞으로: 자연어로 더욱 심리스(Seamless)하게

자립할 수 있게 되었다고는 해도, 아직 "지표와 축을 직접 선택하는" 조작은 남아 있습니다. 다음으로 목표하는 것은 이 부분을 더욱 심리스(Seamless)하게 만드는 것입니다. 예를 들어 "지난달 거점별 매출을 보여줘"라고 자연어(Natural Language)로 입력하면, 그대로 집계 결과가 반환되는 형태를 상정하고 있습니다.

Cube 자체도 시맨틱 레이어(Semantic Layer)와 AI를 결합한 에이전틱 분석(Agentic Analytics) 방향으로 나아가고 있습니다. 의미가 미리 정의된 시맨틱 레이어(Semantic Layer)는 LLM에게도 다루기 쉬운 접점(Interface)이 됩니다. 지표의 정의가 한 곳에 고정되어 있기 때문에, 자연어로부터의 쿼리 생성(Query Generation)도 "정의된 어휘" 위에서 안전하게 조립될 수 있습니다. Databricks가 Genie의 맥락에서 "온톨로지(Ontology)"를 중시하는 것도 같은 방향성이라고 생각합니다. 프로덕트 측에 배치한 시맨틱 레이어(Semantic Layer)는 그 입구로서 유력한 선택지가 될 것입니다.

요약

  • 회계·운영 집계에는 「지금·정확·유연」함이 요구됩니다. 분석 기반을 경유하면 실시간성과 완전성이 손상되기 쉽습니다.
  • 그래서 분석용이 아니라, 프로덕트 측의 시맨틱 레이어(Semantic Layer)로서 Cube를 핵심 애플리케이션에 통합했습니다. 이 점이 일반적인 Cube의 사용법과 가장 다른 점입니다.
  • 실시간성·유연한 집계·SQL 없이도 사용할 수 있는 쿼리 빌더(Query Builder)·자사 앱으로의 임베딩(Embedding)을 동시에 충족할 수 있는 것이 바로 Cube였습니다. 도입의 용이성은 희생되지만, 그 부분은 동반 지원으로 보완했습니다.
  • 결과적으로 SQL을 작성할 수 없는 업무 담당자가 자립하여, 100개가 넘는 리포트가 업무 측에서만 만들어졌습니다.

참고

Discussion

AI 자동 생성 콘텐츠

본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0