Home DDIA - 신뢰할 수 있고 확장 가능하며 유지보수하기 쉬운 애플리케이션
Post
Cancel

DDIA - 신뢰할 수 있고 확장 가능하며 유지보수하기 쉬운 애플리케이션

Table of Contents

  1. 데이터 시스템에 대한 생각
  2. 대부분의 소프트웨어 시스템에서 중요하게 여기는 세 가지 관심사
    1. 신뢰성
      1. 하드웨어 결함
      2. 소프트웨어 오류
      3. 인적 오류
    2. 확장성
      1. 부하 기술하기
      2. 성능 기술하기
      3. 부하 대응 접근 방식
    3. 유지보수성
      1. 운용성: 운영의 편리함 만들기
      2. 단순성: 복잡도 관리
      3. 발전성: 변화를 쉽게 만들기
  3. 정리

오늘날 많은 애플리케이션은 데이터 중심적이다.
이런 경우에 애플리케이션을 제한하는 요소가 데이터의 양, 데이터의 복잡도, 데이터의 변화속도이다.

데이터 중심 애플리케이션은 공통으로 필요로 하는 기능을 제공하는 표준 구성 요소로 만든다.
이때 많은 애플리케이션은 다음 요소를 필요로 한다.

  • 나중에 다시 데이터를 찾을 수 있게 데이터를 저장(데이터베이스)
  • 읽기 속도 향상을 위해 값비싼 수행 결과를 기억(캐시)
  • 키워드로 데이터를 검색하거나 다양한 방법으로 필터링할 수 있게 제공(검색 색인)
  • 비동기 처리를 위해 다른 프로세스로 메시지 보내기(스트림 처리)
  • 주기적으로 대량의 누적된 데이터를 분석(배치 처리)

데이터 시스템이 성공적으로 추상화됐기에 우리는 많은 생각 없이 이런 요소들을 사용할 수 있다.

하지만 현실은 애플리케이션마다 요구사항이 다르고 데이터베이스 시스템 또한 다양한 특성을 가지고 있다.
따라서 애플리케이션을 만들 때 어떤 도구와 어떤 접근 방식이 목적에 가장 적합한지 생각할 수 있어야 한다.

데이터 시스템에 대한 생각

일반적으로 데이터베이스, 큐, 캐시 등을 매우 다른 범주에 속하는 도구로 생각한다.

하지만 데이터 시스템이라는 포괄적 용어로 묶은 이유

  • 분류 간 경계가 흐려지고 있다.
    더 이상 전통적인 분류에 딱 들어맞지 않는다.
    메시지 큐로 사용하는 데이터스토어인 레디스가 있고, 데이터베이스처럼 지속성을 보장하는 메시지 큐인 아파치 카프카도 있다.
  • 많은 애플리케이션이 단일 도구로는 더 이상 데이터 처리와 저장 모두를 만족시킬 수 없는 과도하고 광범위한 요구사항을 갖고 있다.
    대신 작업은 단일 도구에서 효율적으로 수행할 수 있는 단위로 나누고 다양한 도구들은 애플리케이션 코드를 이용해 서로 연결한다.

대부분의 소프트웨어 시스템에서 중요하게 여기는 세 가지 관심사

신뢰성

일반적인 기대치는 다음과 같다.

  • 애플리케이션은 사용자가 기대한 기능을 수행
  • 시스템은 사용자가 범한 실수나 예상치 못한 소프트웨어 사용법을 허용
  • 시스템 성능은 예상된 부하와 데이터 양에서 필수적인 사용 사례를 충분히 만족
  • 시스템은 허가되지 않은 접근과 오남용을 방지

이 모든 것이 “올바르게 동작함”을 의미하는 경우,
대략 “무언가 잘못되더라도 지속적으로 올바르게 동작함”을 신뢰성의 의미로 이해할 수 있다.

