🌱 인프런 아키텍처 2023-2024 - 이동욱님

1년만에 돌아온 인프콘, 그동안 인프런의 아키텍처에는 어떤 변화가 있었을까?

이전 글: 인프콘 2022 - 인프런 아키텍처의 과거와 현재, 그리고 미래

보통 우리가 아키텍처나 구조를 바꿀 때 가장 큰 이유가 장애 해결이나, 트래픽 문제를 해결하기 위해서다.
인프런 역시 장애 해결을 위해 레거시 아키텍처 개편을 시작했었다.
그러나 올해는 장애나 트래픽이 아닌 조직 구조의 효율을 높이기 위해 아키텍처 변경이 필요했다.
인프런과 같은 소규모 조직에서 어떻게 계속해서 아키텍처를 개선해 나갈까?

🌱 2022 인프런 아키텍처 리뷰

인프런은 거대한 레거시 싱글 레포지토리를 조금씩 이관하는 과정을 거쳐서,
점차 (구) 인프런 싱글 레포 의 크기가 줄어들고, (신) 인프런 모노 레포 크기가 늘어나길 기대했다. 과연 2023년에 바라본 모습은 어떨까?

안타깝게도 현실은 여전히 작년과 비슷한 모습 ㅎㅎ

“거대한 레거시 싱글 레포를 이관하면서도, 비즈니스 속도를 유지할 수 있는 방법은 무엇일까? 더 나아가 조직의 규모를 키울 수 있는 방법은 무엇일까?” 라는 고민에서 조직의 형태를 바꿔보자는 결론에 도달한다.

목적조직으로

인프랩은 기존 PM 파트, 디자인 파트, 백엔드 파트, 프론트 파트 등 기능조직에서 여러가지 불편함을 느끼고 있었다.

  1. 파트별로 서로 다른 목표를 가지고 있는데, 계속해서 협업이 필요하다.
  2. 서비스 단위로 보면 매우 작은 기능 개선인데, 무조건 3개의 파트가 회의를 잡고 합의를 해야한다.
  3. 하나의 기능을 치는 것에도 소통이 길게 늘어진다.

이 문제를 해소하기 위해, 개발자 1명, 디자이너 1명, PM 1명씩으로 구성되어 있던 과거 조직 형태로 돌아가보자는 생각을 하게 된다.
온전히 하나의 목적을 가진, Full cycle 목적 조직을 구성하고, 자신의 조직이 담당하는 제품에 대해서는 내부에서 즉시 결정을 내리고 실행.
각 목적 조직별로 병렬 행동이 일어나니, 매월 2~3개 이상의 제품이 개선 및 출시되기 시작했다.
실행력과 제품속도가 크게 상승된 것이다!

그러나, 장기적인 제품 속도와 조직 안정감이 떨어지고 있었다.

  • 목적조직은 제품 지표 개선이 최우선 순위라, 내부 코드 개선이 항상 후순위로 밀린다.
  • 개발자도 서비스 지표가 좋아지는게 재밌어서 내부 코드 개선을 크게 개의치 않는다.
    • 코드 복붙해서라도 일단 기능 출시하고 제품 내보냄.
  • 모든 조직마다 시니어 개발자를 배치할 수가 없다.
    • 조직의 주니어 개발자가 느끼는 안정감이 다르다.
  • 만약 목적조직 내부에서 1명씩 존재하는 직군에 퇴사자라도 발생하면?

전반적으로 속도감을 유지하기 위해 조직 안정감을 포기한 상태였다.

목적 + 기능조직으로

실행력과 속도감을 유지하면서도 장기적 제품속도와 조직 안정감을 개선하기 위해 조직구조를 다시 한번 개선했다.

