Cafe24API 호출제약에의해 로컬에서만 작동하는 백프레셔기를 바이브로 작성하고 유닛테스트까지 수행해보았습니다.
이전활동 : CAFE24-API 호출 안전처리기 by 백프레셔기법 활용
이번장에서는 로컬로만 작성된 액터를 클러스터로 확장을 바이브를 통해 시도해보겠습니다.
왜 액터 모델은 클러스터 확장에 유리한가?
전통적인 스레드 기반 동시성 모델은 공유 메모리와 Lock을 사용하며, 이를 분산 환경으로 확장하려면 네트워크 프로그래밍, 분산 락(Distributed Lock), 메시지 큐(Kafka, RabbitMQ 등) 같은 외부 인프라를 별도로 구축해야 합니다. 반면 액터 모델은 설계 자체가 분산 환경을 전제하고 있어 근본적으로 다른 접근을 제공합니다.
위치 투명성(Location Transparency)이 핵심입니다. 액터 간의 모든 상호작용은 순수한 메시지 패싱을 통해 이루어지며, 모든 것이 비동기적으로 동작합니다. 이 설계 덕분에 단일 JVM/CLR에서 동작하든, 수백 대의 머신 클러스터에서 동작하든 동일한 기능을 제공할 수 있습니다. Akka 공식 문서에서 강조하는 핵심 원칙은 "remote에서 local로의 최적화(go from remote to local by way of optimization)"이며, 이는 "local에서 remote로의 일반화"라는 실패할 수밖에 없는 접근과 대비됩니다.
액터 모델이 클러스터 확장에 유리한 4가지 핵심 이유:
| 특성 | 스레드 기반 모델 | 액터 모델 |
|---|---|---|
| 상태 관리 | 공유 메모리 + Lock → 데드락 위험, 분산 Lock 필요 | 메시지 패싱으로 상태 격리 → Lock-free, 분산 자연스러움 |
| 통신 방식 | 메서드 호출 (로컬 한정) → 원격 시 RPC/REST 필요 | 메시지 전달 (로컬/원격 동일) → ActorRef로 위치 무관 통신 |
| 장애 처리 | try-catch 중심 → 분산 환경 장애 전파 어려움 | 감독 계층구조(Supervision) → Let-it-crash, 자가치유 |
| 확장 방식 | 코드 변경 필수 → 네트워크 레이어 별도 구현 | 설정 변경만으로 확장 → 리모팅은 설정(HOCON)으로 구동 |
이전 활동에서 구현한 Cafe24 API 백프레셔(SafeApiCallerActor)는 Akka Streams 기반의 액터 모델로 구현되었기 때문에, 클러스터 환경으로의 전환 시 핵심 비즈니스 로직의 변경 없이 인프라 설정과 클러스터 패턴(Sharding, Singleton, PubSub 등)만 추가하면 됩니다.
AKKA의 클러스터 개념
아카의 클러스터 특징은 다음 아티컬을 참고 by 아카장시자 요나스 보너
AKKA.net 영상 : 본방 AKKA의 컨셉과 동일
클러스터 핵심 패턴 상세
Akka 클러스터는 여러 ActorSystem 인스턴스를 하나의 논리적 클러스터로 연결하여 분산 액터 시스템을 구성합니다. 클러스터의 핵심 동작 원리는 Gossip 프로토콜을 통한 멤버십 관리와 Failure Detector를 통한 노드 상태 감시입니다.
1. Cluster Membership (클러스터 멤버십)
노드의 생명주기는 다음과 같이 관리됩니다:
Joining → Up → Leaving → Exiting → Removed
비정상 경로: Up → Unreachable → Down → Removed
seed-nodes는 클러스터 부트스트랩을 위한 초기 접점 노드 목록이며, MemberUp/MemberRemoved 같은 이벤트를 구독하여 클러스터 상태 변화에 반응할 수 있습니다. Roles를 부여하면 기능별 분리 배포가 가능합니다.
2. Cluster Singleton (클러스터 싱글톤)
클러스터 전체에서 단 하나의 인스턴스만 실행을 보장합니다. 리더 노드가 다운되면 다른 노드로 자동 핸드오버(handover)됩니다. 이번 Cafe24 API 확장에서는 호출량 측정 및 모니터링을 위한 싱글톤 액터로 활용됩니다. 전체 클러스터의 API 호출 통계를 하나의 중앙 지점에서 집계할 수 있어, 분산된 여러 노드의 백프레셔 상태를 통합 관리할 수 있습니다.
3. Cluster Sharding (클러스터 샤딩)
대량의 엔티티(Entity)를 여러 노드에 자동 분산 배치하는 핵심 패턴입니다. entityId로 메시지를 보내면 해당 엔티티가 있는 노드로 자동 라우팅됩니다. Cafe24 확장에서는 MallId별 SafeApiCallerActor를 Shard Entity로 구성하여, 각 Mall의 API 호출을 독립적인 노드에서 처리합니다.
구조: ShardRegion → Shard → Entity 3단 계층
예를 들어 100개 Mall을 20개 Shard로 나누고 4개 노드에 분산하면, 각 노드당 5개 Shard(약 25개 Mall)를 처리합니다. 노드 추가 시 자동 리밸런싱되어 부하가 균등 분배됩니다.
4. Distributed PubSub (분산 발행/구독)
클러스터 전체에 걸쳐 토픽 기반 메시지 브로드캐스트를 제공합니다. 발행자와 구독자가 서로의 위치를 몰라도 통신 가능하며, 모니터링 데이터의 실시간 전파나 설정 변경 알림에 활용됩니다.
5. Split Brain Resolver (SBR)
네트워크 파티션 발생 시 어떤 노드를 살리고 다운시킬지 결정하는 중요한 안전장치입니다. 프로덕션에서는 반드시 설정해야 하며, keep-majority(다수파 유지), keep-oldest(최고참 유지), down-all(전체 재시작) 전략 중 선택합니다.
로컬 → 클러스터 전환 시 핵심 고려사항
로컬에서 잘 동작하는 액터 모델을 클러스터로 확장할 때 반드시 고려해야 할 사항들입니다:
| 항목 | 로컬(단일 JVM/CLR) | 클러스터(분산 노드) |
|---|---|---|
| 메시지 직렬화 | 불필요 (JVM 내부 참조 전달) | 필수 (Jackson JSON/CBOR/Protobuf 등) |
| 네트워크 지연 | 무시 가능 (나노초) | 고려 필수 (밀리초~초 단위) |
| 메시지 전달 보장 | 거의 확실 | at-most-once (유실 가능, 재시도 로직 필요) |
| 액터 위치 | 동일 프로세스 내 | 어떤 노드든 가능 (위치 투명성) |
| 상태 복구 | 프로세스 재시작 시 소멸 | Event Sourcing/Snapshot으로 영속화 |
| 장애 범위 | 전체 시스템 영향 | 노드 단위 격리, 자동 리밸런싱 |
Cafe24 API 백프레셔의 클러스터 전환 핵심 변경점:
로컬에서는 Mall 구분 없이 단일 SafeApiCallerActor가 모든 API 호출을 처리했습니다. 클러스터 환경에서는 다음과 같이 변경됩니다:
① MallId별 분산배치: Cluster Sharding으로 각 Mall의 ThrottleActor를 entityId(MallId) 기반으로 자동 분산
② 분산 속도 제어: 각 노드에서 독립적으로 백프레셔를 적용하되, 클러스터 싱글톤으로 전체 호출량을 모니터링
③ 더미 API 유지: 실제 Cafe24 API 실호출 없이 Leaky Bucket 더미 서버로 클러스터 동작을 검증
④ Graceful Shutdown: 쿠버네티스 환경에서 노드 종료 시 진행 중인 API 호출이 안전하게 완료되도록 coordinated-shutdown 설정
로컬로 잘 작동된 액터모델을 클러스터로 확장하기 - 프롬프트
## 1.0.6 - CAFE24 API호출 안전처리장치 by 백프레셔이용 - skill-test/plan/TEST-Cafe24APILimit.md : 이 지침에의해 로컬로의 검증활동이 완료되었습니다. - 이 지침및 결과물을 확인해 Kottlin Pekko Typed, Java Akka Classic, C# Akka.NET 3종 세트에 이 컨셉을 추가합니다. - 로컬 vs 클러스터 차이에따른 고려사항 - 제약은 Cafe24 내 MallId(기업구분) 별로 적용되며.. 로컬에서는 Mall구분이 없었으나~ 다양한 Mall을 분산배치 전략을 활용.. 샘플과 유사하게 Cafe24API 실호출없이 더미 API이용 - 클러스터 내에서 분산처리된 액터의 속도를 조절제어해야하며, 호출량 측정및 모니터링을 위해 클러스터 싱글통 액터가 이용될수 있습니다. - 기능이 추가됨에 따라 유닛테스트를 먼저작성하고 수행해주세요 ### 테스트지침 - 개선후 새로운 유닛테스트를 포함 기존유닛테스트가 잘유지되는지 검증합니다. 유닛테스트가 통과후 쿠버를 이용한 구동및 통합 클러스터 테스트를 수행해주세요 - 유닛테스트 검증이 완료되면 이어서 쿠버 인프라를 통해 클러스터 멤버가 잘 조인되는지 확인후...기능확인도 수행해(쿠버를 통한 로그획득기능을 통해) - 새로운 기능이 추가됨에따라 쿠버 구동후 신규기능에 대한 통합테스트도 수행해주세요 - 프로젝트당 쿠버작동이 모두 확인되면.. 그레이스풀 셧다운으로 종료 ### Kottlin Pekko Typed ``` kotlin-pekko-typed kotlin-pekko-typed-infra kotlin-pekko-typed-cluster kotlin-pekko-typed-test 스킬을 활용 다음경로 프로젝트 개선: skill-test/projects/sample-cluster-kotlin ``` ### Java Akka Classic ``` java-akka-classic java-akka-classic-infra java-akka-classic-test akka-testkit java-akka-classic-cluster 스킬을 활용해서 다음경로 프로젝트 개선 : skill-test/projects/sample-cluster-java ``` ### C# Akka.NET ``` dotnet-akka-net dotnet-akka-net-infra dotnet-akka-net-test dotnet-akka-net-cluster 스킬을 활용해서 다음경로 프로젝트 개선 : skill-test/projects/sample-cluster-dotnet ```
- skill-test/plan/TEST-Cafe24APILimit.md : 로컬개발및 테스트는 클러스터(쿠버) 확인전까지 훨씬 빠르게 디벨롭을 완성할수 있으며 기록한 활동을 클러스터 개발시 참고
3개 플랫폼 클러스터 구현 비교
이번 확장은 동일한 비즈니스 로직(Cafe24 API 백프레셔)을 3개 플랫폼에서 클러스터로 구현하는 것이 핵심입니다. 각 플랫폼의 클러스터 API 차이를 이해하는 것이 중요합니다.
| 항목 | Java (Akka Classic 2.7.x) | Kotlin (Pekko Typed 1.1.x) | C# (Akka.NET 1.5.x) |
|---|---|---|---|
| HOCON 네임스페이스 | akka { } | pekko { } | akka { } |
| 프로토콜 | akka:// | pekko:// | akka.tcp:// |
| Remoting 포트 | 2551 | 25520 | 4053 |
| Singleton API | ClusterSingletonManager + Proxy | ClusterSingleton.get().init(SingletonActor.of()) | ClusterSingletonManager + Proxy |
| Sharding API | ClusterSharding.get().start() + MessageExtractor | ClusterSharding.get().init(Entity.of()) + EntityTypeKey | ClusterSharding.Get().Start() + HashCodeMessageExtractor |
| PubSub API | DistributedPubSub.get().mediator() | Topic.create() 액터 기반 | DistributedPubSub.Get().Mediator |
| 트랜스포트 | Artery | Artery | dot-netty.tcp |
| 빌드 도구 | Gradle (Kotlin DSL) | Gradle (Kotlin DSL) | dotnet CLI / csproj |
쿠버네티스 배포 아키텍처
클러스터 테스트는 Docker Desktop Kubernetes에서 StatefulSet + seed-nodes 방식(Type C)으로 수행합니다. 이 방식은 Management/Bootstrap 의존성 없이 최소 의존성으로 멀티노드 클러스터를 검증할 수 있습니다.
배포 파이프라인:
코드 생성(바이브) → 유닛테스트(로컬) → Docker 빌드 → K8s StatefulSet 배포 → 클러스터 조인 확인 → 분산처리 통합테스트 → Graceful Shutdown
K8s 배포 시 핵심 설정:
① imagePullPolicy: Never → 로컬 빌드 이미지 직접 사용 (Docker Desktop K8s 전용)
② publishNotReadyAddresses: true → Headless Service에서 readiness 교착상태 방지 필수
③ canonical hostname = StatefulSet DNS 이름 → Pod IP 사용 시 seed-nodes 불일치로 조인 실패
④ SBR(Split Brain Resolver) → 프로덕션에서 반드시 설정 (개발: keep-majority 권장)
⑤ coordinated-shutdown: exit-jvm=on / exit-clr=on → 안전한 클러스터 이탈
생성결과 : 코드생성 → 유닛테스트 → 쿠버에서 분산처리 통합테스트
- https://github.com/psmon/skill-actor-model/tree/main/skill-test/projects - 개선 대상 프로젝트
- https://github.com/psmon/skill-actor-model/blob/main/skill-test/TEST-RESULT-PART3-Improve.md - 플랜에 의해 개선된 사항
- https://github.com/psmon/skill-actor-model/blob/main/skill-test/TEST-RESULT-PART3.md - 플랜에 의해 검증된사항
바이브 코딩으로 분산 시스템 구축하기
이번 프로젝트의 핵심 가치는 바이브 코딩(Vibe Coding)으로 분산 시스템을 구축하는 것입니다. 사용자는 요구사항(Plan)만 작성하고, Claude Code 스킬이 액터 모델 코드부터 클러스터 설정, Docker/K8s 인프라까지 전체를 자동 생성합니다.
스킬 기반 자동화 파이프라인:
| 단계 | 활동 | 사용 스킬 |
|---|---|---|
| 1. Plan 작성 | 요구사항 정의 (TEST-Cafe24APILimit.md) | 사용자 직접 작성 |
| 2. 로컬 코드 생성 | SafeApiCallerActor + 유닛테스트 | java-akka-classic, kotlin-pekko-typed, dotnet-akka-net + test 스킬 |
| 3. 클러스터 확장 | Sharding/Singleton/PubSub 패턴 적용 | java-akka-classic-cluster, kotlin-pekko-typed-cluster, dotnet-akka-net-cluster |
| 4. 인프라 생성 | Dockerfile, K8s YAML, HOCON 설정 | java-akka-classic-infra, kotlin-pekko-typed-infra, dotnet-akka-net-infra |
| 5. 통합 테스트 | K8s 클러스터 배포 및 분산처리 검증 | 인프라 스킬의 Type C (StatefulSet) |
핵심 교훈:
① 로컬 우선 개발: 로컬에서 유닛테스트로 빠르게 검증 → 클러스터 확장은 검증 완료 후 진행. 로컬 개발이 훨씬 빠르게 디벨롭을 완성합니다.
② 동일 비즈니스 로직, 3개 플랫폼: Java Akka Classic, Kotlin Pekko Typed, C# Akka.NET 3종에 동일 컨셉을 적용하여 크로스 플랫폼 역량을 확보합니다.
③ Code as Infra: 인프라 지식 없이 스킬 호출만으로 Docker/K8s 분산 클러스터 환경을 구축. 바이브만으로 로컬 인프라에서 K8s 위의 분산 클러스터를 구동하고 테스트할 수 있습니다.
④ 점진적 확장: 기능 추가 → 유닛테스트 → K8s 배포 → 통합테스트 → Graceful Shutdown의 사이클을 반복하며 안정적으로 확장합니다.
이 활동은 Codex를 통해 완수되었으며 Claude 를통한 개선이 본방활동으로 교차 수행하고 있습니다. ( 클코드 스킬 → 코덱스 스킬로 주입 )
3진영 클러스터 개선및및 쿠버인프라 테스트검증및 문서화 후 남은 토큰
- 한 세션 컨텍스트 내에서 3진영 언어 모두 수정을 하는것은 일반적이지 않으나 100%소진 없이 38% 남음 - GPT 프로기준
- 이 저장소의 목적이 3진영 분산처리를 지원하는 테스트된 스킬작성에 목적이 있으며 각 진영언어의 차이를 이해하고 동일장치를 일관성있게 코드구성을 하는 부가활동이 포함되어있습니다.
Erik Meijer의 한마디~
"이보게, 브라이언 괴츠, C#,파이선,자바스크립트는 물론 심지어 PHP도 async, await를 지원하고 있다네. 그런 기능이 없는 언어는 자바일뿐이야.
람다를 이용해서 콜백함수를 사용하면 된다고? 천만에 콜백은 최악이야. 도움이 안된다고. 자바 9 버전에 담으려고 하는 걸 다 내려놓고 지금당장
async, await부터 넣으라고. 그래야 모두가 행복해질수 있어"
자바진영 동시성 프로그래밍 차이 : 자바진영 동시성처리 프로그래밍
이 아티컬의 메모리 조각 : https://mcp.webnori.com/ui/view/15f0fd61-0339-4974-99e1-ef07d3567d64


Add Comment