사이트 신뢰성 엔지니어링

created : 2022-10-16T08:00:35+00:00
modified : 2023-12-03T13:26:48+00:00

sre

1. 소개

  • 직접 비용, 간접 비용

서비스 관리에 대한 구글의 해법: 사이트 신뢰성 엔지니어링

  • SRE 중 50~60% 는 구글의 소프트웨어 엔지니어다.
  • SRE팀은 반드시 50%의 시간을 오롯이 개발을 위해 활용해야한다.:
    • 만약 이에 미치지 못한다면, 운영에 대한 부담이 개발팀에 전가되거나 혹은 운영 책임이 없음에도 새로운 팀원이 팀에 배정되는 현상이 발생하고 있음을 암시하고 있다.

SRE의 신조

  • Availability, Latency, Performance, Efficiency, Change Management, Monitoring, Emergency response, capacity planning

지속적으로 엔지니어링에 집중한다.

  • 모든 심각한 장애에 대해서는 알림 여부를 떠나 반드시 포스트모텀을 작성해야한다.:
    • 모니터링되지 않고 있는 부분을 알 수 있기 때문이다.

서비스의 안정성을 유지하면서 변화를 최대한 수용한다.

  • 에러 예산:
    • 더 이상 무정지 시스템 같은 목표를 세우지 않는다.
    • 예측 가능한 시스템 정지

모니터링

  • 알림(alert) : 어떤 문제가 발생했거나 발생하려고 할 때 상황을 개선하기 위해 사람이 즉각적으로 어떤 대응을 취해야 한다는 것을 알린다.
  • 티켓(tickets) : 사람의 대응이 필요하지만 즉가적인 대응이 필요하지는 않는 상황을 의미한다.
  • 로깅(logging) : 누군가 이 정보를 반드시 확인해야 할 필요는 없지만 향후 분석이나 조사를 위해 기록되는 내용이다.

긴급 대응

  • MTTF(Mean Time To Failure)
  • MTTR(Mean Time To Repair)
  • MTTR을 줄이기 위해서는 잘 정리된 포괄적인 행동 지침이 큰 역할을 할 수 있다. (장애 대응 지침)

변화 관리

  • 제품의 단계적 출시
  • 문제를 빠르고 정확하게 도출하기
  • 문제 발생 시 안전하게 이전 버전으로 되돌리기

수요 예측과 수용 계획

  • 자연적 수요에 대한 정확한 예측. 필요한 수용력을 확보하기까지의 시간에 대한 예측을 이끌어낼 수 있다.
  • 자연적 수요와 인위적 수요를 정확하게 합산하기
  • 원천적인 수용력(서버, 디스크 등)을 바탕으로 서비스의 수용력을 측정하기 위한 통상의 시스템 부하 테스트

프로비저닝

  • 프로비저닝 : 변화 관리와 수용 계획을 합한 개념

효율성과 성능

  • 서비스의 효율성을 결정짓는 중요한 요소들 : 수요(부하), 수용력, 소프트웨어의 효율성

2. SRE 관점에서 바라본 구글의 프로덕션 환경

하드웨어

  • 머신(Machine) : 하드웨어(혹은 가상머신, Virtual Machine)을 의미한다.
  • 서버(server) : 서비스를 구현하는 소프트웨어를 의미한다.

하드웨어를 조율하는 시스템 소프트웨어

  • 하드웨어 결함도 소프트웨어로 관리할 수 있다.

머신 관리하기

  • 보그(Borg) : 오늘날의 쿠버네티스

저장소

  • 저장소는 여러 계층으로 구성된다.:
    • 가장 낮은 계층은 D 계층
    • Colossus, 구글 파일 시스템의 후속 제품이다.
    • 콜로서스를 바탕으로 데이터베이스와 유사한 서비스들이 존재한다.:
      • Spanner, Bigtable, Blobstore

네트워킹

  • GSLB(Global Software Load Balancer):
    • DNS 요청에 대한 지역적 로드밸렁싱
    • 사용자 서비스 수준에서의 로드밸런싱
    • 원격 프로시저 호출(RPC) 수준에서의 로드밸런싱

기타 시스템 소프트웨어

잠금 서비스

  • 처비(Chubby), Paxos 프로토콜
  • 요즘 널리사용되는 오픈소스(k8s, kafka 등)은 etcd, zookeeper를 사용하고 이들은 raft 알고리즘으로 동작한다.

모니터링과 알림

  • 치명적인 문제점에 대한 알림 설정
  • 행동 비교: 소프트웨어 업데이트 이후 서버가 빨라졌는가?
  • 수용 계획을 위한 가장 기본적인 지표인 시간의 흐름에 따른 자원 소비 행위의 개선 여부 확인하기

소프트웨어 인프라스트럭처

  • Protocol buffers:
    • 오늘날에는 gRPC를 사용하고 gRPC 는 대부분 Protocol Buffers 를 사용한다.

개발 환경

  • 구글에서의 업무 흐름 중 중요한 암묵적인 합의:
    • 프로젝트 외부의 컴포넌트에서 문제가 발생하면 엔지니어는 문제를 해결하고, 변경사항(cahgnelist, CL)을 소유자에게 보내서 리뷰를 요청한 후 변경된 코드를 제출할 수 있다.
    • 엔지니어가 소속된 프로젝트의 소스 코드 변경은 반드시 리뷰를 거쳐야 한다. 모든 소프트웨어는 제출되기 전에 리뷰를 받아야 한다.

II. 원리와 원칙들

3. 위험 요소 수용하기

  • 사용자의 스마트폰이 99% 의 신뢰성을 가진다면, 99.99%와 99.999% 서비스는 사용자가 구별할수 없다.
  • SRE는 이 점을 이용해서 위험요소, 빠른 혁신, 효과적인 서비스 운영의 균형을 잡는다. (기능, 서비스, 성능)

위험 요소 관리하기

  • 신뢰성을 향상시킬수는 있지만 비용이 증가하는 요소들:
    • 여분의 머신/컴퓨트 자원 비용
    • 기회 비용
  • 가용성 목표치를 초과 달성하려고 노력은 하되, 넘치게 초과하려고는 하지 않는다.
  • 가용성 목표치를 초과 달성했다면, 기술부채를 줄이거나 윤영비용을 줄이려고 시도해야한다.

서비스 위험 측정하기

  • 시간 기준 가용성 : 가용성 = 업타임 / (업타임 + 다운타임)
  • 종합 가용성 : 가용성 = 성공한 요청 수 / 전체 요청수
  • 널리 사용되는 가용성 지표를 측정하는 방법:
    • 주 단위 혹은 일 단위로 목표치에 대한 성능을 측정한다.

서비스의 위험 수용도

소비자 대상 서비스의 위험 수용도 정의하기

  • 위험 수용도를 결정하기 위해서 고려해야 하는 요소:
    • 어느 정도 수준의 위험 수용도가 요구되는가?
    • 장애의 종류에 따라 서비스에 미치는 영향이 달라지는가?
    • 지속적으로 발생하는 위험 중 어느 지점에 서비스 비용을 투입할 것인가?
    • 중요하게 고려해야 할 다른 서비스 지표로는 어떤 것들이 있는가?
  • 목표 가용성 수준:
    • 사용자는 어느 정도 수준의 서비스를 기대하는가?
    • 이 서비스가 수익과 직접적으로 연관이 있는가?
    • 유료 서비스인가? 무료 서비스인가?
    • 시장에 경쟁자가 있다면 경쟁자는 어느 정도 수준의 가용성을 제공하는가?
    • 이 서비스는 개인 사용자를 위한 서비스인가? 기업 사용자를 위한 서비스인가?
  • 장애의 종류:
    • 낮은 비율로 장애가 지속적으로 발생
    • 가끔이지만 전체 사이트가 다운되는 장애
  • 비용:
    • 목표 가용성 수준을 높이려고 한다면 수익에 어떤 긍정적 역향이 미치는가?
    • 발생 가능한 추가 수익이 목표한 가용성 수준에 도달하기 위한 비용을 상쇄할 수 있는가?
  • 기타 서비스 비용

인프라스트럭처 서비스의 위험 수용도 정의하기

  • 목표 가용성 수준, 장애의 종류, 비용

에러 예산 활용해보기

  • 소프트웨어 결함 허용, 테스트, 출시 빈도, 카나리 테스트 빈도와 규모

에러 예산 산정하기

  • SLO(Service Lead Objectives, 서비스 수준 목표)

  • 제품 관리자들이 서비스의 분기별 예상 업타임을 의미하는 SLO를 산정한다.
  • 실제 업타임은 제3자, 즉 우리가 보유한 모니터링 시스템으로 측정한다.
  • 이 두 숫자 사이의 차이점이 분기별로 얼마만큼의 ‘불안정성’을 허용할 것인지를 의미하는 ‘예산’이 된다.
  • 업타임이 SLO를 초과한다면(다시 말해, 에러 예산이 아직 남아있다면) 새로운 릴리즈를 출시할 수 있다.

장점

  • 제품 개발팀과 SRE팀이 혁신과 신뢰성 사이의 올바른 균형을 찾는데 필요한 기준을 제공한다.

핵심 인사이트

  • 서비스의 신뢰성을 관리하는 것은 위험을 관리하는 것이며, 위험을 관리하기 위해서는 비용이 소비될 수 있다.
  • 100%는 절대로 올바른 신뢰성 목표치가 될 수 없다.
  • 에러 예산은 SRE와 제품 개발팀 사이의 공동 소유권을 강조하며 각자의 역할을 명료하게 한다.

4. 서비스 수준 목표

서비스 수준 관련 용어

  • SLI(Service Level Indicator):
    • 응답 속도, 에러율, 시스템 처리량
    • 일반적으로 비율, 평균, 백분율로 계산
    • 가용성
  • SLO(Service Level Objectives):
    • SLI <= 목표치
    • 최솟값 <= SLI <= 최대값
    • 명확한 SLO 가 설정되어 있지 않다면 서비스를 디자인하고 운영하는 사람들의 생각과는 전혀 다른, 자신들이 희망하는 성능을 기대하곤 하다.
  • SLA(Serivice Level Agreements):
    • SLO 를 만족했을 경우(또는 반대의 경우)의 댓가에 대한 사용자와의 명시적 혹은 암묵적인 곙약을 의미한다.

지표 설정

  • 가용성, 응답시간, 처리량, 내구성, 정확성

척도 수집하기

  • 서버사이드 vs 클라이언트 사이드

합산하기

  • 단순함과 유용함을 위해 측정된 원본 데이터를 합산하는 경우도 있다. 다만, 이 경우 상당한 주의를 기울여야한다.
  • 대부분의 지표들은 평균보다는 분포가 더 중요하다.
  • 99.9 등 더 높은 백분위 수 값들에 더 주목한다.

척도의 표준화

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

목표 설정에 대한 실습

목표 설정하기

  • SLO를 100% 만족하는 것은 현실성이 없는 것은 물론이거니와 기대할 수도 없는 상황이다.

목표치 선택하기

  • 현재의 성능을 기준으로 목표치를 설정하지 말것
  • 최대한 단순하게 생각할 것
  • 자기 만족에 얽매이지 말 것
  • 가능한 적은 수의 SLO를 설정할 것
  • 처음부터 완벽하게 하려고 하지 말 것

측정하기

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

