NLP Blog

15. 폐기

|

15. 폐기

  • 새로운 기술, 라이브러리, 기법, 언어 등이 등장하면서 기존의 시스템은 서서히 구식이 되어감
  • 이러한 오래된 시스템을 유지하는데에 비용이 들어가고 난해한 옛 기술에 대한 전문지식이 필요함
  • 낡은 시스템을 떼어 내는 것은 고통스럽지만, 궁극적으로 떼어내는 것이 이득
  • 이주를 순차적으로 신행하여 궁극적으로 낡은 시스템을 완전히 걷어내는 과정을 폐기(deprecation) 이라고 함

  • 폐기는 시스템 관리에 세월을 고민해야하는 소프트웨어 엔지니어링 원칙에 속함
  • 제대로 폐기를 한다면 자원을 아끼고 개발 속도를 높여주지만, 그렇지 못하면 방치보다 더 큰 비용을 치를 수 있음

15.1 폐기시키는 이유

  • 기본 전제 : 코드는 자산이 아닌 부채다.
  • 자산은 기능이다.
  • 코드에는 비용이 따라온다
    • 일부는 구축시 발생하지만, 대부분은 구축 후 생이 끝날 떄까지 유지보수하는 데서 발생
    • 시스템이 오래되었다고 해서 무조건 폐기시켜야 하는 것은 아님 (ex: LaTeX)
  • 같은 일에 구식과 신식 시스템을 모두 사용하는 것도 큰 비용을 초래함
    • 두 시스템간 정보 교류를 위한 복잡한 변환 코드 발생
    • 둘 모두 버전업을 계속하며 서로를 의존하게 됨 -> 망조

코드는 자산이 아닌 부채이다. 코드 자체는 가치를 창출하지 않는다, 기능이 가치를 창출함. 특정 기능을 지원하는 최소한의 단순한 코드가 좋다.

  • 한 조직이 동시에 진행할 수 있는 폐기 작업의 양에는 한계가 있음
    • 어느날 갑자기 좋은 도로를 만들겠다고 모든 도로를 공사하면? -> 망함
  • 폐기 대상을 신중하게 선택한 다음, 집중해서 빠르게 완료하는 것이 중요함

15.2 폐기는 왜 그리 어려운가?

  • 하이럼의 법칙
  • 시스템은 사용자가 늘수록 설계자가 예상하지 못한 이용방식이 늘어나서 폐기 작업이 어려워짐
  • 새로운 시스템은 더 좋지만 기존과 다르다
  • 옛 시스템을 향한 애착이 의외의 저항으로 나타날 수 있음
  • 정치 (politics)적인 문제로 해결해야 함

구글의 농담 : 일을 처리하는 방법은 두가지다. 폐기 중인 시스템을 이용하거나, 아직 준비가 덜 된 시스템을 이용하거나.

15.2.1 설계 단계에서의 폐기

  • 시스템을 처음 구축할 때 폐기 계획을 세울 수 있음
  • 원자로 설계 시, 이를 해체하기 쉬운 설계를 고민한다
  • 큰 회사일수록 마음대로 제품을 폐기할 수 없기 때문에 큰 고민이 필요하다.

15.3 폐기 유형

  • ‘권고’와 ‘강제’로 구분 가능

15.3.1 권고 폐기

  • 권고 폐기 (advisory deprecation) : 기한이 없고 조직에서도 우선순위가 높지 않은 경우
  • 다른 말로 희망 폐기 (aspirational deprecation)
  • 이 유혀으이 폐기에는 대체로 강제성이 없음
  • 하지만, 희망은 전략이 아니다
  • 권고폐기는 새로운 시스템이 사용자에게 주는 혜택이 매우 클 때 효ㅑ과가 좋음
  • ‘정말 좋다’ 정도가 아니라 ‘혁신적이다’ 수준이어야 함
  • 구글에서의 경험 상 구식 시스템의 사용률이 살짝 줄어들 수는 있지만 적극적인 이주로 이어지는 일은 거의 없음

15.3.2 강제 폐기

  • 강제 폐기 (compulsory deprecation) : 낡은 시스템의 지원 종료일을 못 박는 평태
  • 강제 폐기를 효율적으로 수행하려면 기존 시스템을 완전히 제거하는 역할을 전담할 팀을 하나 따로 꾸리는 게 가장 좋음
  • 강제 폐기가 잘 이루어지려면 일정대로 집행할 수 있는 권한이 주어져야 함
  • 그래프 분석만으로 의존성을 빠짐없이 찾아 내기는 어려움
  • 기존 시스템의 가동을 임시로 중단시키는 빈도와 시간을 점차 늘려보는 실험을 해보면 여전히 기존 시스템을 이용중인 서비스들은 작동하지 않을 것

15.3.3 폐기 경고

  • 권고 폐기든 강제 폐기든 해당 시스템이 폐기 대상임을 프로그래밍적으로 알려주면 좋음
  • 실제로 경고들이 날이 갈수록 불어나는 일이 벌어짐 -> 경보 피로 (alert fatigue)

폐기 경고 메시지의 중요한 2가지 특성 실행 가능성 (actionability)과 적시성 (relevance)

  • 실행 가능한 경고 : 폐기 시킬 함수를 호출한 대상에게 대체 API를 알려주는 도구 등 어떤 경우든 경고 메시지에는 폐기될 시스템으로의 의존성을 떼어내기 위해 엔지니어가 수행할 다음 단계를 야려줘야 함
  • 적시에 뜨는 경고 : 사용자가 실제로 관련 동작을 수행할 때 경고가 떠야함, 함수 폐기 경고는 함수를 사용할 때, 데이터 마이그레이션 안내 메일은 기존 시스템 제거 직전 주말이 아니라 몇 달 전에 보내는게 좋음

15.4 폐기 프로세스 관리

15.4.1 프로세스 소유자

  • 시스템이 아무리 경고를 쏟아내도 소유자가 명확하지 않으면 프로세스는 직척되지 않음
  • 소유자 없이는 아무것도 폐기시키지 마라! 폐기 업무를 시스템 이용자들에게 절대 떠넘기지 마라!
  • 소유자 없는 폐기는 모든 낡은 시스템들을 무한정 유지하겠다는 선언과 같음
  • 소유자가 없어진 버린 프로젝트에는 폐기 전문가를 배정하여 하루빨리 제거애햐 함
  • 폐기 전문 팀을 두어 낡은 시스템 제거를 주된 목표로 진행시켜야 함

15.4.2 마일스톤

  • 완전히 제거하는 것만이 유일한 마일스톤이 아니다!
  • 폐기팀을 관리할 때도 측정할 수 있고 고객에게 가치를 전달해주는 명확하고 점진적인 마일스톤들을 세워야 함
  • 폐기시킬 때도 핵심 컴포넌트들을 하나씩 제거하는 걸 점진적 마일스톤으로 삼으면 효과가 좋다.

15.4.3 폐기 도구

