Monitoring and Logging

모니터링과 로깅은 현대 백엔드 시스템의 건강 상태를 파악하고 성능을 최적화하는 데 필수적인 요소이다. 이러한 도구와 전략을 통해 시스템의 병목 현상을 식별하고, 문제가 발생하기 전에 예방적 조치를 취할 수 있으며, 사용자 경험을 크게 향상시킬 수 있다.

모니터링의 기본 원칙과 중요성

모니터링은 백엔드 시스템의 상태와 성능을 실시간으로 관찰하는 과정이다. 효과적인 모니터링은 다음과 같은 이점을 제공합니다:

핵심 모니터링 지표

RED 방법론

RED 방법론은 서비스 모니터링을 위한 간단하고 효과적인 접근 방식이다:

 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 방법론은 리소스 병목 현상을 식별하는 데 중점을 둔다:

주요 모니터링 도구와 플랫폼

Prometheus

Prometheus는 시계열 데이터베이스와 모니터링 시스템으로, 메트릭 수집, 저장, 쿼리 기능을 제공한다.

주요 특징:

설치 및 기본 설정:

 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는 다양한 데이터 소스에서 수집된 메트릭을 시각화하는 도구이다.

주요 특징:

대시보드 구성 예시:

  1. 시스템 개요 대시보드: CPU, 메모리, 디스크, 네트워크 사용률
  2. 애플리케이션 성능 대시보드: 응답 시간, 처리량, 오류율
  3. 비즈니스 지표 대시보드: 사용자 활동, 전환율, 매출

ELK Stack (Elasticsearch, Logstash, Kibana)

ELK Stack은 로그 수집, 처리, 분석 및 시각화를 위한 통합 솔루션이다.

주요 구성 요소:

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) 솔루션은 백엔드 성능 모니터링을 위한 종합적인 기능을 제공한다:

주요 기능:

효과적인 로깅 전략

로깅은 시스템의 동작과 문제를 이해하는 데 중요한 요소이다. 잘 설계된 로깅 전략은 디버깅 시간을 줄이고 문제 해결을 용이하게 한다.

로깅 레벨과 적절한 사용

구조화된 로깅

구조화된 로깅은 로그 메시지를 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();
        }
    }
}

비동기 로깅의 중요성

비동기 로깅은 로깅 작업이 애플리케이션의 주요 실행 경로를 차단하지 않도록 하여 성능을 향상시킨다.

장점:

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>

로그 집계 및 중앙화

대규모 분산 시스템에서는 로그를 중앙 위치에 집계하여 관리하는 것이 중요하다.

집계 방법:

  1. Filebeat: 로그 파일을 읽어서 Logstash나 Elasticsearch로 전송
  2. Fluentd: 다양한 소스에서 로그를 수집하고 다양한 대상으로 전송
  3. 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는 분산 추적, 메트릭, 로그를 위한 오픈 소스 표준이다.

주요 구성 요소:

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은 분산 추적 데이터를 수집, 저장, 시각화하는 플랫폼이다.

주요 기능:

알림 및 인시던트 관리

모니터링 시스템에서 문제가 감지되면 적시에 대응할 수 있도록 알림을 설정해야 한다.

효과적인 알림 전략

PagerDuty, OpsGenie

이러한 도구는 알림 관리, 인시던트 대응 및 온콜 일정 관리를 지원한다.

기능:

SLI, SLO, SLA

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"

비용 효율적인 모니터링 전략

모니터링 시스템도 리소스를 소비하므로 비용 효율적인 접근 방식이 필요하다.

데이터 보존 정책

모든 메트릭과 로그를 무기한 저장하는 것은 비용이 많이 든다. 데이터 중요도에 따라 보존 기간을 설정해야 한다.

예시 정책:

샘플링 전략

모든 요청이나 이벤트를 추적하는 대신 일부만 샘플링하여 저장할 수 있다.

적용 사례:

실제 사례 연구 및 최적화 전략

Netflix의 모니터링 및 로깅 아키텍처

Netflix는 Atlas(시계열 데이터베이스), Kayenta(자동 카나리 분석), Chaos Monkey(복원력 테스트) 등의 도구를 사용하여 대규모 시스템을 모니터링한다.

주요 전략:

대규모 웹 서비스의 모니터링 설계

대규모 웹 서비스 아키텍처에서의 모니터링 설계 예시:

  1. 집계 계층: 각 서비스와 인스턴스에서 메트릭 수집
  2. 스토리지 계층: 시계열 데이터베이스에 메트릭 저장
  3. 분석 계층: 메트릭 분석, 알림 트리거, 대시보드 생성
  4. 응답 계층: 알림 전달, 인시던트 관리

자동화된 대응 전략

모니터링 시스템에서 감지된 문제에 자동으로 대응하여 인적 개입 없이 문제를 해결할 수 있다.

자가 복구 시스템

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
        }
      }
    }
  }
}

용어 정리

용어설명

참고 및 출처