프로그래밍/Backend

신뢰성 ( Reliability )

카카수(kakasoo) 2022. 6. 18. 23:00
반응형

데이터의 양, 복잡성, 변하는 속도 등 데이터가 주요 도전 과제인 애플리케이션을 데이터 중심적이라 한다.

NoSQL, RDB, message Queue, cache, index, 일괄처리 또는 스트림 처리 프레임워크 등,

애플리케이션은 데이터를 다루기 위한 많은 기술들을 조합해서 사용하는데,

이 기술들의 트레이드오프를 올바르고 정확하게 이해해야 한다.

다행히도 이런 기술들에는 변하지 않는 원리가 있다.

application 개발 방법 변천의 원동력

  1. 대기업들이 가진 엄청난 양의 데이터와 트래픽을 다루기 위한 효과적인 도구 필요
  2. Lean하게, 적은 노력으로 가설을 테스트하고 시장을 빠르게 검증할 필요
  3. CPU의 병렬 처리 ( 멀티코어 ) 성능 향상과 고성능 네트워크
  4. AWS 같은 IaaS 덕택에 소규모 팀도 쉽게 이용 가능
  5. 유저들이 고가용성을 요구 ( 정전 등의 사태에서도 서비스를 이용가능하길 원함 )

 

1장. 신뢰, 확장가능, 유지보수하기 쉬운.

신뢰성(reliability), 확장성(scalability), 유지보수성(maintainability) 의 의미와 달성하기 위해 할 일.

 

인터넷은 잘 동작하고 있어서 대부분의 사람들은 인공의 무언가라기보다 태평양 같은 천연 자원으로 생각한다. 이런 규모의 기술이 이토록 오류가 없었던 적은 언제가 마지막일까? - 앨런 케이

 

오늘날 많은 애플리케이션은 계산 중심보다는 데이터 중심적이다.

  • 구동 애플리케이션이나 다른 애플리케이션이 나중에 데이터를 다시 찾을 수 있도록 저장 ( 데이터베이스 )
  • 읽기 속도를 향상시키기 위해 값비싼 수행 결과를 미리 기억해둠 ( 캐시 )
  • 사용자가 키워드로 데이터를 검색하거나 다양한 방법으로 필터링할 수 있도록 제공 ( 검색 색인 )
  • 비동기 처리를 위해 다른 프로세스로 메시지 보내기 ( 스트림 처리 )
  • 주기적으로 대량의 누적된 데이터를 분석 ( 일괄 처리, 배치 프로세싱을 의미 )

 

데이터 시스템에 대한 생각

일반적으로 데이터베이스, 큐, 캐시 등은 매우 다른 범주에 속하는 도구로 생각되지만,

새로운 도구들은 다양한 사례에 최적화되기 위해 전통적인 분류에 들어맞지 않는다.

가령 레디스와 아파치 카프카는 메시지 큐로 사용될 수 있지만, 카프카는 데이터베이스처럼 지속성을 보장한다.

두번째로는 점점 더 많은 애플리케이션이 단일 도구로는 처리와 저장을 만족할 수 없게 되었고,

대신 작업은 단일 도구에서 수행할 수 있는 단위로 나눠, 각각의 도구들을, 애플리케이션을 통해 묶기 때문이다.

 

가령 메인 데이터베이스와 분리된 관리 캐시 계층이 있고,

엘라스틱 서치같은 전문 (full-text) 검색 서버의 경우 동기화나 캐시, 색인을 애플리케이션 코드을 통해 한다.

이러한 이유로 이 도구들을, 좀 더 포괄적으로 데이터 시스템이라는 범주로 묶는다.

 

서비스 제공을 위해, 각 도구를 결합할 때, 서비스 인터페이스, API는 보통 클라이언트가 구현 세부사항을 모른다.

복합 데이터 시스템은 외부 클라이언트가 캐시를 올바르게 무효하게끔 하기도 한다.