목적 조직 + 직군 조직(챕터, 파트)이 합쳐진 형태. 기존 목적 조직의 위키 스페이스에 더해 파트별로 위키 스페이스를 하나 더 신설하고 관리하기 시작한다. 개발자 입장에서는 목적 조직과 기능 조직 2개의 위키 스페이스에 포함되는 셈이다. 주된 업무는 목적 조직을 따르되, 정기적인 파트별 미팅을 통해 장애 상황이나 기술 개선 사항을 공유함으로서 부족함을 매꿔나간다. Github PR 또한 파트 공용 채널에 모두 공유하면서 서로 어떤 작업을 진행중인지 확인하도록 했다.

리뷰가 한정없이 밀리거나 리뷰없이 반영해야하는 부분. 비즈니스 로직은 모두 알 수 없겠지만 클린코드에 대해서는 확인해줄 수 있다. 이번에 사내에서 진행하고 있는 스터디에서도 내가 기대하는 있는 부분이다.

그렇다면 드디어 모든 문제가 해결된 것일까?!

안타깝게도 여전히 거대한 레거시 프로젝트 저장소가 발목을 붙잡았다. 모든 목적 조직이 사용하는 거대한 레거시 시스템은 기능이 추가될 때마다 빌드 속도가 늘어나고, commit log 가 뒤섞였다.

뒤섞인 commit log 는 label 을 붙여 추적 및 관리한다.

서로가 서로의 기능에 영향을 받기 때문에 QA 일정을 추산하기가 굉장히 어려웠다. 가장 중요한 것은, 이 거대한 단일 레거시 프로젝트 저장소를 어떤 조직도 가져가려하지 않는다는 점이다.


🌱 복잡한 문제를 쉽게 해결하기

그렇다면 어떻게 저 거대한 레거시를 해소할 수 있을까? MSA? 소규모 팀이 MSA 를 도입하는 순간 비즈니스 속도가 기하급수적으로 떨어진다.

인프런에서는 이 문제를 해결하기 위해 분할 정복 패턴을 채택했다.

  1. 거대한 레거시 저장소를 여러개로 복제 후 목적 조직별로 가져간다.
  2. 각 목적 조직은 자신들의 관리 포인트만 남긴채, 나머지 부분을 모두 제거한다.

최종적으로 각 목적 조직은 작은 레거시 저장소 1개와, 작은 신규 시스템 1개씩을 나눠 갖게 된다. 레거시 저장소의 코드가 줄어든 만큼 빌드 속도도 개선되었고, commit log 도 체계적으로 관리되며, 격리된 QA 환경 덕분에 일정을 추산하기도 편해졌다. 무엇보다 중요한 것은 레거시 코드 개편 또한 해당 목적 조직의 목표가 되었다는 것이다. 비즈니스 속도 개선을 위해 PM, PO, 디자이너, 개발자가 다 함께 레거시 개편을 검토하기 시작했다.

기가 막힌 방법! 그럼 앞으로도 이런 문제를 마주했을 때 프로젝트를 복제하면 만사 OK 일까?


🌱 구체적 문제와 해결책

하나의 서비스를 N 개로 분리하면서 수 많은 문제가 드러났고, 이것들을 하나씩 해결해나가는 과정을 정리해보자.

1개의 서비스가 N개의 프로젝트로 분할 == N 배로 증설해야할 인프라

1개의 프로젝트가 N 개로 분할됨에 따라 인프라 역시 N 개로 복제가 필요해졌다.

복제하는 것 자체는 큰 일이 아니다! 중요한 것은 ‘어떻게 하면 실수없이 완벽히 동일한 환경을 구축할 것인가?’ 해답은 역시나 IaC(Infrastructure as Code)

기존 IaC 로 Terraform 을 사용하고 있었는데, 이번에 Pulumi 로 갈아탔다.

  • 가장 훌륭한 문서 품질
  • 선언형 언어가 아니라서 IDE 활용, 추상화된 설계 가능
  • 테라폼은 선언형이라 프로그래밍하기가 어려움.
  • (TS 기준) ESLint/Prettier, 모노 레포 등으로 높은 품질 관리
  • (TS 기준) Jest 활용한 단위 테스트

