데이터 중심 애플리케이션 설계 1장 정리

백종현·2023년 7월 16일
0

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

개요

오늘날의 대부분의 애플리케이션이 계산 중심이 아니라, 데이터 중심적이다. CPU 성능보다 더 중요한 부분은 어느 곳에 데이터를 저장할 것인지, 데이터의 양은 얼마인지, 데이터가 얼마나 복잡하고 변화하는지이다. 최근 애플리케이션은 데이터베이스(MySQL, Oracle), 캐시(Redis, Memcached), 검색 색인(ElasticSearch), 스트림 처리(Apache Kafka), 일괄 처리 (Hadoop)와 같은 시스템을 요구한다.

데이터 시스템에 대한 생각

데이터베이스, 큐, 캐시 등은 데이터 시스템이라는 포괄적 용어로 묶어야하는 이유가 무엇일까?
1. 데이터 저장과 처리에 대한 여러 도구는 최근에 만들어졌고, 각 쓰임새에 따라 전통적인 분류에 맞지 않는다. 따라서 분류 간의 경계가 흐려지고 있다.
2. 이제 단일의 도구를 통해서 데이터 처리와 저장 모두를 만족하기 쉽지 않다. 작업을 위해서 단일 도구를 사용하는 것이 아닌, 각 테스크를 나눠 다양한 도구들을 통합해 연결하는 방식을 많이 사용한다.

또한 이러한 부분을 통합하기 위해서는 애플리케이션 단의 코드 구현을 통해 진행해야하고, 최근 개발자들은 애플리케이션 개발자 뿐만이 아닌, 데이터 시스템 설계자의 역할도 수행하게 된다.

소프트웨어 시스템 관심사

소프트웨어에 시스템에서 중요하게 여기는 관심사는 3가지로 분류된다.
1. 신뢰성
2. 확장성
3. 유지보수성

신뢰성

신뢰성의 일반적인 기대치는 아래와 같다.

  • 애플리케이션은 기대한 기능을 수행한다.
  • 시스템은 사용자의 실수나 결함에 대해 대응이 가능하다.
  • 시스템 성능은 예상된 부하와 데이터 양에서 필수적인 사용 사례를 만족한다.
  • 시스템은 허가되지 않은 접근과 오남용을 방지한다.

즉 정리하자면, "무언가 잘못되더라도 지속적으로 올바르게 동작함"을 의미한다.
잘못될 수 있는 일을 결함이라고 부르며, 이를 예측하고 대처할 수 있는 시스템을 내결함성 또는 탄력성을 지녔다고 말한다.

하드웨어 결함

하드웨어 장치의 장애를 의미한다.
이를 해결하는 방법들은 아래와 같다.

  • 디스크 RAID 구성
  • 서버 이중전원 디바이스, hot-swap가능한 CPU
  • 하나가 죽으면 교체되는동안 중복된 구성요소를 대신 사용

최근에는 데이터 양, 계산량 증가 → 더 많은 수의 장비 → 하드웨어 결함율 증가
AWS 같은 클라우드 플랫폼은 단일 장비 신뢰성보다 유연성, 탄력성을 우선 처리.
→ 소프트웨어 내결함성 기술 사용하거나, 하드웨어 중복성을 추가해 전체 장비의 손실을 견딜 수 있는 시스템으로 옮겨가는 추세.

소프트웨어 오류

"체계적 오류"
무작위적이고 서로 독립적인 하드웨어 결함과 달리, 노드간 상관관계 때문에 발생하는 오류. 시스템 오류를 더욱 많이 유발
아래는 소프트웨어 오류의 예시이다.

  • 리눅스 커널 버그 - 2012년 6월 30일 윤초
  • CPU 시간 / 메모리 / 디스크 등 공유자원을 과도하게 사용하는 일부 프로세스
  • 시스템의 속도가 느려져 반응이 없거나 잘못된 응답을 반환하는 서비스
  • 하나 요소의 결함이 다른 구성 요소의 결함을 야기하고 또 다른 결함을 야기하는 연쇄 장애

테스트, 프로세스 격리, 시스템 가정 및 상호작용에 대해 깊게 생각하기, 시스템 모니터링 및 분석, 프로세스 재시작 등 해결해야한다.

인적 오류

인적 오류를 최소화할 수 있는 설계

  • 오류의 가능성을 최소화하는 방향으로 시스템을 설계하라. 잘 설계된 추상화, API, 관리 인터페이스를 사용하자.
  • 실제 데이터를 볼 수 있지만 사용자에게는 영향이 없는 비-production 환경의 샌드박스를 제공하라. (테스트 환경을 의미)
  • 단위 테스트, 전체 시스템 통합 테스트, 수동 테스트까지 모든 수준에서 철저히 테스트하라.
  • 설정 변경은 빠르게 롤백 가능하게, 새로운 코드는 서서히 롤 아웃
  • 성능 지표와 오류 모니터링
  • 조작 교육과 실습

확장성

부하 증가에도 안정적으로 동작할 수 있는가

확장성은 있다/없다 가 아니라, '특정 방식으로 시스템이 커지면 어떻게 대처할까', '추가 부하를 다루기 위해 자원을 어떻게 투입할까'를 고민하는 문제.

부하 기술하기

부하를 기술할 수 있어야 부하 성장(부하가 많아질 떄 어떻게 될지)에 대해 논의할 수 있다. 부하는 부하 매개변수를 통해 나타낼 수 있다.

