NLP Blog

13. 긴급대응

|

13. 긴급 대응

시스템에 문제가 생기면 어떻게 해야 할까?

  • 가장 먼저 당황하지 말아야 한다.
  • 마닝 ㄹ자신에게 너무 부담스럽다고 느껴진다면 다른 사람들에게 도움을 요청하자
  • 만일 회사에 마련된 장애 대응 절차가 있다면 그 절차에 익숙해져야 한다.

테스트로 인한 장애

  • 구글은 재난과 긴급 상황에 대한 사전적 테스트 접근법을 취하고 있다
  • SRE들은 시스템에 장애를 일으킨 후 이로 인해 시스템이 어떻게 실패하는지를 지켜본 다음, 그 현상이 반복해서 발생하지 않도록 신뢰성을 향상시킬 수 있느 변경 사항을 적용
    • 이 과정에서 어떤 취약점이나 숨겨진 의존성을 발견하면 조치 문서에 기록해 둔다.
  • 그러나 간혹 우리의 예상과 실제 결과가 어긋날 때가 있다.

세부 내용

  • 보유 중인 분산 MySQL 데이터베이스 중 하나에 포함된 테스트 데이터베이스를 통해 숨겨진 의존성 확인 하고자 함
  • 계획 : 수백 대의 데이터베이스 중 한 데이터베이스에 대한 접근 차단

대응

  • 테스트를 시작한지 몇 분이 지나지 않아 데이터베이스에 의존하는 여러 시스템으로부터 내부 및 외부 사용자가 핵심 시트엠에 접근하지 못한다는 오류를 보고받기 시작
  • SRE들은 즉각 테스트의 실행을 중단.
  • 그 다음 권한 변경을 되돌리려 했지만 작업에 실패
  • 당황하지 않고 즉시 모여 변경된 권한을 어떻게 복구 할 수 있을 지 의논
  • 이미 테스트가 완료된 방법을 이용해 복제(replicas) 및 장애 대비(failovers) 데이터베이스의 권한을 복구할 수 있었음
  • 동시에 주요 개발자들에게 데이터베이스 애플리케이션 계층 라이르러리의 결함을 수정하도록 요청
  • 한 시간 이내에 권한 복구 완료
  • 이 테스트로 인해 영향을 받는 부분이 너무 광범위했으므로 라이브러리에 대한 신속한 수정이 이루어짐, 이 현상이 재발하지 않도록 하는 테스트 수행 계획도 수립

우리가 발견한 것들

테스트를 진행하면서 잘한 부분

  • 이 장애에 영향을 받은 서비스들이 즉각적으로 문제를 보고 -> 테스트 즉시 종료
  • 첫 장애 보고 이후 한 시간 안에 모든 권한을 완벽히 목구
  • 후속 조치 항목 역시 신속하게 처리되어 동일한 장애에 대응할 수 있게 됨
  • 동일한 장애가 재발하지 않는지 확인하기 위한 정기적인 테스트 계획 수립

깨달은 사실

  • 숨겨진 의존관계에 대해 완전히 이해하고 있지 못함
  • 테스트 환경에서의 롤백 절차를 테스트한 적이 없었으므로 이 절차 역시 결함이 있었음
    • 대량의 테스트를 시행하기에 앞서 롤백 절차를 완벽하게 테스트해야 함

변경으로 인한 장애

  • 구글은 어마어마한 수의 설정을 관리하고 있으며 지속적으로 변경이 발생 함
  • 이로인한 장애를 차단하기 위해, 변경된 설정으로 인해 뭔가 예상하지 못한 결과나 동작이 발생하지 않음을 확인하기 위한 많은 테스트를 수행함
  • 하지만 모든 테스트를 하는 것을 불가능

세부 내용

  • 어느 금요일, 서비스의 악의적인 사용을 방지하기 위한 목적으로 인프라스트럭처의 설정을 변경/적용함
  • 이 인프라스트럭처는 기복적으로 외부로 노출되는 모든 서비스들과 함께 동작하는 것이었고, 변경된 설정을 이런 시스템을에게서 crash-loop를 유발함
  • 구글의 내부 인프라스트럭처 역시 이 서비스들에 의존하고 있었으므로 많은 수의 내부 애플리케이션들도 갑자기 사용할 수 없게 됨

대응

  • 불과 수초 만에 특정 사이트가 다운되엉ㅆ다는 모니터링 알림이 쏟아져 나옴
  • 비상 대기 엔지니어들 몇 명이 근무 중이었지만 이들은 경험상 사내 네트워크 장애에 대한 알림이라고 믿을 수밖에 없는 알림을 계속해서 받았으므로 프로덕션 환경에 대한 백업용 접근이 가능한 (panic room이라고 불리는) 별도의 공간으로 모여듬, 그 후 사내용 네트워크 접근이 차단되어 발을 동동 구르던 엔지니어들도 이 공간에 합류
  • 첫 설정이 적용된 이후 5분쯤 지나, 해당 설정을 적용한 엔지니어도 사내 장애를 인지했지만 더 큰 장애는 인지하지 못하고 첫 설정을 롤백하기 위해 다시 설정을 변경 적용 -> 서비스들이 되살아나기 시작
  • 첫 설정 적용이후 10분쯤 지났을 무렵 비상 대기 엔지니어가 장애를 선언하고 내부 장애 조치 절차를 따르기 시작
  • 사내에 장애 상황을 전파
  • 설정을 적용했던 엔지니어는 비상 대기 엔지니어에게 장애의 원인이 자신이 적용한 설정 변경 때문인 것 같으며, 현재 해당 설정은 롤백된 상태라고 알림
  • 그와는 별개로 일부 서비스들은 그와 무관한 버그 또는 처음 변경된 설정에 영향을 받아 생성된 잘못된 설정 때문에 한 시간이 지나도 여전히 복구가 되지 않음

우리가 발견한 것들

장애를 처리하면서 잘한 부분

  • 모니터링 시스템은 거의 즉시 문제를 인지하고 알림을 발송
    • 하지만 알림이 지속적으로 반복 발송되어 비상 대기 엔지니어들이 그 때문에 고군분투 함
  • 일단 문제를 인지한 후의 장애 관리는 대체적으로 잘 진행 됨
  • 구글이 보유한 대역 외 통신 시스템 적분에, 일부 더 복잡한 소프트웨어 스택이 사용 불가능했던 상황에서도 모든 사람들이 소통할 수 있었음 -> SRE가 고가용적이며 오버헤드가 낮은 백업 시스템을 보유해야 하는 이유
  • 구글은 다르 ㄴ도구들에 대한 접근이 불가능한 상황에서도 업데이트를 수행하거나 설정 변경을 롤백할 수 있는 cli와 대체 접근 방식을 보유함
  • 구글의 인프라스트럭처는 해당 시스템이 새로운 클라이언트에 전체 업데이트를 얼마나 빨리 제공했는지를 측정하는 또 다른 보호 계층을 제공 -> 이 동작 덕분에 크래시 루프의 무한 발생을 어느 정도 막아서 완전한 장애를 차단
  • 행운도 작용함, 장애를 유발한 설정을 적용한 엔지니어가 롤백을 빠르게 함

