본문 바로가기

Study

대규모 시스템 설계 기초 2 - 5장. 지표 모니터링 및 경보 시스템

728x90

잘 설계된 지표 모니터링과 경보 시스템은 인프라의 상태를 상세하게 보여줌으로써 높은 가용성과 안정성을 달성하는 중추적인 역할을 수행합니다. 이번 장은 DATADOG나 Grafana처럼 유명한 대시보드 서비스와 유사한 서비스를 설계하고 있습니다.

 

기능/비기능 요구사항

기능 요구사항

  • 인프라 규모는?
    • DAU 1억명, 서버 풀 1,1000개, 풀당 서버 수 100개, 서버당 100개의 운영지표 수집 => 모니터링이 필요한 지표 수는 1,000만 개
    • 데이터 보관 기간: 1년
    • 수집한 그대로 데이터 보관하는 기간은 1주일, 그 후에는 1분 단위데이터로 변환 후 30일간 보관, 그 후에는 1시간 단위 데이터로 변환 후 1년간 보관 (데이터를 압축해서 저장한다는 뜻으로 지표의 해상도(resolution)를 낮춤)
  • 모니터링할 지표: CPU 사용률, 요청 수, 메모리 사용량, 메시지 큐 내의 메시지 수

비기능 요구사항

  • 규모 확장성 : 늘어나는 지표 수와 경보의 양에 맞게 확장되는 시스템 설계
  • 낮은 응답 지연 : Dashboard, Alert을 신속하게 처리, Query에 대한 빠른 응답 
  • 안정성 : 중요 정보를 소실하지 않는 시스템 설계
  • 유연성 : 미래 신기술을 쉽게 통합할 수 있는 유연하게 변경가능한 시스템 설계

계략 설계

시스템의 기본 기능

    • 데이터 수집 : 여러 출처로부터 데이터를 수집
    • 데이터 전송 : 지표 데이터를 지표 모니터링 시스템으로 전송
    • 데이터 저장소 : 전송되어 오는 데이터를 정리하고 저장
    • 경보 : 전송된 데이터를 분석하고, 이상 징후 감지 및 경보 발생 (다양한 통신 채널로 경보 발송)
    • 시각화 : 데이터를 차트나 그래프로 제공

데이터 모델

지표 데이터는 대부분 시계열(time series) 데이터 형태로 기록합니다. 즉, data 집합에 timestamp가 붙은 형태로 기록됩니다. 

이름 Data type 예시
지표 이름 String Memory Usage, Disk I/O 등
tag/label <key: value> 쌍 리스트 [host=webserver01, region=us-west] 등
지표 value 및 timestamp 배열 <Value, timestamp> 쌍 배열 [<50,  161307265>, <62, 161370727> ]

 

데이터 접근 패턴

'기능 요구사항'에서 확인했듯이, 매일 1,000만 개의 모니터링 지표가 기록됩니다. 즉, 이 모니터링 시스템으로 오는 트래픽은 쓰기가 압도적일 것입니다. 반면, 읽기 부하는 일시적으로 치솟았다 사라지는 Spike 성 호출일 것입니다. 즉, 그래프나 경보를 확인하는 패턴에 따라 읽기 연산이 일시적으로 증가하다가 가라앉게 될 것이죠.

 

데이터 저장소 시스템

이 시스템 설계의 핵심입니다. SQL이나 NoSQL 같은 범용 데이터베이스는 이론적으로는 시계열 데이터를 처리할 수 있다고 합니다. 하지만, 이 설계안의 요구사항인 막대한 트래픽 규모를 감당할 수 있으려면 전문가 수준의 튜닝(tuning)이 필요합니다. 범용 DB는 시계열 데이터 처리 연산에 최적화되어 있지 않기 때문이죠.