발견

  • 낡은 시스템을 누가, 어떻게 이용하고 있는지를 알아내야 함
  • 폐기 작업 초기에는 낡은 시스템을 이용하는 곳을 찾은 다음 예상하지 못한 방식으로 이용하지는 않는지를 알아내는 일이 대부분을 차지 함
  • 구글에서는 Code Search같은 검색 도구와 Kythe 같은 정적 분석 도구를 사용
  • 런타임 의존성은 정적 라이브러리나 씬 클라이언트를 사용할 때 생겨나므로 이 기법으로 폐기 프로세스를 시작하고 진행하는 데 필요한 다양한 정보를 얻을 수 있음
  • 프로덕션 시스템에서 얻은 로그 데이터와 런타임 데이터 샘플은 동적 의존성 관련 문제를 발견하는데 유용
  • 구글은 폐기시킬 심볼의 참조가 모두 제거되었는지를 확인하는 데 전역 테스트 스위트를 신탁처럼 이용함

마이그레이션(이주)

  • 새로운 라이브러리나 런타임 서비스를 이용하도록 코드베이스를 업데이트할 때는 대규모 변경 프로세스와 도구가 매우 유용함

퇴행 방지

  • 새로 작성하는 코드에서 폐기 중인 대상을 이용하는 걸 퇴행이라 함
  • 새로 커밋되는 코드에서 폐기 중인 시스템을 이용하려 든다면 뜨끔해지게끔 경고해주는 것이 좋음
  • 퇴행을 실무 수준에서 방지하기 위해 구글은 Tricorder라는 정적 분석 프레임워크를 이용
    • 폐기 중인 시스템을 호출하는 코드를 추가한 사용자에게 적절한 대체 방법을 피드백함
    • 폐기 시스템의 소유자가 컴파일러 애너테이션에 자바의 @deprecated 애너테이션 같은 폐기 심볼을 추가해두면 Tricorder가 자동으로 알려 줌
    • 거시적으로는 빌드 시스템에 가시성 (visibility) 허용몰곡을 도입하여 폐기된 시스템에 의존하는 시스템이 새로 생겨나는 일을 막음

핵심 정리

  • 소프트웨어 시스템이 존재하는 한 유지보수 비용은 계속 발생하므로 제거하는 비용과 저울질해봐야 함
  • 시스템을 원래 설계 의도와 다르게 사용하는 사용자가 많기 때문에 제거하는 일이 아예 처음부터 만들기보다 어려울 때도 많음
  • 폐기 비용을 생각하면 새로운 시스템으로 교체하기보다 기존 시스템을 개선하는 편이 일반적으로 더 저렴
  • 폐기 여부를 결정하려면 비용을 따져와야 함, 하지만 이는 매우 어려움. 생태계 비용은 곳곳에 퍼져있어서 측정하기 어려움. 폐기와 제거 비용도 마찬가지로 흩어져 있는 경우가 많음

Comment  Read more

10. 문서자료

|

10. 문서자료

  • 구글에서 문서자료를 개선하고자 해본 시도 중 가장 성공적이었던 방법은 문서자료를 코드처럼 취급하여 엔지니어링 워크플로에 통합하는 것

10.1 문서자료란?

  • 문서자료란 엔지니어가 작업을 끝마치기 위해 작성해야 하는 모든 부수적인 텍스트 (코드 주석 포함)

10.2 문서자료가 필요한 이유

  • 다음 질문에 대해 답이 가능
    • 이 설계를 택한 이유가 뭐지?
    • 코드를 왜 이런 식으로 구현했을까?
    • (예컨대 2년후 자신의 코드를 살펴보며) “내가” 왜 이렇게 구현했지?
  • 문서자료의 이런 혜택에도 불구하고 엔지니어들이 “덜 중요하게” 생각하는 이유는?
    • 만흥 ㄴ엔지니어가 글쓰기를 프로그래밍과는 별개의 기술로 봄
    • 글쓰기에 자신 없어함
    • 문서자료는 도구 지원이나 개발 워크플로 통합 측면에서 아직 많이 부족하기 때문에 작성하기가 상대적으로 어려움
    • 문서자료가 기존 코드를 유지보수하기 더 쉽게 해준다고 생각하기보다는 유지보수할 대상이 하나 더 늘어난다고 생각
  • 문서자료는 다양한 부류의 사람에게 혜택을 줌, 심지어 작성자에게도
    • API를 가다듬는데 도움을 줌. 글을 써보면서 설계를 다시 되돌아 볼 수 있음
    • 유지보수를 위한 로드맵과 과거 이력을 제공
    • 코드를 더 전문적이고 매력 있어 보이게 함. 개발자들은 무의식적으로 문서화가 잘되어 있는 API를 더 잘 설계된 것이라고 여김
    • 이용자의 질문이 줄어듬

10.3 문서자료는 코드와 같다

  • 구글에는 문서자료용 스타일 가이드도 있음
  • 꼭 따라야 하는 내부 정책과 규칙이 있어야 함
  • 버전 관리 시스템에 등록해 관리해야 합니다.
  • 관리 책임자를 명시해야 합니다.
  • 변경 시 (문서자료가 설명하는 코드와 함께) 리뷰를 거쳐야 합니다.
  • 코드상의 버그를 추적하듯 문제를 추적해야 합니다.
  • 주기적으로 평가 (혹은 테스트)를 받아야 합니다.
  • 가능하다면 정확성이나 최신 정보 반영 여부 등을 측정해야 합니다. (아쉽게도 아직은 도구들이 충분히 뒷받침해주지 못합니다.)

10.4 독자를 알자

  • 독자 유형
    • 경험 수준: 건문 프로그래머, 혹은 프로그래밍 언어조차 낯선 초보 엔지니어
    • 도메인 지식: 팀원, 혹은 최종 API 정도에만 친숙한 사내의 다른 엔지니어
    • 목적: 여러분이 제공하는 API를 사용해 특정 작업을 수행하거나 급히 정보를 얻어내야하는 최종 사용자, 혹은 아무에게도 유지보수를 맡기고 싶지 않을 만큼 꼬여있는 특정 구현마저 기꺼이 책임지려 하는 소프트웨어 전문가
  • 문서를 접하게 되는 방식
    • 탐색자 : 자신이 원하는 것을 정확히 알고, 읽고 있는 문서자료가 원하는 정보를 담고 있는지를 알고 싶어하는 엔지니어 -> 일관성이 핵심
    • 배회자 : 무엇을 원하는지를 정확하게 알지 못하는 사람 -> 명료한 글이 효과적

10.5 문서자료 유형

  • 참조용 문서자료 (코드 주석 포함)
    • C++ 헤더 파일을 API 설명 문서를 작성해두는 용도로 활용
    • Javadoc, PyDoc, GoDoc…
    • 파일 주석
    • 클래스 주석
    • 함수 주석 (Public Method)
  • 설계 문서
    • 표준 설계 문서 템플릿 - 보안, 국제화, 스토리지 요구사항, 개인정보 보호…
  • 튜토리얼
    • 독자가 수행해야 하는 모든 단계 각각에 번호를 붙여야 함
    • 모든 단계에서 독자가 특정한 일을 수행해야 함
  • 개념 설명 문서자료
  • 랜딩 페이지