깨달은 사실

  • 카나리 테스트에서 이 장애를 잡아내지 못함
  • 다음 분기에서 카나리 테스트와 자동화의 개선에 더 높은 우선순위를 두게 됨
  • 이 장애가 발생하 ㄴ기간 동안, 단 몇 분만에 모든 지역이 오프라인 상태가 되었으므로 엄청난 양의 알림이 발송됨 -> 이는 비상 대기 엔지니어들이 실제로 필요한 작업을 하는데 큰 방해가 되었고, 의사소통도 어렵게 함
  • 구글은 직접 개발한 도구에 대한 의존도가 높음, 장애 조치 및 의사소통을 위해 사용하는 소프트웨어 스택의 상당 부분은 장애 당시 크래시 루프가 발생한 작업들에 의존하고 있었음

절차에 의한 장애

  • 구글은 자동화를 엄청 해놓음
  • 이 자동화가 장애를 유발한 사례

세부 내용

  • 곧 사용이 종료될 동일한 서버에 두 개의 시스템 종료 요청이 연속적으로 전달됨
  • 그런데 두 번째 시스템 종료 요청에 자동화 시스템의 사소한 버그로 인해 전체 인프라스트럭처에서 동일한 설정으로 설치된 모든 서버에 대한 디스크삭제 요청이 큐에 기록됨

대응

  • 두 번째 시스템 종료 요청이 발송되자마자, 비상 대기 엔지니어에게 첫 번째 작은 서버가 오프라인 모드로 전환되었다는 호출이 전달
  • 조사 결과 해당 머신은 디스크삭제 큐의 요청 때문에 종료되는 것으로 파악 -> 통상적인 절차에 따라 비상 대기 엔지니어는 해당 지역의 트래픽을 다른 지역으로 우회 (해당 지역의 모든 머신이 제거되었기 때문)
  • 얼마 지나지 않아 전 세계의 동일한 종류의 모든 서버들로부터 알림이 발송되기 시작… 모든 팀의 자동화 시스템 비활성화
  • 한 시간 정도 지나자 모든 트래픽이 다른 지역으로 전송
  • 복구를 시작함
  • 3일 쯤 지나자 대부분의 서버들이 복구되고, 나머지는 한두 달 후에 복구 됨

우리가 발견한 것들

장애를 처리하면서 잘한 부분

  • 대량의 서버 앞에 놓인 리버스 프록시는 소량의 서버를 처리하는 리버스 프록시와는 관리 방법이 매우 다르므로 대량의 서버가 영향을 받지는 않았다.
  • 비상 대기 엔지니어는 트래픽을 소량의 서버군으로부터 대량의 서버군으로 빠르게 옮길 수 있었음
  • 그러나 일부 네트워크링크에 부하가 몰리면서 네트워크 엔지니어들이 우회방법을 찾을 수밖에 없었음
  • 소량의 서버군에 대한 시스템 종료 과정은 효율적으로 잘 동작함

깨달은 부분

  • 근본적인 문제는 시스템 종료 자동화 서버가 전달된 명령의 유효성을 적절하게 판단하지 못한 것에 있었음
  • 최초의 시스템 종료 문제가 발생한 서버에 대한 조치 이후, 해당 서버가 다시 가동되기 시작했을 때 시스템 종료 서버는 머신 랙으로부터 빈 응답을 받았다.
    • 문제는 이 빈 응답을 걸러내지 못하고 머신 데이터베이스에 빈 필터를 그대로 전달해서 머신 데이터베이스가 디스크삭제 요청 서버에게 모든 머신의 디스크를 삭제할 것을 요청 한 것
  • 머신의 재설치는 느리고 신뢰성이 떨어지는 작업이었음
  • 머신 재설치 인프라스트럭처는 수천 대의 머신에 대한 동시 작업을 제대로 처리하지 못함

모든 문제가 해결 되었다

  • 일단 긴급 상황이 종료되고 나면 뒷정리를 위한 시간을 마련하고 장애에 대해 문서를 작성하는 것

지난 일로부터 배우기. 그리고 반복하지 않기

장애에 대한 기록을 남기자

  • 포스트모텀 (15장)

커다란, 어쩌면 불가능할지도 모를 것에 대한 질문을 던지자: 만일 … 라면?

  • 건물에 전력이 끊어진다면?
  • 네트워크 장비 랙이 물에 잠긴다면?
  • 주 데이터센터에 갑자기 정전이 발생한다면?…
  • 카오스 엔지니어링

사전 테스트 장려하기

  • 회사의 전 직원이 블랙 포레스트로 워크숍을 간 토요일 새벽 2시에 장애가 발생 vs 공들여 리뷰한 테스트를 모니터링하고 있는 도중에 장애발생

결론

  • 장애를 조치하는 사람을 우선 침착해야함 그리고 필요하다면 다른 사람들에게 도움을 요청할 수 있어야 함
  • 이전에 발생한 장애를 연구하고 이로부터 새로운 것을 학습해야 함
  • 시스템이 이런 종류의 장애에 더욱 잘 대처할 수 있도록 개선해야 함
  • 장애가 발생할 때마다 문서화 해야함
  • 사전테스트에 더욱 주의를 기울여야 함

Comment  Read more

4. 실용주의 편집증

|

Tip 36. 여러분은 완벽한 소프트웨어를 만들 수 없다

  • 실용주의 프로그래머는 자기 자신 역시 믿지 않는다. 어느 누구도, 심지어는 자기 자신도 완벽한 코드를 작성할 수 없을을 알기 때문에 실용주의 프로그래머는 자신의 실수에 대비한 방어책을 마련한다.

Topic 23. 계약에 의한 설계

상식과 정의만큼 사람을 놀라게 하는 건 없다 - Ralph Waldo Emerson

  • 정직한 거래를 보장하는 최선의 해법 중 하나는 계약 이다.
  • 소프트웨어 모듈이 서로 소통하는 것을 돕기 위해 계약을 사용할 수 있을까? 그렇다.

DBC (Design By Contract)

  • Eiffel이라는 언어에서 Bertrand Meyer가 창시
  • 프로그램의 정확성을 보장하기 위해 소프트웨어 모듈의 권리와 책임을 문서화하고 합의
  • 소프트웨어 시스템의 모든 함수와 메서드는 뭔가를 한다. 그 뭔가를 시작하기 전에 해당 함수는 세상의 상태에 대해 어떤 전제 조건을 갖고 있을 테고, 루틴이 끝난 후에는 세상의 상태가 어떠할 것이라고 선언할 수 있을 것
  • 선행 조건 precondition
    • 루틴이 호출되기 위해 참이어야 하는 것. 즉, 루틴의 요구사항
    • 루틴의 선행 조건이 위반된 경우에는 루틴이 호출되어서는 안됨
    • 제대로 된 데이터를 전달하는 것은 호출하는 쪽의 책임
  • 후행 조건 postcondition
    • 루틴이 자기가 할 것이라고 보장하는 것. 즉, 루틴이 완료되었을 때 세상의 상태
    • 루틴에 후행 조건이 있다는 것은 곧 루틴이 종국에는 종료될 것 이라는 것 (무한 반복은 허용x)
  • 클래스 불변식 class invariant
    • 호출자의 입장에서 볼 때는 이 조건이 언제나 참인 것을 클래스가 보장함
    • 루틴의 내부 처리 도중에는 불변식이 참이 아닐 수도 있지만, 루틴이 끝나고 호출자로 제어권이 반환되는 시점에는 불변식이 참이 되어야 한다.
  • 루틴과 그 루틴을 호출하려는 코드 간의 계약 : 만약 호출자가 루틴의 모든 선행 조건을 충족한다면 해당 루틴을 종료 시 모든 후행 조건과 불변식이 참이 되는 것을 보장
  • 이런 개념을 더 잘 지원하는 언어 : Clojure - spec library
