Design/Designing Data-Intensive Applications

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

Seung-o 2024. 7. 14. 22:09

오늘날 많은 애플리케이션은 계산 중심보다는 데이터 중심적이다. 고도의 계산으로 인해 CPU의 성능이 중요하기보다는 많고 복잡하며 변화하는 데이터를 잘 다루는 데에 애플리케이션의 방점이 찍혀있다. 

 

이 책은 데이터 시스템의 원칙과 실용성, 그리고 이를 활용한 데이터 중심 애플리케이션을 개발하는 방법을 모두 담고 있다. 책에서 소개된 다양한 도구가 공통으로 지닌 것은 무엇이고 서로 구별되는 것은 무엇인지, 그리고 어떻게 그러한 특성을 구현해냈는지 알아보도록 한다.

 

데이터 시스템에 대한 생각

 

일반적으로 데이터 시스템은 데이터베이스, 큐, 캐시 등 다른 범주의 도구들을 모두 포괄하는 용어이다. 그런 포괄적인 용어를 사용하는 데에는 두 가지 이유가 있다.

 

1. 최근에 등장한 도구들은 다양한 사용 사례(use-case)에 최적화됐기 때문에 더 이상 전통적인 분류에 딱 들어맞지 않는다. 가령, 메세지 큐로 사용하는 데이터스토어인 레디스(Redis)가 있고, 데이터베이스처럼 지속성(durability)를 보장하는 메세지 큐인 카프카(Kafka)도 있다. 즉, 메세지 큐만을 위한 경계는 모호하고, 사용 사례가 깊어진 셈이다.

 

2. 점점 더 많은 애플리케이션이 단일 도구로는 더 이상 데이터 처리와 저장 모두를 만족 시킬 수 없는 과도하고 광범위한 요구 사항을 갖고 있다. 대신 작업은 단일 도구에서 효율적으로 수행할 수 있는 테스크로 나누고 다양한 도구들은 애플리케이션 코드를 이용해 서로 연결한다.

 

다양한 구성 요소를 결합한 데이터 시스템 아키텍처 예시

 

서비스 제공을 위해 각 도구를 결합할 때, 서비스 인터페이스는 API 등의 형태로 추상화하고, 내부적으로는 데이터 베이스 및 인메모리 캐시, 풀텍스트 검색을 위한 엘라스틱서치와 같은 전문 검색 서버 등을 내부적으로 관리한다. 이제부터 개발자는 애플리케이션 개발자뿐만 아니라 데이터 시스템 설계자이기도 하다.

 

데이터 시스템이나 서비스를 설계할 때, 많은 문제를 직면하게 된다. 

 

- 내부적으로 문제가 있어도 데이터를 정확하고 완전하게 유지하기 위해 어떻게 해야 할까?

- 시스템의 일부 성능이 저하되더라도 클라이언트에 일관되게 좋은 성능을 어떻게 제공할 수 있을까?

- 부하 증가를 다루기 위해 어떻게 규모를 확장할까?

- 서비스를 위해 좋은 API는 어떤 모습일까?

 

이 책에서는 대부분의 소프트웨어 시스템에서 중요하게 여기는 세 가지 관심사에 중점을 둔다.

 

1. 신뢰성 ( Reliability )

 

하드웨어나 소프트웨어 결함, 심지어 휴먼 에러 같은 역경에 직면하더라도 시스템은 지속적으로 올바르게 동작해야 한다. ( 올바르게 동작한다는 것은 원하는 성능 수준에서 정확한 기능을 수행하는 것 )

 

2. 확장성 ( Scalability )

 

시스템의 데이터 양, 트래픽 양, 복잡도가 증가하면서 이를 처리할 수 있는 적절한 방법이 있어야 한다.

 

3. 유지보수성 ( Maintainability )

 

시간이 지남에 따라 여러 다양한 사람들이 시스템 상에서 작업할 것이기 때문에 모든 사용자가 시스템 상에서 생산적으로 작업할 수 있게 해야 한다.

 

 

신뢰성

 

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

 

- 애플리케이션은 사용자가 기대한 기능을 수행한다.

- 시스템은 사용자가 범한 실수나 예상치 못한 소프트웨어 사용법을 허용할 수 있다.

- 시스템 성능은 예상된 부하와 데이터 양에서 필수적인 사용 사례를 충분히 만족한다.

- 시스템은 허가되지 않은 접근과 오남용을 방지한다.

 

이 모든 것이 올바르게 동작함을 신뢰성의 의미로 이해할 수 있다. 즉, 무언가 잘못되더라도 지속적으로 올바르게 동작하는 것이 신뢰성이다.

 

잘못될 수 있는 일을 결함(fault)이라고 한다. 결함을 예측하고 대처할 수 있는 시스템을 내결함성(fault-tolerant) 또는 탄력성(resilient)을 지녔다고 말한다. 결함은 장애(failure)와 동일하지 않다. 일반적으로 결함은 사양에서 벗어난 시스템의 한 구성요소로 정의되지만, 장애는 사용자에게 필요한 서비스를 제공하지 못하고 시스템 전체가 멈춘 경우다. 결함 확률을 0으로 줄이는 것은 불가능하다. 따라서 결함으로 인해 장애가 발생하지 않게끔 내결함성 구조를 설계하는 것이 가장 좋다.

 