인프라는 N 개로 잘 복제되었는데, 서비스는 하나의 URL Domain 을 사용하고 있다. 어떻게 하면 각각의 프로젝트(인프라)가 요청을 잘 나눠가지도록 할까?

CF(CloudFront) 에서 Path 에 맞춰 해당 프로젝트의 LB(Load Balancer)로 트래픽 전달 시키는 방법을 채택했다. 굳이 LB 가 아닌 CF 를 앞단에 사용한 이유는 무엇일까? LB 가 지원하지 않는 다양한 서비스로 라우팅이 가능하기 때문!

  • S3
  • API Gateway
  • EC2
  • Lambda

N 개의 프로제긑로 분할- 내부 API 통신이 많아짐.

모든 문제가 해결된 줄 알았는데, 내부 서비스끼리 Public IP 로 인터넷 통신을 한다는 문제가 생겨났다.


Public IP 로 통신한다는 것은 외부 트래픽으로 계산되는 비용과 시간의 문제도 있었고, 사내 Wi-Fi, VPN 기반 내부망 구성이 어렵다는 문제를 의미했다.

하나의 서비스에 Public(VPC) LB, Private (VPC) LB 를 모두 붙이는 방법으로 문제를 해소했다. 이를 통해 네트워크 리소스와 외부 트래픽으로 계산되는 비용 부담도 줄이고, 내부망 구성도 훨씬 쉬워졌다.

트랜잭션 관리

마지막으로 남은 문제.. 기존 하나의 서비스에서 수행되던 로직들이 여러 서비스로 분화되다보니 트랜잭션 관리가 어려워졌다. 모든 API 가 절대 실패하면 안되고 모두 성공해야한다는 가정이 생겨났다.

  • 다른 서비스 로직 수행까지 매번 확인해야하는가?
  • API 중 하나라도 실패하면 어떻게 할 것인가?
  • 모든 API 가 성공할 때까지 대기 시간은 어떻게 할 것인가?

AWS SNS + SQS(혹은 Kafka) 를 이용한 비동기 아키텍처로 간단하게 문제를 해결했다. SNS 를 통해 이벤트 발행만 하면 되는 도메인 의존성을 분리하고, SQS 가 이벤트를 받아가 처리하는 것으로 각 서비스의 최종적 일관성 보장했다. 이 덕분에 각 API 의 결과를 기다릴 필요가 없어졌다.

그러나 역시 트랜잭션이 필요한 곳에는 사용하면 안된다. 여러 로직이 비동기로 실행되어도 무방할 때만 적용한다. 만약 트랜잭션이 꼭 필요한 상황(단일 DB를 사용하는 환경)이라면, 직접 테이블에 SQL 을 사용하는 것이 차라리 낫다. 그 외에는 복잡도가 너무 올라간다.

조직간 데이터베이스 관리

서비스는 N 개로 분리되었지만, 여전히 하나의 데이터베이스를 바라보고 있다. 여러 서비스에서 단일 DB 를 바라본다는 것은, 테이블 변경 사항에 대해 모든 조직이 Sync 를 이루고 있어야 한다는 것을 의미한다.

만약 문제가 발생한다면 문제가 되는 SQL 의 출처를 빠르게 파악해야하고, 여러 서비스 프로젝트에 중복되게 생겨나는 엔티티 클래스의 관리가 필요하다.

DB 를 나누고 DB 간 동기화를 이루는 방법도 있지만, 이것 보다 단일 DB 를 유지하면서 위의 문제들을 해결하는게 훨씬 간결하다고 한다.

