상세 컨텐츠

본문 제목

Chapter 1. Reliability, Scalability, Maintainability

Log.Develop/DDIA

by bluayer 2022. 6. 10. 10:15

본문

소개

본 글은 데이터 중심 어플리케이션(마틴 클레프만)으로 스터디하며 해당 책의 내용을 요약 정리한 내용입니다.

https://github.com/ddia-study/ddia-study

 

GitHub - ddia-study/ddia-study: 데이터 중심 어플리케이션 설계

데이터 중심 어플리케이션 설계. Contribute to ddia-study/ddia-study development by creating an account on GitHub.

github.com

 

서론

computive-intensive <<< data-intensive

 

표준 구성 요소

  • DB : 나중에 다시 데이터 찾을 수 있게 데이터 저장
  • Cache : 값비싼 수행 결과 기억
  • Search Index : 데이터 검색, 필터링 방법 제공
  • Stream processing : 비동기 처리를 위해 다른 프로세스로 메시지 보내기
  • Batch processing : 주기적으로 대량의 누적 데이터 분석

 

데이터 시스템에 대한 생각

첫 번째 이유

데이터 저장과 처리를 위한 여러 새로운 도구는 최근에 만들어졌다.

새로운 도구들은 다양한 use case에 최적화됐기 때문에 더 이상 전통적인 분류에 딱 들어맞지 않는다.

두 번쨰 이유

점점 더 많은 애플리케이션이 단일 도구로는 더 이상 데이터 처리와 저장 모두를 만족시킬 수 없는 과도하고 광범위한 요구사항을 갖고 있다.

이제부터 개발자는 애플리케이션 개발자뿐만 아니라 데이터 시스템 설계자이기도 하다.

 

Reliability

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

이 모든 것이 올바르게 동작함을 의미하는 경우,

대략 무언가 잘못되더라도 지속적으로 올바르게 동작함을 신뢰성의 의미로 이해할 수 있다.

잘못될 수 있는 일을 fault라고 부른다. 그리고 이를 예측하고 대처할 수 있는 시스템을 fault-tolerant 혹은 resilient를 지녔다고 말한다.

 

fault는 failure와 동일하지 않다.

fault는 사양에서 벗어난 시스템의 한 구성 요소로 정의되지만, 장애는 사용자에게 필요한 서비스를 제공하지 못하고 시스템 전체가 멈춘 경우다.

많은 중대한 버그들이 미흡한 오류 처리에 기인한다. 따라서 고의적으로 결함을 유도해서 내결함성 시스템을 테스트 한다. e.g. Chaos Monkey

 

Hardware Fault

하드디스크의 MTTF는 10 ~ 50년. 따라서 10000개의 디스크로 구성된 저장 클러스터는 평균적으로 하루에 한 개의 디스크가 죽는다고 예상해야 한다.

이를 해결하기 위해 하드웨어 구성 요소에 중복을 추가한다. 고장난 구성 요소의 교체 시간 동안 중복 구성 요소를 대신 사용한다.

  • 디스크 : RAID
  • 서버 : 이중 전원 디바이스
  • CPU : 핫 스왑 가능한 CPU
  • 데이터 센터 : 건전지와 예비 전원용 디젤 발전기

데이터 양과 애플리케이션의 계산 요구가 늘어나면서 더 많은 애플리케이션이 많은 수의 장비를 사용하게 됐고 이와 비례해 하드웨어 결함율도 증가했다.

또한 AWS 같은 일부 클라우드 플랫폼은 인스턴스가 별도의 경고 없이 사용할 수 없게 되는 상황이 상당히 일반적이다.

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

 

Software Error

  • 잘못된 특정 입력이 있을 때 모든 애플리케이션 서버 인스턴스가 죽는 소프트웨어 버그
  • CPU 시간, 메모리, 디스크 공간, 네트워크 대역폭처럼 공유 자원을 과도하게 사용하는 일부 프로세스
  • 시스템의 속도가 느려져 반응이 없거나 잘못된 응답을 반환하는 서비스
  • cascading failure

소프트웨어 결함을 유발하는 버그는 특정 상황에 의해 발생하기 전까지 오랫동안 나타나지 않는다.

소프트웨어의 체계적 오류 문제는 신속한 해결책이 없다.

 

Human Error

사람은 미덥지 않다. 시스템을 어떻게 신뢰성 있게 만들까?

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

 

신뢰성은 얼마나 중요할까?

"중요하지 않은" 애플리케이션도 사용자에 대한 책임이 있다.

 

Scalability

확장성은 증가한 부하에 대처하는 시스템 능력을 설명하는 데 사용하는 용어지만, 시스템에 부여하는 일차원적인 표식이 아니다.

"시스템이 특정 방식으로 커지면 이에 대처하기 위한 선택은 무엇인가?"

"추가 부하를 다루기 위한 계산 자원을 어떻게 투입할까?"

 

부하 기술하기

시스템의 현재 부하를 간결하게 기술해야, 부하 성장 질문을 논의할 수 있다.

부하는 부하 매개변수(load parameter)라 부르는 몇 개의 숫자로 나타낼 수 있고, 시스템 설계에 따라 적합한 변수가 달라진다.

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

 

성능 기술하기

시스템 부하를 기술하면 부하가 증가할 때 어떤 일이 일어나는지를 조사할 수 있다.

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

두 질문 모두 성능 수치가 필요하다. 잠깐, 성능 수치?

