Swift에서 분산 액터

Ios_Roy·2025년 9월 26일

WWDC

목록 보기
5/13
post-thumbnail

WWDC22: Swift 분산 액터(Distributed Actor) 전체 요약 & 코드 정리

Swift 5.6은 동시성과 네트워크 프로그래밍을 결합한 분산 액터(Distributed Actor) 기능을 공식 지원합니다.
이 기능은 서버-클라이언트 모델, 멀티플레이어 게임, 분산 처리 시스템에 혁신적인 해법을 제시합니다.


1. 분산 액터의 등장 배경

  • 동시성(Concurrency): 여러 작업을 동시에 처리, 데이터 충돌 막는 구조
  • 네트워크 분산: 여러 서버/클라이언트에서 안전한 데이터 동기화 필요

기존 Swift 액터로는 네트워크 경계 넘는 작업이 어려움
→ 분산 액터로 네트워크 및 동시성 문제를 한 번에 해결


현대 앱 개발에서 단일 디바이스의 한계를 넘어서는 것은 필수가 되었습니다. 실시간 멀티플레이어 게임, 협업 도구, 클라우드 컴퓨팅, 마이크로서비스 아키텍처 등 모든 곳에서 분산 시스템이 요구됩니다.
하지만 분산 시스템 개발은 전통적으로 매우 복잡했습니다:

네트워크 프로그래밍의 복잡성
직렬화/역직렬화 처리
에러 처리와 재시도 로직
네트워크 지연과 실패 관리
동기화 문제

Distributed Actors는 이런 복잡성을 Swift의 강력한 타입 시스템과 컴파일러 지원으로 해결합니다.

Actor 관련 세션들을 보면 "동시성의 바다"라는 표현이 자주 사용된다.

2. 액터(Actor) 구조와 동작 원리

액터는 데이터 무결성과 안전성을 위한 ‘동시성 보호 컨테이너’입니다.

public actor OfflinePlayer: Identifiable {
    nonisolated public let id: ActorIdentity = .random
    let team: CharacterTeam
    let model: GameViewModel
    var movesMade: Int = 0

    public init(team: CharacterTeam, model: GameViewModel) {
        self.team = team
        self.model = model
    }

    public func makeMove(at position: Int) async throws -> GameMove {
        let move = GameMove(playerID: id, position: position, team: team, teamCharacterID: team.characterID(for: movesMade))
        await model.userMadeMove(move: move)
        movesMade += 1
        return move
    }

    public func opponentMoved(_ move: GameMove) async throws {
        do {
            try await model.markOpponentMove(move)
        } catch {
            log("player", "Opponent made illegal move! \(move)")
        }
    }
}
  • 내부 상태는 외부에서 직접 접근 불가
  • 모든 함수는 격리된 실행 환경에서 동작

3. 분산 액터 선언 및 코드 예시

분산 액터는 distributed 키워드로 선언하며,
원격 호출(distributed func)이 가능해집니다.

import Distributed

public distributed actor BotPlayer: Identifiable {
    typealias ActorSystem = LocalTestingDistributedActorSystem
    var ai: RandomPlayerBotAI
    var gameState: GameState

    public init(team: CharacterTeam, actorSystem: ActorSystem) {
        self.actorSystem = actorSystem
        self.gameState = .init()
        self.ai = RandomPlayerBotAI(playerID: self.id, team: team)
    }

    public distributed func makeMove() throws -> GameMove {
        return try ai.decideNextMove(given: &gameState)
    }

    public distributed func opponentMoved(_ move: GameMove) async throws {
        try gameState.mark(move)
    }
}

4. ActorSystem의 역할과 코드

ActorSystem은 네트워크 연결, 액터 인스턴스 관리, ID 발급 및 직렬화까지 담당합니다.

let sampleSystem = SampleWebSocketActorSystem()
let opponentID = BotPlayer.ID.randomID(opponentFor: self.id)
let bot = try BotPlayer.resolve(id: opponentID, using: sampleSystem)