(defn accept-deposit [account-id abount]
  { :pre [ (> amount 0.00)
          (account-open? account-id) ]
    :post [ (contains? (account-transactions account-id) %) ]}
  "입금을 처리하고 거래 id를 반환"
  ;; 이런 저런 처리를 수행...
  ;; 새로 거래를 만들어서 반환.
  (create-transaction account-id :deposit amount))
  • Elixir에는 guard clause가 존재

Tip 37 계약으로 설계하라

  • Lazy 코드를 강조하고 싶음 - 시작하기 전에 자신이 수용할 것은 엄격하게 확인하고, 내어 줄 것에 대해서는 최소한도를 약속하자
  • 무엇이든 수용하고 결과로는 무엇이든 다 준다고 계약에 쓰여 있다면, 정말이지 많은 코드를 작성해야 함

클래스 불변식과 함수형 언어

  • Eiffel은 객체지향 프로그램 언어였으므로 클래스 불변식이라는 용어가 사용되었지만, 진짜로 의미하는 것은 상태(state)다.
  • 함수형 언어에서는 보통 상태를 함수에 넘긴 후 바뀐 상태를 결과로 받는다.

DBC와 테스트 주도 개발

  • TDD에서도 DBC는 필요하다
  • DBC가 테스트에 비해 가지는 장정
    • DBC는 테스트 환경 구성이나 mock이 필요벗다
    • DBC는 모든 입력값에 대해 성공과 실패를 정의한다 (테스트는 하나가 한 가지 경우만 다룸)
    • TDD와 다른 테스트는 빌드 과정 중 테스트할 때만 수행됨, DBC와 단정문은 영원하다 (설계, 개발, 배포, 유지보수 전체)
    • TDD는 테스트 중인 코드 내의 내부 불변식을 확인하는 것에 초점을 두지 않는다. 그보다는 공개 인터페이스를 확인하는 블랙박스 방식에 더 가까움
    • DBC는 방어적 프로그래밍보다 더 효율적이고 더 DRY하다. 방어적 프로그래밍에서는 아무도 데이터를 검증하지 않는 상황에 대비하기 위해 모든 사람이 데이터를 검증한다.

DBC 구현

단정문

  • 계약의 문서화보다는 컴파일러가 직접 확인해주는 것이 좋다
  • 몇몇 언어에서는 조건문을 실행 시점에 확인하는 단정문 Assertion 을 사용해서 부분적으로나마 DBC를 흉내낼 수 있다.
  • 하지만 단정문만을 이용해서 완벽하게 DBC를 지원하기는 힘듦
    • 객체 지향에서의 상속 계층을 따라 단정문이 밑으로 전파되도록 할 수 없을 것 (계약이 자동적으로 집행되지 않음)
    • 이전 값이라는 개념이 내장되어 있지 않음
    • 일반적인 런타임 시스템과 라이브러리가 계약을 지원하도록 설계되지 않아서 이런 코드를 호출할 때는 검사가 이루어지지 않는다

DBC와 일찍 멈추기

  • DBC는 “일찍 작동을 멈춰라” 라는 개념과 잘 어울림
  • 단정문이나 DBC 방식을 사용하여 선행 조건과 후행 조건, 불변식을 검증하면 더 일찍 멈추고, 문제에 대한 보다 정확한 정보를 알려줄 수 있음
  • ex) sqrt 함수는 매개 변수를 양수로 제한하는 DBC precondition이 필요 (오류를 찾기 쉬움)
  • C, C++은 결과로 그냥 NaN이 나옴… (오류를 훨씬 나중에 찾게 될 가능성이 있음)

의미론적 불변식

  • 바뀌지 않을 간단한 법칙
  • 도메인 주도 개발의 도메인과 비슷한 것일까?

동적 계약과 에이전트

  • 에이전트는 자신이 따르길 원치 핞는 요구를 거절할 자유가 있다. 계약을 재협상할 자유도 있다.
  • 하지만 수동으로 계약을 만들 수 없다면 자동화하는 것은 꿈도 꿀 수 없다. 그러니 나중에 소프트웨어를 설계하게 되면 계약 역시 설계하도록 하라.

관련 항목

  • 항목 24. 죽은 프로그램은 거짓말을 하지 않는다
  • 항목 25. 단정적 프로그래밍
  • 항목 38. 우연에 맡기는 프로그래밍
  • 항목 42. 속성 기반 테스트
  • 항목 43. 바깥에서는 안전에 주의하라
  • 항목 45. 요구 사항의 구렁텅이

Topic 24. 죽은 프로그램은 거짓말을 하지 않는다

  • ‘그런 일은 절대 일어날 리 없어’ 라는 사고에 빠지기 쉽다. 하지만 뭐든지 잘못될 수 있음
  • 모든 오류는 정보를 준다. 일단 그놈의 오류 메시지 좀 읽어라.

잡은 후 그냥 놓아주는 것은 물고기 뿐

  • 어떤 개발자는 모든 예외를 catch나 rescue로 잡은 후 로그 메시지를 좀 찍은 다음 다시 예외를 발생시키는 것이 좋은 상식이라고 여기는 듯 하다.
  • 하지만 실용주의 프로그래머는 하지 않는다
    • 애플리케이션 코드가 오류 처리 코드 사이에 묻히지 않음
    • 코드의 결합도를 높이지 않음

Tip 38. 일찍 작동을 멈춰라

망치지 말고 멈춰라

  • 가능한 한 빨리 문제를 발견하면 좀 더 일찍 시스템을 멈출 수 있으니 더 낫다.
  • Erlang을 만든 Joe Armstrong은 방어적 프로그래밍은 시간 낭비다. 그냥 멈추는게 낫다! 라고 함
  • 있을 수 없는 일이 발생했다는 것을 코드가 발견했다면 프로그램은 더는 유효하지 않다고 할 수 있다. 이 시점 이후로 하는 일은 모두 수상쩍은 게 된다. 되도록 빨리 종료할 일이다.
  • 일반적으로 죽은 프로그램이 끼치는 피해는 이상한 상태의 프로그램이 끼치는 피해보다 훨씬 적은 법이다.

관련 항목

  • 항목 20. 디버깅
  • 항목 23. 게약에 의한 설계
  • 항목 25. 단정적 프로그래밍
  • 항목 26. 리소스 사용의 균형
  • 항목 43. 바깥에서는 안전에 주의하라

Topic 25. 단정적 프로그래밍

자기 비난에는 사치성이 있다. 우리가 자신을 비난할 때, 다른 사람은 우리를 비난할 권리가 없다고 우리는 느낀다. - Oscar Wilde

Tip 39. 단정문으로 불가능한 상황을 예방하라.

단정과 부작용

  • 문제를 발견하려노 넣은 코드가 오히려 새로운 문제를 낳을 수 있다. 책의 코드를 참조하라
  • 디버깅 행위가 디버깅하려는 시스템의 행동을 바꿔버리는 일종의 Heisenbug 적인 문제

