이전글 - Concurrency(9) Global Actors
Modern Concurrency in Swift를 읽고 간단 정리
이전 장들에서, 다중 CPU 코어에서 동시성 작업을 병렬로 실행하는 방법들을 배웠다.
또한 액터 타입을 사용하여 동시성을 안전하게 관리하는 방법도 익혔다.
이번 마지막 장에서는 Distributed Actor를 다룬다.
Distributed Actor는 로컬에서만 실행되는 것이 아니라, 다른 프로세스나 다른 기기에서 실행될 수 있다.
Distributed Actor는 다음 상황에서 사용될 수 있다.
- 같은 기기의 자식 프로세스에서 코드 실행
- 동일한 기기에서 메인 프로세스와 독릭접인 자식 프로세스에서 코드를 실행하여 안전성을 높인다.
- 자식 프로세스에 치명적 오류가 발생하더라도, 메인 프로세스는 계속 정상 작동
- 메인 프로세스는 문제가 발생한 자식 프로세스를 종료한 후 새로운 자식 프로세스 시작 가능
- 원격 머신에서 프로세스 실행 (예: 데이터베이스)
- 원격 머신에서 실행 중인 프로세스를 활용하여 작업을 처리한다.
- REST API나 GraphQL 같은 별도의 통신 프로토콜을 사용할 필요 없이, 직접 메서드 호출을 통해 서버에서 실행 중인 객체와 상호작용할 수 있다.
- 이는 코드의 간결설을 높이고 네트워크 통신 로직을 최소화할 수 있다.
- 기기 클러스터를 사용하여 작업 병렬 처리
- 여러 기기를 동시에 사용하여 많은 작업을 분산 처리
- 다수의 기기에서 작업을 병렬로 실행하여 작업 처리속도를 높일 수 있다.
- 대규모 연산 작업이나 데이터 처리에 유용
Understanding the State of distributed Actors in Swift
Distributed actor는 Swift의 동시성 모델에서 제안된 일부이다.
Swift 5.5가 처음 asnyc/await을 도입했을 때,
distributed language 기능에 대한 부분적인 실험적 지원이 있었지만 모든 구현이 완료된 것은 아니다.
이 책이 쓰여지는 시점에 최신 Swift 버전은 5.8이며 여전히 작업이 진행중인 것 처럼 느껴진다.
- 이 기능이 여전히 실험적인 것이라고 설명된다.
- 오픈소스(https://github.com/apple/swift-distributed-actors/)에 여전히 1.0.0-beta ver.
- 문서가 불명확하고 오타가 있고 여전히 초안 버전처럼 보인다.
- 일반적으로 actor system을 구축하는 것은 매우 복잡하다. 그러나 개발자가 사용할 수 있는 Apple의 공식적으로 릴리즈된 시스템은 아직 없다.
- 공식적으로 제공된 예제는 modern concurrency 기능을 활용하기 보다, async/await, calss, lock, notification의 조합을 사용한다.
이번 챕터에서는 거의 완성된 distributed actor system이 포함된 프로젝트에서 작업한다.
네트워크 서비스, actor system, distributed actor 등 몇 가지 사항을 변경해보면서 시스템이 어떻게 작동하는지 배우는 것이 목표이다.
Evolving the Local to Distributed
- 액터는 이들의 내부 상태를 격리하여 내부 상태에 대한 접근을 동기화된 범위로 제한하는 역할을 한다.
- 외부에서 액터 내부에 접근하려면 비동기적 호출이 필요하다.
- 외부에서의 비동기 호출은 임의의 시간이 걸릴 수 있다. 우리는 Chp6. Testing Asynchronous Code에서 비동기 호출에 대한 timeout 처리를 구현해야 했다.
[local actor]
- 컴파일러가 액터의 상태에 접근하는 호출을 자동으로 직렬화한다.
[distributed actor]
- 단순한 로컬 동작이 아니라, 네트워크를 통해 다른 기기나 프로세스와 통신할 수 있는 확장된 기능을 제공한다.
- local actor와 다르게 네트워크 통신을 활용
- 이때 컴파일러가 기본적으로 비동기 논리를 적용하는 격리 계층에 전송 서비스(Transport Service)를 추가
- 다른 기기나 웹 서버와 통신이 가능
[Location Transparency]
- distrtibued actor는 위치 투명성(Loaction Transparency) 개념을 도입
- actor가 어디에 있든지 상관없이, 동일한 방식으로 접근하고 사용할 수 있게 해준다.
- local actor와 distributed actor를 거의 동일한 방식으로 다룰 수 있게 해준다.
- 두 가지를 전환하는 데에 최소한의 코드 변경만 필요
- 위 다이어그램에서 UI(MyView)는 액터가 로컬에서 실행되는지, 네트워크 상의 원격 서버에서 실행되던 차이가 없다.
[Transport agonstic]
- 특정 전송 기술에 구애받지 않는다.
- actor가 서로 다른 네트워크 통신 방법(전송 서비스) 중 어느 것을 사용하더라도 동일하게 동작 가능
- Bluetooth, REST API, WebSocket 관계 없이 지원
[Transport Layer]
- 전송 계층(transport layer)은 로컬에서 실행 중인 distributed actor와 원격에서 실행 중인 distributed actor 사이의 중간 역할
- 로컬 액터의 호출을 원격 액터로 전달, 원격 액터의 응답을 다시 로컬로 받아옴
[Distributed actor의 제약사항]
- 데이터에 대한 직접 접근 금지
- Distributed actor는 외부에서 데이터를 직접 접근할 수 없다.
- local actor와 동일한 개념으로 비동기 메서드 호출을 통해서만 데이터를 변경하거나 읽을 수 있다.
- 전송 계층(Transport Layer)이 요청을 보내고 응답을 기다릴 수 있도록 해주며, 비동기적으로 메서드 호출이 이뤄지도록 강제
- 고유 식별자 (Unique Id)
- 네트워크 상에서 고유하게 식별되기 위해 자유 형식의 ID 속성을 갖는다.
- Codable
- Distributed actor의 메서드에서 사용되는 매개변수와 반환 값은 자동 직렬화되어 네트워크를 통해 전송
- 따라서 Codable을 준수해야 한다. (액터 시스템이 요구하는 다른 직렬화 프로토콜로 대체될 수 있음)
- 모든 속성 및 메서드 호출이 throwing
- 네트워크 통신 실패 같은 오류가 발생할 수 있기 때문에, 모든 속성 접근과 메서드 호출이 throwing
- 오류를 던지지 않을 것 같은 메서드도 항상 try로 호출해야함.
Distributed Actor
https://developer.apple.com/documentation/distributed/distributedactor
Overview
- 모든 distributed actor 타입에 대한 공통의 행동을 정의하는 프로토콜
- Implicit Conformance
- distributed actor는 이 프로토콜을 암시적 준수
- 직접 채택 불가
- DistributedActor 프로토콜은 distributed actor에만 적용할 수 있다.
- 일반 클래스, 구조체에서는 이 프로토콜을 따를 수 없음
- 프로토콜 세분화 및 제네릭 제약
- 다른 프로토콜과 결합하여 특정 타입이 distributed actor임을 보장하는 제약을 만들 수 있다.
Synthesized Properties
Swift의 distributed actor는 actorSystem과 id 두 가지 프로퍼티를 컴파일러가 자동으로 생성한다.
이 속성들은 코드에서 명시적으로 구현하는 것은 불가능
- actorSystem
- distributed actor가 속한 시스템을 나타낸다.
- 원격 호출이 어떤 시스템을 통해 전달되는지를 정의
- id
- 액터를 고유하게 식별하는 값으로, 분산 시스템에서 서로 다른 액터들을 구별할 때 사용
- nonisolated 속성
- actorSystem, id는 모두 nonisolated로 선언된다.
- 이는 분산 액터가 원격에 있더라도 해당 속성에 안전하게 접근할 수 있음을 의미
The ActorSystem associated type
모든 distributed actor는 ActorSystem이라는 연관 타입을 지정해야 한다.
이 시스템은 액터가 어떤 분산 시스템에서 동작하는지를 정의하고 액터의 다른 속성들이 유추된다.
- 직렬화 요구사항(SerializationRequirement)
- 분산 액터의 메서드가 원격에서 호출될 때, 전달되는 인자와 반환 값이 올바르게 직렬화될 수 있는지 컴파일 타임에 확인
- Codable 같은 프로토콜을 통해 직렬화 가능 여부 확인
- ID의 Codable 여부
- 액터의 ID가 Codable이면, 해당 액터 자체도 Codable로 간주된다.
- 이는 액터가 원격 시스템으로 전송될 때 직렬화 및 역직렬화가 가능하다는 것을 의미
- 기본 생성자에서 허용되는 ActorSystem 타입
distributed actor Greeter {
typealias ActorSystem = GreetingSystem // which conforms to DistributedActorSystem
func greet() -> String { "Hello!" }
}
The DefaultDistributedActorSystem type alias
모듈 또는 전체 코드베이스에서 하나의 액터 시스템만 사용하는 경우가 많다.
DefaultDistributedActorSystem이라는 모듈 전역에 typealias 선언 가능
import Distributed
import AmazingActorSystemLibrary
typealias DefaultDistributedActorSystem = AmazingActorSystem
distributed actor Greeter {} // ActorSystem == AmazingActorSystem
특정 액터가 사용하는 시스템을 오버라이딩시킬 수 있음
typealias DefaultDistributedActorSystem = AmazingActorSystem
distributed actor Amazing {
// ActorSystem == AmazingActorSystem
}
distributed actor Superb {
typealias ActorSystem = SuperbActorSystem
}
일반적으로 DefaultDistributedActorSystem는 public을 선언하지 않는다.
(기본 값을 선택하는 것은 프로젝트의 각 모듈에 맡겨야 하기 때문)
Default Initilaizer
- distributed actor는 기본 생성자 init(actorSystem:)을 생성
- 반드시 자신이 속할 액터 시스템을 생성자에서 지정해야 한다.
distributed actor Greeter {
typealias ActorSystem = GreetingSystem
init(actorSystem: GreetingSystem) {
// actorSystem을 받아서 분산 액터를 초기화
}
}
Implicit Properties
모든 distributed actor 타입은 자동 생성된 속성 id와 actorSystem을 받는다.
[Property: Actor System]
- distributed actor의 생명주기 관리에서 중요한 부분
- 초기화와 해제 모두 액터 시스템과의 상호 작용이 필요하다.
- 또한 원격에서 액터에 이뤄지는 모든 상호작용은 액터 시스템이 처리
- 초기화 함수에서 명시적으로 할당해야 함
- 이니셜라이저에서 명시적으로 주입받는 것을 권장
// GOOD
init(name: String, actorSystem: Self.ActorSystem) {
self.name = name
self.actorSystem = actorSystem
}
// BAD
init(name: String, actorSystem: Self.ActorSystem) {
self.name = name
// BAD, will cause compile-time error; the `actorSystem` was not initialized.
}
[Property: Distributed Actor Identity]
- distributed actor가 초기화될 때 액터 시스템에 의해 할당
- 액터 자체가 이를 설정하거나 변경할 수 없음
- 액터의 고유 정체성(Identity)
- 동등성 검사(Equality checks)
- Codable 준수
- id 타입이 Codable을 준수할 경우 액터도 자동으로 Codable 준수
'iOS > Concurrency' 카테고리의 다른 글
Concurrency (9) Global Actors (2) | 2024.10.13 |
---|---|
Concurrency (8) Getting Started With Actors (0) | 2024.09.29 |
Concurrency (7) Concurrent Code With TaskGroup (0) | 2024.09.15 |
Concurrency (6) Testing Asynchronous Code (1) | 2024.09.08 |
Concurrency (5) Intermediate async/await & Checked Continuation (0) | 2024.09.01 |