본문 바로가기

SearchDeveloper/데이터 중심 애플리케이션 설계

[1] 데이터를 중심으로 하는 애플리케이션은 어떤 걸 생각해봐야할까?

데이터 중심 애플리케이션은 어떤 기능을 공통으로 필요할까?

  • 데이터베이스 : 나중에 다시 데이터를 찾을 수 있도록 저장
  • 캐시: 읽기 속도 향상을 위해 값이 비싼 수행 결과를 기억
  • 검색 색인: 사용자가 데이터를 검색할 수 있는 기능 제공
  • 스트림 처리: 비동기 처리를 위해 다른 프로세스로 메시지 보내기
  • 일괄 처리: 주기적으로 대량의 데이터 분석

신뢰성, 확장성, 유지보수성

대부분의 소프트웨어 시스템은 신뢰성, 확장성, 유지보수성에 관심이 많다.

엔지니어링 관점에서 이 3가지를 어떻게 생각해야하는지 알려주겠다. (다음 장에서는 이를 잘 지키기위한 방법에 대해 말할 것이다.)

신뢰성

: 무언가 잘못되더라도 지속적으로 올바르게 동작해야한다.

올바르게 동작해야한다는 것은?

  • 사용자가 기대한 기능을 수행해야 한다.
  • 사용자의 실수나 예상치 못한 사용법을 허용할 수 있다.
  • 예상된 부하나 데이터 양에서 충분히 동작해야 한다.
  • 비허가 접근과 오남용을 방지해야 한다.

신뢰성을 높이기 위해서는?

1. 결함으로 인한 장애를 최소화하자

  • 결함은 잘못될 수 있는 일을 말하고, 장애는 필요한 서비스를 제공하지 못하고 시스템이 멈춘 경우이다.
  • 결함이 장애로 이어지지 않도록 내결함성 구조를 설계하자 (이 책에서 알려주겠다)

2. 결함을 예측하고 대처할 수 있는 내결함성(fault-tolerant) or 탄력성(resilient) 을 갖추자

  • 일부러 결함을 발생시키는 훈련과 테스트(ex. 카오스 몽키) 를 하자
  • 보안이 뚫려 개인정보가 털린다면 해결책이 없는 결함이다. (이 책에서는 해결책이 있는 결함 유형을 다루겠다.)

결함의 종류는?

1.하드웨어 결함

: 하드디스크 고장, 램 결함, 정전, 네트워크 케이블 뽑기

이 결함을 대응하는 방법

  • 중복(redundancy) 구축 - 하나가 죽으면 교체될 수 있도록
    • 디스크 RAID 구성, 이중 전원 디바이스, 핫 스왑 가능한 cpu, 예비 건전지

2. 소프트웨어 오류

: 시스템 내 체계적 오류 (systematic error)

※ 비체계적 오류: 무작위 오류

어떤 오류가 sw 오류일까?

  • 잘못된 특정 입력이 있을 때 죽는 버그
  • 공유 자원(cpu시간, 메모리, 디스크, 네트워크 대역폭) 을 과도하게 사용하는 일부 프로세스
  • 시스템 속도가 느려져 반응이 없거나 잘못된 응답 반환
  • 작은 결함이 다른 결함을 야기해 차례차례 더 많은 결함이 발생되는 연쇄 장(cascading failure)

이 오류를 대응하는 방법

  • 빈틈없는 테스트, 프로세스 격리, 죽은 프로세스 재시작 허용, 프로덕션 환경에서 동작 측정, 모니터링

3. 인적 오류

: 운영자의 설정 오류가 중단의 주요 원인이라 한다. (하드웨어 결함은 10~25%)

이 오류를 대응하는 방법

  • 오류 가능성을 최소화할 수 있도록 설계
  • 프로덕션 환경에서 데이터 분석하지 않게 샌드박스를 제공하라
  • 철저하게 테스트하라
  • 성능지표, 오류율을 확인할 수 있는 명확한 모니터링을 구축하라
  • 조작 교육과 실습

