Page History
...
쿠버도입시 대체가능한 Spring Boot Cloud요소
Spring Cloud Component | Kubernetes 대체 요소 |
Config Server | ConfigMap, Secret |
Service Discovery (Eureka) | DNS, Service |
API Gateway (Zuul, Gateway) | Ingress, Ingress Controller |
추가(고급 통신 관리) | Service Mesh (Istio, Linkerd) |
- 쿠버는 사실상 표준이 되었으며~ 쿠버등장이전 Spring Cloud가 지원하는 장치는 매력적임에 분명합니다.
파편화되는 모놀리식
모놀리식의 문제는 모놀리식 그 자체 보다는~ 초기 모놀리식으로 개발된 어플리케이션이 확장됨에 따라 경계구분이 없는 그자체가 문제되는 경우가 더 많습니다.
만약 모놀리식이 아직 단하나의 어플리케이션만 존재한다고 하면 리팩토링을 통해 경계를 찾고 확장할수 있는 일괄적인 설계를 도입할수 있지만
모놀리식으로 시작해~ 새롭게 요구되는 기능을 빠르게 만들기 위해 모놀리식에서 분리된 무엇인가를 지속 만들고
설계없이 경계구분없이 증가된 파편화된 어플리케이션 그자체이며 ,
- 새롭게 요구되는 기능을 빠르게 만들기위해 모놀리식에 분리된 무엇으로 작성
- 서비스 저장소가 추가됨에 따라 일괄적인 CI/CD를 사용하는것이아닌~ 최근기술을 사용
...
파편화된 모놀리스
...
때때로 "파편화된 모놀리스"라고 불리는 안티 패턴도 있습니다. 서로 독립적으로 빌드되고 배포되는 여러 서비스가 있지만, 공유 클러스터, 서비스 API 호출에 대한 공유 코드 및 종속성 또는 공유 데이터베이스 스키마와 같이 이를 매우 위험하게 만드는 긴밀한 결합이 있습니다. 코드와 배포 단위의 물리적 분리로 인해 자율성에 대한 잘못된 감각이 있지만, 한 서비스의 구현 변경 사항이 다른 서비스의 동작으로 누출되어 문제가 발생할 가능성이 높습니다.
이런 상황에 처한 조직은 종종 여러 서비스의 배포를 중앙에서 조정하려고 시도하여 대응하는데, 이때는 마이크로서비스의 주요 이점을 잃고 비용을 떠안게 됩니다. 실제로 분리할 수 없는 것들을 별도로 빌드하고 배포하는 중간 상태에 있습니다. 어떤 사람들은 이렇게 하고, 어떤 사람들은 이를 작동하게 만들지만, 이는 권장할 만한 일이 아니며 신중하게 관리해야 합니다.
draw.io Board Diagram | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
- 싱글톤 확장
- 단일어플리케이션에서 싱글톤패턴으로 작성된 기능은 중복수행을 하게됩니다. 이 모듈이 일정산이고 중복작동하면 비즈니스의 치명적인 결함을 가져올수 있습니다.
- 세션확장
- 어플리케이션이 수평확장되지만 어플리케이션간 정보를 공유하지 못함으로 세션을 중앙관리할 외부장치를 도입하게 됩니다.
- 단일지점 병목
- RDB단일지점 병목현상이 빠르게 증가합니다. 이때도 Nosql을 포함 다양한 외부장치를 도입하게 됩니다.
모놀리식 확장의 대부분의 문제는 설계없이 즉각 도입한 장치를 사용하고 파편화된 저장소를 계속 만들어가면서 파편화되는 모놀리식을 양산하는데 있으며 마치 이것이
마이크로 서비스의 확장으로 착각하는 경우가 있습니다.
Akka Cluster의 경우 모놀리식으로도 구성이 가능하며 필요하면 분리작동 시킬수 있습니다. 여기서는 모놀리식이란 표현보다 StandAlone으로 작동도 하고 필요하면 특정기능을 분산배치할수도 있는
AkkaCluster의 특징을 살펴보겠습니다.
AkkaCluster 마이크로서비스 특징
경계를 구분하고 분산처리가능 한 클러스터 시스템이 StandAlone 로 구성이 가능하며, 필요하면 특정 기능만 독립적으로 분리 작동시킬수도 있습니다.
전통적인 모놀리식이 확장됨에 따라 어떠한 요소가 필요로하게 되는지 먼저 살펴보겠습니다.
모놀리식으로 구성후 코드의 변경없이 단일지점처리/분산처리를 구성요소 변경만으로 확장할수 있는것이 AkkaCluster의 장점입니다.
모놀리식의 가장 큰장점은 로컬에서 전체가 작동되며 디버깅도 가능하다란 점입니다. 이 지점이 개발을 가속화하는 모놀리식의 특징중 하나입니다.
로컬 디벙깅이 가능하다란점은 유닛테스트로 확장할수도 있다란점이며, 모놀리식의 장점을 잃은 파편화된 모놀리식은 대부분 디버깅능력과 함께 유닛테스트 방법까지 함께 잃게되는 단점이있습니다.
클라우드의 발전과 함께 PaaS를 채택해 로컬에서 수행못하게 되는 경우도 있을수 있지만 로컬에서 AllinOne 작동되고 디버깅되는 StandAlone 방법을 먼저 준비하고
클러스터화된 멀티노드를 유닛테스트 할수 있는 방법까지 살펴보겠습니다.
draw.io Board Diagram | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
- 모놀리식으로 구성되고 단일로 작동시키면서 단일 로컬장치에서 분산처리 설계를 할수 있습니다. - StandAlone
- 단일 개발장치에서 클러스터를 구성해~ 클러스터 모드로 작동확인을 할수 있습니다. - MultiNode
- StandAlone의 구현코드와 분산처리 되는 Cluster구성시 구현코드가 모두동일하며 , 클러스터로 분산작동되어도 하나의 모놀리식 시스템인것처럼 작동되는것처럼 보일수 있는것이 Akka 클러스터가 추구하는 단일지점 병목없는 복잡한 도메인을 처리할시 복잡성을 단순화하는 Akka클러스터의 최종 골입니다.
SpringBoot에 AkkaCluster 탑재하기
AkkaConiguration 작성
- 단일로 작성된 어플리케이션에 akka.conf를 적용시키면서 동일저장소 다른 역할의 Role을 수행할수 있습니다.
- 액터의 구성은 DI가 아닌 계층형 구조를 따르게 됩니다. Cluster 역할을 할 MainStage(with AkkaClusterSystem)를 이 단계에서 생성합니다.
- AkkaSystem이 만든 객체를 RestAPI가 사용하게끔 하려면 이 곳에서 코드작성해 API에서 이용할수 있습니다.
MainStage작성
- AbstractBehavior를 상속받는 일반적인 TypedActor를 생성합니다.
- 지정되는 템플릿은 처리가능 이벤트 유형을 나타내며~ Classic Actor에 비해 Typed제약 이벤트만을 처리 하기때문에 컴파일 타임시 처리하지 못하는 메시지 오류를 검출합니다.
- 오류를 찾는것뿐만 아니라 Typed Actor의 경우 발생한 이벤트가 어떠한 액터가 처리하는지? 코드레벨에서 추적도 가능하게 됩니다.
- Untyped의 경우 IDE단계에서 함수추적하듯 코드추적이 안되며 수신받는 액터의 이벤트 리슨부분의 케이스패턴 코드를 살펴봐야합니다.
MultiNode Runner 작성
전체 작동을 확인을 할수 있는 장치를 초기에 준비하지 못해 각각 개발된 서비스가 통합되기전 개선활동을 확인을 못하는데 있으며 이 부분은 개발가속도를 느리게 하는 마이크로서비스의 단점이 될수도 있습니다.
MultiNode를 로컬에서 구성해 상호연동을 확인하는것은 중요하며 도커의 등장으로 이 부분은 이제 더이상 단점이 아닌 마이크로서비스를 채택했을때 필수로 해야하는 영역이 되었습니다.
- DockerCompose를 이용 멀티 작동을 준비해야하는것은 필수이며, AkkaCluster를 Multi Mode로 작동시킬수도 있습니다.
- CI/CD를 위해 자신이 작성한 어플리케이션의 도커빌드및 이미지 최적화는 이제 누구에게 맡기는 것이 아닌 개발Self의 영역이 되었습니다.
- 도커가 확산되기 전, 그 분야에 전문가에게 빌드스크립트 요청을 하는경우도 있었겠지만 선택이 아닌 필수입니다.
전체코드 : https://github.com/psmon/kopring-reactive-labs/blob/main/KotlinBootReactiveLabs/DOCKER.MD
Gradle Multi Runner
Code Block | ||
---|---|---|
| ||
### Standalone
``` shell
./gradlew bootRun -PserverPort=9090 -PclusterConfig=standalone
```
### Seed Node
``` shell
./gradlew bootRun -PserverPort=9090 -PclusterConfig=lighthouse
```
### Node1
``` shell
./gradlew bootRun -PserverPort=9091 -PclusterConfig=cluster1
```
### Node2
``` shell
./gradlew bootRun -PserverPort=9092 -PclusterConfig=cluster2
``` |
build.gradle.kts
Code Block | ||
---|---|---|
| ||
tasks.named<org.springframework.boot.gradle.tasks.run.BootRun>("bootRun") {
doFirst {
val args = mutableListOf<String>()
if (project.hasProperty("serverPort")) {
args.add("-Dserver.port=${project.property("serverPort")}")
}
if (project.hasProperty("clusterConfig")) {
args.add("-DCluster=${project.property("clusterConfig")}")
}
if (args.isNotEmpty()) {
jvmArgs = args
}
}
} |
Akka가 SpringBoot에 통합될수 있는 이유는 Akka는 프레임워크가 아니라 툴킷으로 분류되며 , Spring이 제공하는 스레드 영역이아닌
독립구성되고 분리된 영역에서 작동되며 자바 비동기처리 활용하면서 상호연동될수 있습니다. 초반 구성하는것에 다소 손이 많이가고 초기구성에 성공하고 몇가지 장치를 이해하면
클러스터된 시스템을 단지 이용하는것이아니~ 구성된 클러스터내에서 액터를 중심으로 분산처리에 이용되는 기능들을 단순화해 활용할수 있습니다.
SigleTone Cluster
단일 어플리케이션에서 단 하나만 작동시켜야하는 싱글톤 패턴을 이용하는 DI는 유용합니다. 단일 시스템내에서 단하나만 작동하기때문입니다.
하지만 이것을 복수개의 어플리케이션으로 확장했을때 클러스터내에서 단 하나만 작동하도록 하려면 배치시스템으로 분리하거나 독립구성을 해야합니다.
Akka 싱글톤 클러스터는 작성한 코드가 단 하나의 노드에서만 작동되도록 보장을 하고~ 해당 노드가 Crash되었을때 대체 노드로 작동이 변경이되는 2중화 기능도 자연스럽게 적용할수 있습니다.
이러한 기능을 분리하기위해 기존작성된 코드를 그대로 유지할수 있으며~ 필요한것은 단지 클러스터 배치옵션을 지정하는것 뿐입니다.
Cluster Config
Code Block | ||
---|---|---|
| ||
# cluster1.conf
akka.cluster {
seed-nodes = ["pekko://ClusterSystem@127.0.0.1:2551"]
roles = ["seed", "helloA", "shard"]
}
pekko.cluster.singleton {
# The actor name of the child singleton actor.
singleton-name = "singleton"
# Singleton among the nodes tagged with specified role.
# If the role is not specified it's a singleton among all nodes in the cluster.
role = "helloA"
}
# cluster2.conf
akka.cluster {
seed-nodes = ["pekko://ClusterSystem@127.0.0.1:2551"]
roles = ["helloB", "shard"]
} |
- 싱글톤 기능을 수행하는 역할노드가 helloA 라고 지정하는것으로 싱글톤클러스터 기능은 해당노드에서만 작동되며~ 나머지 노드에서는 해당 기능을 이용할수 있습니다.
- Seed노드는 일반적으로 주키퍼와 같은 기능을 수행하는 Discovery역할을 하는 노드로 도메인로직 없는 노드를 지정하는것이 권장되며 여기서는 자기자신에게 Seed역할을 부여함으로 2Node로만 Cluster 테스트 수행이 가능합니다.
Cluster UnitTest
- ActorTestKit은 유닛테스트 환경에서 AkkaSystem의 환경을 동일하게 구동합니다.
- 설정파일을 통해 각각 다른 역할을 수행하는 멀티노드를 구성할수 있게됩니다.
- 유닛테스트 작성을 "시간이 없어서~ 유용하지않아서" 라고 이야기하곤 합니다.
- 우리가 만든기능이 분산되었을때 단일지점에서 유닛테스트를 수행 할수 "있느냐? 없느냐?" 의 문제입니다.
유닛테스트 코드작성
Code Block | ||
---|---|---|
| ||
@Test
fun testSingleCluster(){
var givenInItCount = 5
val testProbe = nodeA.createTestProbe<CounterState>()
val testProbe2 = nodeB.createTestProbe<CounterState>()
val sigleton1:ClusterSingleton = ClusterSingleton.get(nodeA.system())
var proxy1:ActorRef<CounterCommand> = sigleton1.init(SingletonActor.of(CounterActor.create("singleId"), "GlobalCounter"))
val sigleton2:ClusterSingleton = ClusterSingleton.get(nodeB.system())
var proxy2:ActorRef<CounterCommand> = sigleton2.init(SingletonActor.of(CounterActor.create("singleId"), "GlobalCounter"))
proxy1.tell(Increment(3))
proxy1.tell(GetCount(testProbe.ref()))
testProbe.expectMessage(CounterState(3 + givenInItCount))
proxy2.tell(Increment(2))
proxy2.tell(GetCount(testProbe2.ref()))
testProbe2.expectMessage(CounterState(5 + givenInItCount))
} |
- 카운트를 증가하고~ 현재 카운트를 알려주는 단순한 액터를 싱글톤 클러스터화 했습니다.
- 각각 다른노드가 카운트를 증가시키고 값을 획득하더라도 ~ 단일지점의 상태서비스를 이용했기때문에 글로벌 카운트 서비스를 이용할수 있게됩니다..
이 장치가 활용될수 있는곳
- DB저장이 사용자 이벤트발생마다 CRUD를 하게되면~ 단일지점 DB의 높은 성능이 필요하게되며 파멸시나리오가 될수 있습니다. 단일지점으로 이벤트를 모아 안정적인 벌크처리를 할시이용될수 있습니다. ( Akka의 FSM Actor와 연계 )
- 외부 API를 이용하는경우 동시성보다는 호출 제약에 걸리는 경우가 많습니다. 이때 호출제약을 호출자에서 고려하지 않고 Max에 도달하면 호출금지 제약에 걸려 API호출을 못할수도 있습니다. 외부연동 API 특히 LLM사용시 호출 토큰모니터링을 할시 단일지점 컨트롤이 가능하게 됩니다. ( AkkaStream의 Throlle와 연계 )
- 시간단위 배치 일단위배치등 별도의 배치시스템없이 라이트한 단일지점 스케줄러가 필요할시 이용할수 있으며, 싱글톤 Role은 복수개로 운영될수 있지만 단 하나만 작동하기때문에 이중화 구성도 자연스럽게 구축됩니다.
SpringBoot API에서이용
- SpringBoot Reactive가 이용되었기때문에 Webflux-Mono 객체와 연결되었으며 API에서는 다음 두가지 액터 함수를 이용해 API에서 이용할수 있습니다.
- Tell : Fire And Forgot 기법으로 이벤트를 전송합니다.
- Ask Pattern : 해당 액터에게 응답을 요구할때 이용되며 CompleteableFuture및 Await(코틀린인경우)를 이용해 응답을 받을수 있습니다.
분산처리 Shard활용
싱글턴 클러스터는 클러스터내에 단하나만 작동시키는 기능으로 분산처리보다는 단일지점 처리를 보장하는 기능이였다고 하면
Shard는 아카클러스터내에 분산객체 처리를 할수 있게됩니다.
설정
Code Block | ||
---|---|---|
| ||
pekko.cluster.sharding {
guardian-name = sharding
role = "shard"
number-of-shards = 100
} |
- key기반으로 분산배치가 자동지원되며~ 해시테이블기법으로 보통 분산되며 role에 부여권 어플리케이션에서 이 기능이 수행됩니다.
- number-of-shard : 분산처리할 객체수를 의미합니다. 만약 노드가 2개라고 하면 50,50 으로 분산처리 될수 있습니다. 이 수치는 연결된 DB의 분산저장 동시처리량에 따라 전략적으로 튜닝할수 있습니다.
여기서는 분산저장을 배제하고 단순한 카운팅기능을 가진 객체만 클러스터내에 분산배치및 분산처리를 시도 해보겠습니다.
분산저장은 별도 전략이 필요한 Part로 여기서 다루지는 않겠습니다.
분산처리 객체 생성
Code Block | ||
---|---|---|
| ||
# AkkaConfiguration
// ClusterSharding
if (selfMember.hasRole("shard")) {
logger.info("My Application Role shard")
for (i in 1..100) {
val entityId = "test-$i"
var typeKey = EntityTypeKey.create(CounterCommand::class.java, entityId)
var shardSystem = ClusterSharding.get(mainStage)
shardSystem.init(Entity.of(typeKey, {
entityContext -> CounterActor.create(entityContext.entityId) }
))
}
} |
- 분산처리 가능 카운팅 액터 100개가 , shard role을 가진 node로 분산생성됩니다.
- 이 기능은 redis의 분산저장및 kafka의 mailbox queue도 내장되어 있으며 해당장치의 메시지딜러버리 Once를 대체용도는 아니며 AkkaCluster가 Inmem에서 StateFull 개발방식을 이용해 단일지점 병목을 부하분산처리할수도 있는 기능을 가지고 있음을 의미합니다.
- 외부 장치(kafka,redis) 와 Stream으로 연동을 하고 더 세부적인 분산처리가 필요할시 확장할수 있습니다.
- 외부 API호출은 kafka,redis와 같은 장치로 할수 있는것이 아닙니다.
- 처리량을 높일때 가장 큰비용은 DB, 분산저장에 유리한것은 Nosql, KeyValu로 빠르게 접근할수 있는것은 Redis입니다. Akka는 외부장치를 대체하는것이 아닌 Perditence장치및 중간 브로커로 다양하게 활용합니다.
Shard객체 테스트
- 각각 다른노드에서 카운트를 증가시키고 값을 검증하는 코드로~ entityID가 어딘가에 shard role을 가진 어플리케이션에서 배치되겠지만 , 다른 노드(Region)에서도 같은 entityID를 객체인경우 하나의 객체를 다루는것처럼 분배된 상태를 증가또는 획득할수 있습니다.
이 테스트는 목업으로 작동되는 것이 아닌 실제 Remote객체를 이용한 클러스터내 어플리케이션은 PeerToPeer 방식이 이용되며 네트워크 프로그래밍을 할필요없이 작동됩니다.
단지 actor를 클러스터로 작동시키는 remote를 정의하는 코드만 있습니다. ( DNS Discovery또는 쿠버 Discovery 이용시 hostname을 0.0.0.0 으로 지정할수 있습니다. - 위치투명성)
Code Block | ||
---|---|---|
| ||
actor{
provider = "cluster"
}
remote.artery {
canonical {
hostname = "127.0.0.1"
port = 2551
}
} |
- netty가 과거에는 기본전송 계층이였으나 artery를 기본계층으로 채택된듯하며 전송계층을 더 성능좋은 장치로 변경도 가능합니다..
객체직렬화
자바의 객체를 로컬에서만 이용하는 경우 메모리 참조만 하면되기때문에 직렬화/역직렬화 과정이 필요없습니다.
하지만 네트워크로 전송되거나 DataBase에 자바객체를 담기위해서는 직렬화 과정이 필요하며 JackSon을 이용하거나 경량화를 위해 바이너리 객체 또는 구글 프로토콜 버퍼를 이용할수도 있습니다.
리모트 객체도 더 빠른 객체가 등장하면 전송계층을 포함 데이터변환 객체등이 고정되는것이 아니라 선택할수 있는것이 Akka의 장점중 하나입니다.
Code Block | ||
---|---|---|
| ||
serializers {
jackson-json = "org.apache.pekko.serialization.jackson.JacksonJsonSerializer"
jackson-cbor = "org.apache.pekko.serialization.jackson.JacksonCborSerializer"
proto = "org.apache.pekko.remote.serialization.ProtobufSerializer"
}
serialization-bindings {
"org.example.kotlinbootreactivelabs.actor.PersitenceSerializable" = jackson-json
} |
Shard 객체 API에서 이용
- 유닛테스트가 완료되면~ 유닛테스트 된 코드를 그대로 spring boot api 에 담기만 하면 됩니다.
akka http가 액터모델과 상호작용하는 기능을 제공해 더 편리하긴하지만~ 이것때문에 웹프레임워크(playframework)를 교체하는것은 akka를 전면채택했을때 고려사항이며
스프링부터 API레벨에서 액터모델을 활용하는 개발 style이 다소 불편해 보일수 있지만~ 다양한 외부장치를 혼합해 분산처리를 하려는 패턴보다 더 심플해질수 있습니다.
분산처리 PUBSUB
- SSE(Simple Sent Event)를 이용해 구독(sub)을 하고
- API 액터모델을 이용해 발행(pub)을 할수 있습니다.
메시지 브로커에서 일반적으로 지원하는 pub/sub 방식도 akka가 지원하는 분산처리 장치중 하나로 여기서는 자세한 설명이 생략되었으나~
아래 코드를 통해 샘플클라이언트를 통해 기능작동 확인을 할수 있으며 유닛테스트도 포함되어 있습니다.
이 장치는 redis 의 pub/sub 에 대응하며 해당장치와 연동하거나 대체할수도 있습니다.
- https://github.com/psmon/kopring-reactive-labs/tree/main/KotlinBootReactiveLabs/src/main/kotlin/org/example/kotlinbootreactivelabs/actor/sse
- https://github.com/psmon/kopring-reactive-labs/blob/main/KotlinBootReactiveLabs/src/main/kotlin/org/example/kotlinbootreactivelabs/actor/MainStageActor.kt
ExacltlyOnce Delivery
Akka의 Actor 메시지전송은 기본적으로 AtMostOnce 로 동작합니다. 전송보장을 위해 별도 설계를 할수도 있겠지만
중요 도메인 이벤트인경우 Kafka와 연동하는것을 권장하며 Reactive Stream(AkkaStream)을 통해 액터모델은 외부장치와 연결해
다양한 Consumer 전략을 선택할수 있습니다.
Link :
- https://pekko.apache.org/docs/pekko-connectors-kafka/current/
- https://pekko.apache.org/docs/pekko-connectors-kafka/current/consumer.html#choosing-a-consumer
At-Most-Once Delivery란?
- 메시지가 최대 한 번만 전달됨을 보장합니다.
- 네트워크 장애 또는 기타 원인으로 인해 메시지가 손실될 수 있음.
- 메시지 중복이 발생하지 않음.
- 성능이 가장 우수하지만, 신뢰성이 낮음.
- 손실이 허용되는 경우
- 예: 모니터링 시스템(일부 로그 손실이 치명적이지 않음)
- 예: 게임 로직에서의 이벤트(일시적인 위치 업데이트)
- 고성능이 중요한 경우
- ACK 기반 재전송이 필요 없기 때문에 메시지 처리 속도가 중요할 때 사용
- 데이터가 중요하지 않거나, 외부에서 보완할 수 있는 경우
- 예: UI 알림 전송 (사용자가 새로고침하면 다시 불러올 수 있음)
At-Most-Once 방식의 메시지 손실 문제를 보완하기 위해 다음과 같은 방법을 고려할 수 있음.
At-Least-Once Delivery
- 재전송을 통해 메시지 전달을 보장하지만, 중복이 발생할 수 있음.
- Akka에서는
ask
패턴 또는 Akka Persistence(이벤트 소싱) 사용.
Exactly-Once Delivery
- 중복 제거 로직을 추가하여 메시지가 정확히 한 번만 처리되도록 보장.
- Kafka 등의 외부 메시지 브로커와 조합하여 구현.
Akka Reliable Delivery 사용
- Akka의
Reliable Delivery
기능을 활용하면 At-Least-Once 또는 Exactly-Once 보장을 구현할 수 있음.
- Akka의
마치며
개인적으로 이 프로젝트를 팀에 활용하기위해 연구하는것은 다음 목표에 있습니다.
- Spring Boot이 주는 기본 Stack만으로도 고성능처리를 하기위해 부족함이 없습니다. 그래서 기본기가 가장중요합니다.
- 액터모델 부분 채택
- Akka의 채택은 SpringBoot Reacrive Adapter가 하지못하는 나머지 영역입니다.
- 전통적으로 웹진영에서 발전해혼 SteteLess기법만으로 대용량을 처리하는 경우 PasS의 의존도가 높아질수 있습니다.
- SteateFul 기법은 대용량 처리시 난이도가 있을수 있지만 비용절감 기법중 하나가 될수 있는 무기가 될수 있습니다.
- 액터모델은 StateFul 개발기법을 분산처리에 도입하고자할때 복잡성을 줄여주는 다양한 툴킷을 제공합니다.
- 외부장치 연동 ( kafka, mq...,nosql)
- 외부장치를 단순하게 풀링으로 이용하는것이아닌 stream으로 연동되어 상호 작동하는 인터페이스가 reactive stream으로 크게 성공한 활동입니다.
- reactive stream을 주도했던 기업이 akka를 만든 라이트벤드사 이며 akka가 아니여도 되지만, akka stream은 reactive stream을 준수하는 모든 장치와 고수준으로 연동하는 장치를 제공합니다.
- https://learn.microsoft.com/ko-kr/azure/event-hubs/event-hubs-kafka-akka-streams-tutoria
- MS에서 자바 특정 프레임워크 akka 연동을 공식문서에 언급하는것은 이례적입니다.
- https://learn.microsoft.com/ko-kr/azure/event-hubs/event-hubs-kafka-akka-streams-tutoria
- akka가 아니여도되지만 액터모델과 연동되는 cqrs의 장치를 적어도 사용하고 작동시킬수 있음으로 이해를 시작 할수 있습니다. crud로만으로 오늘날의 대용량 트래픽을 커버할수 없으며 모든 샘플과 이론은 액터를 중심으로한 cqrs기법이 설명됩니다.
- 그동안 클라우드를 이용한던 웹진영의 StateLess 개발방식의 변화
PasS에 의존하해 클라우드 클러스터를 활용하는것이 개발속도가 분명 가장 빠릅니다.
하지만 오늘날의 달러환률에 따른 클라우드 상승에따라 , 클라우드제공 시스템만을 사용하기에는 인프라비용을 최소화해야하는 오늘날의 개발팀에서 부담으로 다가옵니다.
- 단일지점 병목을 분산된 어플리케이션이 나눠서 처리하는 것이 akka 시스템의 목표이며 ec2의 비용은 저렴합니다. 저렴한 장치의 연산이용을 높이고 값비싼 단일지점 DB의 비용을 줄이는 전략은 앞으로 빠른개발을 위해 PasS를 만을 채택했던 개발기업이 트래픽 증가당 이익을 내기위해서는 클라우드 장치에만 의존하지않고 , 설계된 장치를 함께 운영하는 하이브리드 전략을 사용할것으로 예상합니다.
- aws 의 sqs는 매력적이지만 예측불가한 호출당 비용을 IT비용부서에서는 좋아하지 않습니다. 월과금이 일정한 kafka장치를 채택하거나 필요하면 온프레미스로 운영할수도 있으며 일부장치는 이미 존재하는 어플리케이션이 분산처리를 분담할수 있습니다.
새로운 패러다임의 개발패턴을 적용한다고하면 유닛테스트를 통해 설명가능하고 작동가능한 코드를 먼저 작성하는것이 권장되며
이 변종실험이 어떠한 팀에는 도움되는 장치가 되었으면 하는 오픈소스 마인드로
여기서 설명되는 모든 코드의 유닛테스트 코드를 함께 공유합니다.
Refrences: