이벤트 기반 아키텍처(Event-Driven Architecture)로 Rails 앱 개선하기
카테고리
프로그래밍/소프트웨어 개발
서브카테고리
웹 개발
대상자
Rails 앱 개발자, 중간 이상의 경험을 가진 개발자, 비동기 처리와 복잡한 앱 아키텍처에 관심 있는 개발자
핵심 요약
- 트라디셔널한 요청-응답 패턴의 단점
- after_commit
콜백 체인으로 인한 비즈니스 로직의 과도한 결합
- 테스트 복잡성 증가 (10개 이상의 오브젝트 스텁 필요)
- HTTP 요청 타임아웃으로 인한 비동기 처리 한계
- 이벤트 기반 아키텍처(EDA)의 핵심 장점
- OrderPaid
같은 이벤트로 컴포넌트 분리 (예: Rails.configuration.event_store.publish(event)
)
- 비동기 처리로 인한 30초 요청 타임아웃 문제 해결
- 이벤트 재생 (예: event_store.read.stream("Order$#{order.id}")
)
- 실무 적용 팁
- rails-event_store
사용 시 TestClient
로 CI 테스트
- Karafka
로 Kafka 기반의 스케일링과 내구성 활용
- 이벤트 스키마 검증 (JSON::Validator.validate!(SCHEMA, data)
)
섹션별 세부 요약
1. 트라디셔널한 요청-응답 패턴의 문제점
user.update!(...)
호출로 인한 5개의 사이드 이펙트 트리거로 인한 복잡성after_commit
콜백 체인의 스파게티 코드 심화- 서비스 오브젝트에 "한 가지 더" 기능 추가로 인한 결합도 증가
- 예제 코드:
```ruby
def checkout_order
order.process_payment! # 직접 제어
order.send_receipt! # 더 많은 직접 제어
order.update_inventory! # 누가 이걸 호출했나?
end
```
2. 이벤트 기반 아키텍처(EDA)의 이점
- 이벤트 발행으로 인한 컴포넌트 분리 (예:
OrderPaid.new(order_id: order.id)
) - 비동기 처리로 인한 HTTP 요청 타임아웃 문제 해결
- 이벤트 재생을 통한 디버깅 (예:
event_store.read.stream("Order$#{order.id}")
) - 이벤트 스키마 검증으로 중복 처리 방지 (예:
JSON::Validator.validate!(SCHEMA, data)
)
3. 이벤트 저장소(RailsEventStore) 활용
- 이벤트를 정의하고 발행하는 예:
```ruby
class OrderPaid < RailsEventStore::Event
def self.strict(data)
new(data.merge(metadata: { timestamp: Time.now }))
end
end
event = OrderPaid.strict(order_id: 123)
Rails.configuration.event_store.publish(event)
```
- 이벤트 구독자 설정 예:
```ruby
Rails.configuration.event_store.subscribe(Payments::OnOrderPaid.new, to: [OrderPaid])
```
4. Karafka로 Kafka 기반 아키텍처 구현
- Kafka 설정 예:
```ruby
class KarafkaApp < Karafka::App
setup do |config|
config.kafka = { 'bootstrap.servers': 'kafka:9092' }
end
end
```
- 이벤트 소비자 예:
```ruby
module Payments
class OrdersPaidConsumer < Karafka::BaseConsumer
def consume
params_batch.each do |order|
CreditCard.charge(order[:id])
end
end
end
end
```
5. 간단한 이벤트 버스(Dry::Events) 활용
- 이벤트 발행/구독 예:
```ruby
AppEventBus.broadcast("order.paid", order_id: 123)
AppEventBus.subscribe("order.paid") do |event|
Payments::CreditCardProcessor.call(event[:order_id])
end
```
- 장점: DB/Kafka 의존 없이 간단한 앱에 적합
6. 이벤트 저장소의 장단점
- 장점: ActiveRecord와의 강한 통합, 내장 이벤트 소싱
- 단점: Ruby만 지원 (다국어 이벤트 불가)
- 사용 시기: 서비스 간 메시징이 필요한 앱
7. Karafka의 장단점
- 장점: Kafka의 내구성/스케일링, 다국어 지원 (Java 서비스도 가능)
- 단점: 운영 복잡성 (Kafka 클러스터 관리 필요)
- 사용 시기: 가볍게 결합이 필요한 경우
8. 이벤트 기반 아키텍처의 한계
- 단순 CRUD 앱: 과도한 복잡성
- 저지연 요구: 이벤트 처리로 인한 밀리초 추가 지연
- 운영 팀 없음: Kafka는 Heroku에서 간단히 실행 불가
9. 이벤트 기반 아키텍처 도입 단계
- 작은 규모부터 시작: 하나의 콜백 체인을 이벤트로 대체
- RES 도입: 이벤트 지속성 관리
- 스케일 확장: 서비스 경계를 넘어갈 때 Kafka 도입
결론
- 실무 적용 팁:
- rails-event_store
의 TestClient
로 CI 테스트
- EDA는 트렌드가 아닌 100개 이상의 기능 추가 시 시스템이 무너지지 않는 아키텍처
- 이벤트 스키마 검증과 이벤트 재생을 통해 중복 처리 방지 및 디버깅 효율성 향상
- Kafka 사용 시: 운영 복잡성 고려, 다국어 지원이 필요한 경우에 적합
- 간단한 앱: Dry::Events
로 DB/Kafka 없이 간편하게 이벤트 처리 가능