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의 가치
- 자동화 클래스의 계층구조:
- 자동화를 하지 않는 단계
- 별도로 관리되며 시스템에 특화된 자옫화를 수행하는 단계
- 별도로 관리되는 범용 자동화를 수행하는 단계
- 내재화되었지만 시스템에 특화된 자동화를 수행하는 단계
- 개입이 불필요한 시스템을 도입하는 단계
스스로를 이롭게 하라: 몽땅 자동화하자!
신의 한 수: 클러스터 턴업의 자동화
- 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 들이 중요한 사안에는 모두 참여하므로 개발할 도구의 목적과 요구사항을 손쉽게 이해한다.
- 개발하는 도구를 직접 사용할 사용자와의 관계가 직접적이기 때문에 솔직하고 신속한 사용자 피드백을 기대할 수 있다.
전통적인 수용량 계획
- 수요 예측의 수집
- 빌드 및 할당 계획의 수립
- 리뷰 및 계획의 승인
- 배포 및 자원 설정
- 장단점:
- 본질적으로 불안정하다:
- 서비스의 효율성이 떨어져서 동일한 양의 수요를 감당하기 위해 더 많은 자원을 필요로 하게 되는 경우
- 고객의 유입률이 증가하여 그에 따라 수요가 증가하는 경우
- 클러스터의 새로운 컴퓨트 자원에 대한 배송이 지연되는 경우
- 제품의 성능 목표가 변경되어 서비스 배포 형태와 필요한 자원의 양이 바뀌는 경우
- 노동집약적이며 모호하다
- 본질적으로 불안정하다:
의도 기반 수용량 계획
- 구현이 아닌 요구사항을 명확히 하자
의도를 파악하기 위한 선행 작업
- 의존성
- 성능 지표
- 우선순위 결정
인식의 제고 및 도입의 촉진
- 일관적이고 긴밀한 접근법
- 사용자에 대한 지원
-
제품의 활용성을 알리기 위한 선임 개발자와 관리자의 전폭적인 지원
- 기대치 설정하기
- 적절한 사용자층 정의하기
- 고객 서비스
- 적절한 수준의 디자인
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 이름 셋업
- 서비스와의 통신을 위한 로드밸런서 셋업
- 새 서비스에 대한 모니터링 셋업
수용량 계획
- 확인목록 질문의 예:
- 제품의 출시가 언론이나 광고, 블로그 포스트 혹은 기타 다른 형태로 홍보되었는가?
- 출시 도중 및 출시 후 트래픽과 증가율은 어느 정도로 예상하는가?
- 전체 트래픽을 지원하기 위한 충분한 컴퓨팅 자원이 확보되었는가?
장애 모드
- 확인목록 질문의 예:
- 서비스의 디자인에 있어 단일 실패점이 존재하는가?
- 의존하는 서비스의 장애의 영향을 어떻게 최소화하고 있는가?
- 실행항목의 예:
- 요청이 너무 오래 실행되면서 자원을 소모하는 것을 방지하기 위해 요청 실행에 대한 마감기한을 설정한다.
- 과부화 발생시 새로운 요청을 미리 거부하도록 부하의 정량을 구현한다.
클라이언트 동작
- 확인목록 질문의 예:
- 자동 저장/자동 완성/건강 상태 검사 기능 등을 구현하고 있는가?
- 실행항목의 예:
- 장애 발생 시 클라이언트가 즉각 동작을 중단하도록 한다.
- 자동으로 발생하는 요청을 충분히 고려한다.
절차와 자동화
- 확인목록 질문의 예:
- 서비스가 지속적으로 실행되기 위한 필요한 수동절차가 있는가?
- 실행항목의 예:
- 모든 수동절차는 문서화한다.:
- 서비스를 새로운 데이터센터로 이전하기 위한 절차를 문서화한다.
- 새 버전의 빌드 및 배포 절차를 자동화한다.
- 모든 수동절차는 문서화한다.:
배포 절차
- 실행항목의 예:
- 모든 코드와 설정파일을 버전 관리 시스템에 제출한다.
- 각 릴리즈는 매번 새로운 릴리즈 브랜치에 관리한다.
외부 의존성
- 확인목록 질문의 예:
- 제품의 출시에 어떤 서드파티 코드, 데이터, 서비스 혹은 이벤트에 대한 의존성 영향을 미치는가?
- 우리 서비스에 의존하는 파트너가 있는가? 그렇다면 제품의 출시를 그들에게 알려야하는가?
- 우리 또는 외부 벤더가 제품 출시 기일을 지킬 수 없을 때 어떤 일이 발생하는가?
발표 계획
- 실행항목의 예:
- 서비스를 출시하기 위해 필요한 실행 요소들을 정의한 출시 계획을 수립한다. 그리고 각 요소들을 누가 책임질 것인지도 결정한다.
- 개별 출시 단계마다 위험 요소들을 정의하고 우발적 상황에 대처할 수 있는 방안을 수립한다.
안정적인 출시를 위한 기법들
점진적이고 단계적인 출시
- 시스템 관리 분야의 격언: 운영 중인 시스템은 절대 바꾸지 마라:
- 모든 벼경은 위험을 의미하며, 위험은 시스템의 안정성을 확보하기 위해서는 최소화해야 할 요소다.
- 어떤 변경 이후 일정 기간 동안의 검사를 통과하지 못하면 자동으로 롤백된다.
- 초청 시스템은 점진적 출시의 또다른 형태다.