명령과 조회를 분리하면서, 쓰기 모델과 읽기 모델 분리는 고려안한 이유가 있는지 궁금해요.
초기에는 해당 자료에 따라 쓰기 모델과 읽기 모델에 대한 분리를 고려해보았었습니다.
다만, 명령 서비스 내에서 읽기 기능이 필요한 부분이 있는데요, 명령 서비스 내에서의 읽기 기능에 있어서 하나의 서비스 내에서 두 가지 모델을 사용하게 됩니다.
이에 따라 어떤 모델을 어떻게 쓰였는지 역추적하기가 어려워 코드의 유지보수성이 어렵다고 판단하였습니다.
따라서 역할분리를 하기 위한 코드레벨에서의 분리는 서비스 레이어까지만 분리를 하였습니다!
단순히 primary와 secondary를 구성하기 위해 나눈것뿐인지? 또는 CQRS까지 접목시킬 계획이 있었던건지? 등이 궁금해요.
CQRS를 접목시켜서 구현해놓았습니다!
정확히는 코드레벨의 유지보수성, 아키텍처 레벨의 장애지점대비를 위해 도입해보았는데요,
초기에는 Command / Query 를 코드레벨만을 분리하여 구성하고 있다가, primary와 secondary 를 구성하여 SPOF를 대비하자는 취지에서 CQRS 패턴을 도입하였습니다.
현재 Command와 관련된 Service는 primary DB에서 데이터를 CUD합니다.
Query와 관련된 Service는 @Transactional(readonly = true)를 달아두었고 해당 서비스는 secondary DB에 데이터 조회를 요청하는 방식으로 적용해두었습니다.
메인 인프라는 규빈님이 진행해주셨으며 각자가 필요한 인프라가 있을 경우 규빈님과 함께 인프라에 대하 공부하며 조율해나가며 사용하였습니다. Redis에 관련된 인프라는 재윤님과 함께, RDS와 관련된 인프라는 지훈님, LoadBalance와 관련된 인프라는 규정님과 함께 하는 방식으로 인프라를 구성하였습니다. 이러한 인프라적인 구성에 대한 개별구성원의 깊은 이해도가 부족한 것 같아, 추후 공부를 하며 아키텍처를 개선할 예정입니다!
현재 아키텍쳐에서 대용량 트래픽을 견디게 하기 위하여 AWS의 Elastic Load Balancer를 이용한 Auto Scaling을 적용시켜두었습니다. 이에 따라 대용량 트래픽이 들어올 경우 트래픽을 분산하여 처리할 수 있으며, 추가로 조회 성능에 대하여는 Redis를 이용한 캐싱전략을 이용하여 조회에 대한 부담을 처리해두고 있습니다.
현재는 Read-Replica 기능을 통하여 Primary와 Secondary간 동기화가 진행되고 있는데요, 이러한 구조의 문제점은 데이터 입력과 동기화 과정이 AWS 내에서 실행된다는 것입니다. 이러한 문제를 해결하려면 AWS까지 데이터 입력이 완료된 뒤, Read-Replica의 동기화 작업을 기다리지 않아야 합니다.
메시지 큐를 사용하여 Pub/Sub 구조를 활용하여 더욱 빠른 비동기처리를 할 수 있다고 생각합니다. 또한 캐싱 작업을 통해, 새로운 게시글 생성 시, 이를 캐싱에 우선 생성하여 UX를 높일 수 있다고 생각합니다.
로컬에서 서버를 띄운 경우에는 로컬의 성능에 따라 테스트의 결과가 달라질 수 있다고 생각합니다. 실제로 저희가 사용하는 EC2 서버는 t3.micro로 서버 성능으로는 매우 낮지만, 실제 로컬의 용량은 저 서버에 비해 굉장히 크기 때문입니다. 저희는 현재 EC2의 인스턴스에 대한 부하테스트를 진행하였으며, 로컬에서 jmeter를 사용하여 AWS의 EC2 서버에 트래픽을 전송해, 성능테스트를 진행하였습니다.
현재 중복 예약 혹은 동시성 문제로 인한 데드락 에러가 생긴다는 사실을 알고, 우선 비관적 락을 이용하여 동시성 문제를 해결해놓은 상황입니다. 하지만 저희는 대용량 트래픽에 대하여 대비해야하기 때문에 추후에 Redis의 분산락 등을 좀더 조사하여 저희의 상황에 알맞은 대용량 트래픽 처리를 목표로 수정해 나갈 예정입니다.
좋은 이론을 공유해주셔서 너무나 감사합니다. 일단 CAP 의 각각의 특성에 대해 이해를 해야한다고 생각합니다. - Consistency : 어떤 노드와 통신하는 지 상관없이 같은 데이터를 조회해야 함 - Availability : 모든 요청이 응답을 받을 수 있어야 함 - Partion Tolerance : 시스템 내 분할이 생겼을 때, 시스템이 여전히 작동해야함 ( 즉, 한 노드의 장애발생 시, 다른 복제노드가 응답)
이를 미루어 보았을 때, Master-Slave 구조의 단점은 Availability 이라고 생각합니다.
프라이머리 노드가 중단되었다면, 세컨더리 노드가 승격되는 동안, 쓰기 작업이 잠시 사용 불가능 상태가 됩니다. 따라서 Master-Slave 구조를 채택하게되면 CP를 지원하게 됩니다.
하지만 대용량 트래픽 분산 시스템을 구축하는데는 CP보다 AP가 알맞다고 생각합니다. 이유는 아래와 같습니다.
- C : 대규모 트래픽에 대한 여러 노드의 처리에 대해서 장시간의 LOCK이 걸릴 수 있다고 생각합니다.
- 이를 위해 각각의 DB에서 복구 방법을 지원하는 것으로 알고 있습니다.
- 카산드라 : Eventual Consistency
- Redis : Reddisson, Lettuce
- A : 대규모 트래픽에 따른 장애발생 시에도, 일관적인 응답을 해야한다고 생각합니다.
- P : 분단허용성을 제공하여 대규모 데이터에 따른 끊김없는 실시간 처리를 제공해야한다고 생각합니다.