Skip to content

Latest commit

 

History

History
173 lines (139 loc) · 10 KB

인프런-아키텍처의-과거와-현재-그리고-미래.md

File metadata and controls

173 lines (139 loc) · 10 KB

인프런 아키텍처의 과거와 현재, 그리고 미래 - 인프랩 이동욱(향로)

리스크 기반의 적정 소프트웨어 아키텍처

부제: 적정 소프트웨어 아키텍처
A 라는 목표를 B라는 일정안에 달성하기 위해 감수하는 제약 조건

동료들과 노를 젓는다, 비행기를 탄다 등

여기서 돈과 동료가 없다는 제약조건이 생기면 어떻게 해야하는가? 인프런의 시즌1

시즌1

-> 직접 헤엄쳐서 갈 수 밖에 없다. 혼자서 모든 것을 다 해야한다. 직접 개발을 최소화하고, 외부 자원(SaSS)을 최대한 활용하자.

PHP + jQuery -> 워드프레스 + MySQL (호스팅 서비스 서버 1대) 회원수 10만이 되면서 많은 문제가 발생

  • 미칠듯이 느려지는 서비스
  • 의도를 알 수 없는 데이터
  • 워드프레스로 인한 기능 확장의 한계
  • 직접 관리해야하는 서버, 배포, DB

기능은 그대로 둔채, 서비스를 직접 다시 만들자 -> 많은 기능이 없었기 때문에 충분히 결정할 수 있었음.


시즌2

프론트1, 백1 등등..
이렇게 했을 때 리스크는 무엇인가? 개발자가 1명만 빠져도 해당 영역의 개발이 완전히 멈추어버림
해결방법은?

  1. 기술 스택을 통일하자.
    • FE, BE, DevOps 를 한 언어로
    • JS
  2. 낮은 러닝 커브 배울게 적고,
    • SSR & FxDom, FxSQL
  3. 최소 관리 관리비용 중이기
    • CircleCI, AWS(Fargate, RDS)

정적 HTML을 서버에서 내려주고, 프론트에서 DOM을 선태갛는 방식

  • 구현 코드의 최소화, 단일화된 라이브러리, 익숙한 패턴(서버사이드 랜더링 - 정적 HTML, jQuery), 단일 프로젝트(FE + BE)
  • 3.5명의 개발자로 5개월만에 전체 시스템 전환 완료 (워드프레스 -> 풀 JS 스택)
  • 신규 개발자들이 채용 되면서 점점 발생하는 문제들
    • 구현코드를 최소화하다보니, TypeScript가 아닌 바닐라JS에서는 타입을 표현할 방법이 클래스 밖에 없음. 함수로는 표현 불가능
    • 모든 데이터가 객체(Json)으로만 움직이다보니 SQL 결과물이 무엇인지, API 결과물이 무엇인지 콘솔 log를 찍어봐야만 알 수 있음 (코드로 확인 불가능)
    • IDE의 지원 없는 개발(타입이 없으므로)
    • 검증되지 않는 기존 기능 (일정이 급해서 테스트 코드가 없음)
    • 작업자의 심리적 불안감
    • 단일화된 라이브러리 때문에 부족한 생태계, 커뮤니티, 문서. 생소한 문법, 부족한 레퍼런스
    • 바닐라JS는 라이브러리 버전업을 하지 않는다. 리액트 라이브러리를 쓰라는 표현이 많음
    • 익숙한 패턴은 -> 신규 개발자들에겐 익숙하지 않은 패턴
      • 신입 개발자들이 배우는 스택 (요즘 유행하는 스택)을 회사에서 채용해야 신규 입사자를 쉽게쉽게 구할 수 있다.... 건강한 팀 문화가 발전한다.
    • 단일 프로젝트(BE + FE)이다보니 비효율적인 Reload, bundling
    • 신규입사자들의 높은 진입장벽
    • 작업자의 낮아진 심리적 안정감(타입, 테스트 등이 없어서)
    • 참을 수 없이 느려진 번들링, 리로드 속도
    • COmponent 개발이 불가능한 아키텍처 구조