일괄처리 시스템은 throughput을, 온라인 시스템에서는 response time을 중요하게 여긴다.

 

Response Time

특히 response time은 매번 달라지기 때문에 단일 숫자가 아닌 측정 가능한 값의 분포로 생각해야 한다.

사용자가 보통 얼마나 오랫동안 기다려야 하는지 알고 싶다면 중앙값(p50)이 좋은 지표다.

사용자 요청의 절반은 중앙값 미만으로, 절반은 중앙값보다 오래 걸린다.

참고로 tail latency라고 알려진 p95, p99, p999를 보는 것은 서비스의 사용자 경험에 직접 영향을 주기 때문에 중요하다.

 

SLO vs SLA

image

이미지 출처 : https://www.atlassian.com/incident-management/kpis/sla-vs-slo-vs-sli

 

Queueing delay

높은 백분위에서 응답 시간의 상당 부분을 차지한다.

서버는 병렬로 소수의 작업만 처리할 수 있기 때문에, 소수의 느린 요청 처리만으로도 후속 요청 처리가 지체된다.

이 현상을 선두 차단(head-of-line blocking)이라고 한다.

 

부하 대응 접근 방식

부하 매개변수가 어느 정도 증가하더라도 좋은 성능을 유지하려면 어떻게 해야 할까?

scaling up(vertical scaling) vs scaling out(horizontal scaling)

다수의 장비에 부하를 분산하는 아키텍처를 비공유(share-nothing) 아키텍처라고 부른다.

단일 장비에서 수행될 수 있는 시스템은 보통 간단하지만, 고사양 장비가 비싸기 때문에 대부분은 스케일 아웃을 한다.

 

일부 시스템은 탄력적(elastic)이다. 부하 증가를 감지하면 컴퓨팅 자원을 자동으로 추가할 수 있다.

 

다수의 장비에 stateless 서비스를 배포하는 것은 간단하지만, stateful 시스템을 분산 설치하는 것은 매우 복잡하다.

따라서 최근까지는 데이터베이스를 분산으로 만드는 등의 고가용성 요구가 있을 때까지 단일 노드에 DB를 유지해왔다.

그렇지만 분산 시스템을 위한 도구나 추상화가 좋아지면서 조금씩 바뀌고 있다.

 

대개 대규모로 동작하는 시스템 아키텍처는 해당 시스템을 사용하는 애플리케이션에 특화되어 있다.

one-size-fits-all은 없다.

특정 애플리케이션에 적합한 확장성을 갖춘 아키텍처는 주요 동작이 무엇이고 잘하지 않는 동작이 무엇인지에 대한 가정을 바탕으로 구축한다.

이 가정은 곧 부하 매개변수가 된다.

 

Maintainability

소프트웨어 비용의 대부분 = 유지보수

유지 보수는 고통스럽지만, 고통을 최소화하고 레거시를 직접 만들지 않게끔 소프트웨어를 설계할 수 있다.

  • 운용성(operability) : 운영팀이 시스템을 원활하게 운영할 수 있게 쉽게 만들어라
  • 단순성(simplicity) : 시스템에서 복잡도를 최대한 제거해 새로운 엔지니어가 시스템을 이해하기 쉽게 만들어라
  • 발전성(evolvability) : 엔지니어가 이후에 시스템을 쉽게 변경할 수 있게 하라. 유연성(extensibility), 수정 가능성(modifiability), 적응성(plasticity)으로 이루어져 있다.

Operability

*"좋은 운영은 종종 나쁜 소프트웨어의 제약을 피하는 대안이 될 수 있다. 하지만 좋은 소프트웨어라도 나쁘게 운영할 경우 작동을 신뢰할 수 없다."*

시스템을 지속해서 원활하게 작동하려면 운영 팀이 필수다. 보통 이런 작업을 책임진다.

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

좋은 운영성이란 반복 태스크를 쉽게 수행할 수 있게끔 만든다. 데이터 시스템은 다양한 일을 할 수 있다.

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

 

Simplicity

복잡도의 다양한 증상

  • 상태 공간의 급증
  • tight coupling
  • Complex Dependency
  • 일관성 없는 naming
  • 성능 문제 해결을 목표로 한 해킹
  • 임시방편으로 처리해놓은 특수 사례

복잡한 소프트웨어에서는 변경이 있을 때 버그가 생길 위험이 더 크다.

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

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

이런 우발적 복잡도를 제거하기 위해 추상화를 사용할 수 있다.

좋은 추상화는 많은 세부 구현을 깔끔하게 숨길 수도 있고, 재사용성이 높다.

 

Evolvability

시스템의 요구사항이 영원히 바뀌지 않을 가능성은 매우 적다.

조직 프로세스 측면에서 agile 작업 패턴은 변화에 적응하기 위한 프레임 워크를 제공한다.

또한 애자일 커뮤니티는 TDD, Refactoring 같이 자주 변화하는 환경에서 도움이 되는 기술 도구와 패턴을 개발하고 있다.

데이터 시스템 변경을 쉽게 하고 변화된 요구사항에 시스템을 맞추는 방법은 시스템의 간단함과 추상화와 밀접하다.

 

정리

안타깝게도 애플리케이션을 신뢰할 수 있고 확장 가능하며 유지 보수하기 쉽게 만들어주는 간단한 해결책은 없다.

하지만 여러 애플리케이션에서 계속 재현되는 특정 패턴과 기술이 있다.

관련글 더보기

댓글 영역