단정 기능을 켜 둬라

  • 단정문에 관한 흔한 오해
    • 단정은 코드를 느리게 만든다.
    • 단정은 일어나서는 안 되는 일들을 검사하기 때문에 코드 속에 버그가 있을 때만 단정 검사가 실패할 것이다.
    • 일단 코드가 테느스되고 배포된 다음에는 더 이상 단정이 필요하지 않다.
    • 그러니 코드 실행이 빨라지도록 단정을 꺼버려야 한다.
    • 단정은 디버깅 도구일 뿐이다.
  • 두 가지 명백히 틀린 가정
    • 테스트가 모든 버그를 발경한다는 가정
    • 낙관주의자들은 여러분의 프로그램이 험한 세상에서 돌아간다는 사실을 잊는다.
  • 프로그램을 출시할 때 단정 기능을 꺼 버리는 것은 줄타기 곡예를 하면서 연습으로 한 번 건너 봤다고 그물 없이 건너는 것과 비슷

관련 항목

  • 항목 23. 계약에 의한 설계
  • 항목 24. 죽은 프로그램은 거짓말을 하지 않는다
  • 항목 42. 속성 기반 테스트
  • 항목 43. 바깥에서는 안전에 주의하라

Topic 26. 리소스 사용의 균형

촛불 하나를 켜는 건 곧 그림자도 하나 던지는 거란 말이다. - Ursula K. Le Guin

  • 우리는 코딩할 때 언제나 리소스를 관리한다. - 메모리, 트랜잭션, 스레드, 네트워크 연결, 파일, 타이머 …
  • 리소스를 할당하고, 사용한 다음, 해제한다.

Tip 40. 자신이 시작한 것은 자신이 끝내라

  • 168p ~ 170p 예제 참고
  • 잘 모르겠을 땐 언제나 스코프를 줄이는 편이 낫다.

Tip 41. 지역적으로 행동하라.

중첩 할당

  • 리소스를 할당한 순서의 역순으로 해제하라. 이렇게 해야 한 리소스가 다른 리소스를 참조하는 경우에도 참조를 망가트리지 않는다
  • 코드의 여러 곳에서 동일한 구성의 리소스들을 할당하는 경우에는 언제나 같은 순서로 할당해야 교착 deadlock 가능성을 줄일 수 있다.

객체와 예외

  • 할당과 해제 사이의 균형은 객체 지향 클래스의 constructor와 destructor를 연상시킴
    • 파이썬의 경우 with문으로 할당과 해제를 관리 할 수 있음
      • class는 __enter____exit__으로
      • def는 contextlib.contextmanageryield
  • 객체 지향 언어로 프로그래밍을 한다면 리소스를 클래스 안에 캡슐화하는 것이 유용할 수 있음
  • 특정 유형의 리소스가 필요할 때마다 그 클래스의 객체를 생성하면 됨
    • 그 객체가 스코프를 벗어나거나 가비지 컬렉터가 객체를 수거해 가면 객체의 소멸자가 클래스 안에 들어 있는 리소스를 해제

균형 잡기와 예외

  • 예외가 던져진 경우 예외 발생 이전에 할당된 모든 것이 깨끗이 청소된다고 어떻게 보장할 수 있을까?
    • 변수 스코프를 사용한다. 예를 들어 C++나 Rust의 스택 변수가 있음
    • try~catch 블록에서 finally절을 사용
  • C++나 Rust 같은 언어의 일반적인 스코프 규칙에서는 함수나 블록 종료, 예외 등으로 변수가 스코프를 벗어나면 변수의 메모리가 해제 됨.
  • 하지만 예외가 있다

나쁜 예외 처리 방식

  • 174p 예제 참조

리소스 사용의 균형을 잡을 수 없는 경우

  • 동적인 자료 구조를 사용하는 프로그램에서 리소스 할당 기본 패턴이 맞지 않는 경우가 있음
    • ex) 한 루틴에서 메모리의 일정 영역을 할당한 다음 어떤 더 큰 구조에 그것을 연결한 후, 한동안 그래도 쓰는 식 (python dictionary of dictionary?)
  • 이런 경우의 요령은 메모리 할당에 대한 의미론적 불변식을 정하는 것
  • 한군데 모은 자료 구조 안의 자료를 누가 책임지는지 정해 놓아야 함
  • 자료 구조에서 최상위 구조의 메모리 할당을 해제할 경우 어떻게 처리해야 할까?
    • 최상위 구조가 자기 안에 들어 있는 하위 구조들을 해제할 책임을 진다. 하위 구조들은 또다시 재귀적으로 자기 안에 들어 있는 자료들을 해제할 책임을 지고, 이런 식으로 반복된다.
    • 최상위 구조가 그냥 할당 해제된다. 최상위 구조가 참조하던 하위 구조들은 연결이 끊어져서 다른 곳에서 참조하지 않는 다면 외톨이가 된다.
    • 최상위 구조가 하나라도 하위 구조를 가지고 있으면 자신의 할당 해제를 거부한다.

균형을 점검하기

  • 실용주의 프로그래머는 자신을 포함해서 아무도 믿지 않음. 언제나 정말로 리소스가 적절하게 해제되었는지 실제로 점검하는 코드를 작성하는 것을 좋아한다.
  • 리소스의 종류별로 wrapper를 만들고 그 래퍼들이 모든 할당과 해제 기록을 보관함
  • ex) 계속 실행 중인 상태에서 들어오는 요청을 처리하는 서버 프로그램
    • 프로그램의 주 처리 루프 맨 위에 다음 요청이 도착하기를 기다리는 단일한 지점 존재
    • 이 지점은 직전 요청을 처리하는 동안 리소스 사용량이 증가하지 않았는지 검사하기에 좋은 장소
  • Memory leaks 검사 도구도 활용 가능

관련 항목

  • 항목 24. 죽은 프로그램은 거짓말을 하지 않는다
  • 항목 30. 변환 프로그래밍
  • 항목 33. 시간적 결합 깨트리기

Topic 27. 헤드라이트를 앞서가지 말라

예측은 힘들다. 특히 미래에 대해서는 - Lawrence “Yogi” Berra

  • 소프트웨어 개발에서 우리의 “헤드라이트”는 제한되어 있다.
  • 우리는 너무 먼 미래는 내다볼 수 없고, 정명에서 벗어난 곳일수록 더 어둡다

Tip 42. 작은 단계들을 밟아라. 언제나.

  • 언제나 신중하게 작은 단계들을 밟아라. 더 진행하기 전에 피드백을 확인하고 조정하라.
  • 피드백의 빈도를 여러분의 제한 속도라고 생각하라. ‘너무 큰’ 단계나 작업은 하지 않게 될 것이다.
  • 여기서 피드백이란?
    • REPL의 결과는 API나 알고리즘을 여러분이 제대로 이해하고 있는지 피드백을 줌
    • 단위 테스트는 직전에 고친 코드에 대한 피드백을 줌
    • 사용자 데모 및 사용자와의 대화는 기능이나 사용성에 대한 피드백음 줌
  • 몇 시간이나 며칠 정도의 미래 너머는 경험에 기반한 추측을 벗어난 무모한 억측의 영역
    • 몇 달 후의 완료 일정을 추정하기
    • 미래의 유지 보수나 확장 가능성을 미리 고려하여 설계하기
    • 사용자의 미래 요구 사항 예측하기
    • 미래에 어떤 기술을 쓸 수 있을지 추측하기
  • 하지만 위의 것들은 어떻게든 해내야한다. 이를 위해 우리는 억측을 하기 보다는 “바꾸기 쉽게” 프로그램을 만들어야 한다.