10.6 문서라죠 리뷰

  • 정확성 확인용 기술 리뷰 : 주로 해당 주제 전문가가 수행하며, 팀 동료인 경우가 많습니다. 코드 리뷰 과정에서 함께 다루곤 합니다.
  • 명확성 확인용 독자 리뷰 : 주로 도메인을 잘 모르는 사람이 수행합니다. 팀에 새로 합류한 동료나 해당 API의 고객일 것입니다.
  • 일관성 확인용 작문 리뷰 : 주로 테크니컬 라이터나 자원자가 수행

10.7 문서화 철학

  • 누가, 무엇을, 언제, 어디서, 왜
  • 시작, 중간, 끝
  • 좋은 문서자료의 특징
    • 완전성, 정확성, 명확성
  • 문서 폐기하기
    • 문서에 신선도 보증 기간 붙이기

10.8 테크니컬 라이터가 필요한 순간

  • 팀에 필요한 문서자료는 엔지니어가 충분히 작성 가능
  • API 경계를 넘나드는 문서 작성이 테크니컬 라이터가 필요

핵심 정리

  • 문서자료는 시간이 흐르고 조직 규모가 커질수록 더 중요해집니다.
  • 문서자료 변경도 기존 개발자 워크플로에 통합되어야 합니다.
  • 하나의 문서는 하나의 목적에 집중해야 합니다.
  • 문서자료는 자신이 아니라 독자를 위해 써야 합니다.

Comment  Read more

9. 코드 리뷰

|

9. 코드 리뷰

  • 구글은 자체 리뷰 도구 (Critique)을 활용
  • 버그가 코드베이스로 침투하기 전에 잡아낸다
  • 미묘한 이점도 많음

9.1 코드 리뷰 흐름

  • 구글에서는 프리커밋 리뷰를 활용
  • 절차는 다음과 같음
    • 작성자가 자신의 작업 공간에서 코드베이스에 적용할 변경사항을 작성. 그 다음 젼경의 스냅샷을 만듬. (스냅샷 : 코드 리뷰 도구에 업로드할 코드 패치와 관련된 설명) 이 변경으로 현재 코드베이스와의 diff를 떠서 코드가 어떻게 달라졌는지를 평가
    • 작성자는 초기 패치를 사용하여 자동 리뷰 의견을 받거나 스스로 리뷰를 해봄. 변경 내용이 만족스럽다면 한 명 이상의 리뷰어에게 메일을 보내 리뷰를 요청.
    • 리뷰어들은 코드 리뷰 도구에서 변경을 열고 해당 diff에 댓글로 의견을 남김. 작성자에게 해결해야 할 문제를 던져주거나, 단순히 유용한 정보를 제공해주기도 함
    • 작성자는 피드백을 기초로 변경을 수정하고 새로운 스냅샷을 업로드한 후 리뷰어들에게 회신 (3~4차례 반복 가능)
    • 리뷰어들이 변경 내용에 모두 만족하면 LGTM 태그를 달아줌
    • 커밋 가능!
  • 코드는 부채다! 필요 없는 코드라면 없는게 있는것보다 나음

9.2 코드 리뷰 @ 구글

  • 구글의 방식이 시간과 규모 측면에서 확장하기 용이한 이유를 알아보자
  • Approve를 얻기 위해서 3가지 측면의 리뷰를 통과해야 함
    • 정확성과 이해 용이성 평가
    • 변경되는 코드 영역을 관리하는 코드 소유자로부터 변경 코드가 적정하다는 승인을 방아야 함
    • 가독성 승인을 받아야 함
  • 뭔가 통제가 많고 과해보이긴하지만 구글에서는 한다!
  • 이는 모두 확장성을 위한 것임
  • 구글에서는 소유권을 관리 함 (repository에 OWNERS 파일이 있음)

9.3 코드 리뷰의 이점

  • 코드가 정확한지 확인해줍니다.
  • 변경된 코드를 다른 에니지니어도 잘 이해합니다.
  • 코드베이스가 일관되게 관리됩니다.
  • 팀이 소유권(주인의식)을 더 강하게 느낍니다.
  • 지식이 공유됩니다.
  • 코드 리뷰 자체의 기록이 남습니다.

9.3.1 코드 정확성

  • 결함을 프로세스 초반에 잡아낼수록 시간이 덜 듬
  • 코드 리뷰에 들이는 시간은 테스트, 디버그, 회귀 테스트에 투입 되는 시간을 줄여줌

9.3.2 코드 이해 용이성

  • 코드 리뷰는 주어진 변경이 수많은 다름 사람에게도 쉽게 이해되는지를 평가하는 첫 번째 시험대
  • 코드의 정확성과 이해 용이성 검토는 다른 엔지니어가 LGTM을 주기 위해 평가하는 주요 기준 -> 해당 코드가 의도한 일을 정확히 수행하면서 이해하기도 쉽다는 뜻

9.3.3 코드 일관성

  • 가독성 승인
    • 해당 프로그래밍 언어의 모범 사례들을 잘 따라야 합니다.
    • 구글 코드 리포지터리에서 같은 언어로 작성된 다른 코드들과 일관되어야 합니다.
    • 필요 이상으로 복잡하지 않아야 합니다.

9.3.4 심리적, 문화적 이점

  • 코드는 ‘조직의 공동 소유물’
  • 작업 결과를 검증하고 인정해주는 심리적 이점
  • 자신의 코드를 한번 더 들여다보게 하는 효과

9.3.5 지식 공유

  • FYI 주석
  • 구글 엔지니어들이 코드 리뷰에 쏟아부은 시간으로 유추해보면 축적된 지식의 양이 엄청남을 알 수 있음
  • 코드베이스에 변경이력을 남기기에도 유용

9.4 코드 리뷰 모범 사례

  • 공손하고 전문가답게
  • 작게 변경하기
  • 변경 설명 잘쓰기
  • 리뷰어는 최소한으로
  • 가능한 한 자동화 하기

9.5 코드 리뷰 유형

  • 그린필드 리뷰와 새로운 기능 개발
  • 동작 변경, 개선, 최적화
  • 버그 수정과 롤백
  • 리팩터링과 대규모 변경

핵심 정리

  • 코드베이스 전반의 정확성, 이해 용이성, 일관성 보장 등 코드 리뷰가 주는 이점이 많습니다.
  • 여러분의 가정에 대해 항시 다른 사람의 검토를 받도록 하고, 코드를 읽는 사람에게 최적화 합니다.
  • 전문가다움을 지키면서 중요한 피드백을 받을 기회를 제공하세요.
  • 코드 리뷰는 지식을 조직 전체에 공유하는 데도 중요한 역할을 합니다.
  • 코드 리뷰 프로세스를 확장하려면 자동화가 아주 중요합니다.
  • 코드 리뷰 자체가 변경 이력이 되어줍니다.