게다가 SQL의 경우, 보고자 하는 지표에 따라 SQL 문이 매우 복잡하게 작성해야 하는 까다로움이 있을 것입니다. NoSQL  같은 경우도 확장이 용이한 Schema를 설계해야 하는데, 이를 위해서는 NOSQL DB의 내부 구조를 해박하게 알고 있어야 합니다.

 

시계열 데이터에 최적화된 저장소 시스템은 이미 많이 나와 있습니다. (OpenTSDB - Hadoop과 HBase 기반, MetricsDB, Amazon의 Timestream 등)

심지어, 데이터 보관 기간을 설정하거나 label이나 tag 기준으로 데이터를 집계하는 (aggregation) 기능을 제공하는 제품도 있습니다. 특히나, InfluxDB나 Prometheus와 같은 인기 있는 시계열 데이터베이스는 메모리 캐시와 디스크 저장소를 함께 사용함으로써 데이터를 저장하고 빠른 실시간 분석을 제공합니다. 영속성(durability)과 같은 높은 성능 요구사항도 잘 만족하는 데이터베이스입니다.

 

이 책에서는, 이러한 시계열 DB의 내부구조를 이해하기보다는, 지표 데이터는 본질적으로 시계열 데이터이기 때문에 InfluxDB 같은 DB에 저장할 수 있음을 알고 있는 것이 중요하다고 합니다.

 

추가로, 책에서 InfluxDB 사용 시, label 이 가질 수 있는 값의 Cardinality(가짓수)를 낮아야 함을 강조하고 있습니다. 이 부분이 이해하기 어려워서 추가적으로 정리해 보았습니다.

1. 카디널리티란?
카디널리티는 InfluxDB에서 한 측정(measurement) 내에서 서로 다른 유니크 시리즈(unique series)의 개수를 의미합니다.
예를 들어, 다음과 같은 태그가 있을 때:
device = { "sensor1", "sensor2", "sensor3" }
location = { "New York", "London", "Seoul" }​

가능한 유니크 시리즈는 3 (device) × 3 (location) = 9입니다.

2. 높은 카디널리티가 문제인 이유

InfluxDB는 데이터를 태그와 필드의 조합으로 인덱싱하여 빠른 조회를 가능하게 합니다. 하지만 태그 카디널리티가 높아지면 다음과 같은 문제가 발생합니다

1) 메모리 사용량 증가
유니크 시리즈는 시리즈 인덱스(series index)에 저장됩니다. 카디널리티가 높아질수록 시리즈 인덱스가 커져 메모리(RAM)를 과도하게 소모합니다.

2) 쓰기 성능 저하
새로 생성된 유니크 시리즈마다 인덱스를 업데이트해야 하므로, 태그 조합이 많을수록 쓰기 작업이 느려집니다. 특히, 실시간 데이터 스트림의 경우 높은 태그 카디널리티는 쓰기 작업의 병목을 초래할 수 있습니다.

이는, InfluxDB가 쓰이는 데이터의 태그 조합 이미 인덱스에 존재하는지 확인한 후, 기존에 존재하지 않는 조합이라면, 새로운 시리즈를 생성하기 때문입니다.  즉, 새로운 태그 조합에 대해 새로운 시리즈 ID를 생성하고, 이를 인덱스에 추가하는 작업이 비용과 시간이 많이 들게 됩니다.

3) 쿼리 성능 저하
높은 카디널리티의 데이터에서 특정 조건을 검색할 때, InfluxDB는 많은 시리즈를 스캔해야 하므로 검색 속도가 느려집니다.

예시 1) : 태그 location의 값이 1백만 개 이상이라면, location = 'Seoul' 조건으로 쿼리를 실행할 때 1백만 개의 유니크 시리즈를 스캔하게 됩니다.

예시 2) GROUP BY device_id와 같이 높은 카디널리티의 태그를 기준으로 그룹화하면, 각 유니크 시리즈에 대해 별도의 그룹을 생성해야 하므로 계산 비용이 급증하게 됩니다.

4) 디스크 공간 낭비
유니크 시리즈가 많아질수록 메타데이터와 인덱스에 더 많은 디스크 공간이 필요합니다.