블랙 스완

  • 나심 니콜라스 탈레브는 그의 책 «블랙 스완»에서 역사상 중대한 사건은 모두 다 세간의 이목을 끌고, 예측하기 어렵고, 드문 사건들로부터 발생하는데, 이 사건들은 일반적(normal - 정규 분포) 예상을 넘어서는 것이라고 상정
  • 이런 outlier는 통계적으로는 드물더라도 그 여파는 훨씬 큼

Tip 43. 예언하지 말라.

관련 항목

  • 항목 12. 예광탄
  • 항목 13. 프로토타입과 포스트잇
  • 항목 40. 리팩터링
  • 항목 41. 테스트로 코딩하기
  • 항목 48. 애자일의 핵심
  • 항목 50. 코코넛만으로는 부족하다

Chapter4-map

Comment  Read more

6. 분산 시스템 모니터링

|

6. 분산 시스템 모니터링

정의

  • 모니터링 : 쿼리의 수와 종류, 에러의 수와 종류, 처리 시간 및 서버의 활동 시간 등 시스템에 대한 정량적 실시간 데이터를 모으로 처리하고 집계해서 보여주는 것
  • 화이트박스 모니터링 : 로그나 JVM의 프로파일링 인터페이스 같은 인터페이스의 혹은 내부의 통계 지표를 제공하는 HTTP 핸들러등을 이용해서 얻은 시스템의 내부 지표들을 토대로 하는 모니터링
  • 블랙박스 모니터링 : 사용자가 보게 되는 확인 가능한 동작들을 외부에서 테스트하는 과정
  • 대시보드 : 서비스의 핵심 지표에 대한 요약된 뷰를 보여주는 애플리케이션, 가장 중요한 지표들을 사용자에게 보여주도록 만들어져 있음
  • 알림 : 사람이 읽을 수 있도록 작성된 통지. 메일, 티켓 등으로 보내짐
  • 근본 원인 : 소프트웨어 시스템의 결함이나 사람의 실수는 일단 고쳐지면 그 일이 다시는 발생하지 않을 것이라는 확신을 심어줌, 근본 원인은 해결되어야 함
  • 노드와 머신 : 물리적인 서버, 가상 머신 혹은 컨테이너에서 동작하는 커널의 단일 인스턴스
    • 서로 관련된 서비스 : 캐시 서버와 웹 서버
    • 서로 관련이 없지만 하드웨어만 공유하는 서비스 : 코드 저장소와 퍼펫이나 셰프 같은 설정 시스템의 마스터 노드
  • 푸시 : 서비스가 실행하는 소프트웨어나 관련된 설정에 대한 모든 변경사항

왜 모니터링해야 하는가?

장기적인 트렌드 분석

시간순 혹은 실험 그룹에 대한 비교

  • Acme Budkey of Byte 2.72와 Ajax DB 3.14 중 어느 것이 쿼리를 더 빨리 실행하는가? 노드를 추가했을 때 memcache의 hit rate는 얼마나 좋아지는가? 지난 주 대비 사이트가 느려졌는가?

알림

  • 문제가 생겨서 누군가 당장 수정해야 하거나 혹은 곧 문제가 생길 가능성이 있어서 누군가가 살펴봐야 하는 경우 통지를 보내야 함

대시보드

  • 개발 대시보드는 서비스에 대한 기본적인 궁금증을 해소해주며 보통 어떤 형태의 네가지 golden signal을 포함하고 있음

임시적인 회고 분석의 수행


  • 사람을 호출하는 것은 직원들의 시간을 고려하면 매우 비용이 많이 드는 일
  • 호출이 너무 빈번하면 직원들은 그냥 추측으로 넘어가거나 심한 경우 호출을 무시하게 됨
  • 효과적인 알림 시스템은 정확한 신호와 낮은 오보 비율을 갖춰야 함

모니터링에 대한 적절한 기대치 설정하기

  • 구글에서는 임계값을 학습하고 자동으로 인과관계를 찾아내는 마법같은 시스템은 선호하지 않음
  • 용량 산정이나 트래픽 예측 등에 모니터링 데이터를 활용하면 취약성 때문에 발생하는 복잡성을 완화하는 데도 도움이 됨

증상과 원인

  • 모니터링 시스템은 어떤 장애가 왜 발생했는지에 대한 질문에 답을 제시할 수 있어야 함
  • “무엇”과 “왜” 는 최대 비율의 정상적 알림과 최소 비율의 오보를 목적으로 하는 모니터링 시스템을 작성할 때 고려해야 하는 가장 중요한 간극 중 하나다.

블랙박스와 화이트 박스

  • 중요도가 낮은 서비스들에 대해서는 화이트박스 모니터링
  • 중요한 서비스들에 대해서 는 블랙박스 모니터링
  • 블랙박스 모니터링은 서버 상에 나타나는 증상을 기본으로 하며 현재 문제가 발생하는 상황을 모니터링하는 것. 즉, ‘시스템이 지금 현재 올바로 동작하지 않고 있는’ 상황을 알기 위한 것
  • 화이트박스 모니터링은 로그나 HTTP endpoin와 같은 시스템의 내부 동작들을 규범에 따라 살펴보는 기법들을 토대로 함
  • 다중계층 시스템에서는 하나 사람에게서 발생한 증상이 다른 누군가에게 장애의 원인이 되기도 함
    • 화이트박스 모니터링을 통해 어떤 정보를 얻느냐에 따라 증상에 초점을 맞출 수도 있고 원인에 초점을 맞출 수도 있음
  • 원격으로 디버깅을 수행할 때는 화이트박스 모니터링이 필수적

네 가지 결정적인 지표

  • 네 가지 결정적인 지표 : 지연응답(latency), 트래픽, 에러, 서비스 포화 상태(saturation)

지연응답

  • 요청이 서비스에 의해 처리되기까지의 시간을 말함
  • 이때 성공적인 요청의 응답 시간과 실패한 요청의 응답 시간이 중요함
    • HTTP 500 응답의 경우 실패했지만 빠르게 응답됨, 이는 통계에 나쁜 영향을 미침

트래픽

  • 시스템에 얼마나 많은 요청이 들어오는지를 측정
  • 웹 서비스의 경우는 주로 초당 HTTP 요청의 개수로 측정하며, 요청의 성질로 나누어 분류할 수도 있음
  • 오디오 스트리밍 시스템은 네트워크 입출력이나 동시 접속 세션 수 등을 측정하는 것이 알맞음
  • 키-밸류 저장소 시스템이라면 트랜잭션의 개수나 초당 조회 수 등으로 측정

에러

  • 실패한 요청의 비율
  • 이 때 명시적인 실패 (ex. HTTP 500)과 묵시적인 실패(ex. HTTP 200 성공 응답이지만 잘못된 컨텐츠가 제공된 경우), 혹은 정책과 관련된 실패 (ex. 모든 응답을 1초 내에 제공하기로 했다면 1초 이상 소요된 응답은 에러다) 등을 모두 고려해야 함
  • 사실 프로토콜의 응답 코드는 모든 종류의 실패를 표현하기에는 충분하지 않으므로 내부적인 프로토콜의 사용을 고려해야함. 이런 상황들을 모니터링하는 것은 엄청나게 어려움

