Prometheus는 모니터링과 알림을 위한 오픈 소스 시스템으로, 시스템 성능과 인프라 상태를 모니터링하는 데 널리 사용됩니다. 하지만 시간이 지남에 따라 많은 양의 메트릭 데이터를 수집하고 처리하면서 메모리 사용량이 증가할 수 있습니다. 이를 효율적으로 관리하기 위해서는 메모리 튜닝이 필수적입니다. 이번 글에서는 Prometheus의 메모리 사용을 최적화하는 방법에 대해 다루겠습니다.

Prometheus 메모리 사용

Prometheus 메모리 사용율이 높은 경우, 아래와 같은 사유가 있을 수 있습니다.

  • 타임 시리즈 수 (Time Series): 활성 타임 시리즈의 수는 메모리 사용량에 직접적인 영향을 줍니다.
  • scrape 주기 (Scrape Interval): 데이터를 수집하는 빈도가 높을수록 메모리에 저장되는 샘플 데이터의 양이 증가합니다.

메모리 사용을 낮추는 방법

--storage.tsdb.retention.time 설정

Prometheus는 storage.tsdb.retention.time 설정으로 기간동안 데이터를 보관합니다. 보관되는 기간을 짧게 설정하면 메모리 사용량을 줄일 수 있습니다. 기본 값은 15일입니다.

--query.max-concurrency 설정

Prometheus에서 데이터 조회시 동시에 처리되는 쿼리의 수를 설정할 수 있습니다. 동시에 처리되는 쿼리 수를 낮게 지정하면 메모리 사용량을 줄일 수 있습니다. 기본 값은 20입니다.

Scrape 주기 설정

Scrape 주기(데이터 수집 주기)가 짧으면 더 많은 메트릭이 자주 수집되어 메모리 사용량이 증가합니다. 각 job에 대해 Scrape 주기를 조정함으로써 메모리 사용을 줄일 수 있습니다.

scrape_configs:
  - job_name: 'example'
    scrape_interval: 60s

불필요한 메트릭 제거

Prometheus와 함께 제공되는 promtool 명령어를 사용합니다. promtool tsdb analyze 사용하여 분석하고, 분석한 결과에서 Highest cardinality labels 목록에서 사용하지 않은 label을 삭제하고, 불필요한 메트릭 및 label을 제거하면 메모리 사용율을 낮출 수 있습니다.

# promtool tsdb analyze [data path]
$ promtool tsdb analyze /data

Duration: 2h0m0s
Series: 5547383
Label names: 248
Postings (unique label pairs): 159621
Postings entries (total label pairs): 44259261

Label pairs most involved in churning:
235023 kubernetes_io_os=linux
235023 beta_kubernetes_io_os=linux
235023 kubernetes_io_arch=amd64
235023 beta_kubernetes_io_arch=amd64
171437 app_kubernetes_io_managed_by=Helm
157630 app_kubernetes_io_component=metrics

Label names most involved in churning:
244783 instance
244783 job
244783 __name__
235023 beta_kubernetes_io_os
235023 kubernetes_io_arch
235023 beta_kubernetes_io_arch
235023 kubernetes_io_os
235023 kubernetes_io_hostname
233527 namespace

Most common label pairs:
2851712 beta_kubernetes_io_os=linux
2851712 kubernetes_io_arch=amd64
2851712 beta_kubernetes_io_arch=amd64
2851712 kubernetes_io_os=linux
2085329 app_kubernetes_io_managed_by=Helm

Label names with highest cumulative label value length:
928176 lease
872902 id
855778 container_id
639203 uid
599520 mountpoint
148595 pod
120729 __name__
77262 owner_name
65469 created_by_name
28118 address
27212 interface
25276 secret
24380 image_id
23028 replicaset
17923 instance
14984 device
14900 image
14014 ip
13599 pod_ip
12806 image_spec
9337 kubernetes_io_hostname

# lease, id, uid lables를 제거합니다.
Highest cardinality labels:
31204 lease
21321 id
15463 uid
11114 container_id
5329 mountpoint
4746 pod
3028 __name__
3009 owner_name
2689 created_by_name
1948 interface
1654 address
1091 device
1049 ip
1016 pod_ip
889 secret
878 replicaset
644 instance
418 resource
333 cluster_ip
302 type
263 le
252 configmap
205 endpoint

Highest cardinality metric names:
93302 apiserver_request_duration_seconds_bucket
63602 apiserver_request_slo_duration_seconds_bucket
46852 coredns_dns_request_duration_seconds_bucket
45120 kubelet_runtime_operations_duration_seconds_bucket
38290 storage_operation_duration_seconds_bucket
34305 container_tasks_state
32670 coredns_dns_request_size_bytes_bucket
32670 coredns_dns_response_size_bytes_bucket
27444 container_memory_failures_total
22710 kube_pod_status_phase
22710 kube_pod_status_reason
21577 container_blkio_device_usage_total
20556 kubelet_http_requests_duration_seconds_bucket
20224 apiserver_response_sizes_bucket

불필요한 메트릭 및 lables 제거

analyze 결과에서 Highest cardinality labels top 3개(lease, id, uid)과 불필요한 메트릭을 제거하는 예제입니다.

scrape_configs:
  - job_name: 'kubernetes-service-endpoints'
    honor_labels: true

    kubernetes_sd_configs:
      - role: endpoints

    relabel_configs:
      - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
        action: keep
        regex: true
      - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape_slow]
        action: drop
        regex: true
      - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
        action: replace
        target_label: __scheme__
        regex: (https?)
      - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
        action: replace
        target_label: __metrics_path__
        regex: (.+)
      - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
        action: replace
        target_label: __address__
        regex: (.+?)(?::\d+)?;(\d+)
        replacement: $1:$2
      - action: labelmap
        regex: __meta_kubernetes_service_annotation_prometheus_io_param_(.+)
        replacement: __param_$1
      - action: labelmap
        regex: __meta_kubernetes_service_label_(.+)
      - source_labels: [__meta_kubernetes_namespace]
        action: replace
        target_label: namespace
      - source_labels: [__meta_kubernetes_service_name]
        action: replace
        target_label: service
      - source_labels: [__meta_kubernetes_pod_node_name]
        action: replace
        target_label: node

    metric_relabel_configs:
      # Highest cardinality labels top 3개(lease, id, uid) 제거
      - regex: 'lease|id|uid'
        action: labeldrop
      # 불필요한 메트릭 제거
      - source_labels: [__name__]
        regex: 'apiserver_request_duration_seconds_bucket|apiserver_request_slo_duration_seconds_bucket'
        action: drop

결론

  • Prometheus는 기본적으로 고가용성(High Availability)을 지원하지 않기 때문에, 데이터 보관 기간(storage.tsdb.retention.time)을 짧게 설정하는 것이 좋습니다. 장기간 데이터를 보관해야 하는 경우에는 Grafana Mimir, Thanos, cortex 같은 오픈소스를 설치하여 운영하는 것을 권장합니다.
  • 불필요한 메트릭 및 label을 제거하는 것을 권장합니다. 사용하지 않는 메트릭 또는 label을 제거하면 메모리 사용율을 50%이상 낮출 수 있습니다.