메뉴

문서정보

목차

소개

Cloud Native 환경에서 SRE를 적용해 보려 한다. 다양한 사례들을 수집하고, 수집한 내용들을 운용중인 AWS에 접목하기 위한 나의 고민들로 채워진다. SRE에 대한 이론적인 내용보다는 실질적인 내용을 주로 다룰 것이다.

옛날 아주 먼 옛날에

아주 먼 옛날에 IT 회사는 개발운영이 서로 분리돼 있었다. 좀 더 들어가보면 개발, 운영, 설계, 기획, 마케팅 등이 전부 분리돼있었다. 이러한 구조는 사일로 이펙트를 발생시킨다.

 Silo 이펙트

사일로(silo) 조직을 어떻게 통합할 것인가 ?하는 문제는 IT 비지니스 환경에서 해결해야 할 중요한 문제였다. 사일로 구조의 조직에서는 조직간 정보가 공유되지 않는다. 정보가 공유되지 않으면, 팀들이 잘못된 정보로 업무를 수행한다. 입력 데이터가 쓰레기이면 출력물도 쓰레기라는 원리는 IT 조직에도 그대로 적용된다.

IT 산업은 사일로 문제를 해결하기 위해서 오랜 시간 고민을 해왔다.

DevOps

이런 문제를 해결하기 위해서 DevOps가 도입됐다. DevOps는 잘 작동했으며, 많은 문제를 해결할 수 있었다. 하지만 DevOps는 구체적인 툴이라기 보다는 조직을 통합하기 위한 원칙 혹은 문화에 가까운 추상적인 활동이었다. IT 조직에 따라서 구체적 구현에 있어서 차이가 발생했다. 역량이 뛰어난 회사는 (좋은 활동의 결과)좋은 결과물을 만들 수 있었겠지만, 그렇지 않은 회사에서의 결과는 좋지 않았다.

애자일의 스크럼처럼 참고할 수 있는 레퍼런스가 DevOps에도 필요했다. SRE는 DevOps를 위한 구체적인 가이드를 제공 할 수 있다. 특히 서비스 품질개선, 모니터링, 관제, 장애처리 프로세스 영역에서 현장에서 제공 할 수 있는 방법들을 제공한다.

SRE

SRE(Site Reliability engineering - 사이트 신뢰성 공학)는 DevOps에서의 아래 부분에 대한 구체적인 툴과 프로세스들을 제공한다. 구글에서는 "소프트웨어 엔지니어에게 운영팀을 설계하도록 요청하면 SRE가 발생한다"라고 설명하고 있다.

소프트웨어 엔지니어가 운영팀을 설계하면 어떤일이 벌어질지를 생각해보면, SRE가 하는 일들을 짐작 할 수 있을 것이다. 페이팔(Paypal)의 SRE Job description을 살펴봤다. 슬랙(Slack)의 Job description이다. 좀 더 명확하다.

어떤 일을 하는가 요구되는 기술 자격 보너스

SRE 원칙

서비스 수준/상태 파악

서비스 수준을 파악하기 위해서는 근거자료가 되는 지표정보의 수집이 필요하다.

SRE는 SLI를 이용해서 서비스 수준을 판단의 근거가 되는 정량적 요소들을 측정한다. 응답대기시간, 요청 큐의 크기, 오류율, 가용성 등을 예로 들 수 있다. 평균은 유용하기는 하지만 중요한 정보들을 숨겨버리기도 한다. 따라서 평균외에 MIN,MAX,Trend와 같은 다른 평가 알고리즘의 사용 구간별 측정 등의 방법을 사용해야 한다.

백분율로 SLI를 설정하는 것도 좋은 아이디어다. 응답대기시간의 경우에도 등으로 집계하는게 좋다.

중요한 SLI 항목은 소수다. 모든 항목을 주요 SLI로 잡겠다는 것은 중요 SLI를 설정하지 않겠다는 것과 같은 의미다. 지나치게 많은 항목은 올바른 SRE 활동에 방해가 될 수 있다.