SLO는 기대치를 설정하는 것

  • 안전 제한선을 지킬것
  • 지나친 목표를 설정하지 말 것

5. 삽질은 이제 그만

삽질의 정의

  • 수작업을 필요로 한다.
  • 반복적이다.
  • 자동화가 가능하다.
  • 사후 대처가 필요하다
  • 가치가 지속되지 않는다.
  • 서비스의 성장에 따라 O(n)으로 증가한다

삽질이 줄어들면 좋은 이유

  • 서비스의 크기를 부선형적으로 확장하고 순수한 개발팀이나 순수한 운영팀보다 더 효율적으로 서비스를 관리한다.

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

  • 소프트웨어 엔지니어링
  • 시스템 엔지니어링
  • 삽질
  • 부하

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

  • 경력 개발이 침체된다
  • 의욕이 저하된다
  • 혼란이 가중된다
  • 성장이 저하된다
  • 좋지 않은 선례를 남기게 된다
  • 인력 유출이 발생한다
  • 신뢰에 문제가 생긴다

6. 분산 시스템 모니터링

정의

  • 모니터링: 쿼리의 수와 종류, 에러의 수와 종류, 처리 시간 및 서버의 활동 시간 등 시스템에 대한 정량적 실시간 데이터를 모으고 처리하고 집계해서 보여주는 것을 말한다.
  • 화이트박스 모니터링: 로그나 JVM 프로파일링 인터페이스 또는 내부 통계 지표를 제공하는 HTTP 핸들러 등을 이용해서 얻은 시스템의 내부 지표들을 토대로 하는 모니터링을 의미한다.
  • 블랙박스 모니터링: 사용자가 보게 되는 확인 가능한 동작들을 외부에서 테스트하는 과정
  • 대시보드: 서비스의 핵심 지표에 대한 요약된 뷰를 보여주는 애플리케이션
  • 알림(alert): 사람이 읽을 수 있도록 작성된 Notifation
  • 근본 원인: 고친다면 재발하지 않는다고 확신하는 원인
  • 노드와 머신
  • 푸쉬: 서비스가 실행하는 소프트웨어나 관련된 설정에 대한 모든 변경사항을 의미한다

왜 모니터링해야 하는가?

  • 장기적인 트렌드 분석
  • 시간순 혹은 실험 그룹에 대한 비교
  • 알림
  • 대시보드
  • 임시적인 회고 분석의 수행

  • 사람을 호출하는 것은 직원들의 시간을 고려하면 매우 비용이 많이 드는 일이다.

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

  • 잘못된 알림 비율을 낮게 유지하고, 올바른 알림의 비율을 높게 유지하기 위해서는 호출을 담당하는 모니터링 시스템은 반드시 간결하면서도 안정적이여야 한다.

증상과 원인

  • 모니터링 시스템은 어떤 장애가 왜 발생했는지에 대한 질문에 답을 제시할 수 있어야한다.

블랙박스와 화이트 박스

  • 디버깅을 수행할 때는 화이트박스 모니터링이 필수적이다.
  • 블랙박스 모니터링은 이미 문제가 발생했거나 혹은 실제 증상의 원인이 된 경우에만 사람을 호출하는 원칙을 강제할 수 있다.

네가지 결정적인 지표

  • 지연응답
  • 트래픽
  • 에러
  • 서비스 포화 상태

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

  • 전체 요청에 대한 평균 응답 시간이 느려지는 것과 tail of requests이 아주 느려지는 것을 구분하는 방법:
    • 전체 요청 수와, 전체 지연 응답을 수집하여 분포를 확인하는 것이다.

적당한 측정 방법 선택하기

  • 적당한 측정 방법 예시(CPU):
    • 매 초마다 현재 CPU의 사용량을 기록한다.
    • 5% 단위로 bucket 을 구성하고, 매 초당 CPU 사용량을 측정하여 적절한 버킷의 값을 증가시킨다.
    • 분 단위로 이 값들을 집계한다.

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

  • 가장 빈번하게 발생하는 사건/사고를 탐지 하기 위한 규칙은 최대한 간결하고 예측 가능하며 확실해야 한다.
  • 수정 빈도가 높지 않은 데이터의 수집, 집계 그리고 알림에 관련된 설정은 제거하는 것이 좋다.
  • 수집은 되지만 대시보드에 노출되지도 않고 알림에 사용되지도 않는 데이터는 역시 제거하는 것이 좋다.

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

  • 이 규칙은 해당 규칙이 존재하지 않는다면 알아챌 수 없는 긴급하고, 대처가 가능하며 즉각적으로 사용자가 인지할 수 있는 상태를 탐지할 수 있는가?
  • 긴급하지 않은 알림이라면 무시할 수 있는 알림인가? 언제, 왜 이 알림을 무시할 수 있으며, 이런 알림을 받지 않으려면 어떻게 해야 할까?
  • 이 알림은 분명히 사용자에게 좋지 않은 영향을 미치는 상황에 대한 알림인가? 가용 트래픽이 모두 소모되었거나 테스트 배포처럼 사용자에게 부정적인 영향을 미치지 않는 경우에는 알림이 발생하지는 않았는가?
  • 이 알림에 대해 대응이 가능한가? 이 알림은 긴급한 것인가 아니면 내일 아침까지 기다려도 되는 것인가? 대응책은 안전하게 자동화가 가능한가? 알림에 대한 대응은 장기적인 수정이 될 것인가 아니면 단기적인 우회책이 될 것인가?
  • 다른 사람들이 이 이슈에 대한 호출을 받아서 적어도 하나 이상의 불필요한 호출이 발생힜는가?

  • 기본 철학:
    • 매번 호출기가 울릴 때마다 긴급한 상황임을 인지하고 그에 대응할 수 있어야 한다. 이러한 긴급 호출은 빈번한 호출로 인한 피로를 느끼지 않도록 하루에 단 몇 번정도만 발생해야한다.
    • 모든 호출은 대응이 가능해야 한다.
    • 호출에 대한 모든 대응은 이성적이어야 한다. 만일 호출이 자동화된 응답에 대해서만 가치가 있다면 이 호출은 전파되어서는 안된다.
    • 호출은 새로운 문제나 지금까지 보지 못한 사건에 대한 것이어야 한다.

장기적 모니터링

  • 모니터링 시스템에 대한 의사 결정은 장기적인 목표에 기초해서 판단하는 것이 중요하다.
  • 장애 호출에 대해 이미 정해진 규칙에 의해 대응하는 것은 위험한 신호이다. 팀의 그 누구도 이런 호출에 대해 자동화를 할 의지가 없다는 것은 팀이 스스로 만든 기술 부채를 해소하는 데 자신이 없다는 것을 암시한다.

7. 구글의 발전된 자동화

자동화의 가치

  • 일관성
  • 플랫폼
  • 더 신속한 수리
  • 더 신속한 조치
  • 시간 절감

구글 SRE의 가치

  • 자동화 클래스의 계층구조:
    1. 자동화를 하지 않는 단계
    2. 별도로 관리되며 시스템에 특화된 자옫화를 수행하는 단계
    3. 별도로 관리되는 범용 자동화를 수행하는 단계
    4. 내재화되었지만 시스템에 특화된 자동화를 수행하는 단계
    5. 개입이 불필요한 시스템을 도입하는 단계

스스로를 이롭게 하라: 몽땅 자동화하자!

신의 한 수: 클러스터 턴업의 자동화

  • Prodtest를 이용한 모순의 발견
  • 멱등성을 이용한 모순의 해결
  • 특화된 자동화로의 발전:
    • 자동화의 세가지 관점:
      • 적합성, 지연시간, 자동화와 실제 세계 사이의 연관성
    • 장려 정책:
      • 스크립트의 속도를 높이는 것이 주요 임무인 곳은, 팀의 기술 부채를 해소해야할 의미가 없다.
      • 자동화 스크립트를 실행하지 않은 팀은, 손쉽게 자동화할 수 있는 시스템을 구축해야할 의무가 없다.
      • 자동화 스크트의 품질이 낮더라도, 영향을 받지 않는 제품 관리자는 새로운 기능에 더 높은 우선순위를 둔다.

신뢰성은 근본적인 기능이다

8. 릴리즈 엔지니어링

릴리즈 엔지니어의 역할

  • 일관되고 반복 가능한 방법을 통해 프로젝트를 릴리즈하기 위한 최선의 방법들을 정의한다.

릴리즈 엔지니어링의 철학

  • 자기 주도 서비스 모델
  • 빠른 릴리즈 주기
  • 밀폐된 빌드
  • 원리와 절차의 강제

지속적 빌드와 배포

  • 빌드
  • 브랜칭
  • 테스트
  • 패키징
  • 배포

설정 관리 기법

  • 주 저장소에 관리하는 방법
  • 설정 파일과 바이너리를 동일한 패키지에 묶는 방법
  • 설정 패키지에 설정파일을 추가하는 방법(바이너리 빌드와 분리하는 방법)
  • 설정을 외부 저장소에서 읽는 방법

릴리즈 엔지니어링을 처음부터 도입하라

  • 릴리즈 엔지니어링 자원에 대한 여유를 확보해야한다.

9. 간결함

시스템의 안정성 vs. 신속함

  • 실험적 코딩: 실패할 것을 어느정도 예상하고 코드를 작성해 보는 것이다.
  • 유효날자를 명시하고, 이러한 코드는 테스트 커버리지와 릴리즈 관리에서 조금 더 자유로울수 있다.

지루함의 미덕

  • 책임지고 있는 시스템에 있는 돌발적인 복잡성을 야기하는 요소는 과감히 밀쳐낸다.
  • 자신이 담당하고 운영 책임을 지고 있는 시스템의 복잡도를 제거하기 위해 지속적으로 노력한다.

내 코드는 절대 포기하지 않을꺼야!

  • 전혀 실행 된적이 없는 코드나 항상 비활성화 상태의 플래그가 설정된 코드는 마치 시한 폭탄 같은 것이다.
  • 극단적으로, 분명한 목적이 있는 코드 이외에는 모두 부채라고 생각해야한다.

부정적 영향을 미치는 코드의 지표

  • 소프트웨어 팽창: 소프트웨어가 시간이 지나면서 계속 추가되는 새 기능 때문에 점차 느려지고 비대해지는 현상

최소한의 API

  • API를 최소화하는 것은 소프트웨어 시스템의 간결함을 추구하기 위한 가장 기본적인 관점이다.

모듈화

릴리즈의 간소화

III. 사례

  • 모니터링
  • 장애대응
  • 포스트모텀과 주요 원인 분석:
    • 테스트
    • 수용 계획
    • 개발
    • 제품

10. 시계열 데이터에 대한 실용적인 알림

  • 분석해야할 컴포넌트의 수를 정확히 파악해야 한다.
  • 각 시스템에 대한 엔지니어들의 책임 부담을 최대한 낮추어야한다.

시계열 데이터를 위한 저장소

  • 레이블과 벡터
  • 알림:
    • 일정 시간 동안 참아야하는 조건
    • 다른 알림이 활성화된 상태일때 특정 알림을 억제한다.
    • 동일한 레이블셋을 가진 여러 개의 달느 중복된 알림을 제거한다.
    • 유사한 레이블셋으로부터 여러 개의 알림이 전송된 경우 레이블셋에 딸 ㅏ알림을 축소하거나 확대한다.