서버: ActorSystem 등록 및 핸들러

@main
struct Boot {
    static func main() {
        let system = try! SampleWebSocketActorSystem(mode: .serverOnly(host: "localhost", port: 8888))
        system.registerOnDemandResolveHandler { id in
            if system.isBotID(id) {
                return system.makeActorWithID(id) { OnlineBotPlayer(team: .rodents, actorSystem: system) }
            }
            return nil
        }
        print("=== TicTacFish Server Running on: ws://\(system.host):\(system.port) ===")
        try await server.terminated
    }
}
  • 클라이언트 요청 시, 맞는 액터 인스턴스 동적 생성해 반환
  • 클러스터 내 여러 액터 인스턴스 핸들링 가능

5. 원격 액터 해석(Resolve) 및 동적 생성

네트워크상에서 액터의 ID로 해당 객체를 찾아냅니다.

let opponentID = BotPlayer.ID.randomID(opponentFor: currentPlayerID)
let remoteActor = try BotPlayer.resolve(id: opponentID, using: actorSystem)
  • 동적 매칭, 실시간 동시성 정보 공유 가능

6. 서버와 클라이언트 구조 적용

서버, 클라이언트 모두 ActorSystem을 통해
분산 액터 기반의 서버/클라이언트 구조를 쉽게 구축할 수 있습니다.

서버: onDemand Resolve

서버는 필요한 순간 액터 생성, 클라이언트의 분산 호출에 대응

클라이언트: 원격 액터 resolve

클라이언트에서 서버의 RemotePlayer 등 resolve 후 직접 분산 함수 사용


7. 데이터 직렬화, 보안, 에러 처리

직렬화/역직렬화:

  • 네트워크에서 객체 전달 시 Codable을 준수해야 안전
  • 형식 불일치, 네트워크 장애, 딜레이 등에 robust한 설계 필요

보안:

  • 인증(Authorization), 암호화(Encryption) 고려

에러 처리:

  • try/catch, 재연결, 상태 롤백, 장애 복구 등 패턴 설계 권장

8. 실전 적용 및 패턴

  • 멀티플레이어 게임: 서버/클라 동적 플레이어 액터 관리
  • 실시간 공동 편집: 분산 액터를 통한 동기화
  • 마이크로서비스/서버리스: ActorSystem 기반 분산 처리

9. 장점 및 한계점

장점한계점
동시성 & 네트워크 합친 구조복잡한 ActorSystem 직접 설계 필요
안전성 & 오류 방지직렬화/보안 등 네트워크 코딩 추가 필요
Swift 자체 기술성능 튜닝, 장애복구 직접 구현해야 함
동적 매칭, 확장성실서비스 환경 배포/운영 난이도 있음

10. 미래 전망

  • 다양한 ActorSystem 오픈소스, 프레임워크 등장 전망
  • SwiftNIO, GRPC 등과 직접 연결한 분산 서버 시스템 발전 예상
  • 테스트 도구, 포인트-투-포인트 네트워크 튜닝까지 발전 기대

실전 마무리 포인트

분산 액터는 동시성과 네트워크 분산을 Swift에서 직접 해결하는 최신 패턴입니다.
실제 코딩 시, ActorSystem 설계, 직렬화/복구 패턴, 서버-클라이언트 구조 등
아래 예시처럼 전체 구조/코드/동작 원리를 이해하고 사용하면 성공적인 대규모 Swift 프로젝트가 가능합니다.


// 분산 액터 선언 예시
public distributed actor GamePlayer {
    // 분산 함수
    public distributed func makeMove() -> GameMove { ... }
    public distributed func opponentMoved(move: GameMove) async throws { ... }
}

// ActorSystem을 통한 네트워크 연결
let system = MyActorSystem()
let remotePlayer = try GamePlayer.resolve(id: GamePlayer.ID("player2"), using: system)
// 네트워크를 통해 remotePlayer 분산 함수 호출 가능!

profile
iOS 개발자 공부하는 Roy

0개의 댓글