시즌3

BE3, FE3, DevOps1, (이동욱님)CTO1

  • 심리적 안정감을 끌어올리자. 코드 수정에 대한 자신감, 코드 레벨에서 예측 가능한 결과물을 만들도록
    • Class & Type, 테스트 코드 & 정적 분석, eslint,& prettier
  • 외부 개발자들이 많이 사용하는 라이브러리, 구조, 패턴을 사용해서 진입 장벽을 낮추자
    • TypeScript, React & Next.js, 계층형 아키텍처 DI 테라폼, GO 등
  • 독립성, FE BE가 독립적으로 개발 가능하도록 하자.
    • FE & BE 계층 분리, API 명세 기반 개발, 분리된 저장소

대중적인 기술스택을 선택해서, 생태계에서 필요한 인력을 쉽게 구할 수 있도록 한게 핵심인듯...

그렇다면 이것들을 어떻게 전환할 것인가?

  • 빅뱅
    • 서비스 개선 멈추고 전체를 다시 만들어서 한번에 교체
    • 예상 1년
  • 점진적 개편
    • 서비스 개선과 시스템 개편 병행
    • 기능 그룹별 이관
    • 예상기간 2년

스타트업에서는 6개월이라는 시간은 일반 기업의 2년에 준하는 시간. 스사트업에서 이 시간을 멈춘다는 건 경쟁업체에게 모든걸 양보한다는 뜻

"매년 2~300% 성장하는 서비스를 중단 없이 개편하는 경험을 개발자들에게 주고 싶었다."

부럽다...

백엔드와 프론트를 점진적으로 개편

기존 인프런 백엔드 서버는 API 게이트웨이로서의 역할을 하고, 회원/인증 서버와 비즈니스 로직 서버를 분리해서 개편 (구) 인프런 싱글 게포 + (신) 인프론 프론트엔드 모노레포 + (신) 인프런 백엔드 모노레포


서비스 장애 (강제 시즌4)

  • 한 기능의 장애가 전체 기능의 장애로 확장되는 상황
  • 단일 프로젝트에 모든 하위 서비스 운영
    • 비즈니스 인프런, 인프런 어드민, 인프런 커뮤니티
    • "선착순 쿠폰 이벤트 했더니 전체 장애 발생"
    • "어드민에서 엑셀 다운로드 했더니 인프런 죽어요"
    • "비즈니스 회원 일괄 가입시키니까 인프런이 죽어요."
  • 독립적으로 운영하는 서비스들은 다 분리한다. -> MSA 시작
  • 애플리케이션 서버의 메모리, CPU를 많이 점유하는 작업으로 인한 장애는 격리됨
    • 근데 그럼 데이터베이스 장애 격리는? 과한 쿼리가 들어오면 모든 서비스가 죽는건 그대론데?
    • 데이터베이스 분리를 해야한다. 그걸 언제할까?
    • 시즌5. 지금은 시즌3 작업도 진행중임...
  • 분산된 데이터베이스로 높아지는 복잡도
    • 쿼리를 쪼개서 API 통신으로 변경하는 등... (오 이런 식이구나)
  • 트랜잭션 관리의 어려움
  • 기존 쿼리들의 전체 개편
  • 할 것들이 많음 (기능요구)
    • data lake
    • 검색 기능
    • 전체 회원 조회
  • 적절한 모범답안은
    • RDS, Redis, DDB 등 전부 사용
    • 그러나 인프런 시즌3~4 중에 선택이 불가능
  • 모범답안이 뭔지는 아는데, 일단 기술의 가지수를 줄이자.
  • 가장 좋은 기술/아키텍처보다는 2~3년을 버틸 수 있는 적정 기술을 선택하고, 그 이후에 다시 개편하자.
    • 그래서 선택한게 몽고DB 아틀라스.
    • 다이나모 디비와 같은 noSQL이고, ES와 같은 Lucene 검색앤진과 노리 한글형태소 분석 지원
    • 검색 엔진, 데이터레이크, 실시간 데이터처리 등을 한번에 해결하자 (하나에만 집중하자)
  • 신규로 구축한 검색엔진 아키텍처 (사진1)
    • 구 인프런은 API 게이트웨이로만
    • 신규 인프런 백엔드가 이벤트를 발행하고
    • SNS를 통한 멀티 구독
    • SQS를 통한 최종적 일관성 보장
    • Spring Boot를 통한 배압조절 (Back pressure)
    • Zero Payload를 통한 이벤트 순서 보장
      • 메세지에 다른건 아예 없고 Key값(ID) 1개만 있는걸 제로페이로드라고 부름.
    • "NODE에서 SNS로 이벤트 발행이 실패하면요?"
      • 이벤트 저장소를 중간에 두면 해결이 됩니다..만!
      • 아키텍처 복잡도가 너무 높아지기 때문에...
      • 이번 시즌에서는 에러로그 발생하면 수동으로 재발행
    • '검색 엔진'이라는 추가 의존성, But 기존 서비스와 장애가 격리된 채로 완성되었다.
    • 자세한 내용은 인프랩 기술블로그에 공개할 예정~
      • 왜 카프카를 사용하지 않았는지 등

