ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Moebius Architecture - Phase 1
    Laboratory/Moebius 2020. 7. 18. 01:45

    안녕하세요. Moebius 소개글을 작성한 지 3개월이 지나서야 드디어 실질적인 첫 글로, 아키텍처에 대해서 글을 써보려고 합니다.

    단순히 아키텍쳐를 소개하는 것을 넘어서서, Software Architecture를 구성하는 방법에 대한 내용도 다뤄 볼 예정입니다.

    글을 쓰고 있는 이 시점을 기준으로, Moebius의 아키텍처는 여러 단계에 걸쳐서 조금씩 개선, 확장되어 왔습니다.

    그래서 하나의 글로 쓰기에는 다룰 분량이 많아, 다작으로 나눠서 작성할 예정입니다.

    이제 시작해보겠습니다. ^^;


    Moebius를 시작했을 때, 소개글에서 잠깐 언급했지만 처음에는 첫 서비스(비지니스) 모델인 암호화폐 투자 보조에 집중한 플랫폼을 만들고자 했다. 그래서 거창하게 생각할 것 없이 거래소 하나만 대상으로 잡고 PoC로 빠르게 진행하면서, 실제로 이 모델이 원활하게 작동하는지 보고 싶었다. 

     

    처음 잡은 Phase 1 구조는 다음과 같이 간단하다.

    Moebius Architecture Phase 1

    익숙하고 빠르게 구현할 수 있는 Java 8, Spring boot 2 기반의 App에서 UI(Thymeleaf), 데이터 처리, 외부 거래소 연동, 내부 서비스 처리 등등 모든 것을 담당한다. DB의 경우는 RDBMS보다는 Nosql 기반인 MongoDB를 사용했는데, 이는 향 후 서비스 특징상 데이터 스키마가 자유롭게 변동될 수 있고 이에 따라 데이터 모델링을 수시로 진행해야 됐기 때문이다. 별도의 설명 없이 그림 하나만으로 어떻게 작동하고 돌아가는지 알 수 있을 정도라고 해도 과언이 아닐 만큼 간단하다고 할 수 있다.

     

    그런데 이런 구조로 진행하게 되면 초기 개발은 정말 빨리 될 수 있지만, 여러가지 문제에 봉착하게 된다.

    과연 그 여러가지 문제들이 뭘까?


    보는 사람마다 차이는 있겠지만, 우선 가장 큰 문제라고 할 수 있는 부분은 한 컴포넌트(App)에서 너무 많은 작업을 처리하고 있다는 것이다. 이로 인해 컴포넌트의 기능별 확장이 제한되는 것은 물론이고, 이 자체가 SPOF가 되어 App의 일부에 문제가 생기면 서비스가 즉시 중단되어 버리고 만다.

     

    예를 들어 내부 서비스를 처리하는 부분에 좀 더 리소스를 투입해야 되는 경우가 생겼다고 가정하자. 그렇다면 작업을 처리하는 스레드를 늘리고, 그 스레드를 실제로 수행할 수 있는 인스턴스를 더 생성해야 될 것이다. 그렇게 인스턴스를 더 생성하고 로드 밸런서와 함께 잘 구성해놨지만 서비스를 처리하는 성능 자체는 전혀 개선되지 않을 수 있다. 왜냐하면, 사용자의 데이터 조회 및 저장이 급증하거나 유입되는 외부 거래 데이터의 증가로 인해 컴포넌트 내에서 서비스보다 데이터를 처리하는 쪽에서 더 많은 리소스가 필요하게 될 수 있다. 이로 인해 처음에 원했던 내부 서비스를 처리하는 부분에는 실질적인 개선이 일어나지 않게 된다. 물론 이전에 리소스가 부족한 상황보다는 훨씬 낫겠지만, 우리가 데이터를 잘 처리하기 위해서 리소스를 더 투입한 것이 아니기 때문이다.

     

    다른 측면에서 또 살펴보면, 서비스를 문제없이 잘 운영하다가 UI에 변경이 필요한 경우를 가정해보자. 그래서 요구사항에 맞게 수정을 다 하고, 배포를 진행했는데 갑자기 서비스가 중단되었다. (실제로는 당연히 테스트도 안하고 이렇게 진행하지는 않는다.) 살펴보니 UI를 제공하는데 필요한 데이터를 받아오는 API를 잘못 사용한 것이 원인이었다. 그래서 수정하고 다시 배포하여 행복한 결말을 맞이하는 듯했다. 그런데 서비스에 접속해서 데이터들을 살펴보는데, 이상하게 맞아야 하는 거래 데이터가 맞지 않는다. 아까 잠시 동안 서비스가 중단되면서, UI 수정과는 관련 없는 외부 거래소를 지속적으로 트래킹하면서 거래 데이터를 업데이트해야 되는 작업을 일정 시간 수행하지 못하게 되면서, 동기화 문제가 생기게 된 것이다. 


    흔하게 발생하는 확장성과 고가용성의 측면에서만 접근했지만, 이 외에도 다양한 측면의 많은 경우들이 있을 것이다.

    위의 두 예시를 통해 알 수 있는 것은, 아키텍처 관점의 SRP가 정말 중요하다는 것이다.

    SRP에 대한 많은 정의가 있지만, 개인적으로 가장 와 닿는 SRP의 정의는 다음과 같다.

     

    하나의 모듈(Module)은 하나의, 오직 하나의 액터(Actor)에 대해서만 책임져야 한다.

    - 클린 아키텍쳐, 66P / Robert C. Martin

     

    아키텍처 관점에서 위 정의를 재해석해보면, 모듈(Module)이 컴포넌트(Component)가 된다. 액터(Actor)는 리소스 투입 또는 UI 변경과 같은 서비스 변경을 요청하는 집단을 의미한다.

     

    그렇다면 처음부터 하나의 액터에 대해서 하나의 모듈이 책임지는, SRP를 충실히 따르는 아름다운 아키텍처를 구성하는 게 가능할까?

    미래에 무엇이 바뀔지 아는 것이 아닌 이상, 불가능하다.

    그래서 역설적이게 Phase 1에서 기능에 따라 나누지 않고, 모두 합쳐놓은 것이다. 액터가 무엇인지 정확히 파악이 안 되어 있었기 때문에 섣불리 컴포넌트를 나눴다가, 오히려 불필요한 관리 포인트가 늘어나는 점을 우려한 것이다. 그래서 액터의 요구사항들을 분류하고 우선순위에 따라 컴포넌트를 분리해나가기 시작했다.


    Phase 1은 이정도로 마무리 짓도록 하겠습니다.

    다음 글에는 Phase 2를 다루면서 어떻게 컴포넌트를 분리해나가기 시작했는지 좀 더 면밀하게 살펴보겠습니다.

    읽어주셔서 감사합니다. ^^;

     

    'Laboratory > Moebius' 카테고리의 다른 글

    Moebius Architecture - Phase 2  (0) 2020.11.12
    Introduction  (0) 2020.04.11

    댓글