-
Notifications
You must be signed in to change notification settings - Fork 5
소프트웨어 아키텍처 The Hard Parts 1주차 - 이근주 #579
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,235 @@ | ||||||||
| # 트레이드오프 위에서의 아키텍처 선택 | ||||||||
|
|
||||||||
| ## 1 ~ 3장 | ||||||||
| --- | ||||||||
|
|
||||||||
| ## chapter 1 - '베스트 프랙티스'가 없다면? | ||||||||
|
|
||||||||
| > 정답은 없다. 다만 트레이드오프만 있을 뿐이다. | ||||||||
|
|
||||||||
| 우리는 늘 정답을 찾는다. 나 또한 그렇다. | ||||||||
| 하지만 인생이 그렇듯, 소프트웨어 설계에도 절대적인 정답은 없다. | ||||||||
| 존재하는 것은 언제나 **장점과 단점**, 그리고 그 사이에서의 **선택**뿐이다. | ||||||||
|
|
||||||||
| 아키텍처 설계 역시 마찬가지다. | ||||||||
| "어떤 구조가 가장 좋은가?"가 아니라, | ||||||||
| **"지금 이 시점의 제약과 상황에서 무엇이 가장 합리적인 선택인가?"** 를 고민하는 문제다. | ||||||||
|
|
||||||||
| 그래서 이 책은 정답을 주기보다는, | ||||||||
| 그 선택을 하기 위해 필요한 **사고의 도구들**을 설명한다. | ||||||||
|
|
||||||||
| ### 이 책에서 반복적으로 등장하는 키워드들 | ||||||||
|
|
||||||||
| - coupling / cohesion | ||||||||
| - component 경계 | ||||||||
| - sync / async | ||||||||
| - orchestration / choreography | ||||||||
| - atomicity | ||||||||
| - contract | ||||||||
|
|
||||||||
| 이 단어들은 각각 따로 보면 어려울 수 있지만, | ||||||||
| 결국은 **"무엇을 함께 묶고, 무엇을 분리할 것인가"** 라는 질문으로 수렴한다. | ||||||||
|
|
||||||||
| 책에서 다루는 *한빛가이버* 사례를 읽으면서, | ||||||||
| 나는 지난 5년간 내가 겪어온 MSA 전환 과정과 굉장히 유사하다는 느낌을 받았다. | ||||||||
| 정답을 찾아 적용하기보다는, | ||||||||
| 트래픽·조직·장애·운영이라는 현실 속에서 | ||||||||
| 계속해서 **트레이드오프를 선택해 온 과정**에 더 가까웠기 때문이다. | ||||||||
|
|
||||||||
| 이 챕터는 | ||||||||
| "베스트 프랙티스를 알려주는 장"이 아니라, | ||||||||
| **이후 챕터들을 어떤 관점으로 읽어야 하는지를 정리해 주는 장**이라고 느꼈다. | ||||||||
|
|
||||||||
| ## chapter 2 - 아키텍처 퀀텀 | ||||||||
|
|
||||||||
| > MSA는 '유행'이 아니라, 현재 시스템의 제약과 이해를 바탕으로 선택해야 하는 결과다. | ||||||||
|
|
||||||||
| 나의 경험을 예로 들면, 처음에는 다들 그렇듯이 레이어드 모놀리식으로 시작했다. | ||||||||
| 그 이후 MSA를 목표로 점진적인 전환을 시도하고 있다. | ||||||||
|
|
||||||||
| 아직은 DB를 완전히 분리하지 못해, 엄밀한 의미의 MSA를 적용했다고 보기는 어렵다. | ||||||||
| 다만 향후 DB 분리와 서비스 분리를 가능하게 만들기 위해, 미리 헥사고날 아키텍처와 이벤트 기반 아키텍처를 적용하는 방향으로 설계를 진행 중이다. | ||||||||
| (이벤트 기반 아키텍처의 경우, 늘어나는 트래픽 대응이 주된 목적이다.) | ||||||||
|
|
||||||||
| 또한 비동기 통신을 위한 보상 처리로 Saga 패턴도 함께 적용하고 있다. | ||||||||
|
|
||||||||
| 이처럼 각자의 상황과 제약에 맞게 아키텍처를 선택하는 것이 중요하다고 생각한다. | ||||||||
| MSA가 무조건 좋은 것도 아니고, 모놀리식이 무조건 나쁜 것도 아니다. | ||||||||
|
|
||||||||
| ## chapter 3 - 아키텍처 모듈성 | ||||||||
|
|
||||||||
| > 아키텍처 별 성격 비교 | ||||||||
|
|
||||||||
| 유지 보수성, 시험성, 확장성, 가용성/내고장성 관점에서 보면 | ||||||||
| 모놀리식 < 서비스 기반 < MSA 순으로 점수가 매겨지는 흐름이 나온다. | ||||||||
|
|
||||||||
| ### 정리 | ||||||||
|
|
||||||||
| 아키텍처 모듈성을 | ||||||||
| 유지 보수성, 시험성, 확장성, 가용성/내고장성 관점에서 비교하면 | ||||||||
| 일반적으로 **모놀리식 < 서비스 기반 < MSA** 순으로 평가가 높아진다. | ||||||||
|
|
||||||||
| 이 결과는 "아키텍처의 우열"이라기보다는, | ||||||||
| **결합을 얼마나 잘 분리했는가**에 대한 평가에 가깝다고 느꼈다. | ||||||||
|
|
||||||||
| - 모놀리식은 변경·장애·확장의 범위가 하나로 묶여 있어 | ||||||||
| 규모가 커질수록 리스크가 증폭되기 쉽다. | ||||||||
| - 서비스 기반 아키텍처는 일정 수준의 분리를 제공하지만, | ||||||||
| 공통 로직과 동기 호출 체인이 늘어나면 다시 결합도가 높아진다. | ||||||||
| - MSA는 서비스별 DB 분리와 비동기 통신을 전제로 할 때, | ||||||||
| 변경 영향 최소화, 독립 확장, 장애 격리 측면에서 가장 큰 이점을 가진다. | ||||||||
|
|
||||||||
| 다만 이 점수표는 | ||||||||
| **MSA를 '제대로 운영할 수 있다는 전제'가 붙은 결과**라는 점이 중요하다. | ||||||||
| 운영 성숙도, 관측성, 재처리, 계약 관리가 뒷받침되지 않으면 | ||||||||
| 높은 점수는 오히려 높은 복잡도로 돌아올 수 있다. | ||||||||
|
|
||||||||
| 결국 이 비교는 | ||||||||
| "어떤 아키텍처가 더 낫다"를 말하기보다는, | ||||||||
| **어떤 트레이드오프를 선택할 준비가 되어 있는가**를 묻는 기준이라고 생각한다. | ||||||||
|
|
||||||||
| ### 논의사항 | ||||||||
|
|
||||||||
| 1. **서비스 기반 아키텍처는 ‘과도기’인가, ‘최종 형태’인가?** | ||||||||
| 서비스 기반은 MSA로 가기 위한 단계인가? | ||||||||
| 아니면 **조직·트래픽·운영 역량이 맞으면 충분히 '최종 형태'** 가 될 수 있는가? | ||||||||
|
Comment on lines
+93
to
+95
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 책의 저자가 얘기하는 방향이라면 과도기일텐데, 특정 회사의 특정 조직은 최종 형태가 될 수 있다고도 생각합니다. 책의 내용만 이해한다면 마이크로서비스 아키텍처를 지향해야 하겠지만
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 책에 따르면 서비스 기반 아키텍처는 확장성 3점, 탄력성 2점이고, MSA는 확장성, 탄력성 모두 5점이라고 되어있습니다.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 현재 생각하는 제품 or 어플리케이션의 방향성이 아키텍처의 추구하는 방향과 맞다면 현재 시점에서는 최종 형태로 불릴 수 있겠으나 추후 어떤 식으로든 제품이 확장되고 복잡해지거나 새로운 아키텍처가 대두된다면 .. 다시 과도기적 형태로 돌아가지 않을까 생각되었는데 다른 분들 의견은 또 다르네요 |
||||||||
|
|
||||||||
| 2. **MSA의 장점을 얻기 위해 반드시 필요한 전제는 무엇인가?** | ||||||||
| DB 분리 없이도 MSA를 했다고 말할 수 있는가? | ||||||||
|
Comment on lines
+97
to
+98
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Comment on lines
+97
to
+98
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이것도 역시 책의 내용대로 한다면 서비스 개수 만큼 아키텍처 퀀텀의 개수가 나와야 하고 각 서비스는 아키텍처 특성이 모두 같을 수도 있지만 같지 않게 해야 한다 일 것 같습니다. 정리하면
일 것 같네요. DB의 분리 없이 MSA를 했느냐는 책을 읽었다면 "아니오"라고 해야 맞을 것 같습니다.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
가장 중요한건 **현재의 상황(환경)**이겠지만.. MSA를 충분히 운영 가능한 환경(인원, 지원 등)이라면 아래의 요소들이 필수 전제라고 생각합니다.
|
||||||||
|
|
||||||||
|
|
||||||||
| > 아래 내용은 정리나 결론을 위한 글은 아니다. | ||||||||
| > 혹시 비슷한 규모의 시스템을 운영하면서 | ||||||||
| > 다른 팀은 어떻게 하고 있는지 궁금한 사람이 있다면, | ||||||||
| > 참고가 될 수 있을 것 같아 남겨둔 개인적인 경험 기록이다. | ||||||||
|
|
||||||||
| ### 경험 사례 – 내가 겪은 아키텍처 선택의 흐름 | ||||||||
|
|
||||||||
| #### 여러 아키텍처를 거치며 느낀 점 | ||||||||
|
|
||||||||
| **레이어드 모놀리스**는 전통적이고 빠르게 시작하기에 좋았다. | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||
| 하지만 규모가 커질수록 도메인 경계가 흐려지고, | ||||||||
| 작은 변경이 예상보다 넓은 영역에 영향을 주는 경험을 자주 하게 됐다. | ||||||||
|
|
||||||||
| **모듈러 모놀리스**는 도메인 단위로 모듈을 나누면서 | ||||||||
| 변경 영향 범위를 줄이는 데는 분명 도움이 됐다. | ||||||||
| 다만 시간이 지나면서 | ||||||||
| "이건 어느 모듈 책임이지?" 같은 애매한 지점이 생기기 시작했고, | ||||||||
| 그 순간부터 경계를 지키는 일이 생각보다 어렵다는 걸 체감했다. | ||||||||
|
|
||||||||
| **마이크로커널 아키텍처**는 | ||||||||
| 확장 축(기능/전략)이 반복적으로 추가될 때는 꽤 매력적이다. | ||||||||
| 예를 들어 PG 연동처럼 | ||||||||
| 결제/취소/중단(Abort) 흐름이 유사한 기능이 계속 늘어나는 경우에는 | ||||||||
| 플러그인이나 전략 패턴으로 분리할 가치가 있다. | ||||||||
| 다만 실제로 운영해보니, | ||||||||
| 생각보다 이렇게 반복적으로 확장되는 영역은 많지 않았고 | ||||||||
| 그 외의 영역에서는 과설계가 되기 쉽다고 느꼈다. | ||||||||
|
|
||||||||
| --- | ||||||||
|
|
||||||||
| #### 결국 선택한 방향: 서비스 기반 + 헥사고날 | ||||||||
|
|
||||||||
| 서비스 기반 아키텍처는 | ||||||||
| 팀을 나누고 서비스를 분리하는 데 분명한 장점이 있다. | ||||||||
| 하지만 실제로 운영해보면 | ||||||||
| 공통 로직이 생기는 순간부터 선택이 어려워진다. | ||||||||
|
|
||||||||
| - 그냥 복붙할지 | ||||||||
| - 공용 라이브러리로 묶을지 | ||||||||
| - 아니면 공통 서비스를 하나 더 만들지 | ||||||||
|
|
||||||||
| 이 선택을 매번 고민하게 된다. | ||||||||
|
|
||||||||
| 특히 서비스 간 동기 호출이 늘어날수록, | ||||||||
| 장애가 전파되고 배포가 서로 엮이는 경험을 여러 번 했다. | ||||||||
| 이 지점이 서비스 기반 아키텍처에서 | ||||||||
| 가장 크게 체감한 한계였다. | ||||||||
|
|
||||||||
| 그럼에도 불구하고, | ||||||||
| 현재의 조직 규모와 트래픽을 고려하면 | ||||||||
| 서비스 단위로 나누는 선택 자체는 피하기 어렵다고 판단했다. | ||||||||
| 그래서 내 기준에서의 질문은 | ||||||||
| **"나눌 것인가?"가 아니라 "어디까지 나눌 것인가?"** 였다. | ||||||||
|
|
||||||||
| 그 결과 나는 | ||||||||
| 서비스 기반 구조를 유지하되, | ||||||||
| 헥사고날 아키텍처를 적용해 | ||||||||
| 서비스 내부의 도메인 경계를 최대한 명확히 하려고 했다. | ||||||||
| 그리고 공통 로직은 정말 불가피한 경우에만 | ||||||||
| 내부 모듈이나 라이브러리로 제한하고, | ||||||||
| 도메인 로직이 공통으로 새어나가지 않도록 의식적으로 막고 있다. | ||||||||
|
|
||||||||
| --- | ||||||||
|
|
||||||||
| ### 그리고 EDA | ||||||||
|
|
||||||||
| EDA를 도입한 지점은 **결제 이후**다. | ||||||||
| 결제 자체는 짧고 확실하게 끝내고, | ||||||||
| 결제 이후에 따라오는 후속 작업들을 | ||||||||
| 동기 호출로 묶지 않기 위해 Kafka 기반 이벤트로 분리했다. | ||||||||
|
|
||||||||
| #### 이벤트 발행 (결제 서비스) | ||||||||
|
|
||||||||
| 결제가 완료되면 Kafka로 이벤트를 발행한다. | ||||||||
| 이 이벤트에는 대략 다음 정보가 담긴다. | ||||||||
|
|
||||||||
| - paymentSeq (결제 식별자) | ||||||||
| - amount (금액) | ||||||||
| - item 정보 (상품 / 구성 / 수량 등) | ||||||||
|
|
||||||||
| 중요한 점은 | ||||||||
| "무엇을 해라"가 아니라 | ||||||||
| **"결제가 완료되었다"라는 사실을 발행**한다는 것이다. | ||||||||
|
|
||||||||
| #### 팀1 컨슘: Timeline 적재 | ||||||||
|
|
||||||||
| 팀1은 이 이벤트를 컨슘해서 | ||||||||
| 결제 건을 Timeline에 적재한다. | ||||||||
| 이 작업은 결제의 성공/실패와 운명을 같이할 필요가 없고, | ||||||||
| 지연되더라도 나중에 따라잡을 수 있기 때문에 | ||||||||
| 비동기 방식이 잘 맞았다. | ||||||||
|
|
||||||||
| #### 팀2 컨슘: 적립 계산 및 반영 | ||||||||
|
|
||||||||
| 팀2는 동일 이벤트를 컨슘한 뒤, | ||||||||
| 자기 정책에 따라 적립 금액을 계산하고 적립을 반영한다. | ||||||||
|
|
||||||||
| 적립은 정책·이벤트·프로모션에 따라 변수가 많고, | ||||||||
| 결제 서비스가 직접 알고 있어야 할 이유가 없다고 판단했다. | ||||||||
| 오히려 결제 플로우에 섞이면 | ||||||||
| 변경 영향 범위만 커진다. | ||||||||
| 그래서 계산과 반영의 책임을 아예 분리했다. | ||||||||
|
Comment on lines
+185
to
+202
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [질문]
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 네 그렇습니다. 좀 더 정확히 말씀드리면 내역의 경우, 예~~전에는 여러 팀(쇼핑, 외부결제, 디지털컨텐츠)에 나눠진 결제 데이터를 각각 조회하여 유저에게 보여줬는데, 적립의 경우, 서비스 파트에서 적립율을 주고, 결제 파트에서 계산 및 적립 요청을 하던 구조였는데, |
||||||||
|
|
||||||||
| --- | ||||||||
|
|
||||||||
| #### EDA를 통해 얻은 효과 | ||||||||
|
|
||||||||
| - 결제 서비스는 결제 자체에만 집중할 수 있었다 | ||||||||
| - 동기 호출 체인을 끊으면서 더 빠른 결제 및 더 많은 처리량을 달성할 수 있었다 | ||||||||
| - 후속 작업은 컨슈머 확장으로 처리량을 맞추고, | ||||||||
| 피크 트래픽은 큐가 흡수하도록 만들 수 있었다 | ||||||||
|
|
||||||||
| #### 미래 수정할 점 | ||||||||
|
|
||||||||
| 현재는 **결제 완료 이벤트**를 타 팀에서 직접 컨슘해 | ||||||||
| 내역 적재나 포인트 작업까지 처리하고 있다. | ||||||||
|
|
||||||||
| 하지만 앞으로는 다음 형태로 바꿀 예정이다. | ||||||||
|
|
||||||||
| - 결제 서비스는 **결제 완료(Fact)** 이벤트만 발행한다. | ||||||||
| - 해당 토픽을 컨슘하는 서비스가 | ||||||||
| - **내역 발행 Command** | ||||||||
| - **포인트 적립 Command** | ||||||||
| 를 각각 발행한다. | ||||||||
|
|
||||||||
| 이렇게 하면 내역은 쌓였는데 포인트 적립이 누락된 경우에도 | ||||||||
| Admin을 통해 **포인트 적립 Command만 재발행**하는 형태로 보상이 가능해진다. | ||||||||
|
|
||||||||
| #### 운영하면서 중요했던 포인트 | ||||||||
|
|
||||||||
| - 이벤트 중복/재처리는 전제로 두고 멱등하게 설계한다 | ||||||||
| - 재처리를 항상 가능하게 만든다 | ||||||||
| - 추적을 위해 requestUuid 같은 식별자를 이벤트에 포함한다 | ||||||||
| - 사내에 FDC(financial Data Center)가 존재하고, 매일 bulk로 사내 전체 DB를 조회하여 적재한다. 그리고 매일 배치를 돌려서 누락된 적립이 있는지 확인하고, 존재한다면 노티 이메일을 보내준다. 따라서 | ||||||||
| 재처리가 가능하다. 이것이 운영에서 가장 중요한 포인트였다. | ||||||||
|
Comment on lines
+234
to
+235
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 문장은 여러 절차를 한 번에 설명하고 있어 다소 길고 복잡하게 느껴집니다. 가독성을 높이기 위해 아래와 같이 내용을 분리하여 간결하게 다듬는 것을 제안합니다.
Suggested change
|
||||||||

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
문서 전반의 통일성을 위해 장(Chapter) 제목 표기를
chapter 1과 같은 영문 대신1장과 같이 한글로 수정하는 것을 제안합니다. 43행, 59행의chapter 2,chapter 3도 함께 수정하면 좋겠습니다.