잘못될 수 있는 일을 결함(fault) 이라고 부른다.
그리고 결함을 예측하고 대처할 수 있는 시스템을 내결함성(fault-tolerant) 또는 탄력성(resilient) 를 지녔다고 말한다.
내결함성이라는 용어는 약간 오해의 소지가 있다.
모든 종류의 결함을 견딜 수 있는 시스템을 만들 수 있음을 시사하지만 실제로는 실현 가능하지 않다.
특정 유형의 결함 내성에 대해서만 이야기하는 것이 타당하다.

결함(fault)장애(failure) 와 다르다.

  • 결함 : 사양에서 벗어난 시스템의 한 구성 요소로 정의
  • 장애 : 사용자에게 필요한 서비스를 제공하지 못하고 시스템 전체가 멈춘 경우

결함 확률을 0으로 줄이는 것은 불가능하다.
따라서 대개 결함으로 인해 장애가 발생하지 않게끔 내결함성 구조를 설계하는 것이 가장 좋다.
이 책에서는 신뢰할 수 없는 여러 부품으로 신뢰할 수 있는 시스템을 구축하는 다양한 기법을 다룬다.

하드웨어 결함

  • 소프트웨어 내결함성 기술(예 AWS)을 사용
  • 하드웨어 중복성을 추가해 전체 장비의 손실을 견딜 수 있는 시스템으로 점점 옮겨가고 있다.

소프트웨어 오류

이 결함은 예상하기 더 어렵고 노드 간 상관관계 때문에 상관관계 없는 하드웨어 결함보다 오히려 시스템 오류를 더욱 많이 유발하는 경향이 있다.
소프트웨어의 체계적 오류 문제는 신속한 해결책이 없다.

  • 시스템의 가정과 상호작용에 대해 주의 깊게 생각하기
  • 빈틈없는 테스트
  • 프로세스 격리
  • 죽은 프로세스의 재시작 허용
  • 프로덕션 환경에서 시스템 동작의 측정
  • 모니터링
  • 분석하기

인적 오류

  • 오류의 가능성을 최소화하는 방향으로 시스템을 설계
  • 사람이 가장 많이 실수하는 장소(부분)에서 사람의 실수로 장애가 발생할 수 있는 부분을 분리
  • 단위 테스트부터 전체 시스템 통합 테스트와 수동 테스트까지 철저하게 테스트
  • 인적 오류를 빠르고 쉽게 복구할 수 있게 하기
  • 성능 지표와 오류율 같은 상세하고 명확한 모니터링 대책 마련
  • 교육과 실습

확장성

증가한 부하에 대처하는 시스템 능력을 설명하는 데 사용하는 용어이다.
시스템에 부여하는 일차원적인 표식이 아님을 주의하자.

“시스템이 특정 방식으로 커지면 이에 대처하기 위한 선택은 무엇인가?”
“추가 부하를 다루기 위해 계산 자원을 어떻게 투입할까?”
같은 질문을 고려한다는 의미다.

부하 기술하기

시스템의 부하를 간결하게 기술해야 부하 성장 질문을 논의할 수 있다.
부하는 부하 매개변수(load parameter)로 몇 개의 숫자로 나타낼 수 있다.
가장 적합한 부하 매개변수 선택은 시스템 설계에 따라 달라진다.

성능 기술하기

다음 두 가지 방법으로 부하가 증가할 때 어떤 일이 일어나는지 조사할 수 있다.

  • 부하 매개변수를 증가시키고 시스템 자원은 변경하지 않고 유지하면 시스템 성능은 어떻게 영향을 받을까?
  • 부하 매개변수를 증가시켰을 때 성능이 변하지 않고 유지되길 원한다면 자원을 얼마나 많이 늘려야 할까?

일괄 처리 시스템은 처리량, 온라인 시스템에서는 응답 시간이 보통 중요한 사항이다.
온라인 시스템에 대해서 살펴보자면,
응답 시간은 단일 숫자가 아니라 측정 가능한 값의 분포 로 생각해야 한다.
일반적으로 응답 시간을 평가할 때, 평균 응답 시간을 살핀다. –> 얼마나 많은 사용자가 지연을 경험했는지 알려주지 않음

