[TIL] 데이터 중심 어플리케이션 설계 - ASSIGNMENT01

ksage91·2022년 3월 8일
1

오늘 읽은 범위

서문, Part 1 - 01장의 신뢰성까지 ~ p.10

요약 - 기억할 내용

서문 - 이 책을 활용하기 위한 방법을 알 수 있으므로 다소 길게 적는다.

역자 서문에서

구슬이 서 말이라도 꿰어야 보배 - 데이터는 잘 다듬고 정리해야 가치가 생긴다.
저자는 이 책에서 우리에게 구슬을 잘 꿰는 방법을 우리에게 알려준다.
새로운 기술들은 데이터 처리 기술을 기반이 된다.
대용량 분산 데이터 처리 솔루션은 성숙 단계에 접어들었으나 개발자의 불안감은 전혀 줄지 않았다.
이 불안감을 해소하는데 이 책이 큰 도움이 됐다.

머리말에서

데이터가 주요 도전 과제인 경우 데이터 중심적 CPU 사이클이 병목인 경우 계산 중심적이라 표현한다.
데이터 중심적 애플리케이션은 여러 기술의 조합으로 목표를 달성할 수 있다.
소프트웨어 엔지니어로서 해당 기술들의 트레이드오프를 올바르고 정확하게 이해해야한다.
급격한 기술 변화에도 변하지 않는 원리가 있다.
이 책은 데이터 저장과 처리 기술 분야를 탐험하고 특정 목적에 어떤 기술이 적합한지 결정하는 능력과
도구를 조합하는 방법을 이해하는 능력이 생긴다.

대상 독자

웹 애플리케이션의 백엔드를 개발하는 사람
RDBMS와 SQL에 익숙한 사람
수백만 명의 사용자를 감당할 수 있는 시스템을 만들고 싶은 사람
HA를 갖추고 확장성과 유지보수성이 뛰어난 시스템을 만드는 방법을 알고 싶은 사람
사물의 동작 방식에 호기심이 있는 사람 - ISTP?

이 책에서 다루는 내용

데이터 시스템 아키텍처와 데이터 중심적 애플리케이션으로 데이터 시스템을 통합하는 방법을 주로 다룬다.

이 책의 개요

  1. 1부는 데이터 중심 애플리케이션 설계를 뒷받침하는 근본 개념을 설명
    • 1장 신뢰성(reliability), 확장성(scalability), 유지보수성(maintainability)
    • 2장 여러 데이터 모델과 질의 언어 비교 & 상황에 따른 사용법
    • 3장 저장 엔진 - 데이터 효휼화를 위해 데이터 베이스가 데이터를 어떻게 배치하는지
    • 4장 데이터 부호화(직렬화 serialization)의 형식과 시간의 흐름에 따라 스키마를 발전시키는 방법
  2. 2부는 여러 장비에 분산 저장하는 데이터를 설명
    • 5장 복제(replication)
    • 6장 파티셔닝/샤딩(partitioning/sharding)
    • 7장 트랜잭션(transaction)
    • 8장 분산 시스템에서 발생하는 문제
    • 9장 분산 시스템에서 일관성(consistency)을 달성하고 합의(consensus)에 도달하는 것이 무엇을 의미하는지
  3. 3부는 특정 데이터셋에서 다른 데이터셋을 파생하는 시스템을 설명
    • 10장 데이터를 파생하는 일괄 처리 접근법
    • 11장 스트림 처리로 데이터를 파생하는 방법
    • 12장 책의 모든 내용을 종합하여 미래에 신뢰할 수 있고 확장 가능하며 유지보수하기 쉬운 애플리케이션을 구축하는 접근법

표지 설명

  • 인도 멧돼지
  • 오라일리 표지에 나온 동물 다수가 멸종 위기에 있다.
    이 동물 모두는 세상에 매우 중요한 존재다.

Part 1 데이터 시스템의 기초 - 01장 신뢰할 수 있고 확장 가능하며 유지보수하기 쉬운 애플리케이션

