Monitoring and Logging#
모니터링과 로깅은 현대 백엔드 시스템의 건강 상태를 파악하고 성능을 최적화하는 데 필수적인 요소이다. 이러한 도구와 전략을 통해 시스템의 병목 현상을 식별하고, 문제가 발생하기 전에 예방적 조치를 취할 수 있으며, 사용자 경험을 크게 향상시킬 수 있다.
모니터링의 기본 원칙과 중요성#
모니터링은 백엔드 시스템의 상태와 성능을 실시간으로 관찰하는 과정이다. 효과적인 모니터링은 다음과 같은 이점을 제공합니다:
핵심 모니터링 지표#
- 리소스 사용률: CPU, 메모리, 디스크 I/O, 네트워크 대역폭
- 응답 시간: 요청 처리에 걸리는 시간
- 처리량: 초당 처리되는 요청 수
- 오류율: 실패한 요청의 비율
- 포화도: 리소스가 얼마나 가득 차 있는지를 나타내는 지표
- 가용성: 시스템이 정상적으로 작동하는 시간의 비율
RED 방법론#
RED 방법론은 서비스 모니터링을 위한 간단하고 효과적인 접근 방식이다:
- Rate(비율): 초당 요청 수
- Errors(오류): 실패한 요청의 수
- Duration(지속 시간): 요청 처리에 걸리는 시간
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| # Prometheus 클라이언트를 사용한 RED 메트릭 구현 예시
from prometheus_client import Counter, Histogram, start_http_server
import time
# 요청 수 카운터
REQUEST_COUNT = Counter('app_request_count', 'Application Request Count', ['method', 'endpoint', 'status'])
# 요청 지속 시간 히스토그램
REQUEST_LATENCY = Histogram('app_request_latency_seconds', 'Application Request Latency', ['method', 'endpoint'])
def process_request(request):
# 요청 시작 시간
start_time = time.time()
try:
# 요청 처리
result = handle_request(request)
status = 'success'
except Exception as e:
status = 'error'
raise e
finally:
# 요청 처리 시간 기록
latency = time.time() - start_time
REQUEST_LATENCY.labels(request.method, request.endpoint).observe(latency)
REQUEST_COUNT.labels(request.method, request.endpoint, status).inc()
return result
|
USE 방법론#
USE 방법론은 리소스 병목 현상을 식별하는 데 중점을 둔다:
- Utilization(사용률): 리소스가 얼마나 바쁜지
- Saturation(포화도): 리소스에 대기 중인 작업량
- Errors(오류): 리소스 관련 오류 이벤트 수
주요 모니터링 도구와 플랫폼#
Prometheus#
Prometheus는 시계열 데이터베이스와 모니터링 시스템으로, 메트릭 수집, 저장, 쿼리 기능을 제공한다.
주요 특징:
- Pull 기반 아키텍처: 타겟에서 메트릭을 스크래핑
- 강력한 쿼리 언어(PromQL)
- 알림 관리
- 서비스 디스커버리
설치 및 기본 설정:
1
2
3
4
5
6
7
8
9
10
11
12
13
| # prometheus.yml 기본 설정 예시
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'spring-boot-app'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['localhost:8080']
- job_name: 'node-exporter'
static_configs:
- targets: ['localhost:9100']
|
Grafana#
Grafana는 다양한 데이터 소스에서 수집된 메트릭을 시각화하는 도구이다.
주요 특징:
- 다양한 데이터 소스 지원(Prometheus, InfluxDB, Elasticsearch 등)
- 사용자 정의 대시보드
- 알림 기능
- 애노테이션
대시보드 구성 예시:
- 시스템 개요 대시보드: CPU, 메모리, 디스크, 네트워크 사용률
- 애플리케이션 성능 대시보드: 응답 시간, 처리량, 오류율
- 비즈니스 지표 대시보드: 사용자 활동, 전환율, 매출
ELK Stack (Elasticsearch, Logstash, Kibana)#
ELK Stack은 로그 수집, 처리, 분석 및 시각화를 위한 통합 솔루션이다.
주요 구성 요소:
- Elasticsearch: 로그 및 이벤트 데이터를 저장하고 검색하는 분산 검색 엔진
- Logstash: 다양한 소스에서 데이터를 수집, 변환하여 Elasticsearch로 전송하는 파이프라인
- Kibana: Elasticsearch 데이터를 시각화하고 탐색하는 웹 인터페이스
Logstash 설정 예시:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| # logstash.conf 예시
input {
file {
path => "/var/log/application.log"
type => "application"
}
}
filter {
if [type] == "application" {
grok {
match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} %{GREEDYDATA:message}" }
}
date {
match => [ "timestamp", "ISO8601" ]
}
}
}
output {
elasticsearch {
hosts => ["localhost:9200"]
index => "application-logs-%{+YYYY.MM.dd}"
}
}
|
Datadog, New Relic, Dynatrace#
이러한 상용 APM(Application Performance Monitoring) 솔루션은 백엔드 성능 모니터링을 위한 종합적인 기능을 제공한다:
주요 기능:
- 분산 추적
- 애플리케이션 맵핑
- 인프라 모니터링
- 실시간 알림
- AI 기반 이상 탐지
효과적인 로깅 전략#
로깅은 시스템의 동작과 문제를 이해하는 데 중요한 요소이다. 잘 설계된 로깅 전략은 디버깅 시간을 줄이고 문제 해결을 용이하게 한다.
로깅 레벨과 적절한 사용#
- TRACE: 매우 상세한 디버깅 정보
- DEBUG: 개발 과정에서 유용한 디버깅 정보
- INFO: 일반적인 애플리케이션 상태와 이벤트
- WARN: 잠재적 문제나 경고
- ERROR: 오류 발생, 하지만 애플리케이션은 계속 실행 가능
- FATAL: 심각한 오류로 인한 애플리케이션 중단
구조화된 로깅#
구조화된 로깅은 로그 메시지를 JSON과 같은 구조화된 형식으로 저장하여 쉽게 파싱하고 분석할 수 있게 한다.
Java 예시 (Log4j2 사용):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;
public class UserService {
private static final Logger logger = LogManager.getLogger(UserService.class);
public User getUserById(String userId) {
// 컨텍스트 정보 추가
ThreadContext.put("userId", userId);
ThreadContext.put("operation", "getUserById");
try {
logger.info("Fetching user data");
User user = userRepository.findById(userId);
if (user == null) {
logger.warn("User not found");
return null;
}
logger.info("User data retrieved successfully");
return user;
} catch (Exception e) {
logger.error("Error fetching user data", e);
throw e;
} finally {
// 컨텍스트 정보 제거
ThreadContext.clearAll();
}
}
}
|
비동기 로깅의 중요성#
비동기 로깅은 로깅 작업이 애플리케이션의 주요 실행 경로를 차단하지 않도록 하여 성능을 향상시킨다.
장점:
- 메인 스레드 차단 방지
- 로깅 처리량 증가
- I/O 지연 시간 감소
Log4j2 비동기 로깅 설정 예시:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| <!-- log4j2.xml -->
<Configuration>
<Appenders>
<RollingFile name="RollingFile" fileName="logs/app.log" filePattern="logs/app-%d{MM-dd-yyyy}.log.gz">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
<Policies>
<TimeBasedTriggeringPolicy />
</Policies>
</RollingFile>
<!-- 비동기 래퍼 -->
<Async name="AsyncAppender" bufferSize="1000" blocking="false">
<AppenderRef ref="RollingFile"/>
</Async>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="AsyncAppender"/>
</Root>
</Loggers>
</Configuration>
|
로그 집계 및 중앙화#
대규모 분산 시스템에서는 로그를 중앙 위치에 집계하여 관리하는 것이 중요하다.
집계 방법:
- Filebeat: 로그 파일을 읽어서 Logstash나 Elasticsearch로 전송
- Fluentd: 다양한 소스에서 로그를 수집하고 다양한 대상으로 전송
- Vector: 고성능 관측 가능성 데이터 파이프라인
Filebeat 설정 예시:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # filebeat.yml
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/application/*.log
tags: ["application"]
fields:
service: user-service
environment: production
output.elasticsearch:
hosts: ["elasticsearch:9200"]
index: "application-%{+yyyy.MM.dd}"
|
분산 추적(Distributed Tracing)#
마이크로서비스 아키텍처에서는 단일 요청이 여러 서비스를 통과할 수 있다. 분산 추적은 이러한 요청의 전체 경로를 추적하여 병목 현상과 오류를 식별한다.
OpenTelemetry#
OpenTelemetry는 분산 추적, 메트릭, 로그를 위한 오픈 소스 표준이다.
주요 구성 요소:
- Tracer: 분산 추적 정보 수집
- Meter: 메트릭 수집
- Logger: 로그 수집
- Collector: 텔레메트리 데이터 수집 및 내보내기
Java 예시:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
| import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.Scope;
public class OrderService {
private final Tracer tracer;
public OrderService(OpenTelemetry openTelemetry) {
this.tracer = openTelemetry.getTracer("order-service");
}
public Order processOrder(String orderId) {
Span span = tracer.spanBuilder("processOrder").startSpan();
try (Scope scope = span.makeCurrent()) {
span.setAttribute("orderId", orderId);
// 주문 검증
span.addEvent("Validating order");
validateOrder(orderId);
// 재고 확인
span.addEvent("Checking inventory");
checkInventory(orderId);
// 결제 처리
span.addEvent("Processing payment");
processPayment(orderId);
// 주문 완료
Order order = finalizeOrder(orderId);
span.addEvent("Order completed");
return order;
} catch (Exception e) {
span.recordException(e);
span.setStatus(StatusCode.ERROR, e.getMessage());
throw e;
} finally {
span.end();
}
}
// 기타 메서드…
}
|
Jaeger, Zipkin#
Jaeger와 Zipkin은 분산 추적 데이터를 수집, 저장, 시각화하는 플랫폼이다.
주요 기능:
- 분산 트랜잭션 모니터링
- 서비스 의존성 분석
- 성능 병목 현상 식별
- 오류 분석
알림 및 인시던트 관리#
모니터링 시스템에서 문제가 감지되면 적시에 대응할 수 있도록 알림을 설정해야 한다.
효과적인 알림 전략#
- 알림 피로 방지: 중요한 문제에만 알림 설정
- 적절한 임계값 설정: 너무 민감하거나 둔감하지 않게
- 알림 우선순위 지정: 심각도에 따라 알림 분류
- 온콜 로테이션: 팀 간 책임 분담
이러한 도구는 알림 관리, 인시던트 대응 및 온콜 일정 관리를 지원한다.
기능:
- 다양한 알림 채널(SMS, 이메일, 푸시 알림 등)
- 에스컬레이션 정책
- 인시던트 추적
- 사후 분석 보고서
SLI, SLO, SLA#
- SLI(Service Level Indicator): 서비스 성능을 측정하는 지표(예: 가용성, 응답 시간)
- SLO(Service Level Objective): SLI에 대한 목표 값(예: 99.9% 가용성)
- SLA(Service Level Agreement): 서비스 제공자와 고객 간의 공식 계약
SLO 설정 예시:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| # Prometheus AlertManager 설정
groups:
- name: slo-alerts
rules:
- alert: HighLatency
expr: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) > 0.5
for: 5m
labels:
severity: warning
annotations:
summary: "High latency detected"
description: "95th percentile latency is above 500ms (current value: {{ $value }}s)"
- alert: ErrorBudgetBurn
expr: sum(rate(http_requests_total{status=~"5.."}[1h])) / sum(rate(http_requests_total[1h])) > 0.001
for: 15m
labels:
severity: critical
annotations:
summary: "Error budget burn rate too high"
description: "Error rate is above 0.1%, burning error budget too quickly"
|
비용 효율적인 모니터링 전략#
모니터링 시스템도 리소스를 소비하므로 비용 효율적인 접근 방식이 필요하다.
데이터 보존 정책#
모든 메트릭과 로그를 무기한 저장하는 것은 비용이 많이 든다. 데이터 중요도에 따라 보존 기간을 설정해야 한다.
예시 정책:
- 고해상도 메트릭: 7일
- 저해상도 집계 메트릭: 30-90일
- 중요 로그: 90일
- 일반 로그: 14-30일
샘플링 전략#
모든 요청이나 이벤트를 추적하는 대신 일부만 샘플링하여 저장할 수 있다.
적용 사례:
- 분산 추적: 일정 비율의 트랜잭션만 추적
- 상세 로깅: 오류가 있는 요청이나 특정 임계값을 초과하는 요청만 상세 로깅
실제 사례 연구 및 최적화 전략#
Netflix의 모니터링 및 로깅 아키텍처#
Netflix는 Atlas(시계열 데이터베이스), Kayenta(자동 카나리 분석), Chaos Monkey(복원력 테스트) 등의 도구를 사용하여 대규모 시스템을 모니터링한다.
주요 전략:
- 서비스별 메트릭 수집
- 자동화된 이상 탐지
- 카오스 엔지니어링을 통한 복원력 테스트
대규모 웹 서비스의 모니터링 설계#
대규모 웹 서비스 아키텍처에서의 모니터링 설계 예시:
- 집계 계층: 각 서비스와 인스턴스에서 메트릭 수집
- 스토리지 계층: 시계열 데이터베이스에 메트릭 저장
- 분석 계층: 메트릭 분석, 알림 트리거, 대시보드 생성
- 응답 계층: 알림 전달, 인시던트 관리
자동화된 대응 전략#
모니터링 시스템에서 감지된 문제에 자동으로 대응하여 인적 개입 없이 문제를 해결할 수 있다.
자가 복구 시스템#
- 자동 재시작: 서비스가 실패하면 자동으로 재시작
- 헬스 체크: 정기적인 헬스 체크를 통해 문제 감지
- 부하 분산: 과부하 서버에서 트래픽 리디렉션
Kubernetes 예시:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
| # 자가 복구 설정이 포함된 Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-application
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web-app
image: my-web-app:latest
ports:
- containerPort: 8080
# 헬스 체크 설정
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
# 준비 상태 체크
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
# 리소스 제한
resources:
limits:
cpu: "1"
memory: "512Mi"
requests:
cpu: "0.5"
memory: "256Mi"
|
자동 스케일링#
시스템 부하에 따라 자동으로 리소스를 확장하거나 축소한다.
AWS Auto Scaling 예시:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| {
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"WebServerGroup": {
"Type": "AWS::AutoScaling::AutoScalingGroup",
"Properties": {
"AvailabilityZones": ["us-east-1a", "us-east-1b"],
"LaunchConfigurationName": { "Ref": "LaunchConfig" },
"MinSize": "2",
"MaxSize": "10",
"DesiredCapacity": "2",
"HealthCheckType": "ELB",
"HealthCheckGracePeriod": 300,
"TargetGroupARNs": [{ "Ref": "ALBTargetGroup" }]
}
},
"CPUScalingPolicy": {
"Type": "AWS::AutoScaling::ScalingPolicy",
"Properties": {
"AutoScalingGroupName": { "Ref": "WebServerGroup" },
"PolicyType": "TargetTrackingScaling",
"TargetTrackingConfiguration": {
"PredefinedMetricSpecification": {
"PredefinedMetricType": "ASGAverageCPUUtilization"
},
"TargetValue": 70.0
}
}
}
}
}
|
용어 정리#
참고 및 출처#