보통 평균보다는 백분위 를 사용하는 편이 더 좋다.
P50(50 백분위수)가 중앙값 인데, 사용자가 보통 얼마나 오랫동안 기다려야 하는지 알고 싶다면 좋은 지표가 된다.

특이 값이 얼마나 좋지 않은지 보기 위해서는 상위 백분위(P95, P99, P999가 일반적)를 살펴보는 것도 좋다.

꼬리 지연 시간(tail latency) 로 알려진 상위 백분위 응답 시간은 서비스의 사용자 경험에 직접 영향을 주기에 중요하다.
예를들어서 아마존은 내부 서비스의 응답 시간 요구사항을 P999로 기술함.
추가적으로 P9999와 같이 상위로 갈수록 최적화에 비용이 많이들고 이익은 적다고 여겨진다.

서버는 병렬로 소수의 작업만 처리할 수 있기에 소수의 느린 처리만으로도 후속 요청 처리가 지체되는데 이를 선두 차단(head-of-line blocking) 이라 한다.
서버에서 후속 요청이 빠르게 처리되더라도 이전 요청이 완료되길 기다리는 시간 때문에 클라이언트는 전체적으로 응답 시간이 느리다고 생각할 것이다.
이런 문제 때문에 클라이언트 쪽 응답 시간 측정이 중요하다.

부하 대응 접근 방식

  • 용량 확장(scaling up) / 수직 확장(vertical scaling)
  • 규묘 확장(scaling out) / 수평 확장(hoizontal scaling)

다수 장비에 상태 비저장 서비스를 배포하는 일은 상당히 간단하다.
하지만 상태 유지 데이터 시스템을 분산 설치하는 일은 아주 많은 복잡도가 추가적으로 발생한다.
이러한 이유로 확장 비용이나 데이터베이스를 분산으로 만들어야 하는 고가용성 요구가 있을 때까지 단일 노드에 데이터베이스를 유지하는 것(용량 확장)이 최근까지의 통념

유지보수성

유지보수성을 위해 주의 기울여야 할 소프트웨어 시스템 설계 원칙

운용성: 운영의 편리함 만들기

  • 런타임 동작과 시스템의 내부에 대한 모니터링 제공
  • 자동화와 통합 지원
  • 개별 장비 의존성 회피
  • 좋은 문서와 이해하기 쉬운 운영 모델
  • 만족할 만한 기본 동작을 제공, 필요에 따라 관리자가 기본값을 정의 가능
  • 적절하게 자기 회복, 필요에 따라 관리자가 시스템 상태를 수동으로 제어 가능
  • 예측 가능하게 동작하고 예기치 않은 상황을 최소화

단순성: 복잡도 관리

단순성이 구축하려는 시스템의 핵심 목표여야 한다.

시스템을 단순하게 만드는 일이 반드시 기능을 줄인다는 의미는 아니다.
우발적 복잡도(accidental complexity)를 줄인다는 뜻일 수도 있다.

우발적 복잡도를 제거하기 위한 최상의 도구는 추상화 다.

발전성: 변화를 쉽게 만들기

  • 애자일(조직 프로세스 측면), TDD, 리팩토링

정리

  • 신뢰성 : 결함이 발생해도 시스템이 올바르게 동작하게 만든다는 의미
  • 확장성 : 부하가 증가해도 좋은 성능을 유지하기 위한 전략을 의미
  • 유지보수성
    본질은 시스템에서 작업하는 엔지니어와 운영 팀의 삶을 개선
    좋은 추상화는 복잡도를 줄이고 쉽게 시스템을 변경할 수 있게 하며 새로운 사용 사례에 적용하는 데 도움
    좋은 운용성이란 시스템의 건강 상태를 잘 관찰할 수 있고 시스템을 효율적으로 관리하는 방법을 보유한다는 의미
This post is licensed under CC BY 4.0 by the author.

Emacs에서 PlantUml을 사용하자

Redis - transaction