이제부터 개발자는, 애플리케이션 개발자일 뿐만 아니라, 데이터 시스템 설계자의 역할도 수행해야 한다.

 

데이터 시스템을 설계할 때는 까다로운 문제가 많다.

내부적으로 문제가 있어도, 정확하고 완전하게 유지하려면, 어떻게 해야 하는지.

시스템의 일부 성능이 저하되도 클라이언트에게 일관되게 좋은 성능을 제공하기 위해서는 어떻게 해야 하는지.

부하 증가를 다루기 위해 어떻게 규모를 확장할지,

서비스를 위해 좋은 API는 어떤 모습을 해야 할지,

관련자의 기술 숙련도, 기존 시스템 의존성, 전달 시간 척도, 위험에 대한 조직의 내성, 규제 내약 등…

시스템에 영향을 줄 수 있는 요소는 많고, 이런 요소는 상황에 크게 좌우된다.

다만 여기서는, 대부분의 소프트웨어 시스템에 영향을 줄 수 있는 세 가지에 중점을 둔다.

 

신뢰성 Reliability

하드웨어나 소프트웨어 결함, 휴먼 에러 같은 역경에 직면하더라도 올바르게 동작해야 한다.

 

소프트웨어에 대한 기대치는 보통 아래와 같다.

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

이 모든 것이 올바르게 동작할 경우, 우리는 대략 “무언가 잘못되도 지속적이고 올바르게 동작함"이라 본다.

이를 신뢰성의 의미로 이해할 수 있다.

 

잘못될 수 있는 일을 우리는 결함(fault)이라고 부른다.

결함을 예측하고 대처하는 시스템을 내결함성 (fault-tolerant) 또는 탄력성 (resilient)을 지녔다고 말한다.

다만 사실상 모든 결함을 예측하는 것은 불가능하기에 특정 유형의 결함에 대해서만 이야기하는 게 타당하다.

결함은 장애 (failure)와 동일하지 않다.

결함은 사양에서 벗어난 시스템의 한 구성요소로 정의되지만, 장애는 사용자에게 서비스를 제공하지 못함이다.

결함 확률을 0으로 줄이는 것은 불가능하지만, 대개 결함으로 인해 장애가 발생하지 않는 구조로 가야 한다.

일반적으로 결함 예방을 넘어 내결함성으로 가기를 원하지만 ( 결함이 나더라도 견딜 수 있는 걸 차라리 선호함 ),

보안의 경우에는 예방책이 해결책보다 나은 경우에 속한다.

 

하드웨어 결함

( 우리는 소프트웨어를 만들고 있지만, 목차에 있어서 간략하게 서술한다. )

우리는 하드웨어 결함이 하드디스크 고장, 램 결함, 대규모 정전 사태 등… 일반적이지 않은 케이스로 생각하지만,

규모가 큰 데이터센터에서 일하는 사람은 늘상 일어나는 일이라고 표현한다.

하드디스크의 평균 장애 시간 ( mean time to failure, MTTF, 고장까지 걸리는 시간 )은 약 10 ~ 50년이다.

따라서 10,000개의 디스크로 구성된 저장 클러스트는 평균적으로 하루에 1개 고장난다고 예상할 수 있다.

시스템 장애를 줄이기 위해서는 각 하드웨어 구성 요소에 중복 (redundancy)를 추가하는 방법이 일반적이다.

즉, 디스크는 RAID를 설치하고, 서버는 이중 전원 디바이스와 핫 스왑 가능한 CPU를 갖춘다.

이와 같은 시스템은, 고가용성이 절대적으로 필수적인 소수의 애플리케이션에서만 필요했지만,

데이터 양과 애플리케이션의 계산 요구가 늘어나면서 더 많은 장비가 필요하게 됐고, 결함률도 증가함에 따라,

전체 장비의 손실을 견딜 수 있는 시스템으로 점점 옮겨가고 있다.

소프트웨어 오류

일반적으로는, 보통 하드웨어 결함을 무작위적이고 서로 독립적이라고 생각한다.