신뢰성이 깨진다면...

: 버그로 인한 생산성 저하, 공식 자료 수치 잘못 전달 시 법적으로 위험, 매출 손실, 명성 타격

 

확장성

: 증가한 부하에 대처하는 시스템 능력

확장성을 논의한다는 의미는

  • 시스템이 커지면 어떻게 대처해야 할까?
  • 추가 부하를 다루기 휘애 계산 자원을 어떻게 투입할까?

부하 측정에 대해

: 부하 측정은 간결해야 한다. 그래야 "부하가 두 배면 얼마나 될까" 같은 부하 성장 질문에 답할 수 있다.

부하를 측정하는 종류 (load parameter, 부하 매개변수)

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

[예시] 부하에 대응한 트위터

행동 이벤트 종류

  • 트윗 작성하기 (초당 최대 12,000건)
  • 홈 타임라인 조회하기 (초당 30만 건)

작성한 트윗을 팔로워들의 홈 타임라인에 뜰 수 있게 하는 방법

  • 1번: 작성한 트윗은 db에 넣고 팔로워가 홈타임라인 요청시 트윗 조회 쿼리로 제공
  • 2번: 팔로워마다 홈 타임라인 캐시를 가지고 있음. 트윗 작성 시 각 팔로워 캐시에 삽입. 읽기 요청 결과를 캐시에 미리 담았기 때문에 저렴

→ 트윗 작성 이벤트 수가 홈 타임라인 조회 수 보다 작기 때문에 2번이 유리

하지만 2번도 단점이 있지

인플루언서는 팔로워가 3천만 명도 넘는데, 트윗 작성하면 3천 만번도 넘게 캐시 쓰기 작업이 일어나는게 굉장히 큰 부하이다

해결책은 하이브리드

팔로워 수가 많은 사용자는 1번으로, 나머지는 2번으로

성능 측정에 대해

부하가 증가할 때 필요한 정보는 성능이 얼마나 나올까이다. 성능 측정하는 방법이 필요하다

  • 부하를 늘리되 시스템 자원(cpu, 메모리, 네트워크 대역폭)은 그대로 두면 성능에 얼마나 영향을 줄까?
  • 부하를 늘리되 성능은 유지하려면 시스템 자원을 얼마나 늘려야 할까?

성능을 측정하는 종류

  • 처리량(throughput)
    • 하둡 같은 일괄 처리 시스템에서 사용
    • 초당 처리 가능한 레코드 수
    • 일정 크기의 데이터 집합으로 작업 수행 시 걸리는 전체 시간
  • 응답 시간(response time)
    • 온라인 시스템에서 사용
    • 클라이언트가 요청을 보내고 받기까지의 시간

※ 응답 시간: 클라 관점에서의 시간. 요청 처리하는 실제 시간 + 네트워크 / 큐 지연 시간

지연 시간(latency): 서비스를 기다리면 휴지 상태인 시간

 

응답 시간 측정에 대해

응답 시간 특징

  • 응답 시간은 같은 요청이라도 항상 다르기 때문에 단일 숫자가 아닌 값의 분포로 측정해야 한다.
  • 가끔씩 오래걸리는 특이값(outlier) 이 있다.
    • 이유: 컨텍스트 스위치, 네트워크 패킷 손실/TCP 재전송, 가비지 컬렉션, page fault(물리메모리에 데이터 없어서 가상메모리인 스왑 영역(디스크)에서 읽어옴), 서버 랙 진동