서비스 포화 상태

  • 서비스가 얼마나 ‘포화’ 상태로 동작하는지를 의미함. 시스템의 일부를 측정하며 가장 병목이 발생하는 리소스를 집중해서 측정해야 한다
  • 많은 시스템들이 100% 사용량에 도달하기 전에 체감 성능의 하락이 발생하므로 기본적으로 목표 사용량을 설정해야 함
  • 복합 시스템의 경우, 시스템의 포화 상태는 높은 수준(abstract)의 부하 측정을 통해 보완할 수 있음
  • 시스템의 포화상태는 ‘데이터베이스 서버의 사용 가능한 디스크 공간이 4시간 안에 바닥날 것’과 같은 긴급한 상황을 미리 예측하는 것과 관련이 깊다.

마지막(tail) 요청(혹은 실행과 성능)에 대한 고려

  • 모니터링 시스템을 처음부터 개발하게 된다면, 가능한 한 평범한 수준의 성능을 토대로 시스템을 디자인하려 할 것이다.
  • 하지만 이는 위험함
    • CPU와 데이터베이스는 균형있게 활용되지 못하는 경우가 많음
    • 지연응답도 마찬가지, 초당 1000개의 요청에 대한 평균 지연응답이 100ms인 웹서비스의 경우 요청 중 1% 정도는 5초 정도 지연될 수 있음
  • 전체 요청에 대한 평균 응답 시간이 느려지는 것과 마지막 요청 (tail of requests)이 아주 느려지는 것을 구분하는 간단한 방법은 실제 지연응답이 아니라 전체 요청의 수와 전체 지연응답을 수집하는 것 (분포도 확인)

적당한 측정 방법 선택하기

  • 시스템의 지표들은 각기 다른 수준으로 세분화하여 측정되어야 함
    • CPU 부하를 1분 단위로 관찰한다고 해서 CPU 사용률이 갑자기 치솟아 나중에 유입된 요청들에 대한 지연응답이 발생하는 현상을 파악할 수는 없다.
    • 한편 1년에 9시간 이하의 다운타임 (99.9%의 연간 업타임)을 목표로 하는 웹 서비스에 대해 200 상태의 리턴 여부를 1분에 한두 번 이상 확인해야 한다면 너무 빈번하게 확인하는 것
    • 마찬가지로 99.9%의 가용성을 목표로 하는 서비스에 대해 하드 드라이브에 여유 공간이 있는지를 1~2분마다 한 번씩 확인하는 것 또한 무의미하다
  • CPU 부하를 초단위로 측정하면 유용한 데이터를 얻을 수도 있겠지만 비용이 너무 많이 듬
  • 만일 모니터링 시스템에 주어진 목표가 높은 수준의 분석을 위한 데이터 수집이지만 극단적으로 낮은 지연응답을 필요로 하지 않는다면, 서버에서 내부 샘플링을 수행한 후, 여러 서버에 걸쳐 데이터를 수집하고 시계열로 집계하는 외부 시스템을 구성하면 비용을 줄일 수 있음
    • 매 초마다 현재 CPU의 사용량을 기록한다
    • 5% 단위로 버킷을 구성하고 매 초당 CPU 사용량을 측정하여 적절한 버킷의 값을 증가시킨다
    • 분 단위로 이 값들을 집계한다

더욱 단순하게가 아니라 최대한 단순하게

  • 만약 아래와 같은 요구사항을 모두 고려하면 모니터링 시스템은 매우 복잡해짐
    • 모든 지표에 대해 각기 다른 지연응답 기준치 중에서 백분위수가 달라질 때마다 보내야 하는 알림
    • 발생가능한 장애 원인을 탐지하고 보여주기 위한 추가 코드
    • 이런 발생 가능한 각각의 장애 원인과 관련된 대시보드
  • 모니터링 시스템 역시 복잡도가 증가해서 장애가 쉽게 발생하거나 변경 사항을 수용하기에 너무 복잡해져서 유지보수가 어려워 짐
  • 모니터링 시스템을 디자인할 때는 최대한 간결함을 추구해야 함
    • 가장 빈번하게 발생하는 사건/사고를 탐지하기 위한 규칙은 최대한 간결하고 예측 가능하며 확실해야 함
    • 수정 빈도가 높지 않은 데이터의 수집, 집계 그리고 알림에 관련된 설정은 제거하는 것이 좋다
    • 수집은 되지만 대시보드에 노출되지도 않고 알림에 사용되지도 않는 데이터는 역시 제거하는 것이 좋다

지금까지 살펴본 원리들을 결합하기

  • 모니터링과 알림에 대한 규칙을 정의할 때 다음의 질문들을 활용하자
    • 이 규칙은 해당 규칙이 존재하지 않는다면 알아챌 수 없는 긴급하고, 대처가 가능하며 즉각적으로 사용자가 인지할 수있는 상태를 탐지 할 수 있는가?
    • 긴습하지 않은 알림이라면 무시할 수 있는 알림인가? 언제, 왜 이 알림을 무시할 수 있으며, 이런 알림을 받지 않으려면 어떻게 해야 할까?
    • 이 알림은 분명히 사용자에게 좋지 않은 영향을 미치는 상황에 대한 알림인가? 가용 트래픽이 모두 소모되었거나 테스트 배포처럼 사용자에게 부정적인 영향을 미치지 않는 경우에는 알림이 발생하지는 않았는가?
    • 이 알림에 대해 대응이 가능한가? 이 알림은 긴급한 것인가 아니면 내일 아침까지 기다려도 되는 것인가? 대응책은 안전하게 자동화가 가능한가? 알림에 대한 대응은 장기적인 수정이 될 것인가 아니면 단기적인 우회책이 될 것인가?
    • 다른 사람들이 이 이슈에 대한 호출을 받아서 적어도 하나 이상의 불필요한 호출이 발생했는가?
  • 위 질문은 아래의 기본 철학을 바탕으로 한다
    • 매번 호출기가 울릴 때마다 긴급한 상황임을 인지하고 그에 대응할 수 있어야 한다
    • 모든 호출은 대응이 가능해야 한다
    • 호출에 대한 모든 대응은 이성적이어야 한다
    • 호출은 새로운 문제나 지금까지 보지 못한 사건에 대한 것이어야 한다.

장기적 모니터링

빅테이블 SRE: 과도한 알림

  • 빅테이블의 성능을 개선하는 동안 SLO 목표치를 75% 요청 지연으로 하향 조정
  • 이메일 알림도 중단
  • 팀에 숨통이 트이면서 장기적 문제들을 해결할 시간을 갖게 됨

지메일: 사람이 예측 및 스크립팅할 수 있는 응답

  • 이해못함

한 걸음 더 나아가기

결론

  • 제대로 구성된 모니터링과 알림 파이프라인은 간결하고 명료하다.
  • 증상을 탐지하는 것에 집중하며, 문제를 디버깅하기 위한 방안을 제시함으로써 원인 분석을 통해 스스로 학습하고 성장할 수 있는 기회를 제공

Comment  Read more

5. 삽질은 이제 그만!

|

5. 삽질은 이제 그만

삽질의 정의

  • 프로덕션 서비스를 운영하는 것과 직접적으로 연관이 있지만 수작업을 동반하고, 반복적이며, 자동화가 가능하고, 사후 대처가 필요하며, 지속적인 가치가 결여되어 있으면서도 서비스의 성장에 따라 지속적으로 늘어나는 업무

수작업을 필요로 한다

  • 자동화된 작업을 실행하기 위해 수작업으로 스크립트를 실행하는 경우
  • 스크립트를 실행하기 위해 소비하는 시간은 분명히 삽질에 소비된 시간

