
내가 Capa-Java를 만든 이유: 클라우드 네이티브 시대에 '한 번 작성하여 어디서든 실행(Write Once, Run
요약
Capa-Java는 클라우드 네이티브 환경에서 멀티 런타임 API를 지원하는 리치 SDK 모드 구현체입니다. 사이드카 모델의 복잡한 인프라 변경 없이, 애플리케이션 내부에서 표준화된 API를 통해 다양한 클라우드 환경으로의 이식성을 제공합니다.
핵심 포인트
- 사이드카 없이 애플리케이션 프로세스 내부에서 멀티 런타임 API 실행
- 표준 API와 플러그형 컴포넌트를 결합하여 'Write Once, Run Anywhere' 실현
- 비즈니스 로직 수정 없이 JAR 교체만으로 AWS, Dapr 등 환경 전환 가능
- 기존 엔터프라이즈 Java 애플리케이션의 마이그레이션 비용 절감
내가 Capa-Java를 만든 이유: 클라우드 네이티브 시대에 "한 번 작성하여 어디서든 실행(Write Once, Run Anywhere)"할 수 있게 해주는 멀티 런타임 (Multi-Runtime) SDK
솔직히 말해서, 이 프로젝트에 대해 글을 쓰려고 몇 년 동안 생각만 해왔습니다. 하지만 솔직히 말해도 될까요? 이 주제가 좀 "무서워서" 계속 미뤄왔습니다. 요즘 모두가 사이드카 (Sidecar) 아키텍처에 대해 이야기하고 있는데, 저는 SDK 접근 방식을 주장하고 있으니까요. 제가 시대에 뒤처진 걸까요?
사정은 이렇습니다. 저는 Dapr가 아직 꽤 생소했던 4년 전에 Capa-Java를 만들었습니다. 그리고 시간이 흐른 지금까지도, 이것이 다른 누구도 진정으로 이야기하지 않는 중요한 공백을 메워준다고 생각합니다. 오늘 저는 이것이 무엇인지, 왜 만들었는지, 언제 사용해야 하는지, 그리고 그 과정에서 배운 값진 교훈들을 공유하고자 합니다.
Capa-Java란 정확히 무엇인가?
간단한 질문으로 시작하겠습니다. 수백, 수천 개의 기존 Java 애플리케이션이 있는 엔터프라이즈 환경에서 일하고 있다면, 어떻게 멀티 런타임 (Multi-Runtime) 아키텍처를 도입하시겠습니까?
Dapr, Layotto, 그리고 소위 잘나가는 기술들이 사용하는 사이드카 (Sidecar) 모델은 이론적으로는 훌륭해 보입니다. 하지만 실제로 수천 개의 애플리케이션을 그 모델로 마이그레이션한다고 생각하면... 음, 그건 정말 엄청난 작업이라고 말씀드릴 수밖에 없습니다. 배포 파이프라인 (Deployment pipelines)을 변경해야 하고, 인프라를 추가해야 하며, 팀 간의 조율이 필요합니다. 결코 사소한 작업이 아닙니다.
그 지점에서 Capa-Java가 등장합니다.
Capa-Java는 멀티 런타임 (Multi-Runtime) API의 리치 SDK 모드 (Rich SDK Mode) 구현체입니다. Dapr가 제공하는 것과 동일한 표준화된 API — 서비스 호출 (Service invocation), 상태 관리 (State management), 발행/구독 (Pub/sub), 설정 (Configuration), 텔레메트리 (Telemetry) — 를 제공하지만, 별도의 사이드카 (Sidecar) 컨테이너로 실행되는 대신 애플리케이션 프로세스 내부에서 실행됩니다.
핵심 아이디어는 간단합니다:
표준 API (Standard API) + 플러그형 컴포넌트 (Pluggable Components) = 한 번 작성하여 어디서든 실행 (Write Once, Run Anywhere)
Capa의 표준 API를 대상으로 코드를 한 번 작성하면, 비즈니스 코드를 변경하지 않고도 AWS, Alibaba Cloud, Kubernetes, Dapr 등 무엇이든 배포할 수 있습니다. SPI 구현체가 적응(Adaptation)을 처리합니다.
실제 코드에서는 다음과 같은 모습입니다:
import group.rxcloud.capa.rpc.CapaRpcClient;
import group.rxcloud.capa.rpc.CapaRpcClientBuilder;
import group.rxcloud.cloudruntimes.domain.core.invocation.HttpExtension;
...
이것이 전부입니다. 이것이 당신의 서비스 호출(Service Invocation) 코드의 전부입니다. 동일한 코드가 SPI 구현체가 있는 모든 플랫폼에서 작동합니다. 클래스패스(Classpath)에 있는 구현체 JAR 파일만 변경하면, 비즈니스 로직 코드를 한 줄도 수정하지 않고도 다른 클라우드 제공업체(Cloud Provider)에서 실행할 수 있습니다.
꽤 멋지지 않나요?
하지만 잠깐... 사이드카(Sidecar)가 미래 아닌가요? 왜 SDK를 써야 하죠?
이 질문을 정말 많이 받습니다. "사이드카(Sidecar)가 명백한 미래인데, 왜 굳이 SDK 방식을 사용하나요?"
분명히 말씀드리겠습니다. 저는 사이드카(Sidecar)가 미래라고 생각합니다. 저는 Dapr 프로젝트를 좋아하고, 그들의 GitHub 토론에 기여해 왔으며, 멀티 런타임(Multi-Runtime) 아키텍처가 우리 산업의 올바른 방향이라고 생각합니다.
하지만 아무도 말하지 않는 문제가 있습니다. 대부분의 기업은 스위치를 켜듯 즉시 사이드카(Sidecar)로 전환할 수 없습니다.
생각해 보세요. 지난 10~15년 동안 구축된 거대한 Java 자산(Estate)이 있습니다. 당신의 팀은 이미 현재 시스템을 유지 관리하는 것만으로도 역량이 한계에 다다랐습니다. 그런데 누군가 나타나서 "이봐요, 이 새로운 사이드카(Sidecar) 아키텍처를 사용하도록 모든 애플리케이션을 다시 작성해야 합니다!"라고 말한다면, 경영진이 얼마나 열광할 것 같습니까? 그 작업이 얼마나 빨리 진행될 것 같습니까?
정답은 '수년'입니다. 아니, 영영 일어나지 않을 수도 있습니다.
그것이 바로 우리가 Capa를 만든 이유입니다. Capa는 과도기적 단계입니다. 본격적인 사이드카(Sidecar) 마이그레이션 없이도 오늘 당장 멀티 런타임(Multi-Runtime) API를 채택하기 시작할 수 있게 해줍니다. 서비스를 하나씩 점진적으로 도입할 수 있습니다. 그리고 결국 사이드카(Sidecar)로 이동하게 될 때, 당신은 단지 SPI 구현체만 교체하면 됩니다. 당신의 비즈니스 코드는 그대로 유지됩니다.
이 논의가 이루어졌던 Layotto 프로젝트의 원본 GitHub 이슈는 다음과 같습니다: Java SDK 설계: 기존 산업 표준을 재사용할 수 있을까요?. 이 아이디어는 대규모 Java 환경에 Multi-Runtime을 점진적으로 도입하는 방법에 대한 커뮤니티 논의에서 직접 나왔습니다.
README에 있는 다음 다이어그램이 제가 설명할 수 있는 것보다 아키텍처를 더 잘 보여줍니다:
어떤 기능을 얻을 수 있나요?
이 시점에서, Capa가 실제로 무엇을 기본으로 제공하는지 궁금하실 겁니다. 현재 기능 매트릭스는 다음과 같습니다:
| 기능 | 설명 | 상태 |
|---|---|---|
| RPC / 서비스 호출 | 표준 API를 통해 플랫폼 간 서비스 호출 | ✅ 안정(Stable) |
| 구성(Configuration) | 표준 API를 통한 동적 구성 관리 | ✅ 안정(Stable) |
| 상태 관리(State Management) | 키-값 상태 저장소에 대한 표준 API | ✅ 안정(Stable) |
| 텔레메트리(Telemetry) | 통합 로깅, 메트릭 및 추적(tracing) | ✅ 안정(Stable) |
| 데이터베이스/SQL | 표준 SQL 데이터베이스 API | ⚠️ 알파(Alpha) |
| 스케줄(Schedule) | 스케줄링 작업 추상화 | ⚠️ 알파(Alpha) |
모든 핵심 기능은 안정적이며 프로덕션에서 사용됩니다. 더 새로운 기능들(데이터베이스 및 스케줄)은 여전히 알파 단계이지만, 핵심 API는 갖추어져 있습니다.
제가 가장 좋아하는 설계 결정 중 하나는 API 정의를 Capa 프로젝트와 완전히 독립적으로 유지했다는 것입니다. cloud-runtimes-jvm을 보시면, 모든 API 정의가 그곳에 있습니다. 이것은
이것이 왜 중요할까요? 현재 Dapr의 API는 Dapr 프로젝트에 강하게 결합(Strongly Coupled)되어 있기 때문입니다. 우리는 이 API가 사이드카(Sidecar) 방식을 사용하든 SDK 방식을 사용하든, 어떤 프로젝트에서도 사용할 수 있는 진정한 커뮤니티 표준이 되기를 바랍니다. 그것이 우리가 독립성을 유지하는 이유입니다.
2분 만에 시작하기
Maven을 사용하고 있다면, 시작하는 데 필요한 것은 말 그대로 두 개의 의존성(Dependency)뿐입니다. pom.xml에 다음을 추가하면 됩니다:
<project>
<dependencies>
<!-- 모든 표준 API를 포함한 Core Capa SDK -->
...
정말 이게 끝입니다. 데모 구현체는 학습과 테스트에 매우 유용합니다. 프로덕션(Production) 환경에서는 데모 SPI를 대상 환경에 맞는 SPI 구현체로 교체하기만 하면 됩니다:
- capa-aws - AWS 구현체
- capa-alibaba - Alibaba Cloud 구현체
- capa-dapr - Dapr Sidecar 구현체
비즈니스 코드는 전혀 바뀌지 않습니다. 오직 SPI 구현체 의존성만 변경될 뿐입니다. 이것이 바로 마법 같은 부분입니다.
저는 점진적인 도입(Incremental Adoption)이 전부라는 것을 고통스러운 경험을 통해 배웠습니다. 만약 초기에 너무 많은 변화를 요구하여 팀들이 도입하도록 설득할 수 없다면, 세상에서 가장 뛰어난 아키텍처라도 아무런 의미가 없습니다. Capa는 점진적으로 도입할 수 있도록 설계되었습니다. 오후 시간만 투자해도 기존 서비스에 바로 추가할 수 있습니다.
장단점: 솔직하게 말해봅시다
여러분은 지금 "좋아 보이긴 하는데, 함정이 뭐야?"라고 생각하며 이 글을 읽고 계실 겁니다. 마케팅 용어는 걷어내고, 4년 동안 이를 프로덕션에서 사용하며 느낀 실제 장단점을 말씀드리겠습니다.
장점 ✅
-
점진적 도입 (Incremental adoption) — 이것이 가장 큰 장점입니다. 모든 것을 한꺼번에 바꿀 필요(
-
순수 사이드카 아키텍처(Sidecar architecture)가 아님 — 만약 사이드카(Sidecar)가 유일하고 진정한 방법이라고 믿으며 그린필드(greenfield, 신규 프로젝트)를 시작하려 한다면, Capa는 아마 당신에게 맞지 않을 것입니다. Capa의 핵심 목적은 기존 시스템을 위한 과도기적 단계가 되는 것입니다. Capa는 사이드카가 제공하는 수준의 완전한 관심사 분리(separation of concerns)를 제공하지는 않습니다.
-
언어 종속적(Language-bound) — SDK이기 때문에 특정 언어에 종속됩니다. 현재 우리는 훌륭한 Java 지원을 제공하며, Python과 Go에 대한 알파(alpha) 지원을 제공하고 있습니다. 사이드카는 어떤 언어와도 작동합니다. 이것은 SDK 방식의 근본적인 트레이드오프(trade-off)입니다.
-
SPI 구현 유지보수 필요 — 각 클라우드/런타임(runtime)마다 자체적인 SPI 구현이 필요합니다. 주요 환경들은 우리가 다루고 있지만, 만약 당신이 모호한 클라우드 제공업체를 사용 중이라면 직접 SPI 구현을 작성해야 합니다. 어렵지는 않지만(단순히 몇 개의 인터페이스를 구현하는 것뿐입니다), 작업이 필요합니다.
-
프로세스 동거(Process colocation) — 당신의 애플리케이션은 Capa 런타임과 리소스를 공유합니다. 만약 Capa에 메모리 누수(memory leak)가 발생하거나 충돌(crash)이 발생하면, 당신의 애플리케이션도 함께 중단됩니다. 사이드카 아키텍처에서는 사이드카가 죽더라도 애플리케이션은 여전히 실행 중입니다(물론 호출은 할 수 없겠지만 말입니다). 이것 또한 또 다른 근본적인 트레이드오프입니다.
솔직히 말해서, 마지막 포인트가 가장 큰 단점입니다. 미화하지 않고 말씀드리겠습니다. 모든 것이 동일한 프로세스 안에 있을 때, 한 곳의 버그가 모든 것을 무너뜨릴 수 있습니다. 하지만 대부분의 기존 Java 애플리케이션은 이미 그 문제를 겪고 있습니다. 이미 프로세스 내에 수십 개의 의존성(dependencies)을 가지고 있으니까요. Capa를 추가한다고 해서 그 근본적인 모델이 바뀌는 것은 아닙니다.
이것을 만들며 배운 실전 교훈들
저는 2022년에 이 프로젝트를 시작했습니다. 이 글을 쓰는 시점을 기준으로 4년 전입니다. 그 과정에서 많은 것을 배웠습니다. 그중 큰 것들은 다음과 같습니다:
교훈 1: 업계는 당신이 생각하는 것보다 느리게 움직인다
우리가 이것을 만들었을 때, 기업들이 몇 년 안에 Sidecar (사이드카)를 도입하기 위해 달려들 것이라고 생각했습니다. 하지만 그런 일은 일어나지 않았습니다. 4년이 지났지만, 대부분의 기업은 여전히 "사이드 프로젝트에서 Dapr를 실험하는" 단계에 머물러 있습니다. 이는 비판이 아닙니다. 변화는 어렵기 때문입니다. 핵심은 Capa와 같은 과도기적 솔루션이 제가 예상했던 것보다 훨씬 더 오랫동안 유효하다는 점입니다.
교훈 2: 표준화는 완벽함보다 중요하다
초기에 저는 "완벽한" API를 만들기 위해 많은 시간을 보냈습니다. 제가 배운 것은 모든 사람이 동의할 수 있는 어떠한 표준 API라도 갖는 것이 완벽한 API를 갖는 것보다 더 중요하다는 사실입니다. API가 완벽하지 않더라도, 모든 사람이 동일한 언어를 사용하기 때문에 표준화는 여전히 가치를 제공합니다.
교훈 3: 점진적인 승리가 빅뱅 방식의 재작성(Big Bang Rewrites)을 이긴다
제가 지금까지 봐온 모든 빅뱅 방식의 재작성은 실패했거나 예상보다 훨씬 오래 걸렸습니다. 점진적인 마이그레이션 (Incremental migration)은 대규모 조직에서 새로운 아키텍처를 성공적으로 도입할 수 있는 유일한 방법입니다. Capa는 바로 그것을 위해 설계되었으며, 그러한 설계 선택은 반복해서 증명되었습니다.
교훈 4: API를 구현(Implementation)으로부터 분리한 것은 옳은 결정이었다
API 정의를 완전히 독립된 리포지토리 (Repository)에 두는 것은 우리가 내린 최고의 결정 중 하나였습니다. 이는 여러 프로젝트가 동일한 API를 사용할 수 있고, 개선 사항에 대해 협업할 수 있으며, 특정 프로젝트에 종속되지 않음을 의미합니다. 그것이 바로 커뮤니티 표준을 구축하는 방법입니다.
언제 Capa-Java를 사용해야 할까요?
간단하게 설명해 드리겠습니다:
다음과 같은 경우 Capa-Java를 사용하세요...
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기