Comment  Read more

8. 스타일 가이드와 규칙

|

스타일 가이드와 규칙

  • 규칙 : 은 곧 법. 엄격하고 꼭 지켜야 함
  • 지침 : 권장사항과 모범 사례, 따르면 이득. 변형하여 적용해도 괜찮음
  • 구글에는 프로그래밍 스타일 가이드가 정리되어 있음
    • 외부 조직에도 이를 쓰는 곳이 굉장히 많음 (cpp, python…)
  • 구글의 프로그래밍 스타일 가이드에 담긴 결정들은 구글 코드베이스를 지속 가능하게 관리하기 위한 규칙들

8.1 규칙이 필요한 이유

  • “좋은” 행동을 장려가고 “나쁜” 행동을 억제하기 위함
  • 좋음과 나쁨은 주관적이고 무엇이 필요하냐에 따라 달라지므로, 조직마다 기준이 다를 수 있음
  • 어휘 (즉 코딩 스타일)이 통일되면 엔지니어들은 코드를 표현하는 형식보다 담을 내용에 집중할 수 있음

8.2 규칙 만들기

  • 먼저 생각해야 하는 것 : “어떤 목표를 이루려하지?”
  • 목표에 집중하면 규칙이 따라옴
  • 뭘 넣어야하지? 가 아닌 이게 왜 들어가야하지?

8.2.1 기본 원칙 안내

  • 규모와 시간 양쪽 측면에서 탄력적인 엔지니어링 환경이 지속되도록 하는 것
  • 규칙의 양을 최소화
  • 코드를 읽는 사람에게 맞춤
  • 일관되어야 함
  • 오류가 나기 쉽거나 예상치 못한 동작을 유발하는 구조를 피함
  • 꼭 필요하다면 실용성을 생각해 예외를 허용

규칙의 양을 최소화한다

  • 규칙을 익히는 것 또한 비용
  • 너무 자명한 규칙은 의도적으로 배제 (goto 사용에 대한 규칙은 없음)

읽는 사람에게 맞춘다

  • 코드는 작성되는 횟수보다 읽히는 횟수가 더 많으면 시간이 갈수록 차이가 벌어짐
  • 읽기 난해한 것보다 타이핑하기 지루한 것이 더 나음
    • 파이썬의 조건부 표현 (x = 3 if a % 3 else 4)은 금지하고 if문 사용권장 (if a%3: x=3 else: x=4)
  • 읽기에 간단한 > 스기에 간편한
  • 변수와 타입 이름을 서술식으로 더 길게 짓고 반복해서 타이핑
  • JAVA, JS, C++ 가이드에는 오버라이드하는 메서드에는 오버라이드 어노테이션이나 키워드를 반드시 사용
  • 목적은 “현 위치에서 추론하기” -> 다른 코드를 찾아보거나 참조할 필요 없이, 함수의 구현부를 들여다보지 않고도 호출 지점에서 무슨일이 벌어지는지를 명확히 이해할 수 있도록 해야 함

일관되어야 한다

  • 구글은 코드스타일 뿐만 아니라 다른 인터페이스도 다 일치시켜서 시간을 허비하는 일을 줄임

일관성이 안겨주는 이점

  • 우리가 제한한 특정 수치가 아니라 ‘단 하나의 답’만 사용한다는 일관성
  • 일관성은 규모를 확장하기 쉽게 도와줌
  • 인력을 늘리는 데도 도움이 됨
  • 시간 관점에서도 탄력성을 보장

표준 정하기

  • 구글의 파이썬 스타일 가이드의 indent는 한 때 2개였음… 구글에서 만든 코드를 사용할때 정말 극혐이었음 (대부분 공백을 4개 쓴다)
  • 외부 세상도 중요함!

오류를 내기 쉽거나 예상과 다르게 동작할 여지가 있는 구조는 피하자

  • 복잡한 기능에는 언뜻 봐서는 지나칠 수 있는 미묘한 함정이 숨어있을 수 있음 -> 버그 유발
  • 구글에서는 파이썬의 리플렉션 (hasattr(), getattr())을 사용금지함
    • 근데 외부에는 또 쓰는곳도 많음!
  • 고급 기능들은 기능을 잘 이해하고 활용하는 전문가에게는 이상적인 해법일 수 있지만 일반적으로는 이해하기 더 어렵고 널리 쓰이지 않음
  • SRE에 중요함

실용적 측면을 인정하자

  • 유도리 필요
  • 일관성과 가독성을 희생해서라도 성능을 끌어올려야할 때가 있음
  • 표준 라이브러리 기능, 윈도우 플랫폼 기능, 빌드과정에서 자동 생성된 코드 등에는 예외 적용 가능

8.2.2 스타일 가이드

  • 위험을 피하기 위한 규칙
  • 모범 사례를 적용하기 위한 규칙
  • 일관성을 보장하기 위한 규칙

위험을 피하기 위한 규칙

  • 구글의 스타일 가이드에는 기술적인 이유 때문에 반드시 써야 하거나 쓰면 안되는 언어 특성들에 관한 규칙들이 담겨있음
  • 어떤 언어 특성은 사용하고 어떤 구조는 피해야 하는지

모범 사례 강제하기

  • 코드 작성자가 주석을 어디에 어떻게 작성해야 하는지 명시함
  • 작성자의 의도가 코드 자체에 명확하게 드러나지 않는 경우에는 의도를 주석으로 남겨야 함
    • switch문에서의 fall-through
    • 빈 catch 블록
    • 템플릿 메타프로그래밍
  • 읽기 용이하게 하기 위해 소스 파일의 구조도 규칙으로 정의함
  • 패키지, 클래스, 함수, 변수 드으이 이름을 짓는 규칙도 존재
  • 포맷팅 규칙도 중요 -> 도구 사용 가능!
  • 새로운 도입도 중요! (ex std::unique_ptr 도입)

일관성 구축하기

그 외…

  • 구글 스타일 가이드에는 없는 것도 많음

8.3 규칙 수정하기

  • 세월이 흘러가면 규칙은 변할 수 있음
  • 구글 스타일 가이드의 규칙에는 각각의 결정을 뒤받침하는 근거를 명시해둠
    • 이는 나중에 변경이 필요할 때 도움이 됨

8.3.1 프로세스

  • 스타일 가이드의 수정 대부분이 커뮤니티에서의 토론으로부터 출발
  • 던져진 아이디어에 대해 커뮤니티에서 논의되고 피드백을 받음
  • 커뮤니티의 검토를 거친 제안은 최종 승인 단계로 넘어감

8.3.2 스타일 중재자

  • 구글의 스타일 가이드들은 언어별로 소유자 (언어용 라이브러리팀의 선임자이거나 언어 경험이 풍부한 오랜 구글 직원)가 따로 있어서 최종 결정과 승인을 책임짐
  • 엔지니어링 측면의 트레이드오프를 논의하여 결정함
  • 개인의 선호가 아닌 트레이드오프로 결정

