System Design Interview Volume 2 (4)
지표 모니터링 및 경보 시스템
지표 (metrics) monitoring 및 경보 (alerting) system: Infra의상태를 선명하게 볼 수 있도록 하여 높은 가용성과 안정성을 달성하는 데 중추적 역할 수행
1단계: 문제 이해 및 설계 범위 확정
- 개략적 요구사항 및 가정
- 대규모 infra를 monitoring 해야 함
- 일간 능동 사용자 수 1억 명 (100 million)
- Server pool 1,000개, pool당 server 수 100개의 운영 지표 수집 가정
$\rightarrow$ Monitoring 지표의 수: 약 1,000만개 - Data 보관 기간: 1년
- 수집한 raw data 7일 보관
- 1분 단위 data로 변환 후 30일 보관
- 1시간 단위 data로 변환 후 1년 보관
- Monitoring 지표 예시
- CPU 사용률
- 요청 수
- Memory 사용량
- Message queue 내의 message 수
- 대규모 infra를 monitoring 해야 함
- 비기능 요구사항 및 제약사항
- 규모 확장성: 늘어나는 지표 수 및 경보 양에 맞게 확장 가능
- 낮은 응답 지연: Dashboard와 경보 (alert)를 신속하게 처리할 수 있도록 query에 대한 낮은 응답 지연 보장
- 안정성: 중요 경보를 놓치지 않도록 높은 안정성 보장
- 유연성: 기술 변화에 따라 유연한 통합 가능
- Log monitoring 또는 분산 (distributed) system 추적 (tracing)은 고려 X
2단계: 개략적 설계안 제시 및 동의 구하기
기본적 사항
flowchart LR
sys["지표 monitoring 및
경보 system"]
1["(1) Data 수집"]
2["(2) Data 전송"]
3["(3) Data 저장소"]
4["(4) 경보"]
5["(5) 시각화"]
sys-->1
sys-->2
sys-->3
sys-->4
sys-->5
- Data 수집 (collection): 여러 출처로부터 지표 data 수집
- Data 전송 (transmission): 지표 data를 지표 monitoring system으로 전송
- Data 저장소 (storage): 전송되어 오는 data를 정리 후 저장
- 경보 (alert): 밀려오는 data 분석, 이상 징후 감지, 경보 발생
- 시각화 (visualization): Data를 chart나 graph 등으로 제공
데이터 모델
지표 data는 통상적으로 시계열 (time series) data 형태로 기록
- Write: 매일 1,000만개의 운영 지표가 기록되기 때문에 매우 큰 부하 발생
- Read: 시각화 또는 경보 확인 pattern에 따라 일시적으로 치솟았다 사라지는 (spiky) 부하
데이터 저장소 시스템
- MySQL과 같은 범용 저장소 system을 설계안의 부하 규모에 맞추기 위해선 전문가 수준의 tuning이 필요하여 추천 X
- RDB는 시계열 data를 대상으로 자주 사용하는 연산에 최적화 X
- 또한 많은 양의 쓰기 연산이 지속적으로 발생 시 좋은 성능 X
- NoSQL 중 Cassandra 또는 Bigtable을 사용할 수 있지만, 시계열 data를 효과적으로 질의하기 위해서는 확장이 용이한 내부 구조의 해박한 지식 기반 schema를 설계 필요
- OpenTSDB (Open Time Series Database)는 분산 시계열 database지만 Hadoop과 HBase에 기반하여 cluster를 구축하고 운영해야 하므로 복잡
- DB-engines에서 조사한 결과에 따르면 시장에서 가장 인기 있는 시계열 database는 InfluxDB와 Prometheus
- 다량의 시계열 data를 저장하고 빠른 실시간 분석 지원
- Memory cache와 disk 저장소를 함께 사용
- 영속성 (durability) 요건과 높은 성능 요구사항 만족
- 좋은 시계열 database는 막대한 양의 시계열 data를 label (또는 tag) 기준으로 집계하고 분석하는 기능 제공
개략적 설계안
flowchart LR
ms["Metrics source"]
mc["Metrics collector"]
db[("Time series database")]
qs["Query service"]
as["Alerting system"]
vs["Visualization system"]
ms-->mc-->db
qs-->db
as--"Query 전송"-->qs
vs--"Query 전송"-->qs
as-->Email
as-->msg["단문 message"]
as-->PagerDuty
as-->enp["HTTPS service endpoint"]
- Metrics source: 지표 data가 만들어지는 곳으로 application server, SQL database, message queue 등 어떤 것이든 가능
- Metrics collector: 지표 data를 수집하고 시계열 database에 기록하는 역할
- Time series database: 지표 data를 시계열 data 형태로 보관하는 저장소
- Query service: 시계열 database에 보관된 data를 질의하고 가져오는 과정을 돕는 service (Database의 query interface로 대신 가능)
- Alerting system: 경보를 받아야 하는 다양한 대상으로 경보 알림을 전송하는 역할
- Visualization system: 지표를 다양한 형태의 graph/chart로 시각화하는 기능 제공
3단계: 상세 설계
지표 수집
- Pull model: 실행 중인 application에서 주기적으로 지표 data를 가져오는 지표 수집기가 흐름의 중심
- 지표 수집기는 data를 가져올 service 목록을 알아야함
- etcd 또는 ZooKeeper와 같은 service 탐색 (discovery) 기술을 활용하여 각 service는 가용성 (availability) 관련 정보를 service 탐색 service (SDS)에 기록 및 sercice endpoint 변화 시 지표 수집기에 통보
- 수천 대 server가 만드는 지표 data를 수집하기위해 안정 (consistent) hash ring을 사용하여 여러 지표 수집 server 간 중재 mechanism 수행
flowchart LR
subgraph ms["Metrics source"]
ws["Web server"]
db["DB cluster"]
qu["Queue cluster"]
ca["Cache cluster"]
end
mc["Metrics collector"]
subgraph se["Service 탐색 service"]
etcd
ZooKeeper
end
mc--지표 수집 (Pull)-->ws
mc--지표 수집 (Pull)-->db
mc--지표 수집 (Pull)-->qu
mc--지표 수집 (Pull)-->ca
mc-->se
- Push model
- Monitoring 대상 server에 수집 (collection) agent라 부르는 software 설치
- 수집 agent는 해당 장비에서 실행되는 service가 생산하는 지표 data를 받아 모은 다음 주기적으로 수집기에 전달
- Data 집계 (aggregation)는 수집기에 보내는 data 양을 줄이는 효과적 방법
- 지표 수집기 cluster 자체도 자동 규모 확장이 가능하도록 구성하고 load balancer를 두어 밀려드는 지표 data 처리
flowchart LR
subgraph ms["Metrics source"]
ws["Web server"]
db["DB cluster"]
qu["Queue cluster"]
ca["Cache cluster"]
end
mc["Metrics collector"]
ws--지표 전송 (Push)-->mc
db--지표 전송 (Push)-->mc
qu--지표 전송 (Push)-->mc
ca--지표 전송 (Push)-->mc
Feature | Pull Model | Push Model |
---|---|---|
Data Collection | 실행 중인 application에서 주기적으로 지표 data를 가져오는 수집기가 중심 | Monitoring 대상 서버에 수집 agent 설치, 주기적으로 수집기에 data 전달 |
Aggregation | 수집기가 여러 service에서 data를 수집하여 집계 | 수집 agent가 data를 집계하여 전송 |
Scalability | 안정적인 hash ring을 사용하여 여러 수집기 간 중재 mechanism 수행 | 수집기 cluster 자동 확장 가능, load balancer를 통해 data 처리 |
Service Discovery | etcd 또는 ZooKeeper와 같은 service 탐색 기술 사용 | 필요 없음 |
Advantages | 수집기가 data를 직접 가져와서 신뢰성 높음 | 간단한 설정, 수집 agent가 data 집계 가능 |
Disadvantages | Service 목록을 알아야 하며, service endpoint 변화 시 통보 필요 | 수집 agent 설치 및 관리 필요, network 부하 증가 가능 |
Example | Prometheus | Amazon CloudWatch, Graphite |
지표 전송 파이프라인의 규모 확장
- Pull 및 push model 모두 지표 수집기는 server cluster 형태이며 엄청난 양의 data를 처리해야하기 때문에 시계열 database에 장애 발생 시 data 손실 발생 가능성 존재
- 지표 수집기는 지표 data를 Kafka와 같은 queue system에 전송하고 Apache Storm, Flink, Spark와 같은 소비자 (stream 처리 service)가 해당 data를 받아 시계열 database에 저장
- Kafka는 고도로 안정적이고 규모 확장성이 뛰어난 분산 message platform
- Data 수집 component와 처리 component 사이의 결합도 감축
- Database에 장애가 생겨도 Kafka에 보관하여 data가 소실되지 않음
flowchart LR
ms["Metrics source"]
mc["Metrics collector"]
db[("Time series database")]
qs["Query service"]
as["Alerting system"]
vs["Visualization system"]
kf@{ shape: das, label: "Kafka" }
ms-->mc-->kf-->Consumer-->db
qs-->db
as--"Query 전송"-->qs
vs--"Query 전송"-->qs
as-->Email
as-->msg["단문 message"]
as-->PagerDuty
as-->enp["HTTPS service endpoint"]
- Kafka를 통한 규모 확장
- 대역폭 요구사항에 따라 partition 수 설정
- 지표 이름에 따라 어느 partition에 배치할지 결정하면 소비자는 지표 이름에 따라 data 집계
- Tag/Label에 따라 지표 data를 더욱 세분화한 partition으로 분할
- 중요 지표가 먼저 처리될 수 있도록 지표 분류 및 우선순위 지정
- Kafka의 대안
- FaceBook의 memory 기반 시계열 database system Gorilla 사용 $\rightarrow$ Kafka와 같은 message queue가 없어도 같은 수준의 안정성 제공 주장 가능
데이터 집계 지점
- 수집 agent 집계
- Client에 설치된 수집 agent는 복잡한 집계 logic 지원 어려움
- 어떤 counter 값을 분 단위로 집계하여 지표 수집기에 전송 정도 가능
- Data 수집 pipeline에서 집계
- Data를 저장소에 기록하기 전에 집계할 수 있으려면 Flink 같은 stream processing engine 필요
- Database에는 계산 결과만 늦게 기록하기 때문에 실제로 기록되는 양은 매우 크게 감소
- 하지만 늦게 도착하는 지표 data의 처리가 어려우며 원본 data를 보관하지 않으므로 정밀도 또는 유연성 측면에서 손해 발생 가능
- 질의 시 집계
- Raw data를 그대로 보관 후 질의 시 필요한 시간 구간에 맞춰 집계
- Data 손실 문제는 없지만 질의 처리 시 전체 dataset를 대상으로 집계 결과를 계산해야 하기 때문에 성능 저하
질의 서비스
- 질의 server cluster 형태로 구현
- 시각화 또는 경보 system에서 접수된 요청을 시계열 database를 통해 처리하는 역할
- Client (시각화 또는 경보 system)와 시계열 database 사이의 결합도 감소 $\rightarrow$ 시계열 database를 자유롭게 다른 제품으로 교체 가능
- Cache 계층
- 질의 결과를 저장할 cache server를 도입하여 시계열 database에 대한 질의 부하를 낮추고 질의 service 성능 향상 가능
- 시계열 database 질의어
- Prometheus 또는 InfluxDB 같은 널리 사용되는 지표 monitoring system들은 SQL이 아닌 독자적 질의어 제공 ($\because$ SQL로는 시계열 data를 질의하기 까다로움)
저장소 계층
- 시계열 database는 신중하게 선택
- FaceBook의 연구에 따르면 운영 data 저장소에 대한 질의의 85%는 지난 26시간 내 수집 data 대상
- 저장 용량 최적화
- Data encoding 및 압축: Data를 완전한 형태로 저장하는 대신 기준 값의 차이를 저장
- Downsampling: Data의 해상도를 낮춰 저장소 요구량 감축
- 냉동 저장소 (cold storage): 잘 사용되지 않는 비활성 상태 data를 보관
경보 시스템
flowchart LR
db[("경보 저장소")]
qs["Query service"]
kf@{ shape: das, label: "Kafka" }
rule@{ shape: notch-rect, label: "규칙 설정 file" }
am["경보 관리자"]
cs["경보 소비자"]
am<-->db
rule-->Cache<-->am<-->qs
am-->kf-->cs
cs-->Email
cs-->msg["단문 message"]
cs-->PagerDuty
cs-->enp["HTTPS service endpoint"]
- 설정 file을 가져와 cache server에 보관
경보 규칙은 disk에 file 상태로 보관 (YAML을 주로 사용) - 경보 관리자 (alert manager)는 경보 설정 내역을 cache에서 가져옴
- 설정된 규칙에 따라 경보 관리자는 지정된 시간마다 질의 (query) service 호출 및 설정된 임계값 (threshold)을 위반하면 경보 event 생성
- 경보 filtering, 병합 (merge), 중복 제거 (dedupe): 짧은 시간 동안 같은 instance에서 발생한 경보 병합
- 접근 제어 (access control): 사람의 실수로 빚어지는 장애를 막고 system의 보안을 유지하기 위해 특정한 경보 관리 작업은 특정 개인만 수행할 수 있도록 제한
- 재시도 (retry): 경보 관리자는 경보 상태를 확인 후 알림이 최소 한 번은 전달됨을 보장
- 경보 저장소는 Cassandra와 같은 key-value 저장소이며 모든 경보의 상태 (비활성화, 응답 대기, 경보 발령, 문제 해결 등)가 저장되며 알림이 적어도 한 번 이상 전달되도록 보장
- 경보 evenet를 Kafka에 전달
- 경보 소비자는 Kafka에서 경보 event 소비
- 경보 소비자는 Kafka에서 읽은 경보 event를 처리하여 email, 단문 message, PagerDuty. HTTP service endpoint 등의 다양한 channel로 알림 전송
시각화 시스템
- 지표 dashboard에는 지표를 다양한 시간 범위로 표시하고 경보 dashboard에는 다양한 경보의 상태 표시
- 품질 좋은 시각화 system을 구축하는 것을 어렵기 때문에 상용품을 구입해서 쓰자고 주장하는 것이 바람직함 (ex. Grafana)