Chapter 1: 신뢰할 수 있고 확장 가능하며 유지보수하기 쉬운 애플리케이션
💡 책에서 기억하고 싶은 내용
데이터 시스템에 대한 생각
일반적으로 데이터베이스, 큐, 캐시 등을 매우 다른 범주에 속하는 도구로 생각한다
데이터베이스와 메시지 큐는 표면적으로 비슷하더라도 (둘 다 얼마 동안 데이터를 저장)
매우 다른 접근 패턴
을 갖고 있어서로 다른 특성
이 있기 때문에 구현 방식이 매우 다르다
데이터 저장과 처리를 위한 새로운 도구들
메시지 큐로 사용하는 데이터스토어인
Redis
가 있고,데이터베이스처럼 지속성(durability) 을 보장하는 메시지 큐인
Apache Kafka
도 있다
점점 더 많은 애플리케이션이 단일 도구로는 더 이상 데이터
처리
와저장
모두를 만족시킬 수 없는, 과도하고 광범위한 요구사항을 갖고 있다대신 작업(work)은 단일 도구에서 효율적으로 수행할 수 있는 태스크(task)로 나누고, 다양한 도구들은 애플리케이션 코드를 이용해 서로 연결한다
서비스 제공을 위해 각 도구를 결합할 때
서비스 인터페이스
나애플리케이션 프로그래밍 인터페이스 (API)
는 보통 클라이언트가 모르게구현 세부 사항
을 숨긴다좀 더 작은 범용 구성 요소들로 새롭고 특수한 목적의 데이터 시스템을 만든다
복합 데이터 시스템(composite data system) 은 외부 클라이언트가 일관된 결과를 볼 수 있게끔 쓰기에서
캐시
를 무효화하거나 업데이트하는 등 특정보장 기능
을 제공할 수 있다
대부분의 소프트웨어 시스템에서 중요하게 여기는 세 가지 관심사
신뢰성 (Reliability)
하드웨어나 소프트웨어 결함, 인적 오류 (human error) 같은
역경
에 직면하더라도 시스템은지속적으로 올바르게 동작
(원하는 성능 수준에서 정확한 기능을 수행) 해야 한다
확장성 (Scalability)
시스템의 데이터 양, 트레픽 양, 복잡도가
증가
하면서 이를 처리할 수 있는 적절한 방법이 있어야 한다
유지보수성 (Maintainability)
시간이 지남에 따라 여러 다양한 사람들이 시스템 상에서 작업 (현재 작업을 유지보수하고, 새로운 사용 사례를 시스템에 적용하는 엔지니어링과 운영) 할 것이기 때문에, 모든 사용자가 시스템 상에서
생산적
으로 작업할 수 있게 해야한다
신뢰성
소프트웨어의 일반적인 기대치
애플리케이션은 사용자가
기대한 기능
을 수행한다시스템은
사용자가 범한 실수
나예상치 못한 소프트웨어 사용법
을허용
할 수 있다시스템 성능은
예상된 부하
와데이터 양
에서 필수적인 사용 사례를 충분히 만족한다시스템은
허가되지 않은 접근
과오남용
을방지
한다
무언가 잘못되더라도 지속적으로 올바르게 동작함
을 신뢰성의 의미로 이해할 수 있다잘못될 수 있는 일을
결함 (fault)
라 부른다결함을 예측하고 대처할 수 있는 시스템을
내결함성 (fault-tolerance)
또는탄력성 (resilient)
을 지녔다고 말한다
결함
은장애 (failure)
와 동일하지 않다결함
은 사양에서 벗어난 시스템의 한 구성 요소로 정의되지만,장애
는 사용자에게 필요한 서비스를 제공하지 못하고 시스템 전체가 멈춘 경우다
결함으로 인해 장애가 발생하지 않게끔
내결함성 구조
를 설계하는 것이 가장 좋다결함을 예측하고 대체할 수 있는 시스템
내결함성 시스템
에서 경고 없이 개별 프로세스를 무작위로 죽이는 것과 같이고의적으로 결함을 일으켜
결함률을 증가시키는 방법많은 중대한 버그는 미흡한 오류 처리에 기인한다
고의적
으로 결함을 유도함으로써 내결함성 시스템을 지속적으로 훈련하고 테스트해서, 결함이 자연적으로 발생했을 때 올바르게 처리할 수 있다는 자신감을 높인다ex) Netflix의 Chaos Monkey
하드웨어 결함
시스템 장애율을 줄이기 위한 첫 번째 대응으로 각 하드웨어 구성 요소에
중복(redundancy)
을 추가하는 방법이 일반적이다디스크는
RAID
(Redundant Array of Independent Disk) 구성으로 설치할 수 있고,서버는 이중 전원 디바이스와
hot-swap
가능한 CPU를,데이터센터는 건전지와 예비 전원용 디젤 발전기를 갖출 수 있다
소프트웨어 오류
시스템 내 체계적 오류 (
systematic error
) 는 예상하기 더 어렵고, 노드 간 상관관계 때문에 상관관계 없는 하드웨어 결함보다 오히려 시스템 오류를 더욱 많이 유발하는 경향이 있다ex)
잘못된 특정 입력이 있을 때 모든 애플리케이션 서버 인스턴스가 죽는 소프트웨어 버그
CPU 시간, 메모리, 디스크 공간, 네트워크 대역폭처럼
공유 자원
을 과도하게 사용하는 일부프로세스
시스템의 속도가 느려저 반응이 없거나, 잘못된 응답을 반환하는 서비스
한 구성 요소의 작은 결함이 다른 구성 요소의 결함을 야기하고 차례차례 더 많은 결함이 발생하는
연쇄 장애 (cascading failure)
이 같은 소프트웨어 결함을 유발하는 버그는
특정 상황
에 의해 발생하기 전까지 오랫동안 나타나지 않는다소프트웨어의
체계적 오류 문제
는 신속한 해결책이 없지만 아래와 같은 일들이 문제 해결에 도움을 줄 수 있다시스템의 가정(presume) 과 상호 작용에 대해 주의 깊게 생각하기
빈틈없는 테스트
프로세스 격리
죽은 프로세스의 재시작 허용
프로덕션 환경에서 시스템 동작의 측정
모니터링
분석하기
시스템이 무언가 보장하길 기대한다면, 수행 중에 이를 지속적으로 확인해 차이가 생기면 경고를 발생시킬 수 있다
인적 오류
신뢰성 있는 시스템을 만들기위한 접근 방식
오류의 가능성
을최소화
하는 방향으로 시스템을 설계잘 설계된 추상화, API, 관리 인터페이스를 사용하여
옳은 일
은 쉽게하고,잘못된 일
은 막을 수 있다
사람의 실수로 장애가 발생할 수 있는 부분을 분리
실제 데이터를 사용해 안전하게 살펴보고 실험할 수 있지만, 실제 사용자에게는 영향이 없는
비 프로덕션 샌드박스 (sandbox)
를 활용
단위 테스트 → 전체 시스템 통합 테스트, 수동 테스트까지
모든 수준
에서철저하게 테스트
인적 오류를 빠르고 쉽게
복구
할 수 있게 하기설정 변경 내역에 대한 빠른
롤백
새로운 코드를 서서히
롤아웃
하기 (예상치 못한 버그가 일부 사용자에게만 영향이 미치게 함)데이터 재계산 도구 제공
상세하고 명확한
모니터링 대책
마련문제가 발생했을 때
지표 (metrics)
는 문제를 분석하는 데 매우 중요하다
조작 교육과 실습을 실행
확장성
성능 저하를 유발하는 흔한 이유 중 하나는
부하 증가
다확장성을 논한다는 것은 아래와 같은 질문을 고려하는 것이다
“시스템이 특정 방식으로 커지면 이에 대처하기 위한 선택은 무엇인가?”
“추가 부하를 다루기 위해 계산 자원을 어떻게 투입할까?
부하 기술하기
시스템의 현재 부하를 간결하게 기술해야 한다
그래야 부하 성장 질문 (부하가 두 배로 되면 어떻게 될까?)을 논의할 수 있다
부하는
부하 매개변수 (load parameter)
라 부르는 몇 개의 숫자로 나타낼 수 있다ex)
웹 서버의 초당 요청 수 (RPS)
DB 읽기 vs 쓰기 비율
동시 활성 사용자 (active user)
캐시 적중률 (cache hit)
평균적인 경우가 중요할 수도 있고, 소수의 극단적인 경우가 병목 현상의 원인일 수 있다
성능 기술하기
시스템 부하를 기술하면, 부하가 증가할 때 어떤 일이 일어나는지 조사할 수 있다
부하 매개변수
를 증가시키고, 시스템자원
(CPU, 메모리, 네트워크 대역폭 등)은 변경하지 않고유지
하면 시스템 성능은 어떻게 영향을 받을까?부하 매개변수
를 증가시켰을 때,성능
이 변하지 않고유지
되길 원한다면 자원은 얼마나 많이 늘려야할까?
하둡 같은 일괄 처리 시스템은 보통
처리량 (throughput)
에 관심을 가진다온라인 시스템에서는
서비스 응답 시간 (response time)
, 즉 client가 요청을 보내고 응답을 받는 사이의 시간이 중요하다응답 시간은 단일 숫자가 아니라 측정 가능한 값의
분포
로 생각해야 한다일반적으로 평균보다는
백분위 (percentile)
를 사용하는 편이 좋다응답 시간 목록을 가지고 가장 빠른 시간부터 제일 느린 시간까지 정렬하면, 중간 지점이
중앙값 (median)
이 된다사용자가 보통 얼마나 오랫동안 기다려야 하는지 알고 싶다면
중앙값
이 좋은 지표다중앙값은 50분위로서,
p50
으로 축약할 수 있다중앙값은
단일 요청
을 참고한다!
특이 값
이 얼마나 좋지 않는지 알아보려면, 상위 백분위를 살펴보는 것이 좋다일반적으로 p95, p99, p999를 사용한다
요청의 95%, 99%, 99.9% 가 특정 기준치보다 더 빠르면 해당 특정 기준치가 각 백분위의 응답 시간 기준치가 된다
꼬리 지연 시간 (tail latency)
으로 알려진 상위 백분위 응답 시간은 서비스의 사용자 경험에 직접 영향을 주기 때문에 중요하다큐 대기 지연 (queueing delay)
은 높은 백분위에서 응답 시간의 상당 부분을 차지한다서버는 병렬로 소수의 작업만 처리할 수 있기 때문에, 소수의 느린 요청 처리만으로
후속 요청 처리
가 지체 된다이 현상을
선두 차단 (head-of-line blocking)
이라 한다
서버에서 후속 요청이 빠르게 처리되더라도, 이전 요청이 완료되길 기다리는 시간 때문에 클라이언트는 전체적으로 응답 시간이 느리다고 생각할 것이다
이런 문제 때문에 client side 응답 측정이 중요하다!
지연 시간(latency) 과 응답 시간(response time)
응답 시간
client 관점에서 본 시간으로, 요청을 처리하는 실제 시간 (서비스 시간) 외에도 네트워크 지연과 큐 지연도 포함한다
지연 시간
요청이 처리되길 기다리는 시간
서비스를 기다리며 휴지(latent) 상태인 시간
부하 대응 접근 방식
다수의 장비에 부하를 분산하는 아키텍처를
비공유 (shared-nothing)
아키텍처라 부른다탄력적인 시스템
은 부하를 예측할 수 없을 만큼 높은 경우 유용하지만,수동으로 확장하는 시스템
이 더 간단하고 운영상 예상치 못할 일이 적다다수의 장비에
stateless
서비스를 배포하는 일은 상당히 간단하지만, 단일 노드에stateful
데이터 시스템을분산 설치
하는 일은 아주 많은 복잡도가 추가적으로 발생한다확장 비용이나 데이터베이스를 분산으로 만들어야 하는 고가용성 요구가 있을 때까지, 단일 노드에 데이터베이스를 유지하는 것 (scale-up) 이 최근까지의 통념이다
아키텍처를 결정하는 요소는 읽기의 양, 쓰기의 양, 저장할 데이터의 양, 데이터의 복잡도, 응답 시간 요구사항, 접근 패턴 등이 있다
특정 애플리케이션에 적합한 확장성을 갖춘 아키텍처는 주요 동작이 무엇이고 잘 하지 않는 동작이 무엇인지에 대한
가정
을 바탕으로 구축한다이 가정은 곧
부하 매개변수
가 된다이 가정이 잘못되면, 확장에 대한 엔지니어링 노력은 헛수고가 되고 최악의 경우 역효과를 낳는다
검증되지 않은 제품의 경우 미래를 가정한
부하에 대비해 확장
하기 보다는, 빠르게 반복해서제품 기능을 개선
하는 작업이 좀 더 중요하다
유지보수성
유지보수 중 고통을 최소화하고 레거시 소프트웨어를 만들지 않기 위한 시스템 설계 원칙은 다음 세 가지다
운용성 (operability)
운영팀이 시스템을 원활하게 운영할 수 있게, 쉽게 만들어라
단순성 (simplicity)
시스템의
복잡도
를 최대한제거
해 새로운 엔지니어가 시스템을 이해하기 쉽게 만들어라복잡도를 제거하기 위한 최상의 도구는
추상화
다
발전성 (evolvability)
엔지니어가 이후에 시스템을 쉽게 변경할 수 있게 하라
그래야 요구사항 변경 같은 예기치 않은 사용 사례를 적용하기가 쉽다
이 속성은
유연성 (extensibility)
,수정 가능성 (modifiability)
,적응성 (plasticity)
으로 알려져 있다애자일 (agile)
작업 패턴은 변화에 적응하기 위한 프레임워크를 제공한다
정리
신뢰성
은 결함이 발생해도 시스템이 올바르게 동작하게 만든다는 의미다결함은 하드웨어와 소프트웨어 버그, 그리고 사람에게 있을 수 있다
내결함성 기술은 최종 사용자에게 특정 유형의 결함을 숨길 수 있게 해준다
확장성
은 부하가 증가해도 좋은 성능을 유지하기 위한 전략을 의미한다확장 가능한 시스템에서는 부하가 높은 상태에서 신뢰성을 유지하기 위해
처리 용량
을 추가할 수 있다
유지보수성
에는 많은 측면이 있지만, 유지보수성의 본질은 시스템에서 작업하는 엔지니어와 운영팀의 삶을 개선하는데 있다좋은
추상화
는복잡도
를 줄이고, 쉽게 시스템을 변경할 수 있게 하며, 새로운 사용 사례에 적용하는 데 도움이 된다좋은
운용성
이란 시스템의 건강 상태를 잘 관찰할 수 있고, 시스템을 효율적으로 관리하는 방법을 보유한다는 의미다
Last updated