3. 낮은 카디널리티를 가진 태그를 설정하는 법

1) 태그를 줄이고 필드로 이동
높은 카디널리티를 유발하는 태그를 필드로 변경합니다. (device_id를 필드로 변경)
temperature,location=Seoul temperature=25.4,device_id="sensor1" 1699932000000000000​

2) 동적 값 제한
동적으로 생성되는 태그 값(user_id, session_id)을 줄입니다.
cpu,host=server1,region=US usage=90.1 1699932000000000000 
cpu,host=server1,region=EU usage=85.3 1699932001000000000​

높은 카디널리티를 유발할 수 있는 태그 대신 고정된 카테고리(host, region)를 사용합니다.

3) 데이터 집계
센서에서 데이터를 매 초 단위로 수집하는 대신 주기적으로 집계(예: 1분 평균값)하여 기록합니다.
temperature,device_id=sensor1,location=Seoul mean_temperature=25.6 169993206000000000​



설계안

 

위의 설계안에서 각각의 요소에 대해서 상세한 설계를 진행합니다.

 

지표 출처와 지표 수집기

지표 출처는 metrics source 즉, 지표 데이터가 만들어지는 곳입니다. 애플리케이션 서버, SQL DB, 메시지 큐 등 어떤 것도 가능합니다. 지표 수집기는 지표 출처로부터 데이터를 수집하고 시계열 DB에 저장하는 역할을 합니다.

풀 vs 푸시 모델

지표 수집 방법으로 2가지가 있습니다. 

 

풀 모델의 경우, 지표 수집기가 주기적으로 실행 중인 애플리케이션에서 데이터를 가져옵니다. 이를 위해 지표 수집기는 데이터를 가져올 서비스 목록을 알고 있어야 합니다. etcd나 Apache Zookeeper와 같은 서비스 탐색 기술들이 이런 역할을 수행하는 데 용이합니다. Prometheus가 이러한 방식을 사용하고 있습니다.

 

푸시 모델의 경우, 지표 출처에서 지표 수집기에 직접 데이터를 전송합니다. 이를 위해 대부분 모니터링 대상 서버(지표 출처)에 Collection agent라고 부르는 소프트웨어를 설치하여, 이 수집 에이전트가 실행되는 서비스가 생산하는 지표 데이터를 모아 주기적으로 수집기에 전달하게 됩니다. 간단한 counter와 같은 지표는 수집기에 데이터를 보내기 전에 에이전트가 직접 집계 등의 작업을 처리할 수도 있습니다. Amazon의 CloudWatch, Graphite 등이 이러한 방식을 사용하고 있습니다.

 

지표 수집기가 밀려드는 데이터를 제때 처리하기 위해서 아래처럼 Autoscaling이 가능하도록 구성하고 그 앞에 LoadBalancer를 두는 것이 좋습니다. 이를 통해, 지표 수집기 서버 CPU 부하에 따라 Autoscaling이 가능하도록 설정할 수 있습니다.


 

책에는 자세하게 푸시 모델과 풀 모델의 장단점을 비교하고 있어서 참고하면 좋을 것 같습니다~


지표 전송 파이프라인

지표 수집기와 시계열 DB에 대한 설계입니다. 시계열 DB에 장애가 발생하면 전송 중에 데이터 손실이 발생할 가능성이 있습니다. 이를 위해 지표 수집기와 시계열 DB 사이에 Kafka와 같은 큐를 두어서 문제를 해소할 수 있습니다.


 

카프카에 내장된 partition을 이용하면 시스템의 규모를 아래와 같이 다양한 방법으로 확장할 수 있습니다. (4장. 분산 메시지 큐 참고)

  • 지표 이름 혹은 tag/label에 따라 지표를 파티션에 배치
  • 중요 지표가 먼저 처리될 수 있도록 우선순위 지정
  • 대역폭 요구사항에 따른 파티션 수 설정