이를테면, 각 인스턴스의 CPU 사용율을 지표로 수집한다. 하지만 이 지표는 중요 지표는 아닐 것이다. AWS 같은 클라우드 환경에서 서비스를 이루는 단위 인스턴 중 하나가 중지되더라도 중요 SLI 지표는 아니다. 해당 인스턴스로는 요청이 가지 않을 테고 인스턴스는 잠시 후에 실행이 될 것이며, 일부 API 호출에 이슈가 생겼다고 하더라도, 서버&클라이언트&인프라에서의 예외처리 실제 기능상에 이슈는 없을 것이다. 물론 애초에 이를 감안해서 설계(Cache, 클라이언트/서버 리트라이. Cache만 잘 사용해도 클라이언트에서 발생할 수 있는 문제의 상당부분을 해결 할 수 있다.)를 해야 할 것이다.

CPU, Memory 사용율과 같은 것들은 SLO를 위한 보조적인 수단으로, SLO의 관리, 비용효율화 등의 활동이 필요 할 때 중요지표로 사용 할 수 있을 것이다. 그 자체가 중요 SLI는 아니다.

위험 감수

시스템 엔지니어와 개발조직이 분리돼 있는 상태에서, 기능추가에 따른 시스템 변경에 대해서 시스템 엔지니어가 보수적으로 반응하는 경험이 있는지 모르겠다. 시스템 엔지니어는 기능이 추가 됨으로, 서비스 경험이 좋아지는 것에 대한 책임이 없다. 하지만 시스템 변경의 여파로 발생 할 수 있는 시스템 장애에 대한 책임은 있다. 시스템 엔지니어는 위험을 감수할 필요가 없다.

보통은 개발팀과 시스템 엔지니어팀, 사업팀간에 지루한 회의가 이어지기 마련이며, 사안에 따라서는 조직장의 의사결정까지 진행 될 수 있다.

기민하게 움직이기 위해서는 위험 감수가 필수적이며, 위험을 감수하기 위해서는 책임을 공유해야 한다.

위험을 감수하기 위해서는 주어진 서비스가 감내할 수 있는 위험을 명시적으로 조율 할 수 있어야 한다. 서비스를 충분히 안정적으로 만들려고 노력하지, 필요 이상으로 안정적으로 만들려고 노력하지는 않는다. SRE와 개발자, 운영자는 가용성에 대한 지표를 만들 수 있을 것이다. 위의 것들은 예제일 뿐이다. 중요한 것은 평가가능한 지표를 만들어야 한다는 점이다.

SRE는 오류예산(Error budget)을 유지한다.
Error budget = 100 % - availability target
예를들면 한달에 SLO를 99.99%를 설정했다면, SLO는 0.01%의 다운타임을 허용하며 0.01%가 오류예산이 된다. 한달에 4.3분의 다운타임을 허용하겠다는 의미다.

다운타임에는 1. 예고된 다운타임 과 2. 오류에 의한 다운타임 두 종류가 있다. 예고된 다운타임은 오류예산에 포함하지 않는다. 대신 예고된 다운타임이 오류예산을 초과하면 안된다 등의 정책을 수립 할 수 있다.

예를 들어 소프트웨어 배포로 인한 다운타임이 오류예산을 초과할 것으로 예상되면, 배포 프로세스를 변경해야 한다.

개발팀은 오류예산내에서 릴리즈 배포를 하기 위한 다양한 기술적조치를 하게 될 것이다. 대규모의 서비스 업데이트를 하게 될 경우 오류예산을 맞추는게 불가능해지므로, 사업팀도 개발팀과 논의해서 (짧은 주기로의 기능 배포 등)업데이트 계획을 수립해야 한다. 결과적으로 개발팀과 사업팀 모두 책임을 가지고 업무를 수행하게 된다.

오류예산을 초과 할 경우에는 관련 조직이 모여서 원인파악, 프로세스 점검, 코드 리뷰 등 대응 방안을 만들어야 한다.

오류예산의 장점 중 하나는 SRE팀이 개발팀이 하는 일에 대해서 시시콜콜한 판단을 내리지 않아도 된다는 점이다. SLO에 대한 목표는 함께 설정하지만, 구체적인 실행은 개발팀에 맡기면 되기 때문이다. SLO를 지키라는 기술적 조치를 요구 할 수는 있지만, 개발팀을 평가하거나 판단할 필요는 없다. 개발팀은 오류예산을 날리지 않는다면 기능의 테스트, 설계 변경, 기발한 아이디어의 구현 등 원하는 것들을 할 수 있다.

오류예산도 예산이므로 사안에 따라서 일시적,장기적 예산증액을 요청 할 수 있다. 예산증액이 필요한 경우 각 조직이 모여서 타당성을 검토하면 될 것이다. 필요한 경우 의사결정을 받아야 할 수도 있다.