인프런에서는 각 서비스마다 다른 DB 계정을 사용해서 문제를 추적하기 용이하도록 하고, 모든 DDL query 수행에 대해 단일 채널에서 모니터링을 진행한다고 한다. 또한 중복되는 엔티티 클래스에 대해서는 중복을 허용하는 것으로 결정했는데, 하나의 엔티티 클래스를 만들고 관리하면 모두가 해당 클래스에 로직을 추가하고, 시간이 흘러 클래스 파일 하나의 크기가 거대해지면 그 누구도 건드릴 수 없는 레거시 폭탄이 되어버리기 때문에 중복을 허용하기로 결정했다.

“만약 조직이 수십개가 되면 수 많은 중복을 다 허용할거냐?” 라는 물음에는 “조직의 수가 늘지 줄지는 아무도 모르는데, 불확실한 미래를 고려해서 위기를 키우고 싶지 않다. 불확실한 미래에는 어설픈 추상화/공통화보다는 삭제하기 쉬운 중복이 낫다.” 라는 답변을 남기셨다.

너무너무 설득력이 강한 멘트… “삭제하기 쉬운 중복이 낫다.”. 항상 “여기저기 중복을 만들면 변경이 생겼을 때 한꺼번에 인지하고 다 바꿀 수 있어요?” 라는 질문에 말문이 막히곤 했는데, 충분한 대답이 될 수 있는 강렬한 멘트다!

그럼에도 불구하고 도메인에 종속적이지 않은 공통 유틸 클래스, 함수들은 GIthub Registry 로 관리한다.


🌱 앞으로의 개선점

인프런에는 아직 해결하지 못한, 비즈니스에 독립적인 플랫폼 성격의 API(이메일/문자/카카오톡 발송 등)들이 남아있다. 엄밀히 말하면 비즈니스 로직이 아니기 때문에 어떤 목적 조직도 이걸 목표로 갖진 않는다. 때문에 순수하게 기능로직만 관리하는 DevOps 조직에서 해당 API 들을 관리하도록 할 계획이다.

또한 인증, 권한을 한 곳에서 관리할 수 있도록, 인증 성공시 Request Header 에 있는 값들을 Reqeust Param 으로 전환해서 전달할 수 있는 최소 스펙의 API Gateway 를 준비중이다.

그 외에도 엔드포인트 공유 방지를 위해 public LB 와 private LB 를 각각 나눈 모놀리틱 저장소 구성을 계획중이다.


🌱 정리

인프런은 트래픽, 장애가 아닌 비즈니스 속도 유지를 위해 조직 개편을 진행하면서, 자연스럽게 아키텍처가 개편된 사례다기 “소프트웨어 구조는 해당 소프트웨어를 개발한 조직의 커뮤니케이션 구조를 닮게 된다.” 는 콘웨이의 법칙을 따른 것. 아마 다음 아키텍처 변경 역시도 다음 조직 개선이 진행될 때 진행될 것이라 예상한다.


🌱 후기

거대한 레거시 프로젝트를 작게 분리해서 각 목적 조직이 오너쉽을 갖도록 유도하는 방법은 정말… 동공이 확대되면서 장표화면에 확 빨려들어가는 그 충격은 며칠이 지난 지금도 잊을 수가 없다.

또, 기술적인 문제를 회피하기 위해 사람의 마음을 움직이는 것보다 사람의 마음을 움직이기 위해 기술적인 문제를 맞부딪히는 과정이 짜릿하게 느껴졌다. (어차피 개발자는 기술적인 문제 해결하라고 돈받는 거기도 하고…)

조직을 운영한다는 것은 단순히 높은 시야에서 문제해결에 집중하는 것 뿐만 아니라, 조직의 심리도 적절히 관리하고 이용할 줄 알아야 한다는 걸 느끼게 된다. 사업이나 조직 관리와 마찬가지로, 개발도 결국 사람이 사람과 하는 일이기 때문에 나도 ‘어떻게 하면 기술적으로 더 멋지게 만들 수 있을까?’ 만큼 ‘어떻게 하면 우리 팀원들이 더 만족할 수 있을까?’ 고민을 충분히 해봐야겠다.

댓글남기기