8.3.3 예외

  • 규칙을 따르기보다 예외를 인정하는 쪽이 이득이라고 판단될 때만 예외를 허용함

8.4 지침 (Guidance)

  • 주요 언어의 입문서 (Primer)
  • 구글의 “금주의 팁” 시리즈
  • <언어이름>@Google101 수업 시리즈
  • 유용한 참고 자료
    • 올바로 구현하기 어려운 주제에 관한 언어별 조언 (예: 동시성과 해싱)
    • 언어의 최신 버전에서 소개된 새로운 기능의 상세 설명과 구글 코드베이스에 적용하는 방법에 관한 조언
    • 구글 라이브러리가 제공하는 중요한 추상 개념과 데이터 구조 목록. 이미 만들어둔 구조를 새로 만드는 일을 방지해주고 “필요한 게 있는데 우리 라이브러리에서 이걸 뭐라고 부르는지 모르겠어”와 같은 질문에 답해줌

8.5 규칙 적용하기

  • 교육
  • 코드 리뷰
  • 가독성 프로세스
  • 자동화 도구 활용 (유용하나 만능은 아니다!)

8.5.1 오류 검사기

  • Linter?
  • C++ : clang-tidy
  • JAVA : Error Prone

8.5.2 코드 포맷터

  • Format on save
  • 행렬 포맷팅은 사람이 더 잘하긴 함…
  • 프리서브밋 검사로 포맷터를 반드시 사용하게 함
  • C++: clang-format, Python: YAPF, Go: gofmt, …

8.6 마치며

  • 코딩 스타일과 규칙은 성장하는 조직에 중요합니다!

8.7 핵심 정리

  • 규칙과 지침의 목표는 시간과 확장 관점에서의 탄력성을 높이는 것이어야 합니다.
  • 상황이 변하면 규칙도 달라져야 하니 규칙이 만들어진 근거 데이터를 알고 있어야 합니다.
  • 모든 것을 규칙으로 강제해서는 안 됩니다.
  • 일관성이 핵심입니다.
  • 간으한 한 규칙들이 자동으로 적용되도록 해야합니다.

Comment  Read more

구글 드라이브 설계

|

구글 드라이브 설계

구글 드라이브는…

  • 파일 저장 및 동기화 서비스
  • 문서, 사진, 비디오, 기타 파일을 클라우드에 보관 가능
  • 해당 파일은 컴퓨터, 스마트폰, 태블릿 등 어떤 단말에서도 이용 가능해야 함
  • 보관된 파일은 친구, 가족, 동료들과 손쉽게 공유할 수 있어야 함.

1. 문제 이해 및 설계 범위 설정

  • 여느 인터뷰와 같이 질문을 통해 설계 범위를 좁혀야 함 (구글 드라이브 전체를 면접 시간 내에 설계하는 것을 불가능!)
  • 가장 중요하게 지원해야 할 기능 : 파일 업로드/다운도르, 파일 동기화, 알림
  • 지원 기기 : 모바일, 웹 앱
  • 파일 암호화? : yes
  • 파일 크기 제한 : 10 GB
  • 사용자 수? : DAU 10 M

집중 설계 내역

  • 파일 추가 (Drag-and-drop)
  • 파일 다운로드
  • 여러 단말에 파일 동기화. 한 단말에서 파일을 추가하면 다른 다말에도 자동으로 동기화되어야 함
  • 파일 갱신 이력 조회 (revision history)
  • 파일 공유
  • 파일이 편집되거나 삭제되거나 새롭게 공유되었을 때 알림 표시

논의하지 않을 내용

  • 구글 문서 (Google Docs) 편집 및 협업(collaboration) 기능, 구글 문서는 여러 사용자가 같은 문서를 동시에 편집할 수 있도록 하는데, 이 부분은 설계 범위에서 제외

비기능적 요구사항

  • 안정성 : 저장소 시스템에서 안정성을 아주 중요, 데이터 손실은 발생하면 안됨
  • 빠른 동기화 속도 : 파일 동기화에 시간이 너무 많이 걸리면 사용자는 인내심을 일고 해당 제품을 더 이상 사용하지 않게 될 것
  • 네트워크 대역폭 : 이 제품이 네트워크 대역폭을 불필요하게 많이 소모한다면 사용자는 좋아하지 않을 것. 모바일 데이터 플랜을 사용하는 경우라면 더욱 그렇다.
  • 규모 확장성 : 이 시스템은 아주 많은 양의 트래픽도 처리 가능해야 함
  • 높은 가용성 : 일부 서버에 장애가 발생하거나, 느려지거나, 네트워크 일부가 끊겨도 시스템은 계속 사용 가능해야 함

개략적 추정치

  • 가입 사용자는 50 M, DAU 10 M
  • 모든 사용자에게 10 GB의 무료 저장공간 할당
  • 매일 각 사용자가 평균 2개의 파일을 업로드한다고 가정, 각 파일의 평균 크기는 500 KB
  • 읽기 : 쓰기 비율은 1:1
  • 필요한 저장공간 총량 = 50 M * 10 GB = 500 PB
  • 업로드 API QPS = DAU 10 M * 2 회 업로드 /24 hours/3600 s = 240건/s
  • 최대 QPS = QPS * 2 = 480 건/s

2. 개략적 설계안 제시 및 동의 구하기

  • 모든 것을 담은 한 대 서버에서 출발해 점지적으로 천만 사용자 지원이 가능한 시스템으로 발전시켜보자
  • 아래와 같은 구성의 서버 한대로 시작
    • 파일을 올리고 다운로드 하는 과정을 처리할 웹 서버
    • 사용자 데이터, 로그인 정보, 파일 정보 등의 메타데이터를 보관할 데이터베이스
    • 파일을 저장할 저장소 시스템. 파일 저장을 위해 1 TB의 공간을 사용
  • 아파치 웹 서버 설치, MySQL설치, 업로드 되는 파일을 저장할 drive/ 디렉터리 안에는 namespace라고 불리는 하위 디렉토리를 둠

API

  • 3 가지 API가 필요 : 파일 업로드 API, 다운로드 API, 파일 갱신 히스토리 제공 API

1. 파일 업로드 API

  • 단순 업로드 : 파일 크기가 작을 때 사용
  • 이어 올리기(resumable upload) : 파일 사이즈가 크고 네트워크 문제로 업로드가 중단될 가능성이 높다고 생각되면 사용
이어올리기 API의 예
  • ex : https://api.example.com/files/upload?uploadType=resumable
인자
  • uploadType=resumable
  • data : 업로드할 로컬 파일
절차
  • 이어 올리기 URL을 받기 위한 최초 요청 전송
  • 데이터를 업로드하고 업로드 상태 모니터링
  • 업로드에 장애가 발생하면 장애 발생시점부터 업로드를 재시작

2. 파일 다운로드 API

  • ex : https://api.example.com/files/download