모니터링 토폴로지의 샤딩

  • 수집 전용 계층, 데이터 집계를 위한 계층, 장기보관 시키는 계층

블랙박스 모니터링

  • prober 를 통해 블랙박스로 검사한다.

설정의 유지보수

  • 데이터 자체에 대한 구분을 정희하는 레이블
  • 데이터의 원본을 정의하는 레이블
  • 장소나 서비스 내에서 데이터의 집계가 발생한 지점을 의미하는 레이블

11. 비상대기

비상 대기 엔지니어의 삶

  • 비상 대기 시에 엔지니어는 수 분 이내에 프로덕션 환경에서 필요한 운영 작업을 수행할 수 있어야한다.
  • 사용자에게 노출되는 서비스의 경우 분기별로 99.99%의 가용성을 반드시 확보해야한다.:
    • 분기별로 약 13분 정도

비상 대기 업무의 균형 맞추기

  • 단일 사이트 팀의 규모가 커진다면, 다중 사이트 팀으로 분리 구성하는 것이 선호된다:
    • 야간에 업무를 교대하는 것은 건강에 좋지 않은 영향을 미치므로, 다중 사이트 팀의 해 뜰때 교대하는 방식은 팀 전체가 야간 교대로부터 벗어날 수 있다.
    • 비상 대기 업무에 참여하는 엔지니어의 수를 제한함으로써 엔지니어들이 프로덕션 시스템에 대한 관심을 지속할 수 있다.

품질 균형

  • 비상 대기 시 장애의 주요 원인 분석과 개선, 포스트모텀 작성, 버그 수정 등 후속 작업에 평균 6시간이 소모된다.

보상

안전에 대해 고려하기

  • 일반적으로 취하는 두가지 방식
    • 직관적, 자동화적, 그리고 신속한 대응
    • 합리적, 집중적, 그리고 계획적이며 경험에 기반한 행위
  • 비상 대기 업무는 두 번째 방식이 더 나은 결과를 도출해내며 계획에 따른 장애 조치가 가능하다.
  • 비상 대기에 활용할 수 있는 가장 중요한 자원들:
    • 분명한 장애 전파 경로
    • 잘 정의된 장애 관리 프로세스
    • 비난 없는 포스트모텀 문화
  • 동일한 에러가 다시 반복되지 않도록 하는 것이 무엇보다 중요하다.

부적절한 운영 부하에서 벗어나기

  • 호출 알림은 서비스의 SLO를 위협하는 증상이 발생하는 경우에만 보내져야 한다.
  • 모든 호출 알림은 그에 대한 대응 조치가 가능한 것들이어야 한다.

12. 효과적인 장애 조치

이론

  • 가설 연역방법: 시스템의 문제에 대한 원인을 가설을 세운뒤 확인ㅅ하는 방식으로 검증:
    • 관련 없는 증상을 들여다보거나 시스템의 지표의 의미를 잘못 이해하는 경우, 멍청하게 결과만 쫓는 행동일 뿐이다.
    • 시스템의 변경이나 입력 값 혹은 환경에 대한 잘못된 이해는 안전하고 효과적인 가설의 검증에 방해가 된다.
    • 장애 원인에 대한 가능성이 희박한 가설을 세우거나 과거에 발생한 문제의 원인과 결부시켜 한 번 발생한 문제는 다시 발생할 것이라고 결부해보리는 행위
    • 사실은 우연히 발생했거나 혹은 동일한 원인에 의해 발생한 관련 현상들을 계속해서 쫓아다니는 행위

실전

  • 문제 보고
  • 문제의 우선순위 판단
  • 문제를 관찰하기
  • 진단
    • 단순화하기와 범위를 좁히기
    • 무엇이, 어디서, 왜를 고민하기
    • 가장 마지막으로 수정된 부분에 주목하자
    • 서비스에 특화된 진단
  • 테스트와 조치:
    • 이상적인 테스트는 상호 배타적이여서 가설의 어느 한 집합을 검증함으로써 다른 가설의 가능성이 없음을 밝혀낼 수 있어야한다.
    • 가장 명확한 것을 최우선으로 고려해야한다.: 가능성이 큰 테스트부터 순차적으로 진행하면서 테스트로 인해 시스템에 발생할 수 있는 위험에 대해서도 고려해야 한다.
    • 혼란 요소로 인해 특정 실험이 잘못된 결과를 도출하게 될 수도 있다.
    • 적극적인 테스트가 나중에 실행할 테스트의 결과에 부작용을 초래할 수도 있다.
    • 일부 테스트는 설득력이 떨어질 수도 있다.

부정적인 결과의 마법

  • 부정적인 결과는 무시해서도 안되고 평가절하 해서도 안된다.
  • 부정적인 결과로 끝난 실험 역시 결론이다.
  • 도구와 방법은 실험의 결과와는 무관하며 향후의 작업에 대한 단서가 된다.
  • 부정적인 결과를 공표하는 것은 업계의 데이터 주도 성향을 증진시킨다.
  • 자신의 결과를 공표하자.

처방

  • 시스템은 복잡하다.
  • 운영 중인 프로덕션 시스템에서 문제를 재현하는 것은 피해야 한다.

조금 더 수월하게 장애를 조치하기

  • 화이트박스 지표와 구조화된 로그를 모두 활용해서 처음부터 각 컴포넌트를 관찰할 수 있는 방법을 마련한다.
  • 시스템을 디자인할 때 컴포넌트 간에 이해가 쉽고 관찰이 가능한 인터페이스를 마련한다.

13. 긴급 대응

  • 테스트로 인한 장애
  • 변경으로 인한 장애
  • 절차에 의한 장애

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

  • 장애에 대한 기록을 남기자
  • 커다란, 어쩌면 불가능할지도 모를 것에 대한 질문을 던지자: 만약 …라면?
  • 사전 테스트 장려하기

14. 장애 관리하기

미흡한 장애 처리

  • 기술적인 문제에 대한 날카로운 집중
  • 소통의 부재
  • 프리랜서의 고용

장애 관리 절차의 기본 요소들

  • 책임에 대한 재귀적인 분리:
    • 장애 제어
    • 운영 업무
    • 의사소통
    • 계획
  • 확실한 컨트롤 타워
  • 실시간 장애 조치 문서
  • 명확하고 즉각적인 업무 이관

언제 장애를 선언할 것인가?

  • 아래 조건중 하나라도 만족할시:
    • 문제를 해결하기 위해 다른 팀의 도움이 필요한가?
    • 문제가 사용자에게 영향을 미쳤는가?
    • 문제 발생 이후 한 시간 동안 집중적으로 분석했는데도 문제가 해결되지 않았는가?

요약

  • 장애 조치에 대한 모범 사례:
    • 우선순위: 우선 출혈을 막고 서비스를 되살린 후에 근본 원인에 대한 증거를 찾자.
    • 사전 준비: 장애 조치에 참여한 사람들의 자문을 받아 장애 관리 절차를 미리 개발하고 문서화 해두자.
    • 신뢰: 장애 조치에 참여 중인 모든 사람들에게 충분한 자율권을 보장하자.
    • 감정 조절: 장애를 조치하는 동안 스스로의 감정적 상태에 주의를 기울이자. 만일 너무 부담이 된다면 다른 이에게 도움을 청하자.
    • 대체 방안에 대한 모색: 주기적으로 현재 선택할 수 있는 방법에 대해 다시 생각하고 이 방법이 여전히 유효한지, 아니면 다른 방법을 찾아야 하는지를 판단하자.
    • 실습: 이 과정을 정기적으로 수행해서 자연스럽게 활용할 수 있는 수준으로 만들자.
    • 개선: 계속해서 개선하자. 모든 팀 구성원들이 모든 역할에 익숙해질 수 있도록 독려하자.

15. 포스트모텀 문화: 실패로부터 배우기

  • 비난보다는 생산적인 포스트모텀 문서를 작성해야한다.
  • 모든 포스트모텀 문서는 반드시 리뷰를 거쳐야한다.
  • 올바른 일을 한 사람에게 눈에 보이는 보상을 지급하자.
  • 포스트모텀의 효과에 대한 피드백을 구하자

16. 시스템 중단 추적하기

17. 신뢰성을 위한 테스트

  • 사이트는 반드시 소프트웨어 변경이나 서버군의 변경이 없는 완전히 동일한 상태여야한다. 따라서 향후 시스템의 동작이 과거의 동작과 유사하게 된다.
  • 시스템의 각 변경사항에 의한 불확실성을 고려한다면 사이트에 가해진 모든 변경 사항에 대해 확실하게 설명할 수 있어야 한다.

전통적인 테스트

  • 단위테스트
  • 통합테스트
  • 시스템 테스트:
    • 스모크 테스트
    • 성능 테스트
    • 회귀 테스트

프로덕션 테스트

  • 설정 테스트:
    • 아래 환경에서 설정테스트는 어려워진다.:
      • 암묵적으로 바이너리에 내장된 기본 값을 사용하는 경우: 이 경우 테스트의 결과는 별개의 버전이 된다.
      • 쉘의 명령 줄 플레그 같은 전처리기가 명시된 경우
      • 공용 런타임에 대해 문맥에 의존적인 동작을 명시적으로 제어하는 경우: 테스트가 런타임의 릴리즈 일정에 의존성을 갖게 된다.
  • 스트레스 테스트
  • 카나리 테스트

테스트 및 빌드 환경 구성하기

  • 최소한의 노력으로 최상의 효과를 낼수 있는 테스트를 수행해야 한다.:
    • 어떤 형태로든 기반 코드의 우선순위를 결정할 수 있는가? 기능 개발과 프로젝트 관리 기법을 고려해볼 때 모든 태스크가 높은 우선순위를 가지고 있다면, 그 어떤 태스크도 우선순위가 높다고 할 수 없다. 어떤 식으로든 중요도를 측정해서 시스템 컴포넌트들의 순서를 결정할 수 있는가?
    • 정말로 사활이 걸려있거나 비지니스 관점에서 중요한 기능이나 클래스르 특정할 수 있는가?
    • 다른 팀들이 통합해서 사용하는 API 들이 있는가? 지금까지의 릴리즈 테스트에서 아무런 문제가 없었던 API 들이라 하더라도 다른 개발팀이 제대로 이해하지 못한다면 우리 팀의 API 에 대한 클라이언트를 잘못 작성하거나 혹은 최적의 상태로 구현하지 못할 수도 있다.
  • 문제가 발생한 코드를 보고받으면, 지금 당장 하던 일을 멈추고 문제를 해겷해야한다.:
    • 결함을 발견한 후에 변경된 코드의 어느 부분에서 문제가 생겼는지를 찾아내는 것이 더 어렵다.
    • 소프트웨어에 결함이 발견되면 그에 대한 우회 조치를 취해야 하므로 팀의 업무 수행 속도가 감소한다.
    • 나이틀리 빌드나 위클리 빌드 같은 릴리즈들이 그 가치를 잃게 된다.
    • 긴급 릴리즈에 대한 팀의 대처 능력이 더 복잡하고 어려워진다.