부하 매개변수의 예

  • 웹 서버의 초당 요청 수
  • DB의 읽기/쓰기 비율
  • 대화방의 동시 활성 사용자
  • 캐시 적중률

부하 매개변수의 평균이 중요할 수도, 소수의 극단적 케이스가 병목현상의 원인일 수 있다.

이를 트위터의 예로 설명해보자.

개별 사용자가 트윗 작성을 하면 많은 팔로워들의 타임라인에 함께 들어가야 함. - fan-out (하나의 수신 요청을 처리하는 데 필요한 다른 서비스의 요청 수)
어떻게 해결? (1→ 2→ 3으로 발전함)

  • 트윗 작성은 새로운 트윗을 전역 컬렉션에 삽입한다. 홈 타임라인 read를 요청하면 팔로우하는 모든 사람을 찾고, 그 사람들의 모든 트윗을 찾아 시간순 정렬해서 merge. → 읽기 시점에 비용이 큼.
  • 각 사용자 별로 타임라인 캐시를 유지한다. 사용자가 트윗을 작성하면 해당 사용자의 팔로워를 찾아서 캐시에 새로운 트윗을 삽입 → 쓰기시점에 미리 계산하여 읽기 시점의 계산량을 줄임 (읽기 요청량에 비해 쓰기 요청량이 적으므로 합리적)
  • hybrid: 대부분 2번처럼 홈 타임라인에 넣어주지만, 팔로워 수가 매우 많은 사용자는 팬 아웃에서 제외하고 별도로 가져와 읽는 시점에 사용자의 홈 타임라인에 합치기 → 팔로워 수가 많으면 단일 쓰기가 과한 작업이 되어서 선택

성능 기술하기

  • 부하 매개변수를 증가시켰을 때 성능은 얼마나 영향을 받을까?
  • 성능이 유지되길 원하면 자원을 얼마나 많이 늘려야할까?

위 질문은 모두 성능 수치가 필요하다. 시스템 성능에 대해 알아보자.

일괄 처리 시스템 - 처리량(throughput) : 초당 처리할 수 있는 레코드 수/데이터집합. 작업 수행에 걸리는 전체 시간을 중요하게 여긴다.
온라인 시스템 - response time : 클라이언트가 요청을 보내고 응답을 받는 사이의 시간을 중요하게 여긴다.

  • 응답 시간은 동일한 요청에도 매번 다르므로, 단일 숫자가 아닌 측정 가능한 값의 분포 로 생각해야함
  • 산술 평균은 좋은 지표가 아니다. 얼마나 많은 사용자가 실제로 지연을 경험했는지가 중요.
  • 백분위와 중앙값(median) 사용이 적절함
  • 가장 빠른 시간부터 가장 느린 시간까지 정렬.
  • 사용자 요청의 절반은 중앙값보다 오래 걸린다.
  • 상위 백분위 응답시간(tail latency) 으로 특이 값(outlier)이 얼마나 안좋은지 판단

부하 대응 접근 방식

  • Scale up (용량 확장, 수직 확장)

  • Scale out (규모 확장, 수평 확장)
    실용적인 접근방식의 조합이 필요하다.

  • 다수의 장비에 분산하는 것이, 고사양 장비를 사용하는 것보다 저렴하다.

  • 다수의 장비에 부하를 분산하는 아키텍처를 비공유 아키텍쳐라고 부른다.

  • 최근에 분산 시스템을 위한 도구(auto scaling), 추상화가 좋아져서 통념이 바뀌고 있음. 부하 증가를 감지하면, 컴퓨팅 자원을 자동으로 추가해주는 탄력적 시스템은 부하 예측이 어려울 경우 유용하나, 수동으로 확장하는 시스템이 더 간단하고 운영상 예상치 못한 일이 더 적음.

  • 범용적이고 모든 상황에 맞는 만병통치약 같은 확장 아키텍처는 없다.

  • 아키텍처를 결정하는 요소들

    • 읽기, 쓰기 양
    • 저장할 데이터 양
    • 데이터 복잡도
    • 응답시간 요구사항
  • 주요 동작이 무엇이고, 잘 하지 않는 동작이 무엇인지에 대한 가정이 어떤 아키텍처를 갖출 것이냐에 매우 중요

유지보수성

  • 유지보수의 고통을 줄이고 레거시를 만들지 않게 설계하자

운용성: 운영의 편리함 만들기

  • 동일하게 반복되는 태스크를 쉽게 수행하도록 해서, 운영팀이 더 부가가치 높은 일에 노력을 집중할 수 있게 하자.
  • 모니터링
  • 자동화와 통합을 위한 도구
  • 개별장비 의존성x. 유지보수를 위해 장비를 내리더라도 시스템에 영향 없게
  • 문서, 이해가 쉬운 운영모델

단순성: 복잡도 관리

우발적인 복잡도 제거를 위해 좋은 추상화를.
ex. 고수준 프로그래밍언어는 기계어, CPU레지스터, 시스템 호출을 숨김

발전성: 변화를 쉽게 만들기

  • 요구사항은 끊임없이 발전한다.
  • 애자일
  • TDD
  • refactoring
  • 간단하고 이해하기 쉬운 시스템을 만들기

출처 : https://www.myanglog.com/%EB%8D%B0%EC%9D%B4%ED%84%B0%20%EC%A4%91%EC%8B%AC%20%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98%20%EC%84%A4%EA%B3%84%201%EC%9E%A5%20%EC%A0%95%EB%A6%AC

profile
노력하는 사람

0개의 댓글