• 이 문서는 Designing Data Intensive Applications 책의 1장을 공부하며 메모한 것입니다.
  • 이 문서는 메모일 뿐이니 자세한 내용은 교재를 참고해야 합니다.

개요

옛날 애플리케이션들은 CPU 성능이 애플리케이션의 능력을 제한하는 중요한 요소였다. 따라서 계산 성능 중심적으로 설계되는 경향이 있었다.

그러나 오늘날의 많은 애플리케이션들은 데이터 중심적(data intensive)이다.

왜 이렇게 바뀌었는가? 데이터의 양, 데이터의 복잡도, 데이터의 변화 속도가 예전과 달라졌기 때문이다. 그에 따라 구현 요구사항은 과거에 비해 과도하고 광범위한 스펙을 갖게 되었다. 하나의 애플리케이션으로는 그러한 요구사항을 만족시키도록 만들기가 어렵다.

최근 시점에 한정된 이야기가 아니다. 우리는 이미 꽤 예전부터 하나의 도구로 시스템을 구축하지 않는다. DB, 캐시, 배치 처리 등 같은 추상적인 개념들을 구현한 다양한 도구를 검토하고 목적에 맞게 설정해 결합하는 방식으로 시스템을 구축하고 있다.

따라서 이제 개발자는 하나의 애플리케이션을 개발하는 개발자일 뿐 아니라, 데이터 시스템의 설계자로서의 정체성도 갖는다.

문제는 완벽한 시스템을 만드는 것이 불가능하다는 것이다. 그러므로 신뢰할 수 없는 부품들을 조합해 조금이라도 더 신뢰할 수 있는 시스템을 구축하는 것이 중요하다.

이 책은 다음의 관심사를 기준으로 신뢰할 수 있는 시스템을 구축하는 방법을 조사한다.

  • 신뢰성(Reliability)
  • 확장성(Extensibility)
  • 유지보수성(Maintainability)

신뢰성

어떻게 무언가 잘못되더라도 지속적으로 올바르게 동작하도록 만들 것인가?

데이터 양과 계산 요구가 늘어나면서 애플리케이션은 많은 수의 장비를 사용하게 됐다.

하드웨어 하나 하나는 못 믿는다

예를 들어 하드디스크의 평균 장애 시간(mean time to failure, MTTF)는 약 10~50년이다. 즉 디스크가 10000 개 있는 저장 클러스터는 평균적으로 하루에 디스크 한 개씩 죽는 셈이다.

따라서 하드웨어는 다중 장비 중복(redundancy) 방식으로 나아가게 됐다.

AWS도 못 믿는다

신뢰성보다 AWS 플랫폼은 단일 장비 신뢰성보다 유연성(flexability)과 탄력성(elasticity)을 우선적으로 처리하도록 설계됐다.

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

소프트웨어도 못 믿는다

문제를 예상하기 어렵고, 연쇄 장애도 가능하다.

그래서 빈틈없이 테스트하고, 프로세스 격리하고, 프로세스 죽으면 재시작하고, 모니터링하고, 경고가 발생하게 하는 등의 작업을 한다.

사람도 못 믿는다

보통 사람의 실수가 가장 흔한 오류 원인이다.

그러므로 철저하게 테스트하고, 사람이 실수하더라도 피해를 최소화하는 방향으로 설계하도록 하며, 착실하게 모니터링하도록 한다.

확장성

성능 저하를 유발하는 가장 흔한 이유는 부하 증가이다. 확장성은 증가한 부하에 대처하는 시스템 능력을 설명하는 데 사용하는 용어이다.

확장성을 논한다는 것은 다음과 같은 질문을 고려한다는 뜻이다.

  • "시스템이 특정 방식으로 커지면 이에 대처하기 위한 선택은 무엇인가?"
  • "추가 부하를 다루기 위해 계산 자원을 어떻게 투입할까?"

이러한 질문에 답변하려면 시스템 부하성능을 명확히 표현할 수 있어야 한다.

  • 부하를 설명할 수 없다면 부하가 증가할 때 어떤 일이 일어나는지에 대한 질문에 대답할 수 없다.
    • "부하가 2배가 되면 어떻게 되나?"

부하 기술

부하를 설명하기 위한 부하 매개변수(load parameter)로는 웹 서버의 초당 요청 수, DB의 read/write 비율, 동시 활성 사용자(active user), 캐시 적중률 등이 있다.

이것들을 사용해 부하를 설명할 수 있어야 하는데, 통계의 함정에 빠지지 않게 주의해야 한다. 예를 들어 어떤 경우엔 평균이 전혀 중요하지 않다. 극단적인 경우가 병목의 원인일 수 있다.

단순하게 보지 말고, 실제 시스템에서 일어나는 일을 기준으로 고려할 것.

트위터의 [[/pattern/fan-out]] 사례가 좋은 예시이다.

성능 기술

한편, 성능은 부하를 통해 기술할 수 있다.

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

throughput과 response time 문제는 여기에서도 유효하다.

일괄 처리 시스템이라면 부하 증가시 처리율(throughput)이 중요하고, 온라인 시스템이라면 서비스 응답 시간(response time)이 중요하다.

응답 시간에 대해 사용자가 얼마나 기다리는지 알고 싶다면 산술 평균을 쓰지 말고, 중앙값(p50) 등을 쓰도록 한다.

p50의 의미는 명백하다.

  • 사용자 요청의 절반은 중앙값 응답 시간보다 짧게 걸린다.
  • 사용자 요청의 절반은 중앙값 응답 시간보다 오래 걸린다.

이와 비슷한 방법으로 시스템의 목적에 따라 p95, p99, p999 등을 본다. 각각 95%, 99%, 99.9% 를 말한다.

이런 것들 중 최상위 백분위 응답 시간은 꼬리 지연 시간(tail latency)이라 부르는데, 아마존 같은 곳은 p999를 본다. 즉, 요청 1000개 중 가장 느린 1개의 요청을 본다. 왜냐하면 아마존의 특성상, 이런 요청들은 구매 이력이 많은 고객들의 조회 시간이기 때문이다.

부하 대응 접근 방법

크게 두 가지가 있다.

  • 용량 확장(scaling up), 수직 확장(vertical scaling): 좀 더 강력한 장비로 이동하는 것이라 생각하면 된다.
  • 규모 확장(scaling out), 수평 확장(horizontal scaling): 다수의 낮은 사양 장비에 부하를 분산하는 것을 말하곤 한다.

최고 성능을 고집하지 말고, 비용을 고려해서 상황에 따라 실용적으로 접근하는 것이 중요하다.

유지보수성

신뢰성, 확장성을 달성하기 위한 쉬운 해결책은 없다.

그러므로 운용성, 단순성, 발전성을 염두에 두고 시스템을 생각하자.

  • 운용성(operability): 운영하기 쉽게 만든다.
  • 단순성(simplicity): 복잡도를 최대한 제거한다.
  • 발전성(evolvability): 쉽게 변경할 수 있게 한다.
    • 유연성(extensibility)
    • 수정 가능성(modifiability)
    • 적응성(plasticity)

참고문헌

  • 데이터 중심 애플리케이션 설계 / 마틴 클레프만 저/정재부, 김영준, 이도경 역 / 위키북스 / 초판발행 2018년 04월 12일