콘텐츠로 이동

Bluetape4k Graph Part 1: 그래프 데이터베이스 선택 기준

로봇 엔지니어가 Neo4j, Memgraph, AGE, TinkerGraph, FalkorDB 그래프 데이터베이스 블록을 비교하는 3D 작업대 일러스트
그래프 데이터베이스는 선호도가 아니라 워크로드와 운영 조건에 따라 선택해야 합니다.

이 글은 bluetape4k-graph 시리즈의 1편입니다. 앞서 GraphDB, 언제 도입해야 할까?에서는 관계 자체가 업무의 중심일 때 그래프 데이터베이스를 검토하자는 기준을 세웠습니다. 이번에는 그래프 데이터베이스를 도입하기로 결정한 뒤 마주치는 질문을 다룹니다. Neo4j와 Memgraph 중 무엇을 운영 후보로 삼을지, PostgreSQL 환경에서 Apache AGE를 선택할지, 테스트에는 어떤 저장소를 사용할지 판단하는 기준입니다.

bluetape4k-graph는 그래프 데이터베이스를 다시 구현하지 않습니다. Neo4j, Memgraph, Apache AGE, TinkerGraph, FalkorDB의 저장 엔진과 쿼리 언어는 그대로 사용하고, Kotlin/JVM 서비스에서 반복되는 정점·간선 CRUD, 일괄 쓰기, 탐색, 대량 입출력, 프레임워크 통합을 공통 계약으로 묶습니다.

Neo4j, Memgraph, Apache AGE, TinkerGraph, FalkorDB를 워크로드와 운영 조건에 따라 선택하는 기준
테스트 방식, 운영 환경, 읽기와 쓰기 특성을 구분한 뒤 그래프 데이터베이스를 선택합니다.

현재 프로젝트가 지원하는 그래프 저장소는 다음과 같습니다.

그래프 데이터베이스쿼리 방식적합한 용도
Neo4jNeo4j Java Driver 기반 Cypher성숙한 도구, 인덱스, 트랜잭션 지원이 필요한 운영 그래프 서비스
MemgraphNeo4j 호환 프로토콜 기반 Cypher낮은 지연 시간이 중요한 Cypher 워크로드 후보
Apache AGEPostgreSQL/JDBC 기반 Cypher-over-SQL별도 그래프 서버를 추가하지 않고 PostgreSQL 중심으로 운영하는 환경
TinkerGraphJVM 인메모리 TinkerPop/Gremlin단위·통합 테스트, 예제, 로컬 데모
FalkorDBRedis 모듈 기반 openCypher 부분집합Redis 기반 그래프 워크로드와 경량 그래프 서비스

이 표는 하나의 최적 제품을 고르기 위한 순위표가 아닙니다. 운영 환경과 실제 워크로드에 맞는 후보를 추리는 출발점입니다. 예를 들어 PostgreSQL을 표준 데이터베이스로 운영하는 조직은 Apache AGE로 별도 그래프 서버를 줄일 수 있습니다. Redis 기반 운영 체계와 결합해야 한다면 FalkorDB가 후보가 됩니다. Memgraph의 낮은 지연 시간이나 특정 저장소의 쓰기 성능은 프로젝트 설명만으로 확정할 수 없으므로, 실제 데이터 규모와 쿼리 패턴으로 측정해야 합니다.

TinkerGraph는 외부 서버 없이 빠르게 실행할 수 있어 테스트에 적합합니다. 다만 TinkerGraph에서 공통 계약 테스트가 통과했다는 사실만으로 Neo4j, Memgraph, Apache AGE, FalkorDB의 쿼리 계획, 인덱스, 트랜잭션 의미가 같다고 볼 수는 없습니다. 운영 후보는 해당 백엔드와 Testcontainers를 사용한 통합 테스트로 다시 검증해야 합니다.

Neo4j, Memgraph, Apache AGE, FalkorDB를 검토하면 Cypher가 등장합니다. Cypher는 그래프의 관계 패턴을 표현하는 쿼리 언어입니다. SQL이 테이블과 행을 기준으로 데이터를 조회한다면, Cypher는 정점과 간선이 만드는 관계를 패턴으로 기술합니다.

MATCH (alice:Person {email: $email})-[:KNOWS]->(friend:Person)
RETURN friend.name

이 쿼리는 Person 정점에서 시작해 KNOWS 간선을 따라가고, 연결된 Person의 이름을 반환합니다. 복잡한 조인과 재귀 탐색을 애플리케이션 코드에서 조립하는 대신 조회할 관계의 형태를 데이터베이스에 전달합니다.