마무리

  • 아직도 인프렁느 (구) 인프런이 90%를 차지하고 있다.
  • 아키텍처가 조금씩 조금씩 옮겨지고 있다. 여전히 시즌3~4 진행중
  • 한번에 모든걸 바꾸기 어렵고, 점진적으로...

질문 -> 중간에 메세지를 저장하는걸 준비중이라했는데 뭘로 저장할거?
답변 -> 트랜잭션이 되어야해서, 그걸 지원하는 디비 쓸거임

질문 -> 파이썬 테스트 짜기 어려웠다. 자바 스크립트도 비슷할거 같은데, 어떻게 지키면서 자바로 옮겼나?
답변 -> 함수형 프로그래밍을 하고 있기 때문에, 단일 함수들로 이루어져있어서 테스트 코드를 짜는게 어느정도 가능하긴했다. 단일 함수 + API 엔드포인트에 대한 것만 테스트를 진행하고, 나머지는 블랙박스라고 생각했다...

질문 -> 장애격리를 위해서 서비스를 분리해야하는 이유? 데브옵스 적인 영역으로 가능할거 같은데 굳이 서비스를 분리한 이유?
답변 -> 하나의 큰 저장소 자체가 부담이었음. 독립적으로 떼어내서 단위테스트나 추가나 프로젝트 전환이 편했음. 그러나 모노레포로 모든걸 물고 있으면 JS -> JAVA 전환이 너무 빡셈. 그래서 데브옵스 적인 걸로 해결도 가능하지만, 서비스를 분리했음.

질문 -> 이어지는 문제로, DB 쪽 커넥션이 많아진다던지 문제는? 답변 -> 서비스별로 디비 계정을 발급해서, 디비 계정별로 에러가 발생하는 계정이 무엇인지로 판별해서 어디가 문제인지 판별했고, 커넥션이 많이 필요한 계정에만 풀을 넉넉히 발급하고, 나머지는 커넥션을 줄여서 최적화 했다.

질문 -> 개편을 어떻게 설득하고, 성과지표를 어떻게 측정했는가?
답변 -> 개편안에 대해서 운영파트에서도 먼저 제안을 주셨다. 마케팅적으로 많은 이벤트를 했는데, 그 때마다 최대실적을 달성한적이 없음. 달성하려하면 서버가 죽어버림. 그러니까 운영이나 사업쪽이 계속 먼저 이야기했고, 서버 비용이나 데드횟수 같은걸 모두 체크하고 있었음. 우리가 얼마나 많이 장애나고 있어. 그런걸 모두 발표함. 이 때 장애가 안났더라면 얼마나 많은 회원이 늘었을지, 얼마나 많은 돈을 벌었을지 예상지표를 만들어서 발표했다.