백분위(percentile)로 측정하자

  • 이유: 평균값은 별로다. 실제 사용자 경험을 알 수 없기 때문이다.
  • 중앙값(median)
    • 가장 빠른 시간부터 느린 시간까지 정렬한 후의 중간 지점.
    • ex. 중앙값이 200ms 면 반은 200보다 오래 걸리고 반은 짧게 걸린다.
    • 얼마나 오랫동안 기다려야 하는지 알고 싶다면 중앙값이 좋은 지표다
    • p50 이라고도 부른다.(=50분위)
  • 일반적인 상위 백분위값 (=꼬리 지연 시간(tail latency))
    • 95분위(p95)
      • p95=1.5초면? 100개 중 95개는 1.5초 미만, 나머지 5개는 1.5초 이상 걸림
    • 99분위(p99)
    • 99.9분위(p99.9)
  • 아마존 기준
    • 99.9 분위로 응답 시간 요구사항을 측정한다.
    • 응답 시간 0.1 초 느려지면 판매량 1% 감소, 1초 느려지면 16% 감소
  • 서비스 수준 협약서(Service Level Agreement)
    • 응답 시간 중앙값이 0.2 초 미만, 99분위가 1초 미만이면 정상 서비스 상태
    • 서비스 제공 시간은 99.9% 이상이어야함
    • 충족이 안되면 고객 환불 요구 가능

실전 백분위 테스트

  • 테스트 할 때 클라에서 지속적으로 요청해야 한다. 이전 요청이 완료되길 기다리는 시간 때문에 전체적인 응답 시간이 느려질 것이기 때문이다. (=꼬리 지연 중복 (tail latency amplification))

부하에 대응하는 방법

부하가 증가해도 좋은 성능을 유지하려면?

  • scale up (용량 확장, 수직 확장)
  • scale out(규모 확장, 수평 확장)

아키텍처를 결정하는 요소 (자세한건 책에서 설명해줄게)

  • 읽기 양, 쓰기 양, 데이터 양, 데이터 복잡도, 응답시간, 접근 패턴
  • ex. 크기가 1kb 인 초당 10만건의 요청 처리하는 시스템 vs. 크기가 2GB 인 분당3 건을 처리하는 시스템은 설계가 달라야 한다.

유지보수성

: 유지보수를 최소화하고 레거시 소프트웨어를 만들지 않게끔 설계할 수 있는 원칙 3가지

운용성

: 운영팀이 운영하게 쉽게 만들라

좋은 운영팀이 하는 일

  • 시스템 상태 모니터링, 좋지 않으면 빠른 복원
  • 장애, 성능 저하 원인 추적
  • 보안
  • 문제 생길 수 있는 변경 사항 사전 차단
  • 배포, 설정 관리 도구 마련

좋은 운영성이란 : 동일 반복 태스크를 쉽게 할 수 있는것

  • 런타임동작, 시스템 내부에 대한 모니터링으로 가시성 제공
  • 장비 하나 내려도 시스템 전체 영향 안 주도록 개별 의존성 회피
  • 적절한 자기 회복, 필요하면 관리자가 수동 제어 할 수 있도록
  • 예측 가능한 동작, 예기치 않은 사항 최소화

단순성

: 복잡한 건 최대한 제거 해 시스템을 이해하기 쉽게 만들기, 빠른 진행 속도 유지보수 최소화를 위해!

복잡함의 종류

  • 상태 공간 급증, 모듈 간 강한 커플링, 복잡한 의존성, 일관성 없는 명명, 임시 방편 문제 해결

대응하는 방법

  • 추상화를 잘 하자 (좋은 추상화는 책에서 자세하게 알려줄게)
    • 고수준 프로그밍 언어 - 기계어, cpu 레지스터, 시스템 호출을 숨김
    • SQL -디스크 기록, 메모리 저장, 데이터 구조, 동시 요청 해결 방법을 숨김

발전성

: 시스템 요구사항의 변화를 쉽게 할 수 있도록 하자

애자일 작업 패턴 (소규모)

  • TDD, 리팩토링개발

대규모 데이터 시스템에서의 발전성은 책에서 자세히 알려줄게

정리

애플리케이션을 신뢰할 수 있고 확장 가능하며 유지보수가 쉬운 간단한 해결책은 없다.

하지만 이를 만족할 수 있도록 계속 재현되는 특정 패턴과 기술이 있다.

그게 뭔지 책에서 알려줄게

 

레퍼런스

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