카프카 시스템 구축이 쉽지 않을 경우, 큐 없이도 대규모 데이터 처리가 가능한 페이스북의 메모리 기반 시계열 DB인 Gorilla와 같은 시스템을 사용할 수도 있습니다. 

 

데이터 집계 지점

  • 수집 에이전트가 집계: 복잡한 집계 로직을 지원하기는 어렵습니다.
  • 데이터 수집 파이프라인에서 집계: DB에 저장하기 전에 집계하는 방안으로, Stream Processing Engine이 필요합니다. DB에 저장되는 데이터 양이 감소한다는 장점이 있지만, 늦게 도착하는 지표 데이터 처리가 어렵고, 원본 데이터를 저장하지 않아 정밀도나 유연성 측면에서 손해를 본다는 단점이 있습니다.
  • 질의 시에 집계: 원본 그대로 DB에 저장함으로써 데이터 손실 문제는 없으나, 질의를 처리할 때 전체 데이터셋을 대상으로 계산하므로 시간이 오래 걸립니다.

저장소

시계열 DB는 신중하게 선택해야 합니다. 저장 용량을 최적화하기 위해서 데이터를 인코딩하고 압축하여 저장하는 것이 좋습니다. 그리고 좋은 시계열 DB에서는 대부분 이 기능을 내장하고 있습니다.

 

또한, 다운샘플링(downsampling)으로 데이터의 해상도를 낮춰 저장 용량을 줄일 수 있습니다. 기능 요구사항을 따르려면 아래와 같이 처리합니다.

  • 7일 이내 데이터: 샘플링 X
  • 30일 이내 데이터: 1분 해상도로 낮춰 보관
  • 1년 이내 데이터: 1시간 해상도로 낮춰 보관

마지막으로, cold storage를 사용해 접근 빈도가 낮은 오래된 데이터를 보관하도록 함으로써 비용을 아낄 수 있습니다.


질의 서비스

시각화 시스템 혹은 경보 시스템과 같은 클라이언트와 시계열 DB 사이의 결합도를 낮춤으로써 시계열 DB를 자유롭게 다른 제품으로 교체할 수 있는 유연성을 제공합니다.

질의 결과를 저장할 캐시 서버를 도입하면, 시계열 DB에 대한 질의 부하를 낮추고 질의 서비스의 성능을 높일 수 있습니다.


 

참고할 점은, 대부분의 상용 시각화 및 경보 시스템은 시계열 DB와의 연동을 처리하는 플러그인을 이미 갖추고 있는 경우가 많다는 것입니다. 따라서, 별도 질의 시스템 및 캐시를 도입할 필요 없이 이런 플러그인을 갖춘 시계열 DB를 선택하는 것도 고려할 수 있습니다.


 

경보 시스템과 시각화 시스템

경보 시스템과 시각화 시스템은 직접 만들기보다는 상용품을 가져다 사용하는 것을 책에서 권장하고 있습니다. 하지만 책에서 경보 시스템의 구성 아키텍처를 자세히 설명하고 있으니 책을 통해 해당 아키텍쳐를 확인해 보는 것도 좋을 것 같습니다. :)

 

요약하여 설명해 보면, 규칙 설정 파일을 가져와 캐시에 저장한 뒤, 경보 관리자(alert manager)는 해당 설정 파일을 가져와 규칙에 근거하여 지정된 시간마다 질의 서비스를 호출합니다. 질의 결과가 Threshold을 넘으면 경보 이벤트를 생성한 뒤 kafka에 전달하고, 경보 소비자는 kafka에서 경보 이벤트를 읽어 처리하여 이메일, 메시지, PagerDuty 등 다양한 채널로 알림을 전송합니다. 또한 모든 경보의 상태를 보관하는 경보 저장소(cassandra 같은 key-value)를 두고 경보 정보들을 저장합니다.


 

전체 아키텍처

 

 

728x90
반응형