인자
  • path : 다운로드할 파일의 경로
{
    "path": "/recipes/soup/best_soup.txt"
}

3. 파일 갱신 히스토리 API

  • ex : https://api.example.com/files/list_revisions
인자
  • path : 갱신 히스토리를 가져올 파일의 경로
  • limit : 히스토리 길이의 최대치
{
    "path": "/recipes/soup/best_soup.txt",
    "limit" 20
}

사용자 인증 및 보안

  • 지금까지 나열한 모든 API는 사용자 인증을 필요
  • HTTPS 프토로콜 사용
  • SSL (Secure Socket Layer)를 지원하는 프로토콜을 이용하는 이유는 클라이언트와 백엔드 서버가 주고받은 데이터를 보호하기 위한 것

한 대 서버의 제약 극복

  • 업로드 되는 파일이 많아지다보면 파일 시스템은 가득 차게 되므로, 분산 시스템 필요
  • 가장 간단하게 생각 해 볼 수 있는 것은 user_id 기준으로 데이터 샤딩(sharding)
  • 넷플릭스나 에어비엔비같은 기업은 저장소로 아마존 S3를 사용한다고 함
  • Amazon S3 : 업계 최고 수준의 규모 확장성, 가용성, 보안, 성능을 제공하는 객체 저장소 서비스
  • S3는 다중화 지원 : 같은 지역 안, 여러 지역에 걸쳐 다중화 가능 (그림 15-6 참고)
나머지 연구할 부분
  • 그림 15-7 참고
  • 로드밸런서 : 네트워크 트래픽을 분산하기 위해 로드밸러서 사용. 트래픽 고르게 분산 가능, 특정 웹서버에 장애발생시 우회 가능
  • 웹 서버 : 로드밸런서를 추가하고 나면 더 많은 웹서버를 손쉽게 추가할 수 있음
  • 메타데이터 데이터베이스 : 데이터베이스를 파일 저장 서버에서 분리하여 SPOF를 회피, 다중화 및 샤딩 정책을 적용하여 가용성과 규모 확장성 요구사항에 대응
  • 파일 저장소 : S3를 파일 저장소로 사용하고 가용성과 데이터 무손실을 보장하기 위해 두 개 이상의 지역에 데이터를 다중화

동기화 충돌

  • 구글 드라이브 같은 대형 저장소 시스템의 경우 때때로 동기화 충돌이 발생 가능
  • 두 명 이상의 사용자가 같은 파일이나 폴더를 동시에 업데이트하려고 하는 경우
  • 해결 방안은 그림 15-8 참고, 먼저 처리 되는 변경을 성공한 것으로 보고, 나중에 처리되는 병경은 충돌이 방생한 것으로 표시하는 것
  • 동기화 충돌 오류 시 이 오류는 어떻게 해결해야 하나?
    • 오류가 발생한 시점에 이 시스템에는 같은 파일의 두 가지 버전이 존재
    • 사용자 2가 가지고 있는 로컬 사본(local copy)과 서버에 있는 최신 버전이 그것 (그림 15-9)
    • 이 상태에서 사용자는 두 파일을 하나로 합칠지 아니면 둘 중 하나를 다른 파일로 대체할지를 결정해야 함
  • 동기화 문제를 해결하는 것은 흥미로운 과제임, 관심있는 사람은 다름 두 글을 참고 바람

계략적 설계안

  • 그림 15-10 참고
  • 사용자 단말 : 사용자가 이용하는 웹브라우저나 모바일 앱 등의 클라이언트
  • 블록 저장소 서버 (block server) : 파일 블록을 클라우드 저장소에 업로드하는 서버. 블록 저장소는 블록 수준 저장소(block-level storage)라고도 하며, 클라우드 환경에서 데이터 파일을 저장하는 기술. 이 저장소는 파일을 여러개의 블록으로 나눠 저장하며, 각 블록에는 고유한 해시값이 할당. 이 해시값은 메타데이터 DB에 저장. 각 블록은 독립적인 객체로 취급되며 클라우드 저장소 시스템 (예:Amamzon S3)에 보관. 파일을 재구성하려면 블록들을 원래 순서대로 합쳐야 함. 예시한 설계안의 경우 한 블록은 드롭박스의 사례를 참고하여 최대 4 MB로 정함.
  • 클라우드 저장소 : 파일은 블록 단위로 나누어져 클라우드 저장소에 보관됨
  • 아카이빙 저장소(cold storage) : 오랫동안 사용되지 않은 비활성(inactive)데이터를 저장하기 위한 컴퓨터 시스템
  • 로드밸런서 : 요청을 모든 API 서버에 고르게 분산하는 역할
  • API 서버 : 파일 업로드 외에 거의 모든 것을 담당하는 서버. 사용자 인증, 사용자 프로파일 관리, 파일 메타데이터 갱신 등에 사용
  • 메타데이터 DB : 사용자, 파일, 블록, 버전 등의 메타데이터 정보를 관리. 실제 파일은 클라우드에 보관하며, 이 데이터베이스에는 오직 메타데이터만 둔다.
  • 메타데이터 캐시 : 성능을 높이기 위해 자주 쓰이는 메타데이터는 캐시함
  • 알림 서비스 : 특정 이벤트가 발생했음을 클라이언트에게 알리는데 쓰이는 pub/sub 프로토콜 기반 시스템. 예시 설계안의 경우에는 클라이언트에게 파일이 추가되었거나, 편집되었거나, 삭제되었음을 알려, 파일의 최신 상태를 확인하도록 하는 데 쓰임
  • 오프라인 사용자 배업 큐 (offline backup queue) : 클라이언트가 접속 중이 아니라서 파일의 최신 상태를 확인할 수 없을 때는 해당 정보를 이 큐에 두어 나중에 클라이언트가 접속했을 때 동기화될 수 있도록 함

3. 상세 설계

블록 저장소 서버

  • 정기적으로 갱신되는 큰 파일들은 업데이트가 일어날 때마다 전체 파일을 서버로 보내면 네트워크 대역폭을 많이 잡아적게 됨, 이에 대한 최적화 방법은
    • 델타 동기화(delta sync) : 파일이 수정되면 전체 파일 대신 수정이 일어난 블록만 동기화 (rsync 참고)
    • 압축(compression) : 블록 단위로 압축해 두면 데이터 크기를 많이 줄일 수 있다. 이 때 압축 알고리즘은 파일 유형에 따라 정함. 예를 들어 텍스트 파일을 압축할 때는 gzip이나 bzip2를 쓰고, 이미지나 비디오를 압축할 때는 다른 압축 알고리즘을 씀

하는 일

  • 클라이언트가 보낸 파일을 블록 단위로 나눠야 함
  • 각 블록에 압축 알고리즘 적용
  • 암호화
  • 전체 파일을 저장소 시스템으로 보내는 대신 수정된 블록만 전송
  • 그림 15-11 참고
    • 주어진 파일을 작은 블록들로 분할
    • 각 블록을 압축
    • 클라우드 저장소로 보내기 전에 암호화
    • 클라우드 저장소로 보냄

