PHP PHP에서 이벤트 소싱(Event Sourcing) 구조 구현하기
페이지 정보

영삼이
본문
✅ PHP에서 이벤트 소싱(Event Sourcing) 구조 구현하기
**이벤트 소싱(Event Sourcing)**은 상태를 직접 저장하는 대신, 상태의 변화를 일으킨 "이벤트의 연속"을 저장하는 아키텍처입니다. 전통적인 CRUD 방식과 달리, 변경의 이유와 히스토리를 모두 추적할 수 있는 강력한 도메인 중심 설계입니다. PHP에서도 이 구조를 충분히 구현할 수 있습니다.
🧠 이벤트 소싱이란?
-
현재 상태(state)를 저장하는 것이 아니라
→ 이 상태에 도달하기까지의 모든 이벤트를 저장 -
이력 추적, 감사 로그, 복원, 리플레이 등에 강함
-
복잡한 비즈니스 로직이 많은 도메인에서 유리
📦 핵심 구성 요소
구성 | 설명 |
---|---|
Aggregate | 이벤트를 발행하고 상태를 추적하는 도메인 모델 |
Event | 도메인에서 발생한 사실을 나타냄 |
Event Store | 이벤트들을 순차적으로 저장하는 저장소 |
Projector | 이벤트를 읽어 현재 상태를 계산하거나 View 모델을 만듦 |
🧩 1. 이벤트 클래스 정의
[code=php]
abstract class DomainEvent {
public function __construct(
public readonly string $aggregateId,
public readonly int $occurredAt = null
) {}
}
class UserRegistered extends DomainEvent {
public function __construct(
string $aggregateId,
public readonly string $email,
public readonly string $name
) {
parent::__construct($aggregateId, time());
}
}
[/code]
🧱 2. Aggregate Root
[code=php]
class User {
private array $events = [];
public static function register(string $id, string $email, string $name): self {
$user = new self();
$user->apply(new UserRegistered($id, $email, $name));
return $user;
}
private function apply(DomainEvent $event): void {
$this->events[] = $event;
// 상태 변화 로직도 여기에서 수행 가능
}
public function pullEvents(): array {
$events = $this->events;
$this->events = [];
return $events;
}
}
[/code]
💾 3. 이벤트 저장소 (Event Store)
[code=php]
class InMemoryEventStore {
private array $events = [];
public function append(DomainEvent $event): void {
$this->events[] = $event;
}
public function getAll(): array {
return $this->events;
}
}
[/code]
실제로는 DB (예:
event_store
테이블), 파일, Kafka 등에 저장 가능
🧮 4. Projector (읽기 모델 재구성)
[code=php]
class UserProjector {
private array $users = [];
public function apply(UserRegistered $event): void {
$this->users[$event->aggregateId] = [
'email' => $event->email,
'name' => $event->name
];
}
public function getUsers(): array {
return $this->users;
}
}
[/code]
🚀 사용 예시
[code=php]
$store = new InMemoryEventStore();
$projector = new UserProjector();
$user = User::register('user-1', 'kim@example.com', 'Kim');
foreach ($user->pullEvents() as $event) {
$store->append($event);
$projector->apply($event);
}
print_r($projector->getUsers());
[/code]
✅ 이벤트 소싱의 장점
항목 | 설명 |
---|---|
전체 이력 추적 | 상태 변화의 모든 원인을 저장 |
감사(Audit) | 언제 누가 어떤 변경을 했는지 명확 |
복원 가능 | 이벤트 리플레이로 현재 상태 복구 가능 |
CQRS와 궁합 | 읽기/쓰기 모델 분리 최적 |
⚠️ 주의사항
-
이벤트 구조 변경 시 마이그레이션 고려 필요
-
이벤트 순서 보장 중요 (append 시점 주의)
-
복잡도 상승: 단순 CRUD에는 과도한 구조일 수 있음
🧠 요약
-
이벤트 소싱은 상태가 아닌 변화의 히스토리를 저장하는 구조
-
PHP에서도 도메인 이벤트, 이벤트 스토어, projector로 구현 가능
-
복잡한 업무 도메인, 변경 추적이 중요한 서비스에 매우 유용
- 이전글PHP에서 CQRS + 이벤트 소싱 통합 적용하기 25.03.28
- 다음글✅ PHP에서 유닛 테스트 가능한 아키텍처 구성법 25.03.28
댓글목록
등록된 댓글이 없습니다.