>  기사  >  백엔드 개발  >  PHP에서 이벤트 기반 아키텍처 구현: 이벤트 소싱 및 CQRS에 대한 심층 분석

PHP에서 이벤트 기반 아키텍처 구현: 이벤트 소싱 및 CQRS에 대한 심층 분석

Patricia Arquette
Patricia Arquette원래의
2024-09-22 06:20:48348검색

Implementing Event-Driven Architectures in PHP: A Deep Dive into Event Sourcing and CQRS

이벤트 중심 아키텍처(EDA)는 시스템을 분리하고 이벤트에 응답하여 시스템을 더욱 유연하고 확장 가능하며 유지 관리 가능하게 만드는 데 중점을 둡니다. PHP에서는 EDA에서 자주 사용되는 두 가지 중요한 패턴은 이벤트 소싱CQRS(Command Query Responsibility Segregation)입니다. 다음은 실습 예제와 함께 PHP를 사용하여 구현하는 단계별 가이드입니다.

개념 개요

1. 이벤트 소싱:

  • 데이터베이스에 애플리케이션의 최종 상태만 유지하는 대신 애플리케이션 상태에 대한 모든 변경(이벤트)이 저장됩니다.
  • : 주문 시스템이 있는 경우 최신 주문 상태만 저장하는 대신 "주문 생성", "항목 추가", "결제 완료" 등과 같은 주문에 대한 모든 작업을 저장합니다.

2. CQRS:

  • CQRS는 읽기(쿼리) 작업과 쓰기(명령) 작업을 구분합니다. 비즈니스 로직과 검증에 초점을 맞춘 쓰기 모델과 데이터 표현에 초점을 맞춘 읽기 모델로 두 모델이 별도로 발전할 수 있습니다.
  • : 전자상거래 사이트와 같은 복잡한 시스템의 경우 주문(쓰기) 로직을 주문 세부정보 가져오기(읽기)와 분리할 수 있습니다.

아키텍처 흐름

  1. 명령:

    • 명령은 상태 변경을 요청하는 작업입니다(예: "PlaceOrder", "AddItemToOrder").
    • 명령은 비즈니스 로직을 수행하고 이벤트를 발생시키는 명령 처리기에 의해 처리됩니다.
  2. 이벤트:

    • 명령이 처리된 후 중요한 일이 발생했음을 나타내는 이벤트(예: "OrderPlaced", "ItemAdded")가 발생합니다.
    • 이벤트는 변경할 수 없으며 읽기 모델 업데이트, 외부 시스템 알림 등 시스템의 다른 부분에서 작업을 트리거합니다.
  3. 모델 읽기:

    • 읽기 모델은 이벤트에 반응하여 최신 상태로 유지됩니다. 읽기 작업에 최적화되어 있으며 쓰기 모델과 다른 스키마를 가질 수 있습니다.

단계별 예: 주문 시스템

1단계: 프로젝트 설정

디렉토리 구조 만들기:

event-driven-php/
    ├── src/
    │   ├── Commands/
    │   ├── Events/
    │   ├── Handlers/
    │   ├── Models/
    │   └── ReadModels/
    ├── tests/
    └── vendor/

종속성 설치(예: Symfony/event-dispatcher):

composer require symfony/event-dispatcher

2단계: 명령 정의

명령은 상태를 변경하는 작업을 나타냅니다. 예: PlaceOrderCommand.php.

// src/Commands/PlaceOrderCommand.php
class PlaceOrderCommand
{
    public string $orderId;
    public string $customerId;

    public function __construct(string $orderId, string $customerId)
    {
        $this->orderId = $orderId;
        $this->customerId = $customerId;
    }
}

3단계: 이벤트 만들기

이벤트는 시스템에서 발생한 일을 설명합니다. 예: OrderPlacedEvent.php.

// src/Events/OrderPlacedEvent.php
class OrderPlacedEvent
{
    public string $orderId;
    public string $customerId;

    public function __construct(string $orderId, string $customerId)
    {
        $this->orderId = $orderId;
        $this->customerId = $customerId;
    }
}

4단계: 명령 처리기

