개요
- 데이터가 중심이 되는 애플리케이션에서 신뢰할 수 있고 확장 가능하며 유지보수하기 쉬운 데이터 시스템을 구축하기 위해 필요한 내용을 알아보자.
- 신뢰성, 확장성, 유지보수성의 의미를 명확히 알아보자
데이터 시스템
- 비교적 최근에 등장한 다양한 데이터 저장/처리를 위한 도구 (e.g Kafka, Redis 등)들은 전통적인 데이터 저장소 분류(e.g 큐, 캐시, 데이터베이스)를 위한 경계가 흐려졌다.
- 애플리케이션에서는 다양한 데이터 저장/처리 도구를 사용한다.
- 다양한 도구들을 애플리케이션 코드를 이용해
- 단일 도구에서 작업을 효율적으로 수행하기 위한 여러 태스크를 생성한다.
- 데이터 시스템를 올바르게 설계하기 위해선 신뢰성, 유지보수성, 확장성을 중점을 둬야 한다.
- 신뢰성(Reliability): 하드웨어, 소프트웨어, 휴먼 에러 상황에서도 지속적으로 올바르게 동작해야 한다.
- 확장성(Scalability): 시스템의 데이터 양, 트래픽, 복잡도가 증가할 때 적절히 처리할 수 있어야 한다.
- 유지보수성(Maintainability): 시간이 지날수록 다양한 사람이 시스템 상에서 작업하기 때문에 모든 작업자가 생산적으로 작업할 수 있게 만들어야 한다.
신뢰성
- 신뢰성은 애플리케이션이 “뭔가 잘못되더라도 지속적으로 올바르게 동작하는 것”을 의미한다.
- 결함(Fault)은 잘못될 수 있는 것을 의미하며, 이 결함을 예측하고 대처할 수 있는 시스템을 내결함성(fault-tolerant), 탄력성(resilient)을 가졌다고 말한다.
- 결함 ≠ 장애
- 결함은 사양에서 벗어난 구조를 의미한다.
- 장애는 사용자에게 필요한 서비스를 제공하지 못해 시스템 전체가 멈춘 경우를 의미한다.
- 고의적 결함을 유도해 내결함성 시스템을 지속적으로 테스트해 처리가 가능한지 확인이 필요하다.
넷플릭스의 카오스 몽키(Chaos Monkey)는 대표적인 fault-tolerance 테스트 툴
하드웨어 결함
- 하드웨어 결함(e.g 디스크 고장, 네트워크 단절)이 일어나도 시스템은 올바르게 동작해야 한다.
- 하드웨어 결함에 따른 시스템 장애율을 줄이기 위한 방법으로 하드웨어 구성 요소를 중복(redundancy) 시키는 방법이 있다.
- 최근에는 소프트웨어 내결함성 기술 + 하드웨어 중복성 추가 하는 방식을 주로 사용한다.
- 서버의 재부팅이 필요한 경우 서버 다운타임 없이 이중화(중복성)로 인한 롤링 업데이트 가능하다.
소프트웨어 오류
- 소프트웨어 결함을 유발하는 버그는 특정 상황에 의해 발생하기 전에는 확인하기 어렵다.
- 소프트웨어 결함에 대해선 신속한 해결책이 없으므로 상세한 테스트, 프로세스 격리, 모니터링 등을 통해 지속적인 탐색이 필요하다.
인적 오류
- 인적 오류는 완벽한 해결책이 존재하는 것이 아니기 때문에 오류율을 줄이는 것이 중요하다.
- 오류 가능성을 최소화 하는 방항으로 시스템을 설계하자.
- 사람들이 자주 실수하는 부분을 격리하자.
- 단위 테스트부터 통합 테스트까지 철저하게 진행하자.
- 시스템을 지속적으로 모니터링하자.
- 장애 발생을 최소화하기 위해 오류를 빠르게 롤백할 수 있도록 설계하자.
확장성
- 확장성은 증가하는 부하에 대처하는 시스템 능력을 의미한다.
- 시스템이 특정 방식으로 커질 때 이에 대한 대처 방식이나 추가 부하를 다루기 위한 컴퓨팅 자원을 어떻게 투입할지를 고민하는 것이다.
부하 기술하기
- 확장성을 고려하기 위해선 부하 매개변수를 이용해 시스템의 부하를 판단해야 한다.
부하 매개변수 예시: RPS (Request Per Second), DB Read/Write Rate, Cache Hit Rate
- 병목 현상은 평균적인 부분에서도 발생할 수 있지만, 소수의 극단적인 경우에서도 발생할 수 있다.
- 평균적인 상황에서 방안 2는 “1개의 트윗이 75명의 팔로워에게 전달”되어 부하가 발생하지 않지만, 일부 극단적인 상황 (유저 1명을 팔로워하는 사람이 3,000만 명)인 경우 부하가 발생할 수 있다.
- 트위터 예시에서 사용자당 팔로워의 분포는 트윗의 팬아웃 부하를 결정하기 때문에 부하 매개변수가 된다.
성능 기술하기
- 시스템의 부하를 기술하면 부하가 일어날 때 애플리케이션에 어떤 일이 발생하는지 확인할 수 있다.
- 부하 매개변수를 증가시키고 시스템 자원은 변경하지 않는 경우의 시스템 성능
- 부하 매개변수를 증가시켰을 때 성능이 변하지 않도록 유지하기 위해 필요한 자원
요청 시 응답 시간에 대한 평균 및 백분위
- 시스템의 성능을 판단할 때 평균보다는 백분위를 사용하는 것이 좋다.
- 위의 예시에서 응답 시간을 빠른시간 → 늦은시간으로 정렬했을 때 중간 지점이 중간값(median, p50)이 된다.
- 즉, 50%의 유저는 중간값 이하로 응답을 받고, 나머지 유저는 중간값 이상으로 응답을 받는다는 의미이다.
- 특이 값을 알아보기 위해선 상위 백분위를 살펴보자. (일반적으로 p95, p99, p99.9 사용)
- 꼬리 지연 시간(tail latency)으로 알려진 상위 백분위 응답 시간은 서비스 사용자 경험에 직접적인 영향을 주기 때문에 중요하다.
- 큐잉으로 인한 지연(Queueing Delay)은 이후 들어오는 요청에 대해서도 지연이 발생하는데 이를 선두 차단(head-of-line blocking)이라 한다.
부하 대응 접근 방식
- 일반적으로 확장성은 Scale-Up(Vertical Scaling), Scale-Out(Horizontal Scaling)으로 구분한다.
- 부하 증가를 감지하면 컴퓨팅 자원을 자동으로 추가하도록 탄력적인 시스템을 구축할 수 있다.
- 상태 유지(stateful) 시스템을 분산시키는 것은 복잡도가 크기 때문에 확장 비용이나 데이터베이스에 대한 고가용성 요구가 있을 때까지 단일 노드에 데이터베이스를 유지하는 것(Scale-Up)이 최근까지의 통념이다.
- 일반적으로 대규모 동작 시스템의 아키텍처는 애플리케이션에 특화되어 있다.
- 애플리케이션에 적합한 확장성을 갖춘 아키텍처의 주요 동작을 파악해야 한다.
유지보수성
- 유지보수에 대한 편의성을 제공하도록 시스템을 설계해야 한다.
- 유지보수성을 위한 시스템 설계 원칙
- 운용성(Operability): 운영팀이 시스템을 원활하게 운영하도록 만들자.
- 단순성(Simplicity): 시스템의 복잡도를 최소화하자.
- 발전성(Evolvability): 시스템을 쉽게 변경할 수 있도록 만들자. (= 유연성(extensibility), 수정가능성(modifiability), 적응성(plasticity))
운용성: 운영의 편리함 만들기
- 시스템 운영 중 필요한 부분을 자동화하자.
- 운영성이 좋은 것은 동일하게 반복되는 태스크를 쉽게 수행하게 하는 것이다.
- 모니터링을 통한 런타임 및 시스템 내부 가시성 제공
- 장비 의존성을 제거
- 운영 로그와 같은 문서화
단순성: 복잡도 관리
- 시스템이 복잡해질수록 유지보수 작업이 많아지고 비용이 증가하기 때문에 시스템을 단순하게 설계하는 것이 중요하다.
- 우발적 복잡도를 제거하기 위한 가장 좋은 방법은 추상화이다.
- 좋은 추상화는 세부 구현을 숨길 수 있으며, 다양한 애플리케이션에서 재사용이 가능하다.
- 재사용으로 인해 효율성이 증가하며, 이는 품질 향상에 도움이 된다 .
우발적 복잡도(accidental complexity): 부적절한 설계, 구현, 관리로 인해 발생하는 소프트웨어의 복잡도
발전성: 변화를 쉽게 만들기
- 시스템의 요구사항은 변화한다.
- 애자일 프로세스와 같은 방법론과 TDD, 리팩토링 등을 적용하여 요구사항 변경에 대해 유연하게 대처할 수 있도록 시스템을 설계하자.
반응형
'기술 서적 > 데이터 중심 애플리케이션 설계' 카테고리의 다른 글
3장. 저장소와 검색 (0) | 2025.03.02 |
---|---|
2장. 데이터 모델과 질의 언어 (0) | 2025.01.31 |