본 토이 프로젝트는 Redis Streams를 이용하여 효율적인 효율적인 이벤트 수집 및 처리를 구현하는 것을 목표로 합니다.
Redis Streams의 이해를 돕고, 실제 시스템 구축 경험을 통해 메시징 시스템 및 아키텍처 설계 능력을 향상시키는 데 중점을 둡니다.
EventProducer는 발생하는 이벤트를 Redis Streams에 비동기적으로 추가하고, StreamMessageListenerContainer는 이를 실시간으로 수신하여 다양한 방식으로 이벤트를 처리하는 EventHandler를 호출합니다.
이러한 구조는 다양한 이벤트 처리 요구사항에 대한 유연한 확장을 가능하게 합니다.
더불어, Redis 클러스터의 예기치 않은 장애 발생 시 데이터의 무결성을 보장하기 위한 원자적 예외 처리 메커니즘과 시스템의 안정적인 운영을 위한 자동 복구 및 모니터링 기능을 포함하여 시스템의 안정성을 높였습니다.
- Java 21
- Spring Boot 3.x
- Redis Streams (Cluster Mode) - redis:7.2
- PostgreSQL 14, Flyway
- Docker, Docker Compose
- Spring Data JPA
- Spring AOP, Scheduler
event-system
├── event-docker # 도커 관련 설정
│ └── redis # Redis 설정 및 스크립트
└── event-listener # 이벤트 수집 및 처리 애플리케이션
├── event
│ ├── core # 핵심 비즈니스 로직 계층
│ │ ├── aop # AOP 기능 (예: 이벤트 관리)
│ │ ├── common # 공통 유틸리티
│ │ ├── config # 전역 설정 파일 및 구성 (예: Jackson)
│ │ ├── domain # 도메인 계층 (핵심 비즈니스 로직)
│ │ │ └── access # 액세스 관련 도메인
│ │ │ ├── category # 액세스 카테고리 관련 로직
│ │ │ │ ├── entity # 액세스 카테고리 엔티티 정의
│ │ │ │ └── inout # 액세스 카테고리 요청/응답 DTO
│ │ │ ├── event # 액세스 이벤트 관련 로직
│ │ │ │ ├── entity # 액세스 이벤트 엔티티 정의
│ │ │ │ └── inout # 액세스 이벤트 요청/응답 DTO
│ │ │ └── summary # 액세스 요약 데이터 로직
│ │ └── exception # 예외 처리 계층
│ │ └── handler # 글로벌 예외 핸들러
│ └── infra # 인프라 계층 (외부 시스템과의 통합)
│ ├── event
│ │ ├── config # 이벤트 설정 (예: EventHandler 설정)
│ │ ├── handler # 이벤트 핸들러 정의
│ │ ├── listener # 메시지 리스너 구현
│ │ ├── monitoring # 외부 연동 시스템 모니터링 (예: Redis 클러스터 모니터링)
│ │ │ └── config # 모니터링 관련 설정 파일
│ │ ├── producer # 메시지 프로듀서 (예: Redis Streams)
│ │ └── redis # Redis 기반 설정 및 로직
│ │ ├── config # Redis 연결 설정
│ │ └── event # Redis 이벤트 처리 (예: RedisErrorEvent)
│ ├── scheduler # 작업 스케줄러 구성
│ └── util # 외부 공통 유틸리티 클래스
└── resources # 설정 파일 및 리소스
├── config
│ ├── dev # 개발 환경 설정
│ └── prod # 운영 환경 설정
└── db
└── migration # 데이터베이스 마이그레이션 파일 (예: Flyway)
- Docker Compose를 사용하여 PostgreSQL과 3개의 Redis 노드를 로컬에 구성합니다.
- redis-cluster-entry 노드를 통해 자동 클러스터 구성을 지원합니다.
- 자세한 설정은 event-docker README 파일 참고.
- 클라이언트 요청 발생 시 AOP로 URL 경로를 기준으로 이벤트를 구분합니다.
- EventProducer를 통해 Redis Streams(EVENT_STREAM)에 저장합니다
- 예시:
GET /admin/api/v1/event/access/summary/2025-05-04요청 → AOP → Redis 저장.
- StreamMessageListenerContainer가 Redis Streams를 지속적으로 폴링합니다.
- 마지막으로 읽은 메시지 이후부터 처리하며, ack 처리도 지원합니다.
- EventHandler를 통해 이벤트 타입별 후속 작업을 유연하게 처리합니다.
- 기본 AccessEventHandler는 PostgreSQL 저장을 담당합니다.
- Redis 클러스터 장애를 감지하고 모니터링 시스템(
RedisListenerMonitor)을 통해 자동 복구합니다. CriticalRedisError발생 시 Listener를 중지하고, 복구되면 다시 시작합니다.
- RedisStreamAndDataBaseClearScheduler가 주기적으로 Redis Streams 및 PostgreSQL 오래된 이벤트를 정리합니다.
- 기본 주기: 매일 오전 10시, 60일 이상 된 데이터 제거 (설정 가능).
git clone https://github.com/ljh468/event-system.git# docker-compose 실행
cd event-docker
docker-compose up -d
# 로컬 환경 구성시 /etc/hosts에 cluster-announce-ip 추가 필요
## 자동 스크립트 추가 (1, 2번이 수행됨)
./update-hosts.sh 2번 실행
## 아래의 작업이 수행됩니다.
- 1. chmod +x update-hosts.sh # 실행 권한을 부여
- 2. ENTRY="127.0.0.1 redis-node-1 redis-node-2 redis-node-3" # cluster-announce-ip를 binding docker exec -it redis-node-1 redis-cli -p 7001
AUTH root root
CLUSTER NODES./gradlew :event-listener:bootRun# API 호출 예시
## 날짜별 AccessCategory로 그룹화된 이벤트기록 요약 API 호출
curl -X GET http://localhost:47170/admin/api/v1/event/access/summary/2025-04-27
## AccessCategory 조회 API 호출
curl -X GET http://localhost:47170/admin/api/v1/event/access/categories# PostgreSQL 접속
docker exec -it postgres-db psql -U postgres -d event-system
# 접근 이벤트 테이블 조회
SELECT * FROM access_event ORDER BY created_at DESC;docker stop redis-node-2- 10초 간격으로 모니터링하며 장애 감지 및 복구가 자동으로 수행
- 장애가 난 노드는 이벤트를 통해 확인 가능
INFO --- [taskScheduler-1] c.l.i.l.m.DefaultRedisHealthChecker : redis cluster state: fail
INFO --- [taskScheduler-1] c.l.i.l.monitoring.RedisListenerMonitor : Redis health check result: false
WARN --- [taskScheduler-1] c.l.i.l.monitoring.RedisListenerMonitor : Redis is still unhealthy. Will retry...
INFO --- [xecutorLoop-3-8] i.l.core.protocol.ConnectionWatchdog : Reconnecting, last destination was redis-node-2/<unresolved>:7002docker start redis-node-2INFO --- [taskScheduler-1] c.l.i.l.m.DefaultRedisHealthChecker : redis cluster state: ok
INFO --- [ioEventLoop-5-2] i.l.core.protocol.ReconnectionHandler : Reconnected to redis-node-2/<unresolved>:7002
INFO --- [taskScheduler-1] c.l.i.l.m.DefaultRedisHealthChecker : redis stream readable: true
INFO --- [taskScheduler-1] c.l.i.l.monitoring.RedisListenerMonitor : Redis health check result: true
INFO --- [taskScheduler-1] c.l.i.l.monitoring.RedisListenerMonitor : Redis is healthy. Restarting ListenerContainer and stopping monitor.
INFO --- [taskScheduler-1] .l.l.RedisStreamListenerContainerManager : Restarting Redis Listener Container...
INFO --- [taskScheduler-1] .l.l.RedisStreamListenerContainerManager : Redis Listener Container has been stopped.
INFO --- [taskScheduler-1] .l.l.RedisStreamListenerContainerManager : Redis Listener Container has started successfully.
INFO --- [taskScheduler-1] c.l.i.l.monitoring.RedisListenerMonitor : Stopping redis listener health monitoring...