대규모 환경에서의 테스트

  • 테스트 소프트웨어
    • 수행해야하는 일반적인 동작:
      • 데이터베이스 성능 지표의 조회 및 배포
      • 가용성 위험에 대한 계획 수립을 위한 사용량 예측
      • 사용자가 접근할 수 없는 서비스 복제본의 데이터 리팩토링
      • 서버 상의 파일 변경
    • 추가적인 특징:
      • 도구들의 부작용이 테스트를 수행한 메인스트림 API 에 그대로 남는다.
      • 유효성 검사 및 릴리즈 장벽으로 인해 사용자가 직접 접근하는 프로덕션 환경과는 격리된 환경에서 실행된다.
  • 자동화 도구:
    • 수행해야하는 일반적인 동작:
      • 데이터베이스 인덱스 선택
      • 데이터센터 간의 로드밸런싱
      • 신속한 리마스터링을 위한 릴레이 로그 혼합
    • 추가적인 특징:
      • 실제로 작업은 주로 견고하고, 예측 가능하며, 충분히 테스트된 API들을 대상으로 수행된다.
      • 수행되는 작업의 목적에 따라 작업 수행 도중 다른 API 클라이언트들에게서 알수 없는 중단 현상이 발생할 수 있다.

재해 테스트

  • 재해 복구 도구는 오프라인 상태에서도 동작할수 있도록 세심한 주의를 기울여 만들어져야한다.
  • 재해 복구 도구의 수행동작:
    • 서비스를 깨끗하게 정지시킨 상태와 동일한 체크포인트 상태를 계산한다.
    • 계산된 체크포인트 상태를 기존의 재해 무결성 검사 도구들이 사용할 수 있는 적재 가능한 상태로 만든다.
    • 재시작 절차를 수행하는 릴리즈 경계 도구들을 지원한다.

지금 필요한것은 스피드

프로덕션 환경에 배포하기

  • 버전 관리 시스템에 대한 커밋의 경쟁으로 인해 프로젝트의 수행 속도 역시 어느 한계 이상으로 좋아지지 않는다.
  • 테스트 인프라스트럭처와 프로덕션 환경이:
    • 완전히 분리되었을때:
      • 개발시스템 아키텍처를 보호할수 있다.
      • 개발 속도가 일부 저하될수 있다.
    • 완전히 분리되지 않았을때:
      • 마이그레이션 위험을 완전하게 제거할 수 없다.
      • 테스트를 실제 환경에서 할 수 있다.
      • 위험도가 굉장히 높을 수 있다.

테스트는 얼마든지 실패할 수 있다.

  • 과거에는 릴리즈 주기가 굉장히 길어서, 사용자가 인지할 수 있을만한 문제점이 숨어있는 경우가 많았다.
  • 릴리즈 주기가 짧아지면서, 중간 산출물 마저도 모두 테스트 되기 때문에, 자동화된 테스트 커버리지의 효율성을 온전히 얻을 수 있다.
  • 신뢰성을 관리하여야한다.
  • 목표 릴리즈 주기에 맞추면서 불확실성 수준을 조절해야 한다.
  • 적절한 수준의 신뢰성을 유지하기 위해서는 프로덕션 환경이 거의 자동화되어야 한다.
  • 설정 파일의 신뢰성 관점에서:
    • 각 설정 파일은 통상적인 수정에 대해 충분한 테스트 커버리지를 확보해야 한다.
    • 릴리즈에 앞서 릴리즈 테스트를 수행한 후에 파일의 수정이 이루어져야 한다.
    • 유리 깨기 메커니즘(break-glass mechanism)을 통해 테스트가 완료되기 전에 파일을 밀어넣을 수 있는 방법을 제공해야 한다. 이 방법은 신뢰성을 떨어뜨릴 수 있으므로 나중을 위해 발견된 버그에 대해서는 되도록 문제를 크게 부풀려서 더욱 확실하게 해결할 수 있도록 하는 것이 좋다.

통합

  • 설정파일에 대한 통합테스트를 고려해야한다.
  • 설정파일은 임의의 문법을 사용한다. YAML, JSON 등 런타임에 대한 의존성을 갖지 않아야한다.
  • 프로토콜 버퍼를 사용해서, 런타임에 한정적으로 사용할 수 있다는 장점이 있다.

프로덕션 환경 조사하기

  • 요청의 종류:
    • 이미 문제가 있는 것으로 판명된 요청
    • 문제가 없는 것으로 판명되었으며 프로덕션에 대해 테스트가 가능한 요청
    • 문제가 없는 것으로 판명되었지만 프로덕션에 대해 테스트가 불가능한 요청

18. SRE 조직의 소프트웨어 엔지니어링

SRE 조직의 소프트웨어 엔지니어링 역량이 중요한 이유

  • 확장성이나 장애 발생 시 자연스러운 종료 처리 그리고 다른 인프라스트럭처나 도구들을 쉽게 활용할수 있는 능력 을 통해 소프트웨어를 디자인하고 개발
  • SRE 들이 중요한 사안에는 모두 참여하므로 개발할 도구의 목적과 요구사항을 손쉽게 이해한다.
  • 개발하는 도구를 직접 사용할 사용자와의 관계가 직접적이기 때문에 솔직하고 신속한 사용자 피드백을 기대할 수 있다.

전통적인 수용량 계획

  1. 수요 예측의 수집
  2. 빌드 및 할당 계획의 수립
  3. 리뷰 및 계획의 승인
  4. 배포 및 자원 설정
  • 장단점:
    • 본질적으로 불안정하다:
      • 서비스의 효율성이 떨어져서 동일한 양의 수요를 감당하기 위해 더 많은 자원을 필요로 하게 되는 경우
      • 고객의 유입률이 증가하여 그에 따라 수요가 증가하는 경우
      • 클러스터의 새로운 컴퓨트 자원에 대한 배송이 지연되는 경우
      • 제품의 성능 목표가 변경되어 서비스 배포 형태와 필요한 자원의 양이 바뀌는 경우
    • 노동집약적이며 모호하다

의도 기반 수용량 계획

  • 구현이 아닌 요구사항을 명확히 하자

의도를 파악하기 위한 선행 작업

  • 의존성
  • 성능 지표
  • 우선순위 결정

인식의 제고 및 도입의 촉진

  • 일관적이고 긴밀한 접근법
  • 사용자에 대한 지원
  • 제품의 활용성을 알리기 위한 선임 개발자와 관리자의 전폭적인 지원

  • 기대치 설정하기
  • 적절한 사용자층 정의하기
  • 고객 서비스
  • 적절한 수준의 디자인

SRE 조직에서 소프트웨어 엔지니어링을 육성하는 방법

  • 인력 수급과 개발 시간:
    • 엔지니어가 남는 시간에 개발하는 프로젝트로 남는다.
    • 제대로 된 절차를 거쳐 정식 프로젝트로 승격한다.
    • SRE 의 지휘 아래 적절한 소프트웨어 개발 역량을 투입할 수 있도록 행정적 지원을 받는다.

목표 이루기

  • 명확한 메시지로 소통하라:
    • 일관적이고 충분한 지원을 받은 소프트웨어 솔루션은 신입 SRE들이 업무에 더 빠르게 적응하는 데 도움이 된다.
    • 어떤 작업을 수행할 수 있는 방법들을 몇가지로 제한하면, 전체 부서가 한 팀이 개발한 기술의 혜택을 받게 되고, 그 지식과 인적 자원이 여러 팀으로 옮겨 다니기가 쉬워진다.
  • 조직의 역량을 평가하라
  • 출시하고 반복하라
  • 자신의 기준을 낮추지마라

19. 프론트엔드의 로드밸런싱

모든 일을 힘으로만 해결할 수는 없는 법

DNS 를 이용한 로드밸런싱

  • 클라이언트의 행동을 넘어서는 수준의 제어는 거의 가능하지 않다는 점이다.
  • 클라이언트가 가장 가까운 주소를 결정할 수 없다.

가상 IP 주소를 이용한 로드밸런싱

  • sticky session:
    • id 기반의 sticky session
    • consitent hashing
  • DSR(Direct Server Reply)

20. 데이터센터의 로드밸런싱

이상적인 사례

  • 특정 시점에, 가장 많은 부하를 처리하는 백엔드와 가장 적은 부하를 처리하는 백엔드의 CPU 사용률이 완전히 일치해야한다.

양호하지 않은 태스크 구별하기: 흐름 제어와 레임덕

양호하지 않은 태스크를 식별하는 간단한 방법: 흐름 제어

양호하지 않은 태스크를 식별하는 확실한 방법: 레임덕 상태

  • 양호함: 백엔드 태스크가 올바르게 초기화되어 요청들을 처리 중인 상태
  • 연결 거부: 백엔드 태스크가 응답이 불가능한 상태. 이 상태가 나타나는 이유는 태스크가 시작 중 혹은 셧다운 중이거나 아니면 백엔드가 정상적이지 않은 상태이기 떄문이다.
  • 레임덕(Lame duck): 백엔드 태스크가 포트를 리스닝 중이고 서비스를 제공할 수 있지만 명시적으로 클라이언트에게 요청의 전달을 중단할 것을 요구하는 상태

서브셋을 이용한 연결 풀 제한하기

적절한 서브셋 선택하기

  • 클라이언트의 수가 백엔드의 수보다 훨씬 적은 경우, 이 경우에는 클라이언트당 백엔드의 수를 크게 해서 백엔드 태스크가 트래픽을 전혀 수용하지 못하는 경우를 방지할 수 있다.
  • 클라이언트의 작업 내에서 부하의 불일치가 빈번하게 발생하는 경우, 이 시나리오는 클라이언트가 자주 많은 양의 요청을 보내는 상황에서 발생한다. 많은 수의 요청은 클라이언트에 할당된 서브셋에 집중되므로 서브셋의 크기를 크게 해서 부하가 최대한 많은 백엔드 태스크로 퍼져나가도록 해야한다.

서브셋 선택 알고리즘: 랜덤 서브셋

로드밸런싱 정책

  • 로드밸런싱에서 고려해야하는 것들:
    • 작은 크기의 서브셋
    • 다양한 쿼리 비용
    • 머신의 다양성
    • 예측 불가능한 성능 요인들:
      • 정반대의 이웃들, 태스크 재시작
  • 간단한 라운드로빈
  • 최소 부하 라운드로빈:
    • 가장 적은수의 활성화된 요청을 처리하기
    • 특정 백엔드의 용량을 파악하기에 가장 좋은 방법이 아닐 수도 있다.
    • 각 클라이언트의 활성화된 요청의 수는 다른 클라이언트가 같은 백엔드에 할당한 요청의 수를 포함하지는 않는다.
  • 가중 라운드로빈

21. 과부하 처리하기

초당 쿼리 수의 함정

  • 가비지 컬렉션을 수행하는 플랫폼의 경우, 메모리에 대한 부하는 본질적으로 CPU 사용률의 증가를 동반한다.
  • 다른 플랫폼의 경우, 나머지 자원이 CPU보다 먼저 바닥나는 경우는 극히 드물기 때문에 해당 자원을 준비할 여력이 충분하다.

사용자별 제한

  • 서비스 소유자는 모든 고객들이 자신의 자원을 지속적으로 한계치까지 사용하지 않는다는 사실에 기초해 계획을 수립한다.