bluetape4k-graph의 공통 API는 Cypher를 대체하지 않습니다. 서비스의 기본 CRUD, 일괄 쓰기, 탐색, 테스트는 GraphOperations로 시작할 수 있습니다. 쿼리 계획, 인덱스, 프로젝션처럼 저장소별 조정이 필요한 작업은 선택한 백엔드의 드라이버와 네이티브 쿼리 API를 사용해야 합니다. 공통 API는 반복되는 서비스 코드를 줄이는 계약이지, 서로 다른 저장소의 쿼리 의미를 단일화하는 계층이 아닙니다.

graph-core를 중심으로 저장소 어댑터, 그래프 입출력, Spring Boot와 Ktor 통합, 실행 예제를 배치한 모듈 구성
graph-core의 공통 계약을 중심으로 저장소 어댑터, 대량 입출력, 프레임워크 통합 모듈이 구성됩니다.
모듈역할
graph-coreGraphOperations, 스키마 DSL, 탐색, 알고리즘과 선택적 병합·트랜잭션 기능의 공통 계약
graph-age, graph-neo4j, graph-memgraph, graph-tinkerpop, graph-falkordb그래프 저장소별 구현
graph-io/*CSV, NDJSON, GraphML 대량 입출력과 OkIO 기반 스트리밍·압축·암호화 조합
spring-boot/graph-spring-bootSpring Boot 4 자동 구성
ktor/graph-ktorKtor 3 ApplicationPlugin 통합
examples/*코드 의존성, 사기 탐지, IAM, 추천, 공급망 등 실행 가능한 시나리오

GraphOperationsGraphSession, 정점·간선 저장소, 탐색과 알고리즘 저장소 계약을 조합합니다. 스키마 관리, 병합과 트랜잭션 DSL은 백엔드가 더 강한 보장을 제공할 때 구현하는 선택적 기능입니다. 따라서 공통 인터페이스가 있다고 해서 모든 백엔드가 모든 기능을 같은 방식으로 처리한다고 가정하면 안 됩니다. 지원하지 않는 기능과 실패 의미는 백엔드별 기능 표와 통합 테스트에서 확인해야 합니다.

테스트와 문서 예제는 TinkerGraph로 간단히 시작할 수 있습니다. Docker 없이 그래프를 만들고 정점과 간선을 추가한 뒤 이웃 정점을 조회합니다.

val ops: GraphOperations = TinkerGraphOperations()
ops.createGraph("demo")
val alice = ops.createVertex("Person", mapOf("name" to "Alice"))
val bob = ops.createVertex("Person", mapOf("name" to "Bob"))
ops.createEdge(alice.id, bob.id, "KNOWS", mapOf("since" to 2026))
val neighbors = ops.neighbors(alice.id, NeighborOptions(edgeLabel = "KNOWS"))
ops.close()

이 예제는 GraphOperations의 기본 계약을 설명합니다. 운영 저장소 선택까지 증명하지는 않습니다. 같은 도메인 시나리오를 Neo4j, Memgraph, Apache AGE, FalkorDB 통합 테스트로 옮기고, 운영 데이터 규모에서 쿼리 지연 시간과 쓰기 처리량을 측정해야 합니다.

초기 후보를 정할 때는 다음 순서가 실용적입니다.

판단 기준먼저 검토할 후보추가 검증
성숙한 그래프 전용 운영 도구와 Cypher 지원Neo4j쿼리 계획, 인덱스, 운영 비용
낮은 지연 시간이 중요한 Cypher 워크로드Memgraph실제 데이터와 쓰기 패턴을 사용한 벤치마크
PostgreSQL 중심의 운영 체계Apache AGECypher-over-SQL 제약과 PostgreSQL 자원 경합
외부 서버 없는 테스트와 예제TinkerGraph운영 백엔드와의 의미 차이를 통합 테스트로 보완
Redis 기반 그래프 서비스FalkorDBopenCypher 부분집합과 실제 읽기·쓰기 성능

기본 조합이 필요하다면 Neo4j를 운영 후보로, TinkerGraph를 빠른 테스트 저장소로 삼을 수 있습니다. 이 조합 역시 정답은 아닙니다. PostgreSQL 통합, Redis 운영 체계, 낮은 지연 시간처럼 더 강한 제약이 있다면 해당 제약에 맞는 백엔드를 먼저 후보로 올리고 측정 결과로 결정해야 합니다.

다음 글에서는 graph-core의 API, 스키마 DSL, 트랜잭션과 병합, 동기·가상 스레드·코루틴 실행 모델을 살펴봅니다.

댓글

GitHub 계정으로 의견을 남기거나 reaction을 남길 수 있습니다.