데이터 중심 애플리케이션 설계 - 1장

bloom·2022년 12월 27일
1

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

서론

오늘날의 많은 애플리케이션들은 계산 중심적이기보다는 데이터 중심적인 특성을 가진다. 따라서 CPU의 성능보다는 데이터의 양, 데이터의 복잡도, 데이터의 변화속도에 더 큰 영향을 받는다.
일반적으로 데이터 중심 애플리케이션은 공통으로 필요로 하는 기능을 제공하는 표준 구성 요소를 만들며 다음과 같은 것들을 필요로 한다.

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

애플리케이션은 각 각 다른 요구사항을 가지고 있기 때문에 필요로 하는 시스템 또한 다양하다. 이러한 환경에서 신뢰할 수 있고 확장 가능하며 유지보수하기 쉬운 데이터 시스템을 구축하는 방법에 대해 알아보자.

데이터 시스템에 대한 생각

일반적으로 데이터베이스, 큐, 캐시 등은 서로 매우 다른 접근 패턴을 가지고 있어 서로 다른 성능 특성이 있기 때문에 구현 방식이 매우 다르다. 이러한 특징 때문에 일반적으로 각 각의 도구는 매우 다른 범주에 속한 도구로 생각한다.
서비스 제공을 위해 각 도구를 결합할 때에는 서비스 인터페이스나 애플리케이션 프로그래밍 인터페이스(API)는 보통 클라이언트가 모르게 구현 세부 사항을 숨긴다. 작은 단위의 범용 구성요소들로 새롭고 특수한 목적의 데이터 시스템을 만들게 되고 이러한 과정을 통해 개발자는 애플리케이션 개발자일 뿐만 아니라 데이터 시스템의 설계자이기도 하다.
데이터 시스템이나 서비스를 설계할 때에는 많은 문제들이 발생할 수 있다. 개발자의 기술 숙련도, 기존 시스템의 의존성, 전달 시간 척도, 다양한 종류의 위험에 대한 조직의 내성, 규제 제약 등이 시스템 설계에 양향을 줄 수 있는 요소들이고, 이러한 요소들은 상황에 따라 좌우된다.
이 책에서는 대부분의 소프트웨어 시스템에서 중요하게 여기는 세 가지 관심사에 중점을 둔다.

  • 신뢰성 (Reliability)
    • 하드웨어나 소프트웨어 결함, 심지어 인적 오류와 같은 역경에 직면하더라도 시스템은 지속적으로 올바르게 동작해야 한다.
  • 확장성 (Scalability)
    • 시스템의 데이터 양, 트래픽 양, 복잡도가 증가하면서 이를 처리할 수 있는 적절한 방법이 있어야 한다.
  • 유지보수성 (Maintainability)
    • 시간이 지남에 따라 여러 다양한 사람들이 시스템 상에서 작업할 것이기 때문에 모든 사용자가 시스템 상에서 생산적으로 작업할 수 있게 해야한다.

신뢰성

소트트웨어의 일반적인 기대치는 다음과 같다.

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

잘못될 수 있는 일을 결함이라고 부른다. 그리고 결함을 예측하고 대처할 수 있는 시스템을 내결함성 또는 탄력성을 지녔다고 말한다.
이러한 결함을 고의적으로 유도함으로써 내결함성 시스템을 지속적으로 훈련하고 테스트해야 결함이 자연적으로 생겼을 때, 올바르게 처리할 수 있다는 자신감을 얻게 된다.
보통은 결함 예방을 넘어 내결함성을 가지기를 선호하지만 특정 경우에는 예방책이 해결책보다 더 좋은 경우가 있다. (ex. 보안)

하드웨어 결함

하드디스크가 고장 나고, 램에 결함이 생기고, 대규모 정전 사태가 발생하고, 누군가가 네트워크 케이블을 잘못 뽑는 것과 같은 결함을 의미한다. 하드디스크의 평균 장애 시간은 약 10~50년 정도로 보고되어 있다. 따라서 10,000개의 디스크로 구성된 저장 클러스터는 평균적으로 하루에 한 개의 디스크가 죽는다고 예상해야 한다.
시스템 장애율을 줄이기 위한 첫 번째 대응은 각 하드웨어 구성 요소에 중복을 추가하는 것이다. 디스크는 RAID 구성으로 설치하고, 서버는 이정 전원 디바이스와 핫 스왑 가능한 CPU를 데이터 센터는 건전지와 예비 전원용 디젤 발전기를 갖출 수 있다. 이러한 접근 방식은 하드웨어 문제로 장애가 발생하는 것을 완전히 막을 수는 없지만 보통 수년 간 장비가 중단되지 않고 계속해서 동작할 수 있도록 한다.