즉, 한 장비의 디스크에 장애가 발생한다고 해서 다른 디스크에도 장애가 발생하지는 않는다.

또 다른 결함의 부류로는 시스템 내 체계적 오류 ( systematic error ) 가 있는데,

이 결함은 예상하기 어렵고, 노드 간 상관관계 때문에 하드웨어보다 더 시스템 오류를 많이 유발시킨다.

예를 들면,

  • 잘못된 특정 입력이 있을 때 모든 애플리케이션 서버가 죽는 소프트웨어 버그
  • 2012년에 비트윈 서버를 마비시켰던 윤초 이야기
  • CPU 시간, 메모리, 디스크 공간, 네트워크 대역폭처럼 공유자원을 과도하게 사용하는 일부 프로세스
  • 시스템 속도가 느려져 반응이 없거나 잘못된 응답을 반환하는 서비스
  • 한 구성 요소의 작은 결함이 다른 구성 요소의 결함을 야기하고 점차 더 많은 결함이 발생하는 연쇄 장애

이와 같은 소프트웨어 결함을 유발하는 버그는, 특정 상황 전까지 나타나지 않는다.

소프트웨어의 체계적 오류 문제는 신속한 해결책이 없다.

시스템의 가정과 상호작용에 대해 주의깊게 생각하기, 빈틈없는 테스트, 프로세스 격리, 죽은 프로세스의 재 시작,

프로덕션 환경에서의 시스템 동작 측정, 모니터링, 분석하기와 같은 여러 작은 일이 문제 해결에 도움이 될 수 있다.

시스템이 뭔가 보장하길 기대한다면, 수행 중 이를 지속적으로 확인해 차이가 발생할 시 경고를 발생시킬 수 있다.

 

인적 오류

사람은 최선의 의도를 갖고 있어도 미덥지 않다고 알려져 있다.(…)

예를 들어, 하드웨어의 결함은 중단 원인의 10 ~ 25%를 차지하지만, 운영자의 설정 오류는 주요 원인이다.

사람이 미덥지 않아도 시스템을 어떻게 신뢰성 있게 만들까?

 

  1. 오류의 가능성을 최소화하는 방향으로 시스템 설계하기
    • 잘 설계된 추상화, API, 관리 인터페이스를 사용하면 옳은 일을 쉽게 하고, 잘못된 일을 막는다.
      • 단, 인터페이스가 지나치게 제한적이라면, 사람들은 인터페이스를 피해서 작업한다 (…)
      • 따라서 이런 시스템은 올바르게 작동하게끔 균형을 맞추기가 어렵다.
  2. 사람이 가장 많이 실수하는 장소에서, 사람의 실수로 장애가 발생할 수 있는 부분을 분리한다.
  3. 단위 테스트부터 전체 시스템 통합 테스트와 수동 테스트까지, 모든 수준을 철저히 테스트하라.
  4. 장애 발생의 영향을 최소화하기 위해 인적 오류를 빠르고 쉽게 복구할 수 있도록 하라.
    • 예를 들어 설정 변경 내역을 빠르게 롤백하게, 새로운 코드를 서서히 롤아웃하게 만들어라.
    • 이전 계산이 잘못된 경우를 대비하라.
  5. 성능 지표 오류율과 같은 상세하고 명확한 모니터링 대책을 마련하라.
  6. 조직 교육과 실습을 시행하라.

 

신뢰성은 얼마나 중요할까?

신뢰성은 원자력 발전소나 항공 교통 관제 소프트웨어만 중요한 게 아니다.

중요하지 않은 애플리케이션도 사용자에 대한 책임이 있다.

증명되지 않는 시장을 위해 시제품을 개발하는 비용이나 매우 작은 이익률의 서비스를 운영할 때,

비용을 줄이려 신뢰성을 희생해야 하는 상황이 오기도 한다.

하지만 이 경우에는 비용을 줄여야 하는 시점을 매우 잘 알고 있어야 한다.

반응형