클라이언트 측에서의 사용량 제한

  • 요청을 거부하더라도 자원을 전혀 소비하지 않는건 아니다.
  • 즉, 요청을 거부하는 것도 과부하 상태에 놓이는 것을 완전히 해결하지는 못한다.
  • 클라이언트 측에서 사용량을 제한해야한다.
  • 할당량 초과 에러로 인해 거부되는 것을 인지하면, 자체 조정을 통해 외부로 발신되는 트래픽을 제한한다.
  • 실제로 허용된 수보다 더 많은 요청이 백엔드로 전달되게 되면, 백엔드가 더 많은 자원을 소비하게 되지만, 모든 클라이언트가 이 상태를 인지하기까지의 시간이 더 짧아진다.

중요도

  • criticality:
    • CRITICAL_PLUS: 가장 중요한 요청 값, 실패시 사용자에게 직접적인 영향을 미치게 된다.
    • CRITICAL: 프로덕션 환경에서 전달되는 모든 요청들이 기본적으로 사용하는 값, 사용자에게 영향을 미치지만, CRITICAL_PLUS 보다 영향도가 낮다.
    • SHEDDABLE_PLUS: 어느정도 실패가 용인할수 있는 트래팩을 위한 값. batch 작업들의 기본값
    • SHEDDABLE: 부분적 실패가 발생하거나 간혹 아예 사용이 불가능할 것으로 예상되는 작업들을 위한 값.
  • 요청의 중요도는 지연응답 요구사항에 정비례한다.

활용도에 대한 신호들

과부하 오류 처리하기

  • 데이터센터 내에 대량의 백엔드 태스크에 과부하가 걸리는 상황:
    • 데이터센터 간 로드밸런싱 시스템이 완벽하게 동작한다면 이 상황은 발생하지 않는다.
  • 데이터센터 내의 일부 백엔드 태스크에 과부하가 걸리는 상황:
    • 대부분의 경우 데이터센터는 충분한 수용량이 있지만, 로드밸런싱이 완벽하지 않기 때문에 발생한다.
  • 데이터센터 내의 백엔드 태스크에 광범위하게 과부하가 발생하면 요청의 처리를 재시도해서는 안 된다.
  • 로드밸런싱 정책의 관점에서 재시도 요청과 새로운 요청은 구분되지 않는다. 이렇게 하는게 자연스럽게 부하를 분산하게 된다.

재시도 여부 결정하기

  • 재시도 허용 수준(per-request retry budget):
    • e.g. 최대 3회 재요청한다.
  • 클라이언트별 재시도(per-client retry budget):
    • e.g. 10% 이상의 요청이 실패할경우 재시도하지 않는다.
  • 클라이언트가 요청의 메타데이터 내에 해당 요청에 대한 처리 시도가 몇번이었었는지 기록한다.:
    • 백엔드가 이 값의 변화로 자신의 상태를 알아낸다.

연결에 대한 부하

  • 데이터센터 간 로드밸런싱 알고리즘을 통해 부하를 관리한다. 이렇게 하면 요청에 따른 부하를 여력이 있는 다른 데이터센터로 효율적으로 배분할 수 있다.
  • 일괄 클라이언트 작업은 요청을 기반 백엔드로 전달하고 그 결괄르 다시 클라이언트에게 전달하는 것 외에는 아무런 추가 작업을 수행하지 않는 별도의 일괄 프록시 백엔드 태스크들을 사용하도록 위임한다.:
    • 프록시가 일종의 퓨즈를 맞게 된다.
    • 백엔드에 대한 연결의 수를 절감할 수 있어 로드밸런싱을 개선하는 효과를 얻을 수 있다

22. 연속적 장애 다루기

연속적 장애의 원인과 그 대책

서버 과부화

자원의 부족

  • CPU 자원이 부족한 경우:
    • 처리 중인 요청 수의 증가
    • 비정상적으로 증가하는 큐의 크기
    • 스레드 기아
    • CPU 혹은 요청 기아
    • RPC 시간 초과
    • CPU 캐시 이점의 감소
  • 메모리:
    • 태스크 종료
    • 자바의 가비지 컬렉션 수행률 증가로 인한 CPU 사용률 증가
    • 캐시 활용률의 감소
  • 쓰레드
  • 파일 서술자
  • 자원 간의 의존성:
    • 장애가 발생한 동안 그 인과관계를 정확하게 파악하기 어렵다.

서비스 이용 불가

  • 충돌이 발생하기 시작하면, 다른 서버에도 충돌이 퍼지게 되고, 최초 충돌이 발생한 서버가 복구되더라도 상황이 해소되지 않는다.

서버 과부하 방지하기

  • 서버 수용량 한계에 대한 부하 테스트 및 과부하 상태에서의 실패에 대한 테스트
  • 경감된 응답 제공하기
  • 과부하 상태에서 요청을 거부하도록 서비스를 구현하기
  • 고수준의 시스템이 서버에 과부하를 유발하지 않고 요청을 거부하도록 구현하기:
    • 리버스 프록시의 경우 IP 주소 조건
    • 로드밸런서는 서비스가 전체적인 과부하 상태일 떄 요청을 스스로 차단한다.
    • 개별 작업들은 로드밸런서가 보내요는 요청의 변화에 의해 서버게 갑작스럽게 많은 요청이 몰리지 않도록 이를 제한한다.
  • 수용량 계획을 실행하기

큐 관리하기

  • 쓰레드 풀 크기에 비해 짧은 길이의 큐를 배치해서 서버가 감당할 수 없는 수준의 요청이 유입되는 경우 최대한 이른 시점에 이를 거부하게 하는 것이 좋다.

부하 제한과 적절한 퇴보

  • 부하를 배분하는 가장 직관적인 방법은 CPU, 메모리 혹은 큐의 길이에 따라 태스크별로 제한을 두는 것이다.
  • 적절한 퇴보:
    • 어떤 지표를 활용해서 부하 제한이나 적절한 퇴보의 적용 여부를 결정할 것인가?
    • 서버가 퇴보 모드로 동작하게 되면 어떤 조치를 취해야하는 가?
    • 부하 제한이나 적절한 퇴보는 어느 계층에서 구현해야 하는가? 스택 내의 모든 계층에서 구현해야할까? 아니면 상대적으로 높은 수준의 병목 구간에서만 적용해도 충분할까?
  • 적절한 퇴보는 너무 자주 발생해서는 안된다.
  • 어떤 코드 경로가 한번도 사용된 적이 없다면 이 코드 경로는 동작하지 않을 것이라는 점을 지지 말자. 퇴보 모드에서의 운영 경험을 쌓을 수 없어 오히려 위험 수위가 높아진다.
  • 이 모드에서 동작하는 서버가 너무 많아지지는 않는지 적절히 모니터링하고 경고를 발송해야한다.
  • 부하 제한과 적절한 퇴보를 구현하는 로직이 복잡해지면 그 자체에 문제가 발생할 수 있다.

재시도

  • 자동 재시도를 수행할 때:
    • 적절한 퇴보를 통해 백엔드에 대한 재시도의 영향을 줄일수 있다.
    • 임의의 값을 이용해 지수적으로 간격을 두어야한다. + 지터
    • 요청당 재시도 횟수에 제한을 둔다. 무한정 요청을 재시도하면 안 된다.
    • 서버 수준에서 재시도에 대한 한계 수치를 책정한다.
    • 서비스 전체를 살펴보고 특정 수준의 재시도가 정말로 필요한 것인지를 결정해야 한다.
    • 명확한 응답코드를 사용하고 각기 다른 실패 모드를 어떻게 처리할 것인지를 생각해야 한다.

지연응답과 마감기한

  • 마감기한의 결정:
    • 대부분 마감기한을 설정하는 것이 바람직하다.
    • 마감기한이 너무 길면 스택의 상위 계층이 자원을 너무 많이 소비해서 스택의 하위 계층에서 문제가 발생한다.
  • 마감기한의 상실:
    • 서버가 클라이언트의 마감기한을 넘긴 요청들을 계속 처리하느라 자원을 소비하고 있는 현상이다.
    • 각 요청을 위해 다른 작업을 수행하기에 앞서 각 단계의 마감기한이 얼마나 남았는지를 먼저 확인해야 한다.
  • 마감기한의 전파
  • 이중 지연응답:
    • 일시적인 지연응답 현상이 발생했을 때 이 장애의 원인이 이중 지연응답이라는 것이 명확하게 드러나지 않는다. 평균값과 더불어 지연응답의 분포 역시 살펴보아야한다.
    • 요청이 마감기한까지 기다리지 않고 일찌감치 에러를 리턴하면 이 문제는 자연스럽게 피해갈 수 있다.
    • 통상적인 요청의 지연응답에 비해 몇 배나 긴 마감기한을 설정하는 것은 좋지 않은 방법이다.
    • 공유 자원을 사용할 때는 일부 키 공간에 의해 해당 자원들이 고갈될 수 있다.

느긋한 시작과 콜드 캐싱

  • 초기화가 필요한 경우:
    • 첫 번쨰 요청을 받을 때 필요한 백엔드와의 연결을 설정해야 하는 경우
  • 일부 언어, 특히 자바의 경우 런타임 성능 향상을 위한 추가 작업이 실행되는 경우:
    • JIT(Just-In-Time) 컴파일, 핫스팟(hotspot) 최적화 및 지연된 클래스 로딩 등이 수행되는 경우
  • 콜드 캐시를 갖게 되는 경우:
    • 새로운 클러스터를 켜는경우
    • 유지보수 작업 후 클러스터를 서비스에 제공하는 경우
    • 서비스 재시작
  • 캐시가 서비스에 중요한 영향을 미친다면:
    • 서비스를 오버프로비전한다. 지연응답 캐시와 용량 캐시를 구분하는 것이 중요하다 지연응답 캐시를 사용하게 되면 서비스는 캐시가 비어 있더라도 필요한 부하를 감당할 수 있지만 용량 캐시를 사용하면 캐시가 비어있느 ㄴ경우에는 필요한 부하를 감당할 수 없다. 서비스 소유자는 서비스에 캐시를 추가하는 것에 대해 충분히 주의를 기울여야 하며, 새로 투입되는 캐시가 지연응답 캐시인지 아니면 용량캐시로서 안전하게 잘 동작할 수 있도록 잘 구현된 캐시인지를 확인해야한다. 간혹 서비스의 성능 향상을 위해 투입한 캐시 때문에 의존성 관리만 어려워지기도 한다.
    • 일반적인 연속적 장애 방지 기법을 적용한다.
    • 클러스터에 부하를 위임할 때는 부하의 크기를 천천히 늘려야 한다.

항상 스택의 아래쪽을 살펴보자

  • 내부 계층 간의 통신은 여러 이유로 문제가 될 수 있다.:
    • 분산 데드락의 영향을 받기 쉽다.
    • 어떤 장애나 과부하로 인해 내부 계층 간의 통신이 증가하는 경우 어느 수준 이상으로 부하가 증가하면 내부 계층 간 요청이 빠르게 증가할 수 있다.
    • 계층 간의 통신의 중요도에 따라 시스템의 부트스트랩이 더 복잡해질 수 있다. 일반적으로 계층 간 통신(특히 통신의 경로가 계속 반복되는 경우)은 지양하는 것이 좋다. 클라이언트가 통신을 하도록 주도해야한다.

연속적 장애의 발생 요인

  • 프로세스 중단
  • 프로세스 업데이트
  • 새로운 배포
  • 유기적 성장
  • 계획에 의한 변경, 자원의 감ㅅ소 혹은 서버의 종료:
    • 요청 프로파일의 변화
    • 자원의 제한