아름다운 이상향

  • 오늘날 많은 애플리케이션은 데이터 중심적이다.
    • 데이터를 저장(데이터베이스)
    • 읽기 속도 향상을 위해 값비싼 수행 결과를 기억(캐시)
    • 키워드 검색, 필터링(검색 색인)
    • 느슨한 비동기 처리를 위해 다른 프로세스로 메시지 보내기(스트림 처리)
    • 주기적 대량의 누적된 데이터를 분석(일괄 분석)
  • 애플리케이션을 만들 때 어떤 도구와 어떤 접근 방식이 수행 중인 작업에 가장 적합한지 생각해야한다.

데이터 시스템에 대한 생각

  • 왜 DB, 큐, 캐시 등을 데이터 시스템이라는 포괄적 용어로 묶는가 - Why?
    • 데이터 저장 & 처리 도구들은 최근에 만들어졌고
      새로운 도구들은 다양한 사례에 최적화 되어 분류간 경계가 흐려지고 있다.
    • 애플리케이션이 단일 도구로는 요구사항을 충족시킬 수 없다.
      작업은 단일 도구에서 효율적으로 수행하도록 태스크로 나누고 도구들은 애플리케이션 코드를 이용해 서로 연결한다.
    • 이제부터 개발자는 애플리케이션 개발자뿐만 아니라 데이터 시스템 설계자이기도 하다.
  • 소프트웨어 시스템에서의 3가지 중점
    • 신뢰성(reliability)
      • 하드웨어나 소프트웨어 결함, 심지어 휴먼 에러 같은 역경에도 지속적으로 올바르게 동작해야한다.
    • 확장성(scalability)
      • 데이터 양, 트래픽 양, 복잡도가 증가하면서 이를 처리할 수 있는 적절한 방법이 있어야한다.
    • 유지보수성(maintainability)
      • 모든 사용자가 시스템 상에서 생산적으로 작업할 수 있게 해야한다.

신뢰성

소프트웨어에 대한 기대치 - 대략 무언가 잘못되더라도 지속적으로 올바르게 동작함 == 신뢰성

  • 애플리케이션은 사용자가 기대한 기능을 수행
  • 시스템은 사용자가 범한 실수나 예상치 못한 사용법을 허용
  • 시스템 성능은 예상된 부하와 데이터 양에서 필수적인 사용사례를 충분히 만족
  • 시스템은 허가되지 않은 접근과 오남용을 방지

결함을 예측하고 대처할 수 있는 시스템을 내결함성, 탄력성을 지녔다고 함
결함은 장애와 동일하지 않다.
결함은 사양에서 벗어난 시스템의 한 구성요소이나 장애는 서비스를 제공하지 못하고 시스템 전체가 멈춘 경우다.
결함에 의해 장애가 발생하지 않게끔 내결함성 구조를 설계하는 것이 가장 좋다.
고의적으로 결함을 유도해서 내결함성 시스템을 지속적으로 훈련하고 테스트하여
자신감을 높이는 방법으로 넷플릭스의 카오스 몽키가 있다.

하드웨어 결함

하드웨어 결함은 주로 중속을 추가하는 방법이 일반적이다. - HDD RAID 구성 등
장애가 발생하는 것을 완전히 막을 수 없으나 이해하기 쉽고 수년간 장비가 중단되지 않고 계속 동작할 수 있게 한다.
클라우드 플랫폼은 가상 장비 인스턴스가 갑자기 사용할 수 없게 되는 상황이 상당히 일반적이다.
클라우드는 단일 장비 신뢰성보다 유연성과 탄력성을 우선적으로 처리하게끔 설계됐기 때문에
소프트웨어 내결함성 기술을 사용하거나 하드웨어 중복성을 추가해 견딜 수 있는 시스템을 많이 사용하고 있다.
이런 시스템은 운영상 무중단 배포등의 운영상 장점이 있다.

