1. 데이터 중심 애플리케이션
- 많은 애플리케이션은 계산 중심 < 데이터 중심 이다.
- CPU성능은 애플리케이션을 제한하는 요소가 아니며, 데이터의 양, 복잡도, 변화 속도가 더 큰 문제이다
1) 데이터 시스템
- 다양한 사용사례에 최적화된 데이터 도구(레디스, 카프카)가 있으나 분류 간 경계가 흐려지고 있다.
- 점점 더 많은 애플리케이션이 과도한 요구사항을 가지고 있어 단일 도구로는 만족할 수 없다. 따라서 하나의 작업을 단일 도구에서 수행할 수 있는 태스크로 나누고, 이 도구들은 코드를 이용해 연결되어있다.
- 개발자는 애플리케이션을 개발할 뿐 아니라, 데이터 시스템 설계자이기도 하다.
2) 시스템의 요구사항
- 기능적 요구사항: 데이터를 저장, 조회, 검색하게 하는 작업
- 비기능적 요구사항: 보안, 신뢰성, 법규 준수, 확장성, 호환성, 유지보수성
2. 신뢰성
: 결함이 발생해도 시스템이 지속적으로 올바르게 동작해야 한다.
1) 결함: 잘못될 수 있는 일
- 결함을 예측하고 대처하는 시스템: 내결함성 또는 탄력성
- 결함(사양에서 벗어난 시스템의 한 구성요소) != 장애(사용자에게 필요한 서비스를 제공하지 못하고, 시스템이 멈춘 경우)
- 결함으로 인해 장애가 발생하지 않게끔 하는 것 중요
- 카오스 몽키: 고의적으로 결함을 일으켜 결함율을 증가, 내결함성 훈련
1)-1 결함의 종류
- 하드웨어 결함
- 1개의 하드 디스크의 평생 평균 장애시간: 10~50년
- 10000개의 디스크로 구성된 클러스터는 평균 하루에 1개 죽는다.
- 대응 방안
- HW 구성에 중복을 추가: RAID, hot-swap CPU, 예비 전원
- 과거에는 다중 장비 중복은 고가용성이 절대적인 소수의 애플리케이션에만 해당되었으나, 데이터의 양이 늘어나면서 단일 장비 신뢰성보다 유연성과, 탄력성을 우선적으로 처리하게끔 설계되는 경우가 많다.
- 소프트웨어 결함
- 예상하기 어렵고, 노드 간 상관관계 때문에 HW보다 시스템 오류를 더욱 더 유발하는 경향이 있다.
- 잘못된 입력이 있을 때 SW인스턴스가 죽는 버그
- CPU 시간, 메모리, 디스크 공간, 네트워크 대역폭처럼 공간을 과도하게 사용하는 프로세스
- 시스템의 속도가 느려져 반응이 없거나, 잘못된 응답을 반환하는 서비스
- 연쇄 장애
- 인적 오류
- 잘 설계된 추상화 API, 인터페이스를 사용하라. 옳은 일은 쉽게하고 잘못된 일을 막을 수 있다.
- 실수가 잦게 발생하는 곳은 실제 데이터로 안전하게 실험해볼 수 있는 sandbox 를 제공하라 (ex. stage환경)
- 단위테스트, 통합테스트, 수동테스트를 철저히 해라. 특히 코너케이스에 유의
- 장애를 빠르게 복구 할 수 있게 도구를 만들어라
- 모니터링이 중요하다. 지표를 분석해라
3. 확장성
: 부하가 증가해도 좋은 성능을 유지하기 위한 전략을 의미
1) 부하 기술하기
2) 성능 기술하기
부하가 늘어날 때 시스템 성능에 어떤 영향이 가는지 확인하기 위해서는 성능 수치가 필요.
- 하둡: 처리량(throughput)
- 온라인 시스템: 응답 시간(response time)
* 지연시간(latency): 요청이 처리되길 기다리는 시간, 서비스를 기다리며 휴지 상태인 시간을 말함
- 응답시간을 백분위로 기술, 산술 평균은 의미가 없기 때문에 사용하지 않음
- 중간 값이 200ms이면 클라이언트의 절반은 200ms 미만으로 응답을 받고, 나머지 절반은 초과해서 응답을 받는다는 의미. (50분위, 50p로 기술)
= 동시에 최소한 하나의 요청이 200ms보다 느릴 확률이 50%보다 높다는 의미
- 특이 값이 얼마나 안좋은지 알려면, 99p, 95p등을 확인 = 99p가 1.5초라면 100개의 요청 중 95개는 1.5초 미만이다.
- tail latency: 상위 백분위 응답 시간
- 아마존의 경우 내부 서비스 응답 요구시간을 99.9분위로 기술 => 응답시간이 가장 느린 고객은 많은 구매를 해서 많은 데이터를 가진 고객임으로 이 수치가 중요
- 99.99 분위를 최적화 할 때는 비용이 많이 들어 이익을 가져다 주지 못함
- 꼬리 지연 증폭
3) 부하 대응 접근 방식
-
용량확장=scaling up 과 규모확장=scaling out 사이에서 실용적인 조합이 필요
* 적절한 사양의 장비 몇대 > 값 싼 다수의 장비
-
탄력적(elastic) : 부하 증가를 감지하면 자동으로 자원 추가
* 이것도 항상 좋지는 않다. 수동 확장이 더 간단하고 예상치 못한 운영이슈가 적다.
-
Stateful 한 데이터 시스템을 분산설치하는 일은 복잡도가 크다. 따라서 고가용성 요구가 있을 때에만 분산으로 데이터 시스템을 유지했다. 하지만, 요새는 분산시스템과 추상화가 워낙 좋아져서, 기본 아키텍처로 자리잡을 수 있다.
-
부하 매개변수를 기준으로 아키텍처를 구축한다. 이것이 잘못되면, 역효과를 낳는다. 스타트업 초기단계에는 미래를 가정한 부하에 대비해 확장하기 보다는 빠르게 반복해서 제품 기능을 개선하는 것이 좀 더 중요하다.
4. 유지보수성
: 시스템에서 작업하는 엔지니어와 운영팀의 삶을 개선
많은 사람들은 레거시 시스템을 유지보수하는 것을 좋아하지 않는다.
- 유지보수성 원칙
- 운용성 : 운영팀이 원활하게 운영할 수 있도록 쉽게 만들어라
- 단순성 : 복잡도를 최대한 제거해 새로운 팀원도 잘 이해할 수 있게 만들어라
- 발전성 : 이후 변경에 열려있어야 한다. 요구사항 변경같은 새로운 사용사례를 쉽게 적용할 수 있어야한다.
1) 운용성
- 좋은 운영팀 운영
- 동일하게 반복되는 태스크를 쉽게 수행하게끔 만들어 고부가가치 활동에 노력 집중
- 런타임 동작과 시스템 내부에 대한 가시성 제공
- 개별 장비 의존성을 회피, 장비를 내리더라도 시스템 전체에 영향을 주지 않아야 함
- 이해하기 쉬운 운영모델을 제공: X를 하면 Y가 발생
- 어드민 등으로 기본값을 재정의할 수 있는 권한 부여
- 자기 회복이 가능할 뿐아니라 관리자가 상태를 수동으로 제어할 수 있어야 함
2) 단순성
- 커다란 진흙 덩어리: 복잡도 수렁에 빠진 SW 프로젝트
- 모듈 간 강한 커플링, 복잡한 의존성, 일관성 없는 명명, 성능 문제를 목표로 한 해킹, 임시 방편으로 해결한 특수 사례 등
- 우발적 복잡도 줄이기
- 추상화: 깔끔하고 직관적인 외관 아래로 세부 구현을 숨기는 것
- 예: 프로그래밍 언어는 기계어, CPU 레지스터, 시스템 호출 등을 숨긴 추상화
3) 발전성
- 시스템 요구사항은 계속 바뀐다.
- 애자일(agile) 작업 패턴은 변화에 적응하기 위한 프로세스이다.
- TDD, 리팩토링 등
- 로컬 규모에 초점을 맞춰라