반복적이다

  • 삽질은 계속해서 반복되는 작업
  • 새로운 문제를 해결 중이거나 새로운 솔루션을 개발하는 작업은 삽질이라고 보지 않는다

자동화가 가능하다

  • 작업이 기본적으로 인간의 판단에 의해 실행되어야 한다면 삽질로 분류되지 않을 수도 있다.

사후 대처가 필요하다

  • 업무를 방해하며, 사후에 처리하게 되는 일들

가치가 지속되지 않는다

  • 어떤 작업을 끝냈는데도 서비스가 계속 같은 상태로 남아있다면 그건 삽질이다

서비스의 성장에 따라 O(n)으로 증가한다

  • 작업에 필요한 업무량이 서비스 크기나 트래픽 양, 혹은 사용자의 수에 따라 선형적으로 증가한다면 이건 삽질이다

삽질이 줄어들면 좋은 이유

  • 구글의 SRE조직은 전체 작업 시간 중 삽질을 50% 이내로 유지한다는 목표를 공공연하게 가짐
  • SRE들은 최소 50%의 시간을 엔지니어링 프로젝트 업무에 투입해서 향후에 발생 가능한 삽질을 줄이거나 혹은 서비스에 새로운 기능을 추가해야 함
  • 기능의 개발은 주로 안정성이나 성능 혹은 활용도를 개선하고 결과적으로 삽질의 발생 가능성을 줄이는 것에 중점을 둔다

엔지니어링에 해당하는 업무는?

소프트웨어 엔지니어링

  • 코드를 작성하거나 수정하고, 관련된 디자인이나 문서화 작업을 수행

시스템 엔지니어링

  • 한 번의 노력으로 지속적인 개선을 이루어내기 위해 프로덕션 시스템의 설정을 조정하거나 문서화를 수행

삽질

부하

  • 서비스 운영과 직접 관련되지 않은 관리 업무

삽질은 무조건 나쁜 것일까?

  • 삽질의 양이 얼마 되지 않는다면, 예측이 가능하고 반복되는 작업들은 큰 무리 없이 처리할 수 있다. 이런 업무들을 처리하면 성취감이 있으며, 빠른 시간 내에 처리할 수 있다. 그다지 위험하지도 않고 스트레스도 적은 편이다. 몇몇 사람들을 이 업무를 선호한다.
  • 하지만 삽질의 양이 엄청나지기 시작하면 이것은 문제가 된다.

경력 개발이 침체된다

의욕이 저하된다

혼란이 가중된다

성장이 저하된다

좋지 않은 선례를 남기게 된다

  • 만일 삽질을 너무 많이 하려고 하면, 함께 일하는 개발팀은 더 많은 삽질을 떠넘기려 하고, 심지어는 개발티이 수행해야 할 운영 업무까지도 떠안게 된다.

인력 유출이 발생한다

신뢰에 문제가 생긴다

결론

  • 모두가 매주 조금씩 삽질을 걷어낼 수 있다면 서비스를 지속적으로 깔끔하게 유지할 수 있다
  • 삽질은 줄이고 창의적인 일에 더 집중하자

Comment  Read more

4. 서비스 수준 목표

|

4. 서비스 수준 목표

서비스 수준 관련 용어

척도

  • Service Level Indicator (SLI): 서비스 수준 척도, 서비스 수준을 판단할 수 있는 몇가지를 정량적으로 측정한 값
  • 핵심 SLI
    • 응답 속도 : 요청에 대한 응답이 리턴되기까지의 시간
    • 에러율 : 시스템이 수신한 전체 요청 수 대비 에러
    • 시스템 처리양 (system throughput) : 초당 처리할 수 있는 요청 수
  • 측정 된 값들은 합산되기도 한다. 즉, 일정 기간 동안 측정한 값들을 모아 비율이나 평균 혹은 백분율 등을 계산함
  • SRE가 중요하게 생각하는 SLI 중 하나는 가용성, 서비스가 사용 가능한 상태로 존재하는 시간의 비율
    • 100% 가용성은 실현 불가능
    • 여러개의 ‘9’를 이용해서 백분율로 표현 (99%, 99.99% …)
    • GKE는 three and half nine (99.95%)를 목표로 한다

목표

  • Service Level Objectives (SLO): 서비스 수준 목표, SLI에 의해 측정된 서비스 수준의 목표 값 또는 일정 범위의 값
    • SLO는 SLI <= SLO or 최소값 <= SLI <= 최대값 으로 표현 가능
      • ex) 셰익스피어의 검색 결과를 “빠르게” 리턴하기로 결정했다면, 평균 검색 요청의 응답 시간에 대한 SLO는 100ms 이하로 설정할 수 있다
    • 적절한 SLO를 성정하는 것은 생각보다 복잡하다. 무엇보다, 필요한 값을 항상 얻어낼 수가 없다
      • ex) 외부에서 서비스로 유입되는 HTTP 요청의 경우, 기본적으로 QPS라는 지표는 사용자가 서비스를 얼마나 사용하느냐에 따라 결정되므로 이 지표에 대한 SLO를 설정하는 것은 말이 되지 않는다
      • 반면, 요청당 평균 응답 시간을 100ms 이내로 달성하겠다는 목표는 설정가능. 또한 이 목표를 달성하기 위한 다양한 노력을 해볼 수 있다
  • SLO를 설정하고 고객에게 이를 공개하는 것은 서비스의 동작에 대한 예측을 가능하게 한다.
    • SLO가 공개되어있지 않다면, 서비스를 디자인하고 운영하는 사람들의 생각과는 전혀 다른, 자신들이 희망하는 성능을 기대하곤 한다.
    • 이는 잠재 고객들이 서비스를 실제보다 저평가하는 현상을 유발하게 된다.
    • 글로벌 처비의 경우 연간 SLO를 달성하면 예정된 장애를 일으켜서 의존성을 없애는 방식을 사용함

협약

  • Service Level Agreements (SLA) : 서비스 수준 협약, SLO를 만족했을 경우 (혹은 그렇지 못할 때)의 댓가에 대한 사용자와의 명시적 혹은 암묵적인 계약
  • SLA는 사업부의 영역, SRE는 관여하지 않음
  • 구글 검색은 중요한 서비스임에도 불구하고 SLA가 존재하지 않는 서비스
  • 기업용 구글 앱스 등 다른 서비스는 SLA 체결하고 있음
  • SLA 체결 여부와는 무관하게 서비스마다 SLI와 SLO를 설정하고 이를 토대로 서비스를 관리해야 함

지표 설정

정말 중요한 것은 무엇인가?

  • 너무 많은 지표를 선택한다면 정작 중요한 것에 집중하기가 어렵고, 너무 적은 수의 척도를 선택한다면 오히려 중요한 부분을 놓칠 수 있다
  • 적절한 SLI의 선정과 관련해 시스템들을 다음 몇가지로 분류 가능
    • 사용자가 직접 대면하는 시스템 : 가용성, 응답 시간, 처리량
    • 저장소 시스템 : 응답 시간, 가용성, 내구성
    • 빅데이터 시스템 : 처리량, 종단 간 응답 시간
    • 모든 시스템 : 정확성

척도 수집하기

  • 많은 척도들은 기본적으로 Borgmon이나 Prometheus, 또는 전체 요청 대비 HTTP 500 오류가 발생한 비율 등을 파악하기 위해 일정 기간에 대해 실행하는 로그 분석 등의 방법을 통해 주로 서버 측에서 수집된다.
  • 그러나 일부 시스템은 클라이언트에서 측정될 필요도 있다