소프트웨어 오류

시스템 내 체계적 오류는 에상하기가 어렵고 노드 간 상관관계 때문에 상관관계가 없는 하드웨어 결함보다 오히려 시스템 오류를 더 많이 유발하는 경향이 있다.
이러한 소프트웨어 결함을 유발하는 버그는 특정 상황에 의해 발생하기 전까지 오랫동안 나타나지 않는다.
소프트웨어의 체계적 오류 문제는 신속한 해결책이 없지만 다음과 같은 방법이 도움이 될 것이다.

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

인적 오류

사람들은 소프트웨어 시스템을 설계하고 구축하며, 운영자로서 시스템을 계속 운영한다.
보통 이들은 최선의 의도를 가지고 설계, 운영 등의 행동을 하더라도 미덥지 못하다고 알려져 있다.
이러한 사람들이 미덥지 않더라도 다양한 접근 방식의 결합을 통해 신뢰성있는 시스템을 만든다.

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

확장성

현재 안정적으로 동작하는 시스템이 미래에도 안정적으로 동작할 것이라는 보장은 없다.
성능 저하를 유발하는 흔한 이유 중 하나는 부하 증가이다.

부하 기술하기

부하는 부하 매개변수라 부르는 몇 개의 숫자로 나타낼 수 있다.

  • 웹 서버의 초당 요청 수
  • 데이터베이스의 읽기 대 쓰기 비율
  • 대화방의 동시 활성 사용자
  • 캐시 적중률

평균적인 경우가 중요한 상황도 있는 반면에 소수의 극단적인 경우가 병목 현상의 원인이 될 수도 있다.

성능 기술하기

시스템 부하를 기술하면 부하가 증가할 때 어떤 일이 일어나는지 조사할 수 있다. 다음 두가지 방법으로 살펴볼 수 있다.

  • 부하 매개변수를 증가시키고 시스템자원(CPU, 메모리, 네트워크 대역폭 등)은 변경하지 않고 유지하면 시스템 성능은 어떻게 영향을 받을까?
  • 부하 매개변수를 증가시켰을 때 성능이 변하지 않고 유지되길 원한다면 자원을 얼마나 많이 늘려야할까?

두 질문 모두 성능 수치가 필요하다.
하둡과 같은 일괄 처리 시스템은 보통 처리량(throughput)에 관심을 가진다. 하지만 온라인 시스템에서 더 중요한 사항은 서비스의 응답 시간(response time)이다.
보통 보고된 서비스의 평균 응답 시간을 살피는 일이 일반적이다. 하지만 전형적인 응답 시간을 알고 싶다면 평균은 그다지 좋은 지표가 아니다. 왜냐하면 평균은 얼마나 많은 사용자가 실제로 지연을 경험했는지 알려주지 않기 때문이다.
따라서 평균보다는 백분위를 사용하는 편이 좋다. 사용자가 보통 얼마나 오랫동안 기다려야 하는지 알고 싶다면 중앙값이 좋은 지표이다. 특정 값이 얼마나 좋지 않은지 알아보려면 상위 백분위 값을 살펴보는 것도 좋은 방법이다.

부하 대응 접근 방식

사람들은 확장성과 관련해서 용량 확장(scale up)이나 규모 확장(scaling out)으로 구분해서 말하곤 한다.
탄력적인 시스템은 부하를 예측할 수 없을 만큼 높은 경우 유용하지만 수동으로 확장하는 시스템이 더 간단하고 운영상 예상치 못한 일이 더 적다.
대개 대규모로 동작하는 시스템의 아키텍처는 해당 시스템을 사용하는 애플리케이션에 특화되어 있다. 범용적이고 모든 상황에 맞는(one-size-fits-all) 확장 아키텍처는 없다.
아키텍처를 결정하는 요소는 다음과 같다.

  • 읽기의 양
  • 쓰기의 양
  • 저장할 데이터의 양
  • 데이터의 복잡도
  • 응답 시간 요구사항
  • 접근 패턴

유지보수성

소프트웨어 비용의 대부분은 초기 개발이 아니라 지속적인 유지보수에 들어간다는 사실이 알려져있다.
유지보수의 고통을 최소화하고 레거시 소프트웨어를 직접 만들지 않도록 소프트웨어를 설계하기 위해서 주의를 기울여야할 소프트웨어 시스템 설계 원칙은 다음 세가지이다.

  • 운용성(operability)
    • 운영팀이 시스템을 원활하게 운영할 수 있게 쉽게 만들어라.
  • 단순성(simplicity)
    • 시스템에서 복잡도를 최대한 제거해 새로운 엔지니어가 시스템을 이해하기 쉽게 만들어라.
  • 발전성(evolvability)
    • 엔지니어가 이후에 시스템을 쉽게 변경할 수 있게하라

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

