https://product.kyobobook.co.kr/detail/S000220221456
LUVIT EPL과 유튜브 데이터로 배우는 DuckDB | 이기준 - 교보문고
LUVIT EPL과 유튜브 데이터로 배우는 DuckDB | 복잡한 데이터 분석 흐름을 더 단순하게 만드는 DuckDB 최근 주목받고 있는 DuckDB를 활용해 SQL 기반 데이터 분석과 실전 프로젝트를 학습할 수 있도록 구
product.kyobobook.co.kr
지난 몇 년간 데이터베이스 분야에서 가장 흥미로운 이야기는 더 큰 클러스터에 관한 것이 아닙니다. 분석을 다시 로컬 환경으로 되돌리는 것에 관한 이야기입니다.
DuckDB는 빠르게 데이터 엔지니어들이 가장 선호하는 도구 중 하나로 자리 잡고 있습니다. 로컬 우선(Local-First) 분석 모델이 현대 데이터 워크플로를 어떻게 변화시키고 있는지 알아보겠습니다.
데이터 웨어하우스는 모든 문제를 해결할 것으로 기대되었다
지난 10년 가까이 대부분의 데이터 엔지니어링은 비슷한 아키텍처를 따랐습니다.
데이터는 객체 스토리지에 저장되었습니다.
데이터는 데이터 웨어하우스로 적재되었습니다.
쿼리는 데이터 웨어하우스에서 실행되었습니다.
그래서 데이터 웨어하우스 사용료는 계속 늘어났습니다.
그러는 사이 또 다른 데이터 웨어하우스가 도입되었습니다.
어느 순간부터 많은 팀은 이러한 아키텍처가 정말 필요한지 질문하는 대신, 이것이 피할 수 없는 방식이라고 받아들이기 시작했습니다.
업계는 데이터 자체가 그다지 크지 않은 경우에도 분산 시스템에 집착하게 되었습니다.
그런데 지금은 이상한 일이 벌어지고 있습니다.
수년 동안 Spark 클러스터를 구축하고, ETL 파이프라인을 관리하며, 데이터 웨어하우스 워크로드를 튜닝해 온 데이터 엔지니어들이 갑자기 하나의 프로세스 안에서 실행되는 데이터베이스에 열광하고 있습니다.
클러스터도 아닙니다.
플랫폼도 아닙니다.
서비스도 아닙니다.
라이브러리입니다.
그 데이터베이스가 바로 DuckDB입니다.
그리고 DuckDB의 부상은 현대 데이터 인프라에 대해 다소 불편한 사실을 보여줍니다.
놀랄 만큼 많은 분석 작업은 애초에 분산 컴퓨팅이 필요하지 않았습니다.
진짜 문제는 쿼리 속도가 아니었다
분석 인프라에 대한 대부분의 논의는 성능에 초점을 맞춥니다.
하지만 그것은 핵심을 놓치고 있습니다.
많은 조직에서 가장 큰 병목은 쿼리 실행 속도가 아닙니다.
마찰(friction)입니다.
일반적인 데이터 처리 과정을 생각해 보겠습니다.
CSV → S3 → ETL 작업 → 데이터 웨어하우스 → BI 도구
모든 단계는 추가적인 조율을 필요로 합니다.
권한 설정.
비용.
인프라.
배포 파이프라인.
모니터링.
거버넌스 검토.
결국 누군가는 단순히 다음과 같은 질문에 답하고 싶을 뿐입니다.
"지난주에 어떤 고객이 업그레이드했을까?"
하지만 쿼리를 실행하는 대신 조직 내 복잡한 절차를 헤매게 됩니다.
숨겨진 비용은 CPU가 아닙니다.
기다림입니다.
DuckDB는 바로 이 문제를 정면으로 해결합니다.
데이터를 컴퓨팅 계층으로 이동시키는 대신, DuckDB는 컴퓨팅을 데이터가 있는 곳으로 직접 가져오는 방식을 선택하는 경우가 많습니다.
겉으로는 작은 차이처럼 보일 수 있습니다.
하지만 결코 작은 차이가 아닙니다.
DuckDB는 데이터베이스보다 Pandas에 더 가깝게 느껴진다
DuckDB가 엔지니어링 팀 안에서 빠르게 확산되는 이유 중 하나는 기존의 데이터베이스 소프트웨어처럼 느껴지지 않기 때문입니다.
데이터 엔지니어는 DuckDB를 설치한 뒤 곧바로 파일에 대해 쿼리를 실행할 수 있습니다.
import duckdb
result = duckdb.sql("""
SELECT
country,
COUNT(*) as users
FROM 'users.parquet'
GROUP BY country
ORDER BY users DESC
""").fetchall()
print(result)
서버가 필요하지 않습니다.
클러스터도 필요하지 않습니다.
배포도 필요하지 않습니다.
인프라 요청 티켓도 필요하지 않습니다.
DevOps 회의도 필요하지 않습니다.
쿼리는 파일을 대상으로 직접 실행됩니다.
이러한 단순함은 작업 방식을 바꿉니다.
엔지니어들은 인프라를 계획하는 대신 데이터를 탐색하기 시작합니다.
실험 비용이 거의 들지 않기 때문에 개발자의 생산성도 높아집니다.
그리고 대부분의 가치 있는 분석은 바로 이러한 실험에서 시작됩니다.
이것이 사람들이 생각하는 것보다 더 중요한 이유
복잡할수록 뛰어난 엔지니어링으로 여겨졌습니다.
대규모 조직은 실제로 분산 시스템이 필요했기 때문에 이를 구축했습니다.
하지만 규모가 작은 조직들은 단지 그것이 최신 아키텍처처럼 보인다는 이유만으로 같은 방식을 따라 했습니다.
그 결과는 무엇이었을까요?
50GB 규모의 문제를 해결하면서도 500노드 규모의 사고방식을 적용하는 팀들이 생겨났습니다.
백엔드 아키텍처에서도 같은 패턴이 존재합니다.
많은 기업이 실제 확장성의 한계를 제대로 이해하기도 전에 마이크로서비스를 도입했습니다.
그리고 이후 수년 동안 관측성(Observability), 분산 추적(Tracing), 인증(Authentication), 배포 파이프라인, 서비스 간 통신 체계를 다시 구축하는 데 시간을 보냈습니다.
데이터 엔지니어링에서도 같은 일이 벌어졌고, 분산 분석은 기본적인 옵션이 되어 버렸습니다.
DuckDB는 이제 팀들에게 다시 한번 질문을 던지고 있습니다.
"이것을 분산할 수 있는가?"가 아니라,
"정말 분산해야 하는가?"입니다.
모듈형 모놀리식 아키텍처와의 숨은 공통점
DuckDB가 경험 많은 엔지니어들에게 특히 공감을 얻는 이유 중 하나는 거대한 업계에서도 사용 가능하기 때문입니다.
몇 년 전만 해도 모두가 마이크로서비스를 지향했습니다.
하지만 오늘날에는 많은 팀이 다시 모듈형 모놀리식(Modular Monolith) 아키텍처로 돌아가고 있습니다.
마이크로서비스가 잘못된 접근이었기 때문이 아니고, 복잡한 시스템일수록 그만큼 운영 부담도 커지기 때문입니다.
이와 같은 원칙은 데이터 분석에도 그대로 적용됩니다.
분산 분석 아키텍처
데이터 소스
│
▼
Kafka Streams
│
▼
Spark 클러스터
│
▼
데이터 웨어하우스
│
▼
BI 계층
장점:
- 대규모 데이터 처리
- 팀 간 독립성
- 장애 허용(Fault Tolerance)
- 독립적인 소유 및 운영
- 단점:
- 운영 부담 증가
- 높은 인프라 비용
- 긴 피드백 주기
- 복잡한 시스템 구성
DuckDB 기반의 실용적인 워크플로
Parquet 파일
│
▼
DuckDB
│
▼
분석
장점:
- 최소한의 설정
- 빠른 반복 작업
- 낮은 비용
- 쉬운 디버깅
단점:
- 단일 노드의 한계
- 모든 워크로드에 적합하지는 않음
이런 현상은 이제 낯설지 않습니다.
대부분의 확장성 문제는 CPU 문제가 아니라, CPU 문제처럼 보이는 조율(Coordination)의 문제인 경우가 많습니다.
실제 운영 환경의 예: 이벤트 분석
고객 이벤트를 생성하는 백엔드 시스템이 있다고 가정해 보겠습니다.
일반적인 아키텍처는 다음과 같습니다.
FastAPI
│
Kafka
│
Spark
│
데이터 웨어하우스
│
대시보드
이벤트 생성 코드입니다.
from fastapi import FastAPI
from aiokafka import AIOKafkaProducer
import json
app = FastAPI()
producer = AIOKafkaProducer(
bootstrap_servers="kafka:9092"
)
@app.on_event("startup")
async def startup():
await producer.start()
@app.post("/events")
async def create_event(payload: dict):
await producer.send_and_wait(
"customer-events",
json.dumps(payload).encode()
)
return {"status": "accepted"}
이 구조는 일반적이지만, 하지만 많은 조직에서 하루에 생성되는 이벤트는 수백만 건 수준에 불과합니다.
즉, 겉으로는 매우 큰 규모처럼 보일 수 있지만, 하지만 실제로는 그렇지 않은 경우가 많습니다.
이제 더 단순한 분석 방식을 살펴보겠습니다.
import duckdb
query = """
SELECT
event_type,
COUNT(*)
FROM 'events/*.parquet'
GROUP BY event_type
"""
results = duckdb.sql(query).df()
많은 보고서 작성 및 분석 업무에서는 두 번째 접근 방식만으로도 훨씬 적은 인프라를 사용하면서 수초 안에 원하는 결과를 얻을 수 있습니다.
아무도 이야기하지 않는 성능의 비결
DuckDB가 인기를 얻는 이유는 단순히 사용하기 편리해서만은 아닙니다.
DuckDB의 쿼리 실행 엔진은 매우 뛰어나게 설계되어 있습니다.
DuckDB는 벡터화된 쿼리 처리(Vectorized Query Processing) 방식을 사용합니다.
한 번에 한 행(Row)씩 처리하는 대신, 여러 행을 하나의 배치(Batch)로 묶어 처리합니다.
개념적으로 살펴보면 다음과 같습니다.
기존 실행 엔진
Row 1
Row 2
Row 3
Row 4
DuckDB
Batch 1
Batch 2
Batch 3
이러한 방식은 CPU 캐시(Cache)를 훨씬 효율적으로 활용할 수 있게 해줍니다.
현대의 프로세서는 예측 가능한 메모리 접근 방식을 매우 효율적으로 처리하기 때문에, 많은 분석 시스템은 실제 계산보다 메모리에서 데이터를 옮기는 데 더 많은 시간을 소비합니다.
DuckDB는 이러한 불필요한 메모리 이동을 최소화하는 데 매우 뛰어난 성능을 보여줍니다.
그렇기 때문에 엔지니어들은 노트북에서도 기대 이상의 쿼리 성능을 경험하는 경우가 많습니다.
백엔드 아키텍처가 주는 교훈
데이터 엔지니어링과 백엔드 아키텍처는 많은 사람들이 생각하는 것보다 점점 더 닮아가고 있습니다.
오늘날 효과적인 아키텍처의 핵심은 무조건 분산하는 것이 아닙니다.
필요한 곳에만 분산을 적용하는 것입니다.
뛰어난 엔지니어링 팀은 먼저 단순한 구조에서 시작하고, 꼭 필요한 경우에만 복잡성을 추가합니다.
비동기 워크플로를 예로 들어 보겠습니다.
좋지 않은 구현 방식
@app.post("/order")
async def create_order(order):
save_order(order)
send_email(order)
generate_invoice(order)
notify_inventory(order)
return {"status": "ok"}
모든 작업이 동기(Synchronous) 방식으로 처리되면서, 응답 시간은 계속 길어집니다.
또한 하나의 장애가 연쇄적으로 다른 장애를 유발하며, 이 때문에 시스템을 확장하는 일도 점점 어려워집니다.
더 나은 구현 방식
@app.post("/order")
async def create_order(order):
save_order(order)
await queue.publish({
"type": "order_created",
"order_id": order.id
})
return {"status": "accepted"}
Consumer:
async def process_order(event):
await send_email(event)
await generate_invoice(event)
await update_inventory(event)
이것이 확장성을 고려한 백엔드 시스템의 설계 방식입니다.
DuckDB 역시 비슷한 철학을 따릅니다.
불필요한 조율 과정을 제거함으로써, 핵심 처리 경로(Critical Path)는 최대한 짧게 유지합니다.
복잡한 구조는 필요한 경우에만 적용합니다.
과거의 데이터 플랫폼은 왜 과도하게 복잡해졌을까?
그 이유는 누군가가 일을 잘못해서가 아닙니다. 이해관계 때문입니다.
관리자는 안정성을 원하고, 아키텍트는 미래에도 사용할 수 있는 확장성을 원했습니다.
엔지니어는 유연성을 원하고, 벤더는 더 큰 플랫폼을 원했습니다.
각각의 결정은 모두 합리적으로 보였습니다.
하지만 그 결과는 거대한 데이터 생태계였습니다.
결국 많은 팀은 다음과 같은 시스템을 유지·관리하게 되었습니다.
- Kafka 클러스터
- Spark 작업(Job)
- Airflow DAG
- 데이터 웨어하우스 모델
- 모니터링 파이프라인
- 데이터 거버넌스 시스템
이들 도구 자체에 문제가 있는 것은 아닙니다.
문제는 복잡성이 계속해서 누적된다는 점입니다.
새로운 구성 요소가 하나 추가될 때마다 운영 부담도 함께 증가하고, 관측(Observability)은 점점 어려워집니다.
누가 무엇을 책임지는지 불분명해지고, 장애 원인을 분석하는 데 더 많은 시간이 걸립니다.
이로 인해, 어느 순간 시스템 아키텍처는 비즈니스보다 더 빠르게 복잡해집니다.
실제 운영 환경의 패턴: 멱등성을 고려한 데이터 처리
백엔드 엔지니어들은 오래전부터 재시도(Retry)는 피할 수 없는 일이라는 사실을 알고 있었습니다.
분석 파이프라인도 마찬가지이지만, 좋지 않은 구현 방식입니다.
def process_event(event):
db.execute(
"INSERT INTO analytics VALUES (...)"
)
이 방식은 재시도가 발생하면 동일한 데이터가 중복으로 저장됩니다.
다음이 더 나은 구현 방식입니다.
def process_event(event):
db.execute("""
INSERT INTO analytics(
event_id,
payload
)
VALUES (%s, %s)
ON CONFLICT(event_id)
DO NOTHING
""", (
event["id"],
event["payload"]
))
데이터 처리 시스템에서는 최고의 성능을 내는 것보다 멱등성(Idempotency)을 보장하는 것이 더 중요한 경우가 많습니다.
예측할 수 없이 실패하는 빠른 시스템보다 안정적으로 동작하는 시스템이 훨씬 더 뛰어난 확장성을 제공합니다.
쿼리 속도보다 더 중요한 것은 관측성이다
놀랄 만큼 많은 데이터 장애는 가시성 부족 때문에 발생합니다.
성능 문제가 아닙니다.
다음은 운영 환경에서의 로그 기록 예제입니다.
import structlog
logger = structlog.get_logger()
logger.info(
"analytics_job_started",
job_id=job_id,
file_count=len(files)
)
다음은 메트릭 수집 예제입니다.
analytics_rows_processed.inc()
analytics_job_duration.observe(
duration_seconds
)
아무리 빠른 쿼리라도 어제와 오늘의 분석 결과가 왜 달라졌는지 아무도 설명할 수 없다면 아무런 의미가 없습니다.
DuckDB와 데이터 분석의 미래
DuckDB가 흥미로운 이유는 데이터베이스 자체 때문만은 아닙니다.
그 이면에 있는 철학 때문입니다.
업계는 이제 숙련된 엔지니어들이 오래전부터 알고 있던 한 가지 원칙을 다시 발견하고 있습니다.
복잡성은 정말 필요할 때만 도입해야 합니다.
그동안의 기본적인 접근 방식은 다음과 같았습니다.
"서비스를 하나 더 추가하자."
"클러스터를 하나 더 추가하자."
"계층을 하나 더 추가하자."
하지만 이제는 질문이 달라지고 있습니다.
"무언가를 없앨 수는 없을까?"
DuckDB는 이러한 변화를 상징하는 데이터베이스입니다.
DuckDB가 적합하지 않은 경우
모든 워크로드에 DuckDB가 적합한 것은 아닙니다.
대규모 분산 처리가 필요한 환경은 여전히 존재합니다.
다음과 같은 환경이라면
- 페타바이트(PB) 규모의 데이터셋
- 멀티테넌트 분석 플랫폼
- 수천 명의 동시 사용자
- 실시간 스트리밍 처리
- 엔터프라이즈 수준의 데이터 거버넌스 요구 사항
Spark, Snowflake, BigQuery, Databricks와 같은 시스템은 여전히 필수적인 선택입니다.
숙련된 엔지니어라면 언제 단순한 구조만으로는 충분하지 않은지를 판단해야 합니다.
오늘날 뛰어난 팀들이 실제로 선택하는 방식
가장 효과적인 조직은 로컬 분석과 분산 분석 중 하나를 선택하지 않습니다.
두 가지를 함께 활용합니다.
현대적인 데이터 아키텍처의 한 예는 다음과 같습니다.
FastAPI
│
PostgreSQL
│
Kafka
│
Parquet 파일
│
DuckDB
│
BI 계층
운영 업무는 PostgreSQL, 이벤트 스트리밍은 Kafka가 처리합니다.
데이터는 객체 스토리지에 Parquet 파일 형태로 저장됩니다.
DuckDB는 로컬 환경에서의 데이터 탐색, 테스트, 검증, 그리고 경량 분석을 담당하고, 정말 필요한 경우만 분산 시스템을 활용해야 합니다.
이러한 균형은 불필요하게 복잡한 시스템을 만드는 일을 피하면서도 개발자의 생산성을 극대화합니다.
마무리
DuckDB의 등장은 단순히 새로운 데이터베이스에 관한 이야기가 아닙니다.
지난 10년 동안 점점 무거워진 데이터 인프라에 대한 반작용입니다.
엔지니어들은 오랫동안 분산 시스템을 최적화하는 데 많은 노력을 기울여 왔습니다.
이제는 애초에 최적화해야 할 시스템의 수를 줄이는 것이 더 중요하다는 사실을 다시 깨닫고 있습니다.
때로는 가장 뛰어난 확장성을 제공하는 해법이 더 큰 클러스터가 아닐 수도 있습니다.
더 단순한 아키텍처일 수도 있습니다.
그리고 이것이야말로 DuckDB가 데이터 업계에 전하고 있는 가장 중요한 메시지일 것입니다.
'EPL과 유튜브 데이터로 배우는 DuckDB' 카테고리의 다른 글
| Spark 클러스트를 대체하는 DuckDB: 비용 70%를 절감하다 (0) | 2026.06.28 |
|---|---|
| DuckDB vs PostgreSQL: 아무도 예상하지 못했던 분석 혁명 (0) | 2026.06.27 |
| Pandas, Polars, DuckDB로 테스트 데이터 생성하기 (0) | 2026.06.22 |
| DuckDB: 2026년 데이터 분석가를 위한 가장 과소 평가된 도구 (0) | 2026.06.21 |
| DuckDB + Python: SQL로 CSV 파일 다루기 part 1 (0) | 2026.06.20 |
댓글