3D 애플리케이션에서 지도 위 한 점을 클릭했을 때, 우리는 보통 하나의 객체가 로딩되기를 기대합니다.
예를 들어, 지도의 어떤 지점을 클릭했을 때 그곳에 스타벅스 건물 하나가 로딩되는 장면을 떠올립니다.
하지만 실제 그 지점에는 스타벅스만 있는 것이 아닙니다.
- 스타벅스 건물
- 주변 나무
- 가로등
- 신호등
- 땅(토지)
즉, 하나의 좌표(타일) 위에는 여러 개의 3D 객체가 동시에 존재합니다.
“이것들은 꼭 하나의 모델일 필요는 없다”
이 객체들이
- 하나의 3D 모델로 미리 합쳐져(Merge) 있을 수도 있고
- 여러 개의 3D 모델로 분리되어 있을 수도 있습니다
이건 개발자의 설계 영역입니다.
“이 타일을 클릭했을 때 클라이언트와 서버는 어떻게 요청/응답 하는가?”
개발자가 고려해야하는 3가지 요소

- 요청 모델: 단일 요청 vs 멀티 요청
- 응답 모델: 단일 응답 vs 멀티 응답
- 병합 시점(단일 응답 시): 런타임 vs 컴파일(pre-merge)
이 세 가지 선택지의 조합으로부터 6가지 시나리오를 만들 수 있습니다.
(병합은 5개의 3D 모델(스타벅스 건물, 주변 나무, 가로등, ...) 을 1개의 파일로 병합하는 상황, 단일 응답일 때만 의미가 있습니다.)
| 번호 | 요청 모델 | 응답 모델 | 병합 시점 |
| 1 | 단일 | 단일 | 런타임 |
| 2 | 단일 | 단일 | 컴파일(pre-merge) |
| 3 | 단일 | 멀티 (단일 요청에 대한 멀티 응답은 상식적으로 비효율) | 없음 |
| 4 | 멀티 | 단일 | 런타임 |
| 5 | 멀티 | 단일 | 컴파일 |
| 6 | 멀티 | 멀티 | 없음 |
각 요소들은 성능, 복잡도, 운영 비용에서 서로 다른 트레이드오프를 가집니다.
1) 요청 모델 트레이드오프
| 요청 모델 | 장점 | 단점 |
| 단일 요청 (+ 병합) | 네트워크 RTT(Round Trip Time) 감소, 인터페이스 단순 | 서버가 fan-out 책임 |
| 멀티 요청 | 서버 단순, 개별 캐시 효율 높음 | 요청 수 증가, Tail Latency |
단일 요청
장점: 네트워크 RTT 감소, 인터페이스 단순
클라이언트는 3D 모델 요청 시 한 번만 요청하면 되므로 네트워크 왕복(RTT)이 줄어듭니다.
또한 “타일 하나 = 요청 하나”라는 명확한 인터페이스를 가지게 되어, 클라이언트 측 요청 관리와 오류 처리가 단순해집니다.
단점: 서버가 fan-out 책임
서버는 하나의 요청을 받아 내부적으로 여러 리소스(GLB)를 조회해야 합니다.
즉, 요청 분해(fan-out), 병렬 처리, 실패 처리, 타임아웃 관리 등의 책임이 서버로 이동하며, 서버 로직과 운영 복잡도가 증가합니다.
(1개의 요청이 N개의 3D 모델을 포함함을 알아야 합니다. ㅡ 예: Lookup 파일)
멀티 요청
장점: 서버 단순, 개별 캐시 효율 높음
서버는 각 요청을 독립적으로 처리하면 되므로 구조가 단순합니다.
각 GLB는 개별 리소스로 캐시되기 때문에 CDN/브라우저 캐시 효율이 높고, 변경되지 않은 리소스는 그대로 재사용할 수 있습니다.
단점: 요청 수 증가, Tail Latency 발생
클라이언트는 여러 요청을 동시에 보내야 하며, 전체 렌더링은 가장 느린 요청에 의해 지연됩니다.
이로 인해 사용자 체감 응답 시간이 늘어나고, 네트워크 상태에 따라 지연 편차(Tail Latency)가 커집니다.
Tail Latency 예시
한 지점에 스타벅스 건물, 나무, 가로등, 신호등, 땅이 있어 클라이언트가 5번의 요청을 보냈다고 가정합니다.
스타벅스는 1초, 나무는 1.2초 만에 도착했지만, 가로등·신호등·땅은 2초 뒤에 도착합니다. 이 경우 화면에는 일부만 먼저 보이거나, 순서 없이 뜨는 혼란을 막기 위해 클라이언트는 5개의 응답이 모두 도착할 때까지 렌더링을 지연합니다.
결과적으로 사용자는 가장 느린 요청(2초) 만큼을 기다리게 됩니다.
이처럼 전체 응답 시간이 가장 느린 요청에 의해 결정되는 현상을 Tail Latency라고 합니다.
2) 응답 모델 트레이드오프
| 응답 모델 | 장점 | 단점 |
| 단일 응답 | 클라이언트 로직 단순, 렌더링 부담 낮음 | 병합(Merge) 비용 발생 |
| 멀티 응답 | 원본 재사용 용이, 부분 업데이트에 강함 | 클라이언트 로딩·조합 로직 복잡 |
단일 응답
장점: 클라이언트 로직 단순, 렌더링 부담 낮음
클라이언트는 하나의 GLB만 로딩하면 되므로, 여러 요청을 관리하거나 응답을 조합할 필요가 없습니다.
렌더링 파이프라인 역시 단일 모델 기준으로 동작해 draw call 관리, 로딩 순서 제어, 부분 로딩에 따른 시각적 불일치를 고려하지 않아도 됩니다.
단점: 병합(Merge) 비용 발생
여러 GLB를 하나로 제공하려면 서버 또는 빌드 단계에서 새로운 GLB를 생성해야 합니다.
이 과정은 단순한 데이터 합치기가 아니라 geometry, material, buffer, transform 정합성을 맞추는 작업이 포함되며, CPU·메모리 사용과 추가 저장 공간(캐시 또는 빌드 산출물)을 필요로 합니다.
멀티 응답
장점: 원본 재사용 용이, 부분 업데이트에 강함
각 객체가 독립적인 GLB로 유지되므로, 나무나 가로등처럼 일부 요소만 변경되었을 때 해당 GLB만 교체하면 됩니다.
이미 배포된 GLB는 그대로 재사용할 수 있어 캐시/CDN 효율이 높고, 전체를 다시 빌드하거나 병합할 필요가 없습니다.
단점: 클라이언트 로딩·조합 로직 복잡
클라이언트는 여러 GLB 요청을 동시에 관리하고, 모든 응답이 도착했는지 판단해야 합니다.
또한 로딩 순서, 렌더링 타이밍, 일부만 먼저 도착했을 때의 처리 방식 등 상태 관리 로직이 필요해지며, Tail Latency와 같은 사용자 체감 지연 문제도 함께 고려해야 합니다.
3) 병합 시점 트레이드오프 (단일 응답 기준)
| 병합 시점 | 장점 | 단점 |
| 런타임 병합 | 유연함, 빌드 비용 없음 | CPU/메모리, 캐시·락 복잡도 |
| 컴파일(pre-merge) | 런타임 안정성·지연 시간(Latency) 제일 좋음 | 병합 비용, 저장 비용, 실시간 업데이트 취약 |
런타임 병합
장점: 유연함, 빌드 비용 없음
빌드 단계에서 미리 모든 경우를 생성할 필요가 없으므로, 데이터 변경이나 조합 변경에 유연하게 대응할 수 있습니다.
새로운 타일 구성도 런타임에 즉시 처리할 수 있어 배포 부담이 적습니다.
단점: CPU/메모리 사용, 캐시·락 복잡도
요청 시점마다 병합 작업이 발생할 수 있어 CPU·메모리 부하가 커집니다.
중복 병합을 막기 위한 캐시, 동시 요청을 제어하기 위한 락(single-flight) 등 운영 로직이 필수가 되며, 캐시 미스 시 지연이 급증할 수 있습니다. (멀티 요청을 런타임에서 병합한 후 이를 캐싱하지 않으면 매번 런타임에 병합해야 합니다. 따라서 캐싱 정책 혹은 스토리지 정책 도 중요합니다.)
컴파일(pre-merge) 병합
장점: 런타임 안정성·성능 최고
런타임에는 이미 완성된 GLB를 정적 파일로 서빙하기만 하면 되므로, 응답 시간(Latency)이 짧고 변동성이 거의 없습니다.
서버는 계산을 하지 않아도 되어 운영 안정성이 매우 높습니다.
단점: 병합 비용, 저장 비용, 실시간 업데이트 취약
타일 조합이 조금만 변경되어도 다시 병합하고 배포해야 하므로 빌드 시간이 늘어나고 스토리지 사용량이 약 2배 증가합니다.
실시간으로 부분 업데이트가 어려워, 변화가 잦은 데이터에는 부적합합니다.
GraphQL / BFF 문제
GraphQL과 BFF(Backend for Frontend)는 “한 화면을 만들기 위해 여러 시스템의 데이터를 어떻게 조합할 것인가”라는 문제를 다룹니다.
프론트엔드가 여러 API를 직접 호출하면 요청 수가 늘고, 가장 느린 응답이 전체 로딩을 지배하는 Tail Latency 문제가 발생합니다.
이를 해결하기 위해 서버가 fan-out을 대신 처리하고, 화면 단위로 한 번의 요청에 조합된 응답을 제공합니다.
GraphQL은 클라이언트가 필요한 필드를 선언해 서버가 그 형태로 조합하고, BFF는 화면에 맞춘 전용 API로 이를 해결합니다.
현재 3D 타일 문제도 비슷한 문제 같지만, 조합 결과가 JSON이 아니라 GLB라는 바이너리 모델이어서 단순 응답 조립이 아닌 아티팩트 병합 비용까지 함께 고려해야 한다는 점에서 다릅니다.
'개발 노트 > 실무 프로젝트' 카테고리의 다른 글
| 분산 시스템 시간 정합성: UTC, NTP, 그리고 관용 (0) | 2025.12.23 |
|---|---|
| [마이그레이션] Spring 4 → Boot 3.4: Java 17, Gradle, JAR, 그리고 제어권의 변화 (0) | 2025.12.12 |
| 대용량 파일 업로드의 정합성 보장 전략: Atomic Rename과 SeaweedFS 활용 (0) | 2025.11.27 |
| SRP를 만족하는 모듈화 리팩토링 과정 (0) | 2025.11.16 |
| Gzip, Zstandard, Brotli 압축 비교 - 3D 모델 파일 (0) | 2025.10.07 |
| 전 세계 공간정보를 관리하는 자료구조 구현기 - Implicit Tiling (7) | 2025.07.20 |