소프트웨어 오류

  • 시스템 내 체계적 오류
    • 특정 입력이 있을 때 모든 애플리케이션 서버 인스턴스가 죽는 소프트웨어 버그
      ex) 리눅스 커널 버그 - 2012-06-30 윤초
    • 공유 자원을 과도하게 사용하는 일부 프로세스
    • 속도가 느려져 반응이 없거나 잘못된 응답을 반환하는 서비스
    • 연쇄 장애

이런 버그는 특정 상황에 의해 발생하기 전까지 오랫동안 나타나지 않는다.
체계적 오류 문제는 신속한 해결책이 없다.
시스템의 가정과 상호작용에 대해 주의 깊게 생각하기,
빈틈 없는 테스트, 프로세스 격리, 죽은 프로세스의 재시작 허용,
프로덕션 환경에서 시스템 동작의 측정, 모니터링, 분석하기와 같은 여러 작은 일들이 문제 해결에 도움을 줄 수 있다.

인적 오류

다양한 접근 방식을 결합한다.

  • 오류 가능성을 최소화하는 설계
    추상화, API, 관리 인터페이스를 사용하면 옳은 일은 쉽게 하고 잘못 된 일은 막을 수 있다.
  • 사람이 가장 많이 실수하는 부분에서 장애 가능 부분을 분리하라 - 비 프로덕션 샌드박스 제공
  • 단위 테스트, 전체 시스템 통합 테스트, 수동 테스트까지 모든 수준에서 철저하게 테스트하라.
  • 장애 발생의 영향을 최소화하기 위해 쉬운 복구(빠른 롤백, 새로운 코드를 서서히 롤아웃)와
    데이터 재계산 도구 제공
  • 성능 지표와 오류율 같은 상세하고 명확한 모니터링을 대책 마련한다.
    문제 발생시 지표는 문제 분석에 매우 중요하다.
  • 조작 교육과 실습을 시행하라.

신뢰성은 얼마나 중요할까

비즈니스 애플리케이션에서 버그는 생산성 저하의 원인이고
이커머스 사이트의 중단은 매출 손실이며 브랜드 가치에 타격을 주므로 비싸다.
애플리케이션은 사용자에 대한 책임이 있다.
MVP를 개발하는 비용을 줄이려 신뢰성을 희생해야하는 상황도 있을 수 있으나
이 경우 비용을 줄여야하는 시점을 매우 잘 알고 있어야한다.

확장성

확장성은 증가한 부하에 대처하는 시스템 능력을 설명하는 용어지만 확장 가능 여부의 일차원적인 표식이 아니다.
"시스템이 특정 방식으로 커지면 이에 대처하기 위한 선택은 무엇인가?"와
"추가 부하를 다루기 위해 컴퓨팅 자원을 어떻게 투입할 것인가?" 같은 질문을 고려한다는 의미다.

부하 기술하기

시스템의 현재 부하를 간결하게 기술해야 한다. 그래야 부하 성장 질문을 논의 가능하다.
부하는 부하 매개변수로 나타낼 수 있는데 웹 서버의 초당 요청 수, 데이터베이스의 읽기:쓰기 비율,
액티브 유저, 캐시 적중률 등이 될 수 있다.
트위터를 예로 들자면

  • 트윗 작성 기능
    사용자는 팔로워에게 새로운 메시지를 게시 - 평균 초당 4.6k 요청, 피크 시 12k 이상 요청

  • 홈 타임라인 기능
    사용자는 팔로우한 사람이 작성한 트윗을 조회 - 초당 300k 요청

단순 초당 1.2만건의 쓰기는 쉽지만 트위터의 경우 확장성 문제는 fan-out에 있다.
이 두 가지 기능을 구현하는 방법은 크게 두 가지다

  1. 트윗 작성은 간단히 새로운 트윗을 트윗 전역 컬렉션에 삽입하고
    사용자가 홈 타임라인을 요청하면 팔로우하는 모든 사람의 모든 트윗을 찾아 시간순으로 정렬해서 합친다.

     # 홈 타임라인 조회 SQL
     SElECT tweets.*. users.* FROM tweets
     	JOIN users ON tweets.sender id = users.id
     	JOIN follows ON follows.followee id = users.id
     	WHERE follows.follower_id = current_user
  2. 수신 사용자용 트윗 우편함처럼 개별 사용자의 홈 타임라인 캐시를 유지하고
    사용자가 트윗을 작성하면 해당 사용자를 팔로우하는 사람을 모두 찾아 각자의 캐시에 새로운 트윗을 삽입한다.
    그러면 타임라인 읽기 요청은 결과를 미리 계산해서 비용이 저렴하다.