수고를 없애라

프로세스를 만들고 자동화 하며, 필요하면 솔류션을 도입한다. 그렇지 않으면, 서비스를 개선하기 위한 활동을 할 수 없을 것이다.

왜 그런지 알 수 있다.

데이터 기반 활동을 해야 한다. 평가 지표를 수집하고, 분석하고 평가 할 수 있어야 한다. 측정가능해야 의미가 있다.

신뢰 할 수 있는 릴리스를 유지하라

개발, QA, Staging, 프러덕션까지의 CICD 환경을 만든다. 여기에는 로컬 테스트, 개발환경에서의 테스트, API 문서화, 배포버전관리, 배포단계에서 상태변화에 대한 모니터링과 레포팅, 무중단 배포(블루그린, 카나리, 롤링), 롤백시스템을 구성해야 한다.

간결하게 유지하라

복잡도를 제거하고 자연스럽게 엔지니어링이 이루어져야 한다. 기능이 복잡해지는데, 복잡도를 제거 할 수 있는가? 라고 반문 할 수 있을 것 같다.

나는 AWS 환경에서 업무를 한다. 다른 서비스와 마찬가지로 AWS 기반 서비스도 품질을 관리하기 위한 가장 중요한 요소는 로그의 수집과 분석이다. 로그 하면 우선 떠오르는 솔류션이 ELK(혹은 EFK)이다. 결과적으로 ELK를 선택하지 않았는데, Logstash와 ElasticSearch, Kibana의 구성이 너무 복잡하다고 생각했기 때문이다.

대신 애플리케이션 표준출력 -> CloudWatch -> S3, ELB의 경우 S3->아테나로 통일해버렸다. 애플리케이션 개발자는 로깅하고 싶은 정보를 표준출력 하면 된다. 로깅 라이브러리, Logstash Endpoint등을 신경쓸 필요가 없다. 표준출력은 자동으로 CloudWatch에 전송되고, 주기적으로 람다가 CloudWatch의 로그를 S3에 저장한다. 시스템 엔지니어도 신경쓸게 없다. 기본적인 이벤트는 Cloudwatch에서 제공하는 서비스로 관리 할 수 있다. 인시던트 관리는 Opsgenie에 맡긴다. 상세 분석이 필요 할 때는 아테나를 이용한다.

물론 언젠가는 다른 복잡한 시스템을 넣어야 할 수 있을 것이다. 하지만 가능한 가볍고 간단하게 시작하도록 주의를 기울여야 한다.

SLI와 SLO의 설정

SLI와 SLO, SLA 용어를 한 줄로 간단히 정리해보자. 효과적인 SLI의 설정은 엔지니어링 팀이 보다 나은 의사결정을 내릴 수 있도록 도와준다. SLO는 서비스가 충분한 수준의 성능과 가용성을 제공하고 있는지에 대한 명확한 정보를 제공함으로써 빠른 의사결정을 내릴 수 있도록 한다. 엔지니어링, 운영/관리 조직은 SLI와 SLO를 이용해서 시스템에 대한 투자 수준을 결정 할 수 있다.

시스템 경계를 따라서 SLI와 SLO를 설정한다.

현대 소프트웨어 플랫폼은 높은 복잡도를 가지고 있다. AWS를 기반으로 소프트웨어를 전개한다고 가정해보자. EC2(서버), ECS(컨테이너), ELB(로드 밸런서), Route 53(도메인서비스), RDS(RDBMS), DynamoDB 혹은 DocumentDB, ElastiCache(Redis), SQS(메시지 큐), SNS(Push), EKS(메시지 스트리밍), ElasticSearch(검색솔류션), S3(오브젝트 스토리지), Redshift(데이터 웨어하우징), Athena(빅 데이터 쿼리), VPC(네트워크) 대충 생각나는 컴포넌트들이 이렇다. 이들 컴포넌트들을 구성하는 세부 요소까지 생각하면, 수백가지의 요소들로 구성될 수 있다. 이들 모든 구성요소에 대해서 SLI, SLO를 시도하는 것은 현실적이지도 않고 효과적이지도 않다.

SLI, SLO는 개별 구성요소가 아닌, 시스템 경계에 중점을 두는게 낫다. 일반적으로 플랫폼은 시스템 경계가 단순하며 여기에서 설정하는 SLI/SLO가 더 가치가 있다.