연속적 장애 테스트하기

  • 장애가 발생할 때까지 테스트하고 조치하기:
    • 만약 컴포넌트가 과부하 상태에서 퇴보 모드에 들어간다면 사람의 개입 없이 퇴보모드에서 원래의 동작에서 돌아올 수 있는가?
    • 과부화 상태에서 몇 개의 서버에서 충돌이 발생한다면 시스템을 안정화시키기 위해서는 어느 정도의 부하가 절감 되어야 하는가?
  • 테스트 예시:
    • 예상되는 트래픽 패턴과 더불어 태스크의 수를 빠르게 혹은 천천히 줄여본다.
    • 클러스터의 수용량을 신속하게 줄여본다.
    • 다양한 백엔드를 시스템에서 감춰본다.

사용량이 높은 클라이언트 테스트하기

  • 확인해야 하는 내용:
    • 서비스가 다운된 동안 클라이언트는 얼마나 빠르게 작업을 처리하는가?
    • 에러 상황에서 클라이언트가 임의의 지수 백오프를 사용하는가?
    • 클라이언트가 대량의 부하를 유발하는 취약점을 가지고 있는가?

상대적으로 덜 중요한 백엔드 테스트

  • 중요한 컴포넌트들이 그에 따른 간섭을 받는지 확인해야한다.

연속적 장애를 처리하기 위한 즉각적인 대처

  • 자원의 추가투입
  • 건강 상태 점검의 중지
  • 서버의 재시작: 죽음의 gc 소용돌이, 특별한 마감기한 없이 자원을 소비중인 요청이 있을때, 데드락 등 (반드시 일부 서버만을 재시작하고 천천히 진행해야한다.)
  • 트래픽의 경감
  • 퇴보 모드로 들어가기
  • 일괄 작업 부하 배제하기
  • 문제가 있는 트래픽 배제하기

23. 치명적인 상태 관리하기: 신뢰성을 위한 분산에 대한 합의

  • 프로세스의 그룹은 아래 질문에 명확한 답이 있어야한다.:
    • 프로세스 그룹에서 어떤 프로세스가 리더 역할을 수행하는가?
    • 프로세스 그룹에서 프로세스의 집합은 무엇인가?
    • 메시지가 분산 큐에 정상적으로 추가되었는가?
    • 프로세스가 임대한 자원을 계속해서 보유하고 있지는 않는가?
    • 주어진 키로 데이터 저장소에 저장된 값은 무엇인가?
  • ACID(Atomicity, Consistency, Isolation, Durability), BASE(Bascially Available, Soft state and Eventual concistency)
  • 결과적 인과성을 개발자들이 직접 처리하도록 하는 것은 너무나도 어려운 일이며 일관성의 문제는 반드시 데이터베이스 수준에서 해결되어야 한다.

합의는 왜 필요할까: 분산 시스템 감 협업의 실패

  • split-brain
  • 사람이 개입해야하는 장애 조치
  • 그룹-멤버십 알고리즘의 오류

분산에 대한 합의가 동작하는 방식

  • 비동기 분산 합의 vs 동기 합의
  • crash-fail vs crash-recover:
    • 상대적으로 충돌 복구(crash-recover) 알고리즘이 더 유용한다.
  • Byzantine failure vs non-Byzantine failure

분산 합의를 위한 시스템 아키텍처 패턴

  • 저수준이며 원시적이기 때문에 현실적으로 추상화 된것을 사용해야한다.
  • Zookeeper, Consul, etcd

신뢰할 수 있는 복제된 상태 머신

  • 복제된 상태 머신:
    • 슬라이딩 윈도우 프로토콜(sliding-window protocol)
  • 신뢰할 수 있는 복제된 데이터 저장소와 설정 저장소
    • 분산 시스템에서는 타임스템프의 사용은 문제가 많다. 여러 머신 사이 시간을 정확하게 동기화하는 것이 불가능하기 때문이다.
  • 리더 선출을 이용한 고가용성 프로세싱
  • 분산 조정과 잠금 서비스
  • 신뢰할 수 있는 분산 큐와 메시지

분산 합의의 성능

  • 작업의 부하를 결정하는 요소:
    • 처리량: 부하가 최대치일 때 단위 시간에 만들어진 제안의 수
    • 요청의 종류: 상태를 변경하는 작업의 분량
    • 읽기 작업에 필요한 일관성의 정도
    • 데이터 페이로드의 크기가 다양한 경우 요청의 크기
  • 배포 전략:
    • 배포가 지역적으로 진행되는지 전역적으로 진행되는지 여부
    • 과반수를 결정하는 알고리즘은 무엇인지, 그리고 대부분의 프로세스들은 어디에 위치하는지
    • 시스템이 샤딩, 파이프라이닝, 일괄 작업을 사용하는지

읽기 작업 부하의 확장

  • 많은 부하가 읽기 작업을 주로 수행하기 때문이다.
  • 읽기 일관성을 위해:
    • 읽기 전용 합의 작업을 수행한다.
    • 가장 최신 데이터를 보장하는 복제 서버로부터 데이터를 읽는다. 안정적인 리더 프로세스를 사용하는 시스템이라면 리더가 이를 보장한다.
    • 과반수 임대를 사용한다.

과반수 임대

  • 읽기 작업이 많은 부하에 특히 유용하다.

분산 합의 성능과 네트워크 지연응답

  • 합의 시스템의 두가지 무리적 제약:
    • 네트워크 라운드 트립 시간
    • 영속 저장소에 데이터를 기록하는 시간
  • 많은 합의 시스템이 TCP/IP 를 지양하며, 메시지의 FIFO를 강한 신뢰성을 보장한다.
  • 느린 초기 대역폭
  • 모든 클라이언트가 합의 클러스트에 대한 연결을 영구적으로 열어두는 것은 실용적이지 못하다.
  • 프록시는 샤딩과 로드밸런싱 전략을 캡슐화 하는 것은 물론 클러스터 맴버와 리더들의 발견 측면에서도 좋은 방법이다.

성능에 대한 고려: Fast Paxos

  • 클라이언트로부터 모든 수락자에게 전달되는 하나의 병렬 메시지로 대체한다.
  • 많은 시스템들이 처리량을 향상시키기 위해 일괄 작업을 통해 여러 작업을 수락자 내의 하나의 트랜잭션으로 처리한다.
안정적 리더
  • 상태를 변경하는 모든 작업은 리더를 통해 보내져야 하며, 리더와 가까이 있지 않은 클라이언트에서는 추가적인 네트워크 지연응답이 있을 수 있다.
  • 리더 프로세스에서 외부로 나가는 네트워크 대역폭은 시스템에 있어서는 병목지점이다., 그 이유는 다른 메시지들은 처리된 트랜잭션 수 외에 다른 데이터 페이로드를 포함하지 않지만 리더의 수락 메시지는 제안과 관련된 모든 데이터를 가지고 있기 때문이다.
  • 리더가 성능에 문제가 있는 머신에서 동작한다면 전체 시스템의 처리량이 감소하게 된다.
일괄처리
  • 파이프라이닝
디스크 접근
  • 하나의 합의 작업에 대한 지연응답에 포함되는 내용:
    • 제안자가 한 번의 디스크 쓰기 작업을 수행하는 시간
    • 수락자에게 병렬로 메시지를 보내는 시간
    • 수락자들이 병렬로 디스크에 기록하는 시간
    • 리턴 메시지를 보내는 시간

분산 합의 기반 시스템의 배포

복제 서버의 수

  • 복제 서버의 수에 대한 결정:
    • 신뢰성에 대한 수요
    • 시스템에 영향을 미치는 계획된 유지보수의 빈도
    • 각종 위험 요소
    • 성능
    • 비용

복제 서버의 위치

  • 장애 도메인(failure domain): 하나의 장애가 발생했을 때 사용이 불가능한 상태가 되는 시스템 컴포넌트의 집합
  • 예시:
    • 하나의 물리적 머신
    • 한 데이터센터 내에서 하나의 전원 공급기를 통해 서비스되는 랙(rack)
    • 한 데이터센터 내에서 하나의 네트워크 장비에 의해 서비스되는 여러 개의 랙들
    • 태풍 같은 자연재해에 영향을 받을 수 있는 동일 지역 내의 여러 데이터센터들
  • 시스템이 손실을 감당할 수 있다고 해서 장애 도메인을 지속적으로 늘리는 것이 항상 바람직하지는 않다.:
    • 현실적으로 지연응답, 처리량, 컴퓨팅 자원 측면에서 아무런 이익이 없다.

수용량과 로드밸런싱

  • 샤드에 대한 배포
  • 리더 프로세스의 위치에 따라 대역폭을 골고루 활용하지 못하게 될 수도 있다.
  • 한 곳의 리더에서 집단적으로 장애 조치가 실행되면 네트워크 활용 패턴이 극적으로 변화하게 된다.
  • 예상치 못한 패턴 예시:
  • 리더에 가까이 위치한 클라이언트는 리더를 통해 수행하는 작업들의 지연응답이 훨씬 나아지는 것을 경험할 수 있다. 가까운 리더를 선택하는 알고리즘에 의해 많은 클라이언트가 혜택을 받게 된다.
  • 이 알고리즘은 최상의 성능을 발휘하는 머신의 리더를 선택하려고 한다. 하지만 여기에는 세 데이터센터 중 한 곳이 더 빠른 머신을 보유하고 있다면 불균형적인 양의 트래픽이 해당 데이터 센터로 보내지고, 트래픽의 극적인 변화로 인해 데이터센터에 장애가 발생할 수 있다.
  • 리더 선출 알고리즘으로 인해 프로세스의 실행시간이 길어질 수 있다. = - 과반수 조합 =

분산합의 시스템 모니터링

  • 각 합의 그룹 내에서 실행중인 맴버의 수와 각 프로세스의 상태
  • 지속적으로 지연이 발생하는 복제 서버
  • 리더의 존재 여부
  • 리더의 변경 횟수
  • 합의 트랜잭션 횟수
  • 확인된 제안의 횟수 및 합의된 제안의 횟수
  • 처리량과 지연응답

  • 성능이슈 관련:
    • 제안의 수락과 관련된 지연응답의 분산 정도
    • 지리적으로 떨어진 시스템들의 네트워크 지연응답의 분산 정도
    • 수락자들이 안정적인 로그를 작성하는 데 걸리는 시간
    • 시스템이 초당 받아들이는 전체 바이트

24. 크론을 이용한 분산된 주기적 스케줄링

크론

신뢰성 관점에서의 크론

  • 크론의 장애 도메인: 하나의 머신
  • crond 의 영구적 상태는 crontab 설정이며, (fire-and-forget) 형태로 실행한다.
  • anacron 은 시스템이 다운되었을때 지금까지 실행했던 작업들을 다시 실행한다.

크론 작업과 멱등성

  • 가비지 컬렉션은 멱등성을 가진다.
  • 정확한 정답은 없지만, 두번 실행되었던 작업을 되돌리는 것은 어렵거나 불가능하다. 변경 없이 실패 방식을 선호한다.

대용량 시스템 내에서의 크론

인프라스트럭처의 확장

요구사항의 확장

  • 부분적인 시작 실패가 발생했을 때, 복구되는 복구 절차 역시 수집해야한다.

구글에서 구현한 크론 서비스