명령 핸들러는 실제 비즈니스 로직을 수행하고 이벤트를 발생시킵니다. 예: PlaceOrderHandler.php.

// src/Handlers/PlaceOrderHandler.php
use Symfony\Component\EventDispatcher\EventDispatcher;

class PlaceOrderHandler
{
    private EventDispatcher $eventDispatcher;

    public function __construct(EventDispatcher $eventDispatcher)
    {
        $this->eventDispatcher = $eventDispatcher;
    }

    public function handle(PlaceOrderCommand $command)
    {
        // Business logic (e.g., check stock, validate order)

        // Emit the event
        $event = new OrderPlacedEvent($command->orderId, $command->customerId);
        $this->eventDispatcher->dispatch($event, 'order.placed');
    }
}

5단계: 이벤트 핸들러(읽기 모델에 데이터 예측)

이벤트 핸들러는 특정 이벤트를 수신하고 읽기 모델을 업데이트합니다. 예: OrderProjection.php.

// src/ReadModels/OrderProjection.php
class OrderProjection
{
    private array $orders = [];

    public function onOrderPlaced(OrderPlacedEvent $event)
    {
        // Save or update read model with necessary data
        $this->orders[$event->orderId] = [
            'orderId' => $event->orderId,
            'customerId' => $event->customerId,
            'status' => 'placed'
        ];
    }

    public function getOrder(string $orderId)
    {
        return $this->orders[$orderId] ?? null;
    }
}

6단계: 종합하기

use Symfony\Component\EventDispatcher\EventDispatcher;

// Bootstrapping the system
$dispatcher = new EventDispatcher();
$orderProjection = new OrderProjection();

// Register event listeners
$dispatcher->addListener('order.placed', [$orderProjection, 'onOrderPlaced']);

// Create the command and command handler
$command = new PlaceOrderCommand('123', 'cust_001');
$handler = new PlaceOrderHandler($dispatcher);

// Handle the command (Place the order)
$handler->handle($command);

// Query the read model for the order
$order = $orderProjection->getOrder('123');
print_r($order);

출력:

Array
(
    [orderId] => 123
    [customerId] => cust_001
    [status] => placed
)

7단계: 이벤트 저장소(선택 사항)

전체 이벤트 소싱을 위해 이벤트 저장소를 구현하여 이벤트를 데이터베이스에 보관할 수도 있습니다.

class EventStore
{
    private array $storedEvents = [];

    public function append(Event $event)
    {
        $this->storedEvents[] = $event;
    }

    public function getEventsForAggregate(string $aggregateId): array
    {
        return array_filter($this->storedEvents, function($event) use ($aggregateId) {
            return $event->aggregateId === $aggregateId;
        });
    }
}

부품별 분석

  1. 명령 생성: 무언가를 변경하려는 사용자의 의도를 나타냅니다.
  2. 명령 처리: 명령을 처리하고 이벤트를 발생시키는 비즈니스 로직
  3. 이벤트 발생: 명령이 성공적으로 처리된 후 발생하는 이벤트입니다.
  4. 이벤트 처리: 최적화된 쿼리를 위해 이벤트 데이터를 읽기 모델에 투영합니다.
  5. CQRS 분리: 명령 모델은 도메인 로직에 초점을 맞추고 쿼리 모델은 빠른 조회에 최적화되어 있습니다.
  6. 이벤트 스토어: 선택적으로 필요할 때 상태를 재생하기 위해 이벤트를 유지합니다.

결론

이 예는 PHP에서 CQRS이벤트 소싱을 간단히 적용하는 방법을 보여줍니다. 이러한 패턴을 사용하면 강력한 감사 기능과 유연한 읽기/쓰기 처리 기능을 제공하면서 확장성과 유지 관리가 용이한 시스템을 구축할 수 있습니다. 추가 예측, 더욱 복잡한 이벤트 처리, 메시징 대기열이나 타사 알림과 같은 외부 통합을 통해 아키텍처가 확장될 수 있습니다.

위 내용은 PHP에서 이벤트 기반 아키텍처 구현: 이벤트 소싱 및 CQRS에 대한 심층 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.