시스템 경계란 사용자에게 기능을 제공하는 지점을 의미한다. REST 기반 서비스라면, REST API 호출 영역이 될테다. 즉 인증 API, 데이터 조회 및 입력 API 영역이다.

인증 API의 경우에도 API 서버와 데이터베이스 등의 하부 구성요소를 가지고 있을텐데, 이들 구성요소는 고객에게 노출되는게 아니므로 시스템 경계가 아니다. SRE는 이러한 특성을 감안해서 SLI/SLO를 설정해야 한다.

 SLI/SLO 설정

AWS 서비스라면 위의 그림처럼 SLI/SLO를 위한 티어를 만들 수 있을 것이다. 요점은 "서비스에 직접적인 영향을 줄 수 있는 요소들을 SLI/SLO로 설정"해야 한다는 거다. 각 티어별로 설정을 해보자.

UI tier: 사용자와 직접 상호작용 하는 영역이다. 사용자가 직접적으로 체감 할 수 있는 영역이므로 주의해서 SLI/SLO를 설정해야 한다. UI를 구성하는 각 요소의 실패, 반응 속도, API의 호출에서 응답까지의 지연, 요청의 실패 등등이 영향을 미친다. AWS를 사용하는 백앤드의 경우에는 가용성 구성과 오토 스케일링(Auto scaling), CloudWatch를 중심으로 하는 로깅시스템을 사용해서 SLO를 높은 수준으로 유지하는 것 처럼, UI 에서도 그러한 장치들을 마련해야 한다. 핵심은 로깅이다.

모든 상태변화 로그를 남기려고 하지 말고, 중요한 부분을 찾아서 측정 가능한 데이터를 수집하기 위해서 노력한다. 자의적이지 않은가 ? 라고 생각 할 수 있겠는데, 자원은 무한하지 않다는 것을 상기하기 바란다. 자원(개발자, QA, 시간, 돈, 출시일, 분석할 수 있는 데이터 엔지니어)이 충분하지 않은 상태에서 많은 데이터 수집 해 봤자, 효과만 더 떨어질 뿐이다.

API Endpoint tier: 클라이언트 애플리케이션이 API를 호출하는 영역이다. 많은 UI 구성요소들이 API를 호출 하고, 사용자와 상호작용하는 부분이므로 UI와 함께 신경써야 하는 부분이다.

ELB나 API-Gateway를 사용한다면, Client 요청/응답 로그를 모두 남길 수 있다. 가장 중요한 정보는 HTTP Status Code일 것이다. 1차로 CloudWatch를 이용해서 카운트 기반으로 SLI/SLO를 설정 할 수 있을 것이다. 가용성의 경우 아래와 같이 설정 할 수 있다.
  1. SLI : HTTP Status Code 500 ~ 599를 실패로 간주한다. 그렇다면 요청 성공률에 대한 공식 성공 / (성공+실패) 을 SLI로 설정 할 수 있다.
  2. SLO : 99.98% 를 목표로 한다.
응답속도의 경우
  1. SLI : 400msec 이상이면 충분히 빠름, 400msec 이상 800msec 이상이면 용인 가능한 수준, 800msec 이상이면 느림으로 설정 한다.
  2. SLO : 800msec 미만을 99.8%로 설정한다.
와 같이 설정 할 수 있다.

로깅 및 모니터링 시스템

로깅과 모니터링은 SRE를 위한 기반이 된다. 두 개가 없으면 아무것도 할 수 없다. 모니터링 시스템을 위한 기본 원칙은 아래와 같이 정의 할 수 있다.
  1. 중앙 집중화된 로깅 및 모니터링 시스템의 구축
  2. 자동화
  3. 인시던트 관리 시스템과의 통합
아래는 로깅/모니터링 시스템의 레퍼런스 아키텍처다.(모범 사례라고 불러도 될 것 같다.)

 모니터링 시스템

모든 로그는 CloudWatch 로 통일한다.

이전에는 ELK를 이용했으나, 이제는 CloudWatch로 통일하고 있다. 관리,운영 복잡도가 가장 큰 이유다. 물론 모든 것을 CloudWatch로 수집할 수는 없다. 시스템 경계에 잇는 대표적인 구성요소인 ELB의 경우 Count 기반의 정보들이 CloudWatch로 전달되지만, 일반 엑세스 로그는 전달되지 않는다. 대신 S3로 저장을 한다. 여기에서 중요한 점은 관리,운영,복잡도를 클라우드 서비스 제공자에게 맡긴다는 점이다.