크론 작업의 상태 주적하기

  • 데이터를 분산 저장소에 저장하는 방법
  • 크론 서비스 자체에 상태의 일부를 저장하는 서비스를 덧붙이는 방법:
    • GFS 나 HDFS 는 매우 큰 파일에 적합하지만, 매우 작은 크기의 크론 작업을 저장해야 할 경우 지연응답이 높아진다.
    • 장애의 영향이 큰 기반 서비스는 다른 서비스에 대한 의존도를 최소화 해야한다.

25. 데이터 처리 파이프라인

파이프라인 디자인 패턴의 기원

  • 데이터 파이프라인:
    • 코루틴, DTSS 커뮤니케이션 파일, 유닉스 파이프, ETL 파이프라인

단순한 파이프라인 패턴을 적용한 빅데이터의 기본적인 효과

  • 복합 단계 파이프라인

정기적 파이프라인 패턴의 과제

  • 정기적 파이프라인은 일반적으로 데이터를 처리할 충분한 작업자가 있으며, 처리에 대한 수요를 연산 능력으로 감당할 수 있을때 안정적으로 동작한다.
  • 정기적 파이프라인은 맵리듀스와 플럼 과 같은 프레임워크들을 기반으로 작성된다.

작업의 불균형 분산으로 인해 발생하는 문제

  • 빅데이터의 핵심은 무조건적 병렬 알고리즘을 이용해 대용량 부하를 개별 머신으로 처리할 수 있을 정도의 청크로 나누어 애플리케이션에 전달하는 기법
  • 파이프라인은 대부분 체크포인트 기능을 구현하지 않아, 데이터 청크를 다시 처리하게 될때 자원을 낭비하게 된다.

분산 환경에서 정기적 파이프라인의 단점

  • 몇 시간 정도의 지연은 매일 실행되는 파이프라인에서는 용인할 수 있는 부분이다.
  • 개발팀은 자원이 공용 풀에 의해 관리되거나 공유되는 경우 이 자원을 확보하는 단계를 거치는 것을 별로 내켜하지 않는 경향이 있다.
  • 일괄 처리 예약 자원과 서비스에 우선순위를 두는 자원을 구별함으로써 합리적인 비용으로 자원을 획득할 수 있다.

정기적 파이프라인의 문제점 모니터링하기

  • 정기적 파이프라인 안에서는 모니터링으로 인한 문제가 발생해서는 안되지만 이 둘 사이에는 강력한 연관성이 존재한다.

‘천둥 소리’ 문제

  • 작업자 프로세스가 너무 많거나 설정이 잘모소디었거나, 재시도 로직이 오작동한다면 서버에 많은 부하를 발생시키고 결국 네트워크 인프라스트럭쳐까지 영향을 받게 된다.
  • 사람의 개입이 있다면 더 심화될수 있다.:
    • 원하는 시간 내에 종료되지 않는다면 프로세스를 추가해서 문제를 확대시키는 경향이 있다.

모이어 부하 패턴

  • 두개 혹은 그 이상의 파이프라인이 동시에 실행되면서 실행 순서가 겹쳐서 공용자원을 동시에 소비하게 되는 문제

구글 워크플로우

모델-뷰-컨트롤러 패턴에 응용

  • 태스크 마스터(모델) -> 작업자(뷰) 에게 작업단위 넘기기
  • 작업자(뷰)는 완료된 작업단위를 태스크 마스터에게 반환
  • 컨트롤러는 작업 사이클, 확장 혹은 스냅샷 생성을 태스크마스터에게 전달

  • 워크플로우가 보장하는 4가지 정확성:
    • 설정 작업을 통한 작업자의 출력은 작업을 예측하기 위한 영역을 만든다.
    • 작업자가 작업을 완료하기 위해서는 반드시 유효한 임대 기록을 보유하고 있어야한다.
    • 출력 파일은 작업자마다 고유한 이름의 파일에 기록된다.
    • 클라이언트와 서버는 모든 작업마다 서버 토큰을 검사하여 태스크 마스터에 대한 유효성을 판단한다.

비지니스의 지속성 보장하기

  • 빅데이터 파이프라인은 광섬유의 단절, 기후로 인한 사고, 연속적인 전력 공급 문제 등 어떤 종류의 장애가 발생하더라도 계쏙 동작해야한다.
  • 워크플로우는 전역적인 일관성을 확보하기 위해 태스크마스터는 저널을 스패너에 저장한다. -스패너는 처리량이 높은 파일시스템을 제공하지 못하므로, 워크플로우 시스템은 태스크에 대한 참조는 전역 워크플로우에 저장하되, 고유의 클러스터에서 실행한다.

Chatper 26. 데이터 무결성: 내가 기록한 그대로 읽을수 있어야한다.

  • 데이터 무결성에 대한 엄밀한 정의가 필요하다.

데이터 무결성의 중요한 조건

  • 데이터 무결성: 클라우드 상의 서비스들이 사용자들이 계속 사용할 수 있는 상태를 유지하는 것이며, 특히 데이터에 대한 사용자의 접근이 완벽하게 동작해야한다.

최상의 데이터 무결성을 위한 전략의 수집

  • 업타임: 가용성, 사용자들이 서비스를 정상적으로 사용하는 시간의 비율을 의미한다.
  • 지연응답: 사용자에 대한 서비스의 응답성을 의미한다.
  • 확장: 서비스의 지연응답이 증가하기 전까지 서비스가 감당할 수 있는 사용자의 규모와 작업 부하를 의미한다.
  • 속도: 합리적인 비용으로 최상의 가치를 사용자에게 제공하기 위해 서비스를 얼마나 빨리 혁신 할 수 있는지를 의미한다.
  • 정보보안: 복합적이지만, 한정적 의미로 데이터는 사용자가 삭제한 후 적절한 시간 내에 반드시 파기되어야 한다.

  • 무결성은 데이터들이 복잡하게 엮이면서 각종 과제에 부딪히게 된다.:
    • 스키마 변경
    • 데이터 마이그레이션
    • 기존 기능을 바탕으로 새로운 기능을 쌓아 올리는 습관
    • 코드의 재작성

백업과 보관

  • 백업과 보관을 구분해야한다.
  • 보관: 감사, 발견 등 법적 준수 사항을 만족하기 위해 장기간 데이터를 안전하게 보관하는 것. 업타임 요구사항을 만족할 필요가 없다.
  • 백업 전략 수집:
    • 얼마나 신속하게 복구할 수 있는지, 가장 최신의 데이터에 대한 유실은 어느정도 감수할 것인지

클라우드 환경에 대한 거시적 요구사항

  • 운영 환경에서 트랜잭션을 지원하는 백업 및 복구 솔루션과 트랜잭션을 지원하지 않는 솔루션을 혼합해서 사용하고 있다면 복구된 데이터가 반드시 올바르지는 않다.
  • 만약 서비스가 무중단 운영을 지원해야 한다면 각기 다른 버전의 비지니스 로직이 병렬로 데이터를 조작할 수 있다.
  • 서비스와 함께 동작하는 다른 외부 서비스가 독자적으로 버전을 관리하고 있다면 잠시 동안이라도 외부 서비스의 불완전한 버전이 동작하게 되어 데이터의 변조나 유실이 발생할 수 있다.

  • 고려해야할 사항:
    • 데이터의 위치와 캐시
    • 지역 및 전역 데이터 분산
    • 갇력한 일관성 및 혹은 최종적 일관성
    • 데이터의 내구성, 백업 및 복구

데이터 무결성과 가용성을 유지하기 위한 구글 SRE의 목표

데이터 무결성은 의미이며, 데이터 가용성은 목표이다.

  • 데이터 무결성: 데이터의 생명 주기 동안의 정확성과 일관성:
    • 사용자의 관점에서 볼 때 일정 수준 이상의 데이터 가용성을 제공할수 없는 데이터 무결성은 데이터가 전혀 존재하지 않는 것이나 다름이 없다는 점이다.

백업 시스템보다 복구 시스템을 제공하자

  • 팀은 다양한 형태의 장애를 고려하여 데이터 가용성에 대한 서비스 수준 목표를 정의해야 한다.
  • 팀은 SLO를 만족시킬 수 있는 능력을 지속적으로 연습하고 입증해야 한다.

데이터 유실을 유발하는 장애의 종류들

  • 근본 원인:
    • 사용자의 행위, 운영자의 실수, 애플리케이션의 벅, 인프라스트럭처의 결함, 특정 지역의 장애
  • 범위
  • 비율

  • 시점 기반 복구(또는 시간 여행)이라 불리는 것을 제공하고 싶지만, 비용 목표를 만족시키면서 이를 제공하는 것은 망상이다.
  • 속도를 희생시키는 것이 가장 현실적이며, 비용적인 부분을 감안하여 스내뱟ㅅ을 적당한 기간 보관해야한다.

더 깊고 폭넓은 데이터 무결성 관리의 어려움

  • 복제와 다중화는 회복성이 아니다.
  • 확장성 이슈: 전체, 증분 백업의 경쟁 세력과 복구:
    • 데이터의 복사본을 서비스에서는 사용하지 않되, 다른 형태로 만들어 보관한다.:
      • 복제로 해결하지 못하는 에러로부터 보호할수 있다.
      • 의미적으로 일치하지 않거나, 각정 기술 스택의 문제로 데이터 유실을 방지하지는 못한다.
  • 데이터 보존

구글이 데이터 무결성의 문제를 해결하는 방법

데이터 무결성 장애가 발생할 수 있는 24가지 조합

  • 1 계층: 소프트 삭제 - 부주의로 인한 데이터의 삭제에 효과적으로 대응할 수 있다.
  • 2 계층: 백업 및 그와 관련된 복구 방법들
  • 3 계층: 규칙적인 데이터의 검증

첫 번째 계층: 소프트 삭제

  • 고객 지원 문제는 소프트 삭제를 지원하면 현저히 혹은 완전히 해결할 수 있다.
  • 소프트 삭제 이후 일정 시간 이후 실제로 파기된다.
  • 보통 60일 정도가 적합하다.
  • 데이터 보호의 첫번째 계층에서 고려할 사항:
    • 휴지통 폴더를 이용해 데이터 삭제를 취소할 수 있게 함으로써 사용자의 실수로부터 데이터를 보호한다.
    • 소프트 삭제는 개발자의 실수에 대한 일차적 방어선인 동시에 사용자의 실수에 대한 이차적 방어선 역할을 수행한다.
    • 개발자의 입장에서는 지연 삭제는 내부 개발자의 실수에 대한 일차적 방어선이자 외부 개발자의 실수에 대한 이차적 방어선이 될 수 있다.
  • 수정 기록:
    • 데이터가 변조 되었을때 이전의 상태로 복구하는 것은 유용하다.
    • 데이터 유실에 대해서는 그다지 유용하지 않는다.

두 번째 계층: 백업 및 그와 관련된 복구 방법들

  • 백업을 통해 데이터를 복구하기 위해서 고려할 사항:
    • 사용할 백업 및 복구 방법
    • 데이터의 전체 및 증분 백업을 통한 복구 지점의 생성 빈도
    • 백업 저장 위치
    • 백업의 보관 기간
  • 백업을 가장 오랜 기간 동안 보관해야두어야 하는 경우는 애플리케이션 코드에 비교적 덜 심각한 데이터 변경 혹은 삭제의 버그가 있고, 몇달이 지난 뒤에 발견되는 경우다.
  • 합리적인 비용으로 여러가지 실패 시나리오를 처리하기 위해 단계적 백업 전략이 필요하다.
  • 특정 지역의 임의 분산 파일 시스템에 10일 혹은 15일 미만의 기간에 백업을 보관한다.