델타 동기화 전략

  • 그림 15-12 참고
    • 검정색으로 표시된 블록 2와 5는 수정된 블록
    • 갱신된 부분만 동기화해야 하므로 이 두 블록만 저장소에 업로드
  • 델타 동기화 전략, 압축 알고리즘을 도입하면 네트워크 대역폭 사용량 절감 가능

높은 일관성 요구사항

  • 이 시스템은 강한 일관성 (strong consistency) 모델을 기본으로 지원해야 함.
  • 같은 파일이 단말이나 사용자에 따라 다르게 보이는 것은 허용할 수 없다
  • 메타데이터 캐시와 데이터베이스 계층에도 같은 원칙이 적용되어야 함
  • 메모리 캐시는 보통 최종 일관성 (eventual consistency)모델을 지원함. 따라서 강한 일관성을 달성하려면 다음 사항을 보장해야 함
    • 캐시에 보관된 사본과 데이터베이스에 있는 원본(master)이 일치
    • 데이터베이스에 보관된 원본에 변경이 발생하면 캐시에 있는 사본을 무효화
  • 관계형 데이터베이스는 ACID (Atomicity, Consistency, Isolation, Durability)를 보장하므로 강한 일관성을 보장하기 쉬움
  • 하지만 NoSQL 데이터베이스는 이를 기본으로 지원하지 않으므로, 동기화 로직 안에 프로그램해 넣어야 함.
  • 본 설계안에서는 ACID를 기본 지원하는 RDBMS를 채택

메타데이터 데이터베이스

  • 그림 15-13 참고 (Metadata DB ERD)
  • user : user 테이블에는 이름, 이메일, 프로파일 사진 등 사용자에 관계된 기본적인 정보들이 보관
  • device : device 테이블에는 단말 정보가 보관. push_id는 모바일 푸시 알림을 보내고 받기 위한 것. 한 사용자가 여러 대의 단말을 가질 수 있음에 유의 (ERD 상에서 user_id와 일대다 관계)
  • namespace : namespace 테이블에는 사용자의 루트 디렉터리 정보가 보관
  • file : file 테이블에는 파일의 최신 정보가 보관
  • file_version : 파일의 갱신 이력이 보관되는 테이블. 이 테이블에 보관되는 레코드는 전부 읽기 전용. 이는 갱신 이력이 훼손되는 것을 막기 위한 조치
  • block : 파일 블록에 대한 정보를 보관하는 테이블. 특정 버전의 파일은 파일 블록을 올바른 순서로 조합하기만 하면 복원 가능

업로드 절차

  • 그림 15-14 참고
  • 그림 15-14는 두 개 요청이 병렬적으로 전송된 상황을 보여줌
    • 첫 번째 요청 : 파일 메타데이터 추가
    • 두 번째 요청 : 파일을 클라우드 저장소로 업로드 하기 위한 것
    • 두 요청은 전부 클라이언트 1이 보낸 것
파일 메타데이터 추가
  1. 클라이언트 1이 새 파일의 메타데이터를 추가하기 위한 요청 전송
  2. 새 파일의 메타데이터를 데이터베이스에 저장하고 업로드 상태를 대기 중(pending)으로 변경
  3. 새 파일이 추가되었음을 알림 서비스에 통지
  4. 알림 서비스는 관련된 클라이언트(클라이언트 2)에게 파일이 업로드되고 있음을 알림
파일을 클라우드 저장소에 업로드
  1. 클라이언트 1이 파일을 블록 저장소 서버에 업로드
  2. 블록 저장소 서버는 파일을 블록 단위로 쪼갠 다음 압축하고 암호화 한 다음에 클라우드 저장소에 전송
  3. 업로드가 끝나면 클라우드 스토리지는 완료 콜백(callback)을 호출. 이 콜백 호출을 API 서버로 전송
  4. 메타데이터 DB에 기록된 해당 파일의 상태를 완료(uploaded)로 변경
  5. 알림 서비스에 파일 업로드가 끝났음을 통지
  6. 알림 서비스는 관련된 클라이언트(클라이언트 2)에게 파일 업로드가 끝났음을 알림

다운로드 절차

  • 파일 다운로드는 파일이 새로 추가되거나 편집되면 자동으로 시작됨
  • 클라이언트는 다른 클라이언트가 파일을 편집하거나 추가했다는 사실을 어떻게 감지할까? 두 가지 방법을 사용
    • 클라이언트 A가 접속 중이고 다른 클라이언트가 파일을 변경하면 알림 서비스가 클라리언트 A에게 변경이 발생했으니 새 버전을 끌어가야 한다고 알림
    • 클라리언트 A가 네트워크에 연결된 상태가 아닐 경우에는 데이터는 캐시에 보관. 해당 클라이언트의 상태가 접속 중으로 바뀌면 그때 해당 클라리언트는 새 버전을 가져감
  • 어떤 파일이 변경 되었음을 감지한 클라이언트는 우선 API 서버를 통해 메타데이터를 새로 가져가야하고, 그 다음에 블록들을 다운받아 파일을 재구성해야함
  • 그림 15-15 참고
    1. 알림 서비스가 클라이언트 2에게 누군가 파일을 변경했음을 알림
    2. 알림을 확인한 클라이언트 2는 새로운 메타데이터를 요청
    3. API 서버는 메타데이터 데이터베이스에게 새 메타데이터 요청
    4. API 서버에게 새 메타데이터가 반환됨
    5. 클라리언트 2에게 새 메타데이터가 반환됨
    6. 클라이언트 2는 새 메타데이터를 받는 즉시 블록 다운로드 요청 전송
    7. 블록 저장소 서버는 클라우드 저장소에서 블록 다운로드
    8. 클라우드 저장소는 블록 서버에 요청된 블록 반환
    9. 블록 저장소 서버는 클라리언트에게 요청된 블록 반환. 클라리언트 2는 전송된 블록을 사용하여 파일 재구성

알림 서비스

  • 파일의 일관성을 유지ㅏ하기 위해, 클라이언트는 로컬에서 파일이 수정되었음을 감지하는 순간 다른 클라이언트에 그 사실을 알려서 충돌 가능성을 줄여야 함
  • 알림 서비스는 그 목적으로 이용된다. 단순하게 보자면 알림 서비스는 이벤트 데이터를 클라이언트들로 보내는 서비스이며 두 가지 선택지가 있음
    • 롱 폴링(long polling) : 드롭박스가 이 방식을 채택
    • 웹소켓(WebSocket) : 클라이언트와 서버 사이에 지속적인 통신 채널을 제공. 따라서 양방향 통신이 가능
  • 둘 다 좋은 방안이나 본 설계안의 경우에는 롱 폴링 사용. 이유는 다음과 같다
    • 채팅 서비스와는 달리, 본 시스템의 경우에는 알림 서비스와 양방향 통신이 필요하지않음. 서버는 파일이 변경된 사실을 클라이언트에게 알려주어야하지만 반대 방향의 통신은 요구되지 않음
    • 웹소켓은 실시간 양방향 통신이 요구되는 채팅 같은 응용에 적합. 구글 드라이브의 경우 알림을 보낼 일은 그렇게 자주 발생하지 않으며, 알림을 보내야 하는 경우에도 단시간에 많은 양의 데이터를 보낼 일은 없다.
