본문 바로가기

System Design

Basic Steps to System Design for Real Service

반응형

시스템 디자인은 실제 서비스를 개발로 옮길 때 있어서 매우 중요함. 왜냐하면, 같은 기능을 구현하더라도, 이게 얼마나 많은 유저가 사용하고, 어떻게 확장을 해나가야하는 것 등등 까지 고려를 한다면, 같은 코드라도 고려할 것들이 많아진다. 이를 해결하기 위한 것이 시스템 디자인이고, 특히 백엔드 개발이라면 시스템 디자인에 대해 생각하고 공부해야 되는 것이다.

아래는 시스템 디자인을 하기 위한 기본 스텝들이다.

  1. Requirement Clarifications(요구 사항을 명확히 하기)
    • 시스템 디자인에 대해 생각하기 앞서, 최대한 효과적인 질문을 통해 우리가 풀고자 하는 문제의 exact scope 을 명확히 잡는 것은 매우 중요함
    • 가령 트위터 같은 서비스를 시스템 디자인한다고 떠올려 보자. 그럼 아래와 같은 flow로 문제를 명확히 하기 위한 질문을 가져야 할 것이다.
      • 유저들이 post tweet 하고, 다른 사람들을 follow 할 것인지?
      • 또한, 유저의 타임라인을 만들고 보여주는 것도 디자인 할 것인지?
      • tweets는 사진과 비디오를 포함할 것인지?
      • 우리가 백엔드에만 포커싱 하는지, 혹은 프론트엔드도 함께 개발하는지?
      • 유저가 tweets를 검색할 수 있는지?
      • Hot trending topics를 따로 보여줄 필요가 있는지?
      • 새로운 혹은 중요한 tweets 에 대해 push_notifications 가 있을 것인지?
    • 이러한 위와 같은 질문들이 우리의 end design이 어떻게 생길지를 결정할 것이다.
  2. Back-of-the-envelope estimation(어림잡은 사용량 예측 평가)
    • Back-of-the-envelope는 간단히 정리한, 어림잡아 계산한 정도의 관용적 표현이니 참고하시고.. 여하튼 Estimating The Scale That we’re gonna build 는 언제나 중요한 생각이다. 스케일을 정확히 측정해야, 추후에 스케일링, 파티셔닝, 로드 밸런싱, 그리고 캐싱 등을 할 때, 도움이 될 것이다. 아래는 스케일을 예측하기 위한 여러 질문들이다.
      • 이 시스템에서 어떤 스케일 들이 예상되는지?( number of new tweets, 트윗뷰, timeline 생성 수(per sec 마다 생성되는지? 등등)
      • 우리가 필요한 스토리지 용량이 얼마나 될 것인지? 만약 유저가 photo나 비디오도 그들의 트윗에 함께 둔다면, 이 데이터들을 다른 스토리지로 분리시킬 것인지?)
      • 우리가 예상하는 네트워크 대역폭 사용량은 어떤지? 이 정보는 우리가 트래픽을 관리하고, 서버간 로드를 밸런싱하는데 매우 중요할 것이다.
  3. System Interface Definition(시스템 인터페이스 정의)
    • 시스템 인터페이스 디자인이라는 것은 우리가 만드는 시스템에서 필요한 API들을 명확히 정의하는 것이다. (그러니까 인터페이스..) api 명세가 정확해야할 뿐 아니라, requirment(파라미터 정도가 되겠다.)가 잘못받았는지를 검증하는 로직까지 갖춰야한다. (Param validation)
    • 아래 예시는 twitter like service 의 api 명세 예시가 되겠다.
      • postTweet(user_id, tweet_data, tweet_location, user_location, timestamp)
      • generateTimeline(user_id, current_time, user_location)
      • markTweetFavorite(user_id, tweet_id, timestamp)
  4. Defining Data Model(데이터 모델 정의)
    • 데이터 모델을 최대한 early stage 에서 정의내리는 것은 중요함.. 데이터 모델을 초반에 명확히 정의해야만, 데이터가 추후에 시스템의 다른 컴포넌트들 사이에서 흘러가는지를 명확하게 파악할 수 있을 것이다.
    • 예를 들면, 아래와 같이 트위터 같은 서비스의 기본 데이터 모델을 정의해보았다고 하자.
      • User: User_id, name, email, DoB, CreationData, LastLogin, etc..
      • Tweet: Tweet_id, content, tweet location, numberoflikes, timestamp, etc..
      • UserFollower: userid1, userid2
      • FavoriteTweets: user_id, tweet_id, timestamp
    • 위와 같은 데이터 모델을 우리가 정의했을 때, 어떤 db system을 사용해야할까? nosql을 쓸지, mysql 같은. rdbms를 쓸지, 혹은 포토나 비디오 데이터는 block storage를 어떤거로 사용해야 할지 등을 고려해야 한다.
  5. High-level Design(하이 레벨 디자인)
    • 우리 시스템의 코어 컴포넌트들을 block diagram 박스로 그려보자. 우리는 이러한 컴포넌트들이 현재 문제를 풀기에 충분한지 확인해야 한다. 예로 들면, 위에 이어지는 트위터같은 경우 하이 레벨 단에서는 우리는 read/write 리퀘스트를 감당하기위한 multiple application Server 와 그 앞단에 LB가 필요할 것이다. 만약 read traffic이 write에 비해 더 많이 발생할 것으로 예상된다면, 또 서버를 분리 시키는것을 결정할 수도 있다. 백엔드 단에서는 tweet들을 모두 저장하고, 많은 read를 모두 서포트할 효율적인 데이터베이스가 필요하다. 우리는 또한 photo와 videos를 저장하기 위한 분산된 파일 스토리지 시스템도 필요할 것이다.
  6. Detailed Design(세부 디자인)
    • 세부 디자인에 대해서 여러 어프로치를 제시하고, 그들의 각 장단점을 말할 수 있어야 함.. 그리고, 우리가 선택한 어프로치에 대한 합당한 근거가 있어야 한다. 아래는 우리가 생각할 수 있는 디자인에 대해 고려해야할 문제들의 예시임
      • 만든 데이터를 우리가 저장해야하는데, 이거를 multiple dbs에 분산 시켜서 파티션을 해야하는가 ? 아니면 같은 db에 모든 데이터를 저장해야하는가? 그렇게 된다면 발생할 수 있는 이슈는 무엇일까?
      • 유저의 타임라인이 최근의 트윗을 포함할 것이라면, 데이터의 저장도 마찬가지로 scanning the latest tweets에 최적화 해서 저장할 수 있는 방식으로 해야하는가?
  7. Identifying and resolving bottlenecks(병목구간을 식별하고, 해결하기)
    • 가능한 한 최대한 병목구간에 대해 많이 생각을 미리 해봐야 함. 그리고, 이를 완화(mitigate)시킬만한 여러 옵션 어프로치를 생각해내야 함
      • 우리 시스템에 single point of failure가 있는지?
      • 만약 몇개의 서버를 잃을 때를 대비해, 충분한 데이터 replicas 를 갖고 있는지? 즉, 여전히 유저에게 안정적으로 서비스를 제공할 수 있는지?
      • 우리 서비스를 어떻게 모니터링 할 것인지? 크리티컬한 컴포넌트가 fail 이 나거나, 퍼포먼스가 나빠지면 alert를 받아야 하는지?
  8. Summary
    • 1~7 스텝을 숙지하고, 이제 다음부터는 실제 Use Case 들을 생각해보자.
반응형