가장 중요한 단계: 복제

  • 이상적으로, 백업을 저장하고 있는 저장소를 포함한 모든 저장소 인스턴스는 복제가 되어야한다.
  • RAID, 리드-솔로몬 소거, GFS 형식의 복제
  • 이중화 시스템을 선택할때는 테스트 용도만 복구를 수행하는 사용 빈도가 낮은 스키마가 아닌 지속적으로 사용하는 빈도 높은 스키마를 선택해야한다.

1T vs. 비교: ‘단순히’ 더 큰 백업만을 의미하지 않는다.

  • 데용량 데이터를 백업하는 데 가장 자주 사용되며 효과적인 기법은 데이터에 대한 신뢰지점을 수립하는 것이다.
  • 신뢰지점: 저장된 데이터 중 시간의 추이에 따라 더 이상의 변경이 발생하지 않은 후로 검증이 완료된 부분을 일컫는다.
  • 백업이 아니라 복구가 중요하다.
  • 스키마 디자인 고려항목:
    • 데이터의 올바른 균형
    • 각 샤드의 독립성 보장
    • 동시에 실행 중인 작업들 간의 경쟁 방지

세 번째 계층: 조기 발견

  • 클라우드 개발자가 당명한 과제들:
    • 데이터 저장소 간의 참조 무결성
    • 스키마의 변경
    • 오래된 코드
    • 제로 다운타임 데이터 마이그레이션
    • 다른 서비스들과의 통합 지점의 향상

대역 외 데이터 검증

  • 데이터 변조 버그를 알고 있는 엔지니어들은 운영 환경에서 더 신경을 많이 쓴다.
  • 프로젝트 주기의 초기에 단위 테스트를 수행했을 때의 효과와 마찬가지로 데이터 검증 파이프라인의 투입 결과 역시 소프트웨어 개발 프로젝트의 전반적인 속도를 개선한다.
  • 대역 외 데이터 검증은 올바르게 구현하기에 난해한 면이 있다.:
    • 너무 엄격하게 구현하면 간단하고 별 문제 없는 변경 사항으로 검증이 실패gkftn dlTek.
    • 결과적으로 엔지니어는 데이터 검증 전체를 거부하게 된다.
    • 올바른 균형을 찾기 위해서, 대부분 변경이 일어나지는 않지만 한번 변경이 일어나면 사용자의 데이터에 문제를 일으킬 수 있는 부분만을 검증하면 된다.

데이터 복구의 동작 여부 확인하기

  • 일반 운영 엄무와 함께 복구 프로세스를 지속적으로 테스트한다.
  • 복구 프로세스의 성공 여부를 지속적으로 파악하기 위해 복구 프로세스가 실패했을 때 전송될 알림을 설정한다.
  • 복구 계획의 관점에서 확인해야할것:
    • 백업이 유효하고 완전한 상태인가 아니면 비어있는 상태인가?
    • 복구를 위한 설정, 복원 및 사후 처리를 실행하기에 충분한 머신 자원을 확보하고 있가?
    • 복구 프로세스가 적절한 시간 내에 완료되는가?
    • 복구 프로세스가 진행되는 동안 상태를 모니터링할 수 있는가?
    • 무정지 운영을 지원하지 않는 타지역의 미디어 저장소에 대한 접근 같이 직접 통제할 수 없는 외부 자원에 대한 의존도로부터 자유로운가?

데이터 무결성과 관련된 SRE의 일반 원리들

초심자의 마음가짐

  • 신뢰하되 검증하고, 다중 방어 장치를 도입하라

    신뢰하되 검증하라

    희망은 전략이 아니다

    다중 방어 조치

    결론

  • 데이터의 사용성은 모든 데이터 기반 시스템이 최우선적으로 고려해야할 사항이다.
  • 어떤 종류의 장애도 발생할 수 있다는 생각보다는 모든 것이 잘못될 수 있다는 생각을 갖는 것은 실제로 발생할 긴급 사태를 대비하기로 위한 중요한 과정이다.
  • 어떤 장애가 발생하더라도 적절한 시간 N 내에 복구할 수 있게 된다면 더욱 신속하고 세밀한 데이터 유실 탐지 매커니즘을 통해 이 시간을 더 줄일 수 있는 방법을 찾아 N=0을 만드는 목표를 달성하기 위해 노력하자.

27. 대용량 환경에서의 신뢰할 수 있는 제품 출시

출시 조율 엔지니어링

  • 컨설팅팀이 제품 출시 절차를 도와준다:
    • 구글의 신뢰성 표준과 모범 사례를 준수하도록 제품과 서비스를 감사하고 신뢰성을 향상시키기 위해 도움을 준다.
    • 출시에 함류한여러 팀 사이의 연락책 역할을 수행한다.
    • 작업의 추진력을 유지함으로써 출시의 기술적 관점들을 주도한다.
    • 출시가 안전하게 진행될 수 있도록 통제원 역할을 수행하며 출시의 완료를 선언한다.
    • 개발자들에게 모범 사례 및 구글의 서비스들과 통합하는 방법을 교육하며 신속한 학습을 위해 내부 문건 및 교육 자료를 이용한다.

제품 출시에 대한 LCE팀의 역할

  • 경험의 전파
  • 교차 기능(cross-functional) rhkswja
  • 객관성(objectivity)

출시 절차 마련하기

  • 성공적인 출시 절차의 특징
    • 경량(lightweight): 개발자들이 접근하기 쉬워야한다.
    • 견고함(robust): 오류를 명확하게 잡아내야 한다.
    • 주도면밀함(thorough): 중요한 부분은 일관적이고 재현 가능하게 다루어야 한다.
    • 확장성(scalable): 더 많은 출시를 단순화하고 복잡한 출시를 줄여야한다.
    • 순응동(adaptable): 일반적인 종류의 출시와 새로운 종류의 출시를 모두 잘 지원할 수 있어야한다.
  • 성공적인 전략:
    • 간결성(simplicity): 기본적인 것들은 완수한다. 모든 우발적 가능성에 대한 계획을 세우지는 않는다.
    • 직접 부딪히기: 경험이 있는 엔지니어들이 각 출시별로 절차를 최적화하도록 한다.
    • 빠른 공통 경로: 항상 공토엊ㄱ인 패턴을 따르는 출시를 정의하고 이 종류의 출시를 위한 간소화된 출시 절차를 제공한다.
  • 엔지니어는 너무 부담스럽거나, 그 가치가 미약하다고 생각하는 절차는 잘 지키지 않으려는 경향을 보인다.

출시 확인목록

  • 가이드라인:
    • 모든 질문의 중요도를 입증해야한다. 이전의 출시에서 발생했던 문제에 의해 생겨난 질문이면 이상적이다.
    • 모든 지시 사항은 견고하고 실용적이며 개발자들이 달성할 수 있는 합리적인것이어야 한다.

집중과 간소화 진행하기

  • 규모가 큰 조직에서는 엔지니어가 공통적인 업무를 수행할 때 활용할만한 인프라스트럭쳐가 존재한다는 것을 모를 수도 있다.
  • LCE는 출시 작업을 수행하는 동안 발생하는 모든 문제점들의 최초 목격자가 된다.

예상치 못한 제품의 출시

출시 확인목록 개발하기

아키텍처와 의존성

  • 확인목록 질문의 예:
    • 사용자의 요청은 프론트엔드를 거쳐 백엔드까지 어떻게 전달되는가?
    • 요청의 종류별로 지연응답에 대한 요구사항이 서로 다른가?
  • 실행항목의 예:
    • 사용자와 관련된 요청을 관련이 없는 요청과 따로 분리한다.
    • 요청의 규모에 대한 예측을 검증한다. 한 페이지에서 더 많은 수의 요청을 생성할 수 있다.

통합

  • 실행항목의 예:
    • 서비스를 위한 새 DNS 이름 셋업
    • 서비스와의 통신을 위한 로드밸런서 셋업
    • 새 서비스에 대한 모니터링 셋업

수용량 계획

  • 확인목록 질문의 예:
    • 제품의 출시가 언론이나 광고, 블로그 포스트 혹은 기타 다른 형태로 홍보되었는가?
    • 출시 도중 및 출시 후 트래픽과 증가율은 어느 정도로 예상하는가?
    • 전체 트래픽을 지원하기 위한 충분한 컴퓨팅 자원이 확보되었는가?

장애 모드

  • 확인목록 질문의 예:
    • 서비스의 디자인에 있어 단일 실패점이 존재하는가?
    • 의존하는 서비스의 장애의 영향을 어떻게 최소화하고 있는가?
  • 실행항목의 예:
    • 요청이 너무 오래 실행되면서 자원을 소모하는 것을 방지하기 위해 요청 실행에 대한 마감기한을 설정한다.
    • 과부화 발생시 새로운 요청을 미리 거부하도록 부하의 정량을 구현한다.

클라이언트 동작

  • 확인목록 질문의 예:
    • 자동 저장/자동 완성/건강 상태 검사 기능 등을 구현하고 있는가?
  • 실행항목의 예:
    • 장애 발생 시 클라이언트가 즉각 동작을 중단하도록 한다.
    • 자동으로 발생하는 요청을 충분히 고려한다.

절차와 자동화

  • 확인목록 질문의 예:
    • 서비스가 지속적으로 실행되기 위한 필요한 수동절차가 있는가?
  • 실행항목의 예:
    • 모든 수동절차는 문서화한다.:
      • 서비스를 새로운 데이터센터로 이전하기 위한 절차를 문서화한다.
      • 새 버전의 빌드 및 배포 절차를 자동화한다.

배포 절차

  • 실행항목의 예:
    • 모든 코드와 설정파일을 버전 관리 시스템에 제출한다.
    • 각 릴리즈는 매번 새로운 릴리즈 브랜치에 관리한다.

외부 의존성

  • 확인목록 질문의 예:
    • 제품의 출시에 어떤 서드파티 코드, 데이터, 서비스 혹은 이벤트에 대한 의존성 영향을 미치는가?
    • 우리 서비스에 의존하는 파트너가 있는가? 그렇다면 제품의 출시를 그들에게 알려야하는가?
    • 우리 또는 외부 벤더가 제품 출시 기일을 지킬 수 없을 때 어떤 일이 발생하는가?

발표 계획

  • 실행항목의 예:
    • 서비스를 출시하기 위해 필요한 실행 요소들을 정의한 출시 계획을 수립한다. 그리고 각 요소들을 누가 책임질 것인지도 결정한다.
    • 개별 출시 단계마다 위험 요소들을 정의하고 우발적 상황에 대처할 수 있는 방안을 수립한다.

안정적인 출시를 위한 기법들

점진적이고 단계적인 출시

  • 시스템 관리 분야의 격언: 운영 중인 시스템은 절대 바꾸지 마라:
    • 모든 벼경은 위험을 의미하며, 위험은 시스템의 안정성을 확보하기 위해서는 최소화해야 할 요소다.
  • 어떤 변경 이후 일정 기간 동안의 검사를 통과하지 못하면 자동으로 롤백된다.
  • 초청 시스템은 점진적 출시의 또다른 형태다.

기능 플래그 프레임워크