트위터 예시 그림

평균적으로 트윗 게시 요청량이 타임라인 읽기 요청량 보다 수백배 적으므로 접근 방식 2가 훨씬 잘 동작한다.
그러나 접근 방식 2의 문제는 트윗 작성 기능 자체에 많은 부가 작업이 필요하다는 것이다.
팔로워가 3천만인 사용자가 트윗을 작성했을 경우 타임라인에 3천만건의 쓰기 요청이 필요해진다.
트위터는 사용자당 팔로워의 분포가 팬아웃 부하를 결정짓기 때문에 확장성을 논의할 때 핵심 부하 매개변수가 된다.

트위터는 접근 방식 1에서 2로 변경하였다가 최종적으로 두 접근 방식을 혼합해서 사용하고 있다.
팔로워가 매우 많은 사용자는 팬아웃에서 제외되고
사용자가 팔로우한 유명인의 트윗은 별도로 조회해서 타임라인에 합친다.

성능 기술하기

시스템 부하를 기술하면 부하 증가 시 어떤 일이 일어나는지 조사할 수 있다.

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

두 질문 모두 성능 수치가 필요하다.
일괄 처리 시스템은 보통 처리량을 중점으로 보고 온라인 시스템에서는 서비스 응답 시간에 중점을 둔다.

지연시간(latency)과 응답 시간(response time)
종종 같은 뜻으로 사용하지만 동일한 개념은 아니다.

응답 시간: 클라이언트 관점에서 요청을 처리하는 실제 시간 외 네트워크, 큐 지연등을 포함
지연 시간: 요청이 처리되길 기다리는 시간으로 서비스를 기다리며 휴지 상태인 시간

응답 시간은 단일 숫자가 아니라 측정 가능한 값의 분포라고 생각해야한다.
대부분의 요청은 꽤 빠르지만 여러가지 이유로 가끔 꽤 오래걸리는 특이 값이 있다.
모니터링 시 평균 응답 시간 보다 백분위의 중앙값(50분위, p50)을 사용하는 것이 좋다.
특이 값이 얼마나 안좋은지 알기 위해선 상위 백분위를 보면 된다.
p95, p99, p999가 일반적이고 각각이 특정 기준치보다
더 빠르면 그 특정 기준칙가 백분위 응답 시간 기준치가 된다.

꼬리 지연 시간(tail latency)로 알려진 상위 백분위 응답시간은 서비스의 UX에 직접 영향을 주므로 중요하다.
꼬리 지연 시간에 포함된 고객들은 보통 구매를 많이한 중요한 고객이다.
이 중요 고객들에게 빠른 서비스를 제공하는 것이 중요하다.
아마존은 응답 시간이 100ms 증가하면 판매량이 1% 줄어들고
1초가 느려지면 고객 만족도가 16% 줄어드는 현상을 관찰했다.
반면 99.99분위를 최적화하는 작업은 비용이 너무 많이 들지만 실효성이 없다.

큐 대기 지연은 상위 백분위 응답시간에 많이 포함 된다. 이 현상을 선두 차단이라고 한다.
이전 요청이 완료되길 기다리는 시간 때문에 클라이언트 입장에서는 전체적으로 응답 시간이 느리다고 생각하게 된다.
그래서 클라이언트 쪽 응답시간 측정이 중요하다.
부하 테스트를 진행하는 경우 클라이언트는 응답 시간과 독립적으로 요청을 지속적으로 보내야한다.
그렇지 않으면 대기시간이 짧아져서 평가가 왜곡된다.