시스템이 지속해서 원활하게 작동하려면 운영팀이 필수적이다. 좋은 운영팀은 일반적으로 다음과 같은 작업등에 책임을 진다.

  • 시스템 상태를 모니터링하고 상태가 좋지 않다면 빠르게 서비스를 복원
  • 시스템 장애, 성능 저하 등의 문제의 원인을 추적
  • 보안 패치를 포함해 소프트웨어와 플랫폼을 최신 상태로 유지
  • 다른 시스템이 서로 어떻게 영향을 주는지 확인해 문제가 생길 수 있는 변경 사항을 손상을 입히기 전에 차단
  • 미래에 발생 가능한 문제를 예측해 문제가 발생하기 전에 해결
  • 배포, 설정 관리 등을 위한 모범 사례와 도구를 마련
  • 애플리케이션을 특정 플랫폼에서 다른 플랫폼으로 이동하는 등 복잡한 유지보수 태스크를 수행
  • 설정 변경으로 생기는 시스템 보안 유지보수
  • 예측 가능한 운영과 안정적인 서비스 환경을 유지하기 위한 절차 정의
  • 개인 인사 이동에도 시스템에 대한 조직의 지식을 보존함

좋은 운영성이란 동일하게 반복되는 태스크를 쉽게 수행하게끔 만들어 운영팀이 고부가가치 활동에 노력을 집중할 수 있도록 한다는 의미이다. 데이터 시스템은 동일 반복 태스크를 쉽게 하기 위해 다음과 같은 일들을 할 수 있다.

  • 좋은 모니터링으로 런타임 동작과 시스템의 내부에 대한 가시성 제공
  • 표준 도구를 이용해 자동화와 통합을 위한 우수한 지원을 제공
  • 개별 장비 의존성을 회피, 유지보수를 위해 장비를 내리더라도 시스템 전체에 영향을 주지 않고 계속해서 운영 가능해야 함
  • 좋은 문서와 이해하기 쉬운 운영 모델(예를 들어 "X를 하면 Y가 발생한다") 제공
  • 만족할 만한 기본 동작을 제공하고, 필요할 때 기본값을 다시 정의할 수 있는 자유를 관리자에게 부여
  • 적절하기 자기 화복(self-healing) 이 가능할 뿐 아니라 필요에 따라 관리자가 시스템 상태를 수동으로 제어할 수 있게 함
  • 예측 가능하게 동작하고 예기치 않은 상황을 최소화함

단순성: 복잡도 관리

프로젝트가 커짐에 따라 시스템은 매우 복잡하고 이해하기 어려워진다. 복잡도는 작업하는 모든 사람의 진행을 느리게 할 뿐만아니라 유지보수 비용을 증가시킨다.
복잡도는 다양한 증상으로 나타난다. 상태 공간의 급증, 모듈간 강한 커플링, 복잡한 의존성, 일관성 없는 명명과 용어, 성능 문제 해결을 목표로 한 해킹, 임시방편으로 문제를 해결한 특수사레 등이 이와 같은 증상이다.
시스템을 단순하게 만드는 것이 기능을 줄인다는 의미가 아니다. 우발적 복잡도를 줄인다는 뜻일 수도 있다.
우발적 복잡도를 제거하기 위한 최상의 도구는 추상화이다. 좋은 추상화는 깔끔하고 직관적인 외관 아래로 많은 세부 구현을 숨길 수 있다. 또한 좋은 추상화는 다양한 애플리케이션에서도 사용 가능하다.

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

시스템의 요구사항은 끊임없이 변할 가능성이 높다. 데이터 시스템 변경을 쉽게 하고 변화된 요구사항에 시스템을 맞추는 방법은 시스템의 간단함과 추상화와 밀접한 관련이 있다. 간단하고 이해하기 쉬운 시스템은 복잡한 시스템보다 수정하기 쉽다.

정리

1장에서는 신뢰성, 확장성, 유지보수성에 대해서 설명하고 있다. 이러한 특징들에 대해 구체적으로 설명하고 예시를 통해 이해를 돕고 있고, 위의 특징들을 가지기 위해 도움이 될만한 정보들을 제공하고 있다.

profile
in spring

0개의 댓글