롱폴링 사용 시 작동 시나리오
  • 각 클라이언트는 알림 서버와 롱 폴링용 연결을 유지하다가 특정 파일에 대한 변경을 감지하면 해당 연결을 끊음
  • 이 때 클라이언트는 반드시 메타데이터 서버와 연결해 파일의 최신 내역을 다운로드 해야함
  • 해당 다운로드 작업이 끝났거나 연결 타임아웃 시간에 도달한 경우에는 즉시 새 요청을 보내어 롱 폴링 연결을 복원하고 유지해야 함

저장소 공간 절약

  • 파일 갱신 이력을 보존하고 안정성을 보장하기 위해서는 파일의 여러 버전을 여러 데이터센터에 보관할 필요가 있음
  • 그런 상황에서 모든 버전을 자주 백업하게 되면 저장용량이 너무 빨리 소진될 가능성이 있음
  • 이런 문제를 피하고 비용을 절감하기 위해서 아래 3가지 방법을 사용
    • 중복 제거(de-dupe) : 중복된 파일 블록을 계정 차원에서 제거하는 방법. 두 블록이 같은 블록인지는 해시 값을 비교하여 판단
    • 지능적 백업 전략 도입
      • 한도 설정 : 보관해야 하는 파일 버전 개수에 상한을 두는 것. 상한에 도달하면 제일 오래된 버전은 버림
      • 중요한 버전만 보관 : 어떤 파일은 아주 자주 바뀐다. 예를 들어 편집 중인 문서가 업데이트될 때마다 새로운 버전으로 관리한다면 짧은 시간 동안 1000개가 넘은 버전이 만들어질 수도 있다. 불필요한 버전과 사본이 만들어지는 것을 피하려면 그 가운데 중요한 것만 골라내야 한다.
    • 자주 쓰이지 않는 데이터는 아카이빙 저장소(cold storage)로 옮긴다. 몇달 혹은 수년간 이용되지 않은 데이터가 이에 해당한다. 아마존 S3 글래시어(glacier)같은 아카이빙 저장소 이용료는 S3보다 훨씬 저렴하다.
      • Amazon S3 Glacier : 가격은 S3의 1/3 수준, 안정성도 S3와 동일, 하지만 용량의 최대 5%에 대해서만 검색가능 (초과시 과금), 저장도 3개월 이상만 가능, 그 전에 삭제시 패널티 금액 지불, 아카이브 데이터를 다운로드에 3~5시간 소요

장애 처리

  • 로드밸런서 장애 : 로드밸런서에 장애가 발생할 경우 부(secondary) 로드밸런서가 활성화되어 트래픽을 이어받아야 함. 로드 밸런서끼리는 보통 박동(heartbeat) 신호를 주기적으로 보내서 상태를 모니터링 함. 일정 시간 동안 박동 신호에 응답하지 않은 로드밸런서는 장애가 발생한 것으로 간주
  • 블록 저장소 서버 장애 : 블록 저장소 서버에 장애가 발생하였다면 다른 서버가 미완료 상태 또는 대기 상태인 작업을 이어받아야 한다.
  • 클라우드 저장소 장애 : S3 버킷은 여러 지역에 다중화할 수 있으므로, 한 지역에서 장애가 발생하였다면 다른 지역에서 파일을 가져오면 됨
  • API 서버 장애 : API 서버들은 Stateless이다. 따라서 로드밸런서는 API 서버에 장애가 발생하면 트래픽을 해당 서버로 보내지 않음으로써 장애 서버를 격리한다.
  • 메타데이터 캐시 장애 : 메타데이터 캐시 서버도 다중화함. 따라서 한 노드에 장애가 생겨도 다른 노드에서 데이터를 가져올 수 있음. 자애가 발생한 서버는 새 서버로 교체
  • 메타데이터 데이터베이스 장애
    • 주 데이터베이스 서버 장애 : 부 데이터베이스 서버 가운데 하나를 주 데이터베이스 서버로 바꾸고, 부 데이터베이스 서버를 새로 하나 추가함
    • 부 데이터베이스 서버 장애 : 다른 부 데이터베이스 서버가 읽기 연산을 처리하도록 하고 그동안 장애 서버는 새 것으로 교체
  • 알림 서비스 장애 : 접속 중인 모든 사용자는 알림 서버와 롱 폴링 연결을 하나씩 유지. 따라서 알림 서비스는 많은 사용자와의 연결을 유지하고 관리해야 함 (드롭박스의 경우 서버하나당 1M 개의 연결 관리). 따라서 서버 한대에 장애가 생기면 백만 개 이상의 롱 폴링 접속을 다시 시작해야함. 하지만 롱 폴링 접속 백만 개를 동시에 시작할 수는 없으므로, 복구가 상대적으로 느릴 수 있음
  • 오프라인 사용자 백업 큐 장애 : 이 큐 또한 다중화해 두어야 함. 큐에 장애가 발생하면 구독 중인 클라이언트들은 백업 큐로 구독 관계를 재설정해야 함

4. 마무리

  • 높은 수준의 일관성, 낮은 네트워크 지연, 빠른 동기화가 요구되는 설계과정을 거침
  • 이번 장에서 만든 설계안은 크게 두 가지 부분으로 구성
    • 파일의 메타데이터를 관리하는 부분
    • 파일 동기화를 처리하는 부분
    • 또한 알림 서비스도 위 두 부분과 병존하는 또 하나의 중요 컴포넌트 (롱 폴링 사용)
몇 가지 더 생각해볼 수 있는 부분
  • 만약 블록 저장소 서버를 거치지 않고 파일을 클라우드 저장소에 직접 업로드 한다면?
    • 장점
      • 파일은 클라우드 저장소로 바로 하면되므로 업로드 시간이 빨라질 수 있음
    • 단점
      • 분할, 압축, 암호화 로직을 클라이언트에 두어야 하므로 플랫폼별로 따로 수현해야 함 (IOS, Android, Web 등). 당초 설계안에서는 블록 저장소 서버에서 처리하므로 구현을 한번만 하면 됨
      • 클라이언트가 해킹 당할 가능성이 있으므로 암호화 로직을 클라이언트 안에 두는 것은 적절치 않음
  • 접속 상태를 관리하는 로직을 별도 서비스로 옮긴다면?
    • 다른 서비스에서도 쉽게 활용할 수 있게 되므로 좋을 것임

참고자료

  • 알렉스 쉬, 가상 면접 사례로 배우는 대규모 시스템 설계 기초 15장

Comment  Read more