부하 대응 접근 방식

  • 용량 확장(scaling up) - 수직 확장(vertical scaling) - 더 강력한 장비로 이동
  • 규모 확장(scaling out) - 수평 확장 (horizontal scaling) - 다수의 낮은 사양 장비에 부하를 분산
    다수의 장비에 부하를 분산하는 아키텍처를 비공유 아키텍처라 한다.
    현실적으로 좋은 아키텍처는 실용적인 접근 방식의 조합이 필요하다.
    (적당한 사양의 장비를 적당한 갯수로 조합)

탄력적(elastic)으로 부하 증가를 감지하면 컴퓨팅 자원을 자동으로 추가하는 시스템과
수동으로 추가해야하는 시스템이 있다.
탄력적인 시스템은 부하가 예측할 수 없을 만큼 높아지는 경우 유용하지만
수동 확장 시스템이 더 간단하고 예상치 못한 일이 더 적다.
모든 상황에 맞는 마법의 확장 소스는 존재하지 않는다.

아키텍처를 결정하는 요소는 읽기의 양, 쓰기의 양, 저장할 데이터의 양, 데이터의 복잡도, 응답 시간 요구사항, 접근 패턴등 다양하다.
1kb 초당 10만건의 요청 처리 시스템과 2GB 분당 3건의 요청을 처리 시스템은 같은 데이터 처리량이라 해도 완전 다르다.
그래서 가정을 잘해야하고 가정은 곧 부하 매개변수가 된다. 이 가정이 잘못되면 역효과를 낳는다.
초기 단계나 검증되지 않은 제품의 경우 미래 확장을 대비하기 보다 빠르게 반복해서 제품 기능을 개선하는 작업이 더 중요하다.

유지보수성

  • 운용성(operability)
    운영팀이 시스템을 원홀년꺼| 운영할수 있게 쉽게 만들어라

  • 단순성(simplicity)
    시스템에서 복잡도를 최대한 제거해 새로운 엔지니어가 시스템을 이해하기 쉽게 만들어라
    사용자 인터퍼 이스의 단순성과는 다르다는점에유의하라

  • 발전성( evolvability)
    엔지니어가 이후에 시스템을 쉽게 변경할 수 있게 하라.
    그래야 요구사항 변경 같은 예기치 않은 사용 사례를 적용하기가 쉽다.
    이 속성은 유연성(extensibility), 수정 가능성(modifiability), 적응성(plasticity)으로 알려져 있다.

느낀점

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

위 그림에 대응되는 기술들을 빨간 글씨로 써보면서
그동안 개발을 하면서 그냥 당연하게 사용하던 기술들이 01장에 잘 정리되어있다는 생각이 들었다.
현재 개발하는 제품에 대해 어떤 기술을 어떻게 도입하는게
과연 맞을까에 대한 질문을 스스로 끊임없이 하고 있었는데 (특히나 트레이드오프에 대해서)
좋은 영향을 주는 책을 만난 것 같다.

작년 12월에 오픈 베타중인 서비스의 유저들의 외부 API 접근 KEY를 전면 교체해야할 일이 있었는데
인적 오류를 최소화 하기 위해서 실행 코드를 2주간 짜고 2주간 리허설을 진행했던 것이 생각났다.
실행 코드 만큼이나 많은 테스트 코드를 작성하고 실제로 전면 교체하는 날의 상황을 시나리오를 작성해서
시뮬레이션하고 페어 프로그래밍과 코드 리뷰를 받으면서 준비했던 기간이었는데
샌드박스, 테스트, 조작 교육과 실습 실행 등의 인적 오류에 대한 내용이 녹아들어가 있었다.

궁금하거나 잘 이해가 되지 않는 내용

궁금한 내용
리눅스 커널의 2012년 6월 30일 윤초 버그

잘 이해가 되지 않는 내용

약간 번역서 특유의 장황한 설명이 와닿지 않는 경우가 있었던 것 같다.
p.9 - '일종의 가정이 있다는 사실'에 대한 문장 같은 것들

profile
좋은 서비스를 만드는 회사를 위하여!

0개의 댓글