Target Group의 Health Check, HTTP Status Code Count 로도 빠른 반응이 필요한 핵심적인 이벤트는 모니터링 할 수 있으므로 이걸로 충분하다. S3에 저장되는 데이터는 분석용으로 Athena를 이용해서 주기적으로 분석해서 추이를 확인한다.

애플리케이션은 두 가지 방법 중 하나로 로그를 CloudWatch로 보낸다.
  1. EC2기반 애플리케이션의 경우 CloudWatch agent를 이용한다.
  2. 컨테이너 기반 애플리케이션의 경우 표준출력을 CloudWatch로 전송한다.
두 가지 방법 모두 개발자와 SRE 모두 관리해야 할 게 거의 없다. 일단 CloudWatch로 전송되면, CloudWatch 설정을 이용해서 이벤트를 발생 할 수 있다.

모든 이벤트는 SNS를 이용해서 Incident management 로 전송한다. Opsgenie 같은 인시던트 관리 프로그램의 대부분은 SNS 연동을 지원하므로 간단하게 통합할 수 있다.

물론 다른 전문화된 툴에 비해서 CloudWatch가 제한적이다라고 생각 할 수 있을 것이다. 환경과 관점에 따른 차이가 있을 수 있다. 내 관점은 아래와 같다.

애플리케이션의 주요 로그는 Error tracking 시스템을 이용

Sentry, rollbar 같은 솔류션을 이용한다. 이들 솔류션은 incident management 솔류션과 통합할 수 있다. 예전에는 ELK로 구성했으나 운영/관리/기능 비용을 생각하면 전문 솔류션이 효과적이다. ELK의 경우 크래시로그를 이벤트로 받아보기 위해서는 개발하거나 X-Pack 같은 ElasticSearch 플러그인을 붙여야 한다. ELK가 쉽다고들 하는데 학습,유지보수,운영 쉬운게 하나도 없다.

인시던트 관리 시스템을 도입한다

인시던트 관리 시스템을 도입한다. 모든 이벤트가 중앙으로 전송되며, 인시던트의 라우팅, 그룹, 스케쥴링, 중요도, 애플리케이션 타입에 따라서 처리해야 할 팀 혹은 담당자에게 전달된다. 중요도에 따라서 메일, SMS, Slack 등 다양한 수단으로 전송 할 수 있다. Opsgenie를 참고하자.

CICD와의 통합

CICD와 관련된 자세한 내용은 다루지 않는다. SRE와의 통합 부분만을 다룬다.

CodePipeline을 이용해서 CICD를 구현할 것이다. SRE와 통합하기 위한 주요 구성요소는 아래와 같다.
  1. Build, Test, Stage(dev, qa, production) 상태변경 정보를 incident management 시스템과 통합한다. 개발자, QA, SRE, 운영자가 상태변화에 대응 할 수 있다.
  2. Blue/Green 배포를 자연스럽게 적용 할 수 있다. 프러덕션 배포에서 발생할 수 있는 서비스 중단은 SLO에는 포함되지 않는다. 하지만 SLO를 초과하지 않도록 관리하는 등의 목표를 세워야 한다. B/G 배포는 이러한 요구사항을 만족하기 위한 좋은 툴이 될 수 있다.
  3. 롤백. 애플리케이션 실패가 발생 했을 때, SLO에 영향을 주기전에 롤백 할 수 있다. 역시 CodePipeline에 통합할 수 있다.
  4. 웹 서비스의 경우 API 문서의 관리가 필요하다. CICD에서 API 문서는 개발주기와 함께한다. API는 빌드 과정에서 생성이 되며, QA는 이 문서로 품질관리 활동을 한다. 문서는 연동을 원하는 다른 조직이나 외부 서비스에 제공이 된다. 운영 단계에서 API 문서는 서비스 품질을 위한 중요 자산으로 활용 할 수 있다.
CICD와 SRE의 통합은 아래와 같은 흐름을 가질 것이다.

 CICD와 SRE의 통합

정리

SRE에서 다뤄야하는 각 영역에 대한 활동을 정리하는 것으로 마무리 한다.

해야 할 것들

참고