고의적으로 결함을 유도함으로써 내결함성 시스템을 지속적으로 훈련하고 테스트해서 결함이 자연적으로 발생했을 때 올바르게 처리할 수 있다는 자신감을 높일 수 있다. 넷플릭스의 카오스 몽키(Chaos Monkey)가 이런 접근 방식의 한 예다.

 

카오스 몽키란?


카오스 몽키의 최초 고안자 중 몇 명이 정리한 카오스 엔지니어링 원칙은 “프로덕션 환경의 예측할 수 없는 상황에 버틸 수 있는 확고한 시스템 역량을 구축하기 위한 실험 방법”이다.
 
실무에서는 다음과 같은 4단계의 형식을 취한다.

1. 시스템의 “정상 상태”를 정의해 정상 동작의 기준선을 설정한다.
2. 대조군과 실험군 양쪽에서 모두 이 정상 상태가 계속된다는 가설을 세운다.
3. 서버 멈춤, 하드 드라이브 고장, 네트워크 연결 끊김과 같은 실제 상황을 반영하는 변수를 도입한다.
4. 대조군과 실험군 사이의 차이점을 확인해 가설이 틀렸음을 입증한다.
 
정상 상태를 무너뜨리기가 어렵다면 견고한 시스템이고, 약점이 있다면 찾아서 수정해야 한다.

출처:https://www.itworld.co.kr/news/152680#csidx9277921bdb24b68b70ce2b75349f995 

 

 

하드웨어 결함

 

시스템 장애의 원인은 대표적인 것은 바로 하드웨어 결함이다. 하드디스크의 평균 장애 시간 (mean time to failure, MTTF )은 약 10년 ~ 50년으로 보고되었다. 따라서 10,000개의 디스크로 구성된 저장 클러스터는 평균적으로 하루에 한 개의 디스크가 죽는다고 예상해야 한다.

 

데이터 양과 애플리케이션의 계산 요구가 늘어나면서 더 많은 애플리케이션이 많은 수의 장비를 사용하게 됐고, 이와 비례해 하드웨어 결함율도 증가했다. 또한, AWS 같은 일부 클라우드 플랫폼은 가상 장비 인스턴스가 별도의 경고 없이 사용할 수 없게 되는 상황이 상당히 일반적이다. 이런 플랫폼은 단일 장비 신뢰성보다 유연성 (flexibility)과 탄력성 (elasticity)을 우선적으로 처리하게끔 설계됐기 때문이다. 

 

따라서 소프트웨어 내결함성 기술을 하용하거나 하드웨어 중복성을 추가해 전체 장비의 손실을 견딜 수 있는 시스템으로 점점 옮겨가고 있다. 이는 운영상의 이점도 갖는데, 가령 보안 패치 등을 적용하기 위해 장비를 재부팅해야하는 경우, 한 노드씩 적용하여 전체 시스템의 중단 시스템 없이 패치를 진행할 수 있다.

 

소프트웨어 오류

 

보통 하드웨어 오류는 무작위적이고 서로 독립적이다. 즉, 한 장비에 장애가 발생했다고 해서 다른 장비에 장애가 발생하지는 않는다는 의미이다. 반면, 시스템 내 체계적 오류 (systematic error)는 예상하기 어렵고, 노드 간의 상관 관계 때문에 시스템 오류를 더 많이 유발하는 경향이 있다. 

 

예시

- 시스템의 속도가 느려져 반응이 없거나 잘못된 응답을 반환하는 서비스

- CPU 시간, 메모리, 디스크 공간, 네트워크 대역폭처럼 공유 자원을 과도하게 사용하는 일부 프로세스

- 한 구성 요소의 작은 결함이 다른 구성 요소의 결함을 야기하고 차례로 더 많은 결함이 발생하는 연쇄 장애

 

이 같은 소프트웨어 결함을 유발하는 버그는 특정 상황에 의해 발생하기 전까지 오랫동안 나타나지 않는다. 소프트웨어의 체계적 오류 문제는 신속한 해결책이 없다. 시스템의 가정과 상호작용에 대해 주의 깊게 생각하기, 빈틈 없는 테스트, 프로세스 격리, 죽은 프로세스의 재시작 허용, 모니터링 등 여러 작은 일들이 문제 해결에 도움을 줄 수 있다. 시스템이 뭔가를 보장하길 기대한다면 수행 중에 이를 지속적으로 확인해 차이가 생길 경우 경고를 발생시킬 수 있다.

 

인적 오류

 

사람은 소프트웨어 시스템을 설계하고 구축하며, 운영자로서 시스템을 계속 운영한다. 이들이 최선의 의도를 갖고 있어도 서비스의 대부분의 원인은 휴먼 에러로 알려져 있으며, 하드웨어 결함은 휴먼 에러의 10%~25% 정도에 그친다.

 

휴먼 에러를 막기 위해서는 다양한 접근 방식이 필요하다.

 

- 오류의 가능성을 최소화하는 방향으로 시스템을 설계하라. 

- 사람이 가장 많이 실수하는 부분에서 사람의 실수로 장애가 발생할 수 있는 부분을 분리하라.( 테스트 환경 제공 )

- 장애 발생의 영향을 최소화하기 위해 인적 오류를 빠르고 쉽게 복구할 수 있게 하라. (롤백/롤아웃에 대한 대비)

- 성능 지표와 오류율 같은 상세하고 명확한 모니터링 대책을 마련하라.