합산하기

  • 단순함과 유용함을 위해 측정된 원본 데이터를 합산하는 경우가 있다 하지만 주의를 기울여야 함
  • 대부분의 지표들의 경우 평균보다는 분포(distribution)가 중요하다
  • 그림 4-1 이해가 잘 안됨… 어떻게 보는건지 질문
  • 척도에 백분위 수(percentile)를 사용하면 분포와 더불어 독특한 특징을 알아볼 수 있다.
    • 99번째나 99.9번째 백분위 수 같은 높은 수 들은 최악의 경우의 상황을 보여줌
    • 50번째 (emdian)은 일반적인 경우의 상황을 보여줌
    • 사용자에 대한 연구에 의하면 사람들은 응답 시간의 변동이 큰 경우보다는 살짝 느리게 동작하는 시스템을 더 선호하므로, 99.9 번째 백분위 수의 값이 양호하다면 사용자 경험이 훨씬 나아질 거라는 근거를 가짐

척도의 표준화

  • SLI들에 대한 일반 적인 정의를 표준화하기를 권장함
    • 집계 간격 : 평균 1분
    • 집계 범위 : 하나의 클러스터에서 수행되는 모든 태스크들
    • 측정 빈호 : 매 10초
    • 집계에 포함할 요청들: 블랙박스 모니터링 잡이 수집한 HTTP GET 요청들
    • 데이터의 수집 방식 : 모니터링 시스템에 의해 서버에서 수집
    • 데이터 액세스 응답 시간 : 데이터의 마지막 바이트가 전송된 시간

목표 설정에 대한 실습

  • 중요한 것은 어떤 값을 측정할 수 있는지가 아니라 사용자가 중요하게 생각하는 것이 무언인지에 대해 생각해보는 것
  • 사용자가 중요하게 생각하는 것은 대부분 측정하기 어렵거나 불가능 한 것
  • 단순히 어떤 값을 측정할 수 있는지만을 생각하면 쓸모없는 SLO를 설정하게 됨
  • 목표를 먼저 설정한 후 적절한 척도를 찾는 것이 더 낫다

목표 설정하기

  • 명확성을 극대화하기 위해 SLO는 측정 방식과 유효한 기준이 반드시 명시되어야 함
    • Get RPC 호출의 99%(1분 간의 평균)는 100ms 이내에 수행되어야 한다 (모든 백엔드 서버에서 측정된 평균 시간이어야 한다).
    • Get RPC 호출의 99%sms 100밀리초 이내에 수행되어야 한다.
  • 만일 성능 그래프가 중요하다면 다음과 같이 여러 개의 SLO를 설정할 수 있다
    • Get RPC 호출의 90%는 1ms 이내에 수행되어야 한다
    • Get RPC 호출의 99%는 10ms 이내에 수행되어야 한다
    • Get RPC 호출의 99.9%는 100ms 이내에 수행되어야 한다
  • 만일 사용자의 작업 부하가 처리량을 중시하는 대량 처리 파이프라인과 응답 시간을 중시하는 대화형 클라이언트로 분산되다면 각 부하의 종류에 따라 개별적인 목표를 설정하는 것이 좋다
    • 처리량 중시 : Set RPC 호출의 95%sms 1초 이내에 수행되어야 한다
    • 응답 시간 중시 : 페이로드(payload) 크기 1kb 미만의 Set RPC호출은 10초 이내에 수행되어야 한다.
  • SLO를 100% 만족하는 것은 현실정도 없고 혁신과 배포의 속도가 저하되며 높은 비용을 소비하거나 지나치게 보수적인 솔루션이 됨
  • 그래서 에러 예산 (SLO를 만족하지 못하는 비율)을 산정하고 이를 일단위 혹은 주단위로 추적하는 것이 훨씬 낫다
  • 어떤 SLO를 달성하지 못한 비율은 사용자가 인지한 서비스의 상태에 대한 유용한 척도가 됨
  • SLO들을 일단위 혹은 주단위로 추적해서 트렌드를 파악하고 잠재적인 문제가 실제로 발생하기 전에 미리 그 조짐을 파악하는 것은 매우 유용
  • 상위 관리자한테는 월/분기 단위 보고가 좋다
  • SLO 위반율을 에러 예산과 비교해서 그 차이를 프로세스를 대입해보면 언제 새로운 릴리즈를 출시할 수 있는지를 판단할 수 있음

목표치 선택하기

  • SLO를 선택하는 것은 순수한 기술적 활동은 아님, 사업적 선택이 필요함
  • SRE는 이런 논의에 반드시 참여해야 하며, 발생 가능한 위험과 여러 선택 사항들의 실행가능성(viability)에 대해 조언을 할 수 있어야 함

현재의 성능을 기준으로 목표치를 설정하지 말것

최대한 단순하게 생각할 것

자기 만족에 얽매이지 말 것

  • 응답 시간의 저하 없이 시스템의 부하를 ‘무한정’ 확장하는 것은 상당히 매력적인데다가 ‘언제든지’ 가능하기는 하지만 사실 이런 요구는 현실성이 없음
  • 이런 시스템은 디자인하고 구축하는데 엄청난 시간이 들고 운영비용도 엄청남

가능한 적은 수의 SLO를 설정할 것

  • 시스템의 특성을 잘 확인할 수 있는 최소한의 SLO를 선택하는 것이 중요함

처음부터 완벽하게 하려고 하지 말 것

  • SLO의 정의와 목표는 시간이 지남에 따라 시스템의 동작을 살피면서 언제든지 다시 정의 할 수 있음
  • 우선은 조금 느슨한 목표를 설정한 후 조금씩 강화하는 것이 낫다

측정하기

  1. 시스템들의 SLI들을 모니터하고 측정하기
  2. SLI를 SLO와 비교해서 별도의 대응이 필요한지 판단하기
  3. 대응이 필요한 경우 목표치를 달성하기 위해 어떻게 대응할지 파악하기
  4. 대응하기

SLO는 기대치를 설정하는 것

  • 안전 제한선을 지킬 것
    • 사용자에게 광고한 SLO보다는 내부적으로 더 보수적으로 설정된 SLO를 지키면 만성적으로 발생하는 문제들이 외부로 노출되기 전에 적절하게 대응할 수 있는 여력을 가질 수 있음
  • 지나친 목표를 설정하지 말 것
    • 만일 서비스의 실제 성능이 공개된 SLO를 훨씬 웃돈다면 더 많은 서비스의 현재 성능에 계속 의존하게 될 것이다.
    • 이 경우 의도적으로 시스템이 다운되게 하거나, 요청 수를 제한하거나 또는 부하가 낮은 상황에서도 아주 빠르게 동작하지 않도록 시스템을 디자인해서 전체적으로 서비스에 대한 의존도가 높아지는 것을 방지할 수 있음
  • 이러한 설정은 시스템에 대한 투자 방향을 결정하는데 도움이 됨

협약에 대한 실습

  • SLA를 수립하려면 사업부와 법무팀이 위반하는 경우에 대한 적절한 보상과 댓가를 수립해야 한다
  • 사용자에게 공개하는 내용은 조금 보수적으로 설정하는 편이 좋다. 왜냐하면 사용자 층이 두터워질수록 SLA를 변경하거나 삭제하기가 더 어려워지기 때문이다.

Comment  Read more