Blog
prometheuspushgatewaymetricsbatchobservabilitypromql

Prometheus Pushgateway로 메트릭 송신하기 — 클라이언트와 순수 HTTP, 그리고 METHOD별 동작

짧게 살다 죽는 배치 잡의 메트릭을 Prometheus로 보내는 방법을 정리합니다. Pushgateway의 grouping key 개념, Python·Java 클라이언트 라이브러리 송신, 순수 HTTP(curl) 송신, 그리고 PUT/POST/DELETE에 따라 Pushgateway가 내부적으로 메트릭을 어떻게 처리하는지, honor_labels 설정과 staleness 운영 주의점까지 다룹니다.

Data Dynamics2026年6月12日15 min read
This post is not yet translated. The original Korean version is shown below.

새벽 2시에 돌고 3분 만에 끝나는 백업 잡이 있다고 상상해 봅시다. Prometheus 는 15초마다 타깃을 긁어 메트릭을 가져가는데, 3분짜리 잡이 살아 있는 짧은 순간에 scrape 타이밍이 맞을 리 없습니다. 이런 짧게 살다 사라지는 배치·크론 잡을 위한 중간 다리 역할을 하는 것이 바로 Pushgateway 입니다. 잡이 종료 직전에 메트릭을 Pushgateway 로 밀어 넣으면, Pushgateway 가 그 값을 보관하고, Prometheus 는 평소처럼 Pushgateway 를 pull 합니다.

이 글에서 배우는 것

  • Pushgateway 를 언제 쓰고, 언제 쓰면 안 되는가
  • 모든 송신의 단위가 되는 grouping key 개념
  • Prometheus 클라이언트 라이브러리(Python·Java)로 송신하는 방법
  • 순수 HTTP(curl) 로 송신하는 방법
  • PUT/POST/DELETE 에 따른 Pushgateway 내부 처리 차이
  • honor_labels 설정과 staleness 운영 주의점

1. Pushgateway는 언제 쓰는가 (그리고 언제 쓰면 안 되는가)

Pushgateway 의 정체를 먼저 이해해야 합니다. Pushgateway 는 메트릭 캐시입니다. 푸시된 값을 메모리에 보관했다가 /metrics 로 그대로 노출할 뿐, 합산·집계를 하지 않습니다. 같은 자리에 새 값이 오면 덮어쓸 뿐입니다.

쓰는 경우

  • 수명이 짧은 배치/크론/ETL 잡 — "마지막 성공 시각", "처리 레코드 수", "소요 시간" 등을 잡 종료 직전에 송신

쓰면 안 되는 경우 (안티패턴)

  • 일반 상시 서비스의 메트릭 — 이건 그냥 /metrics 를 열고 Prometheus 가 pull 하게 하세요(앞선 글 《Prometheus Exporter 개발하기》 참고)
  • 카운트를 "여러 인스턴스에서 보내 합치고 싶을" 때 — Pushgateway 는 합치지 않습니다. 마지막 푸시가 이전 값을 덮습니다
  • 고빈도·요청 단위 메트릭 — Pushgateway 가 병목·단일 장애점이 됩니다

한 줄 요약: "긁힐 만큼 오래 살지 못하는 잡" 에만 쓰세요.

2. 핵심 개념 — grouping key

Pushgateway 를 쓸 때 가장 먼저 이해해야 할 개념입니다. Pushgateway 의 모든 송신·삭제는 그룹 단위로 일어납니다. 그룹을 식별하는 것이 grouping key 이고, 이는 URL 경로로 표현됩니다.

/metrics/job/<JOB_NAME>{/<LABEL_NAME>/<LABEL_VALUE>}
  • job 은 필수이고, 그 뒤에 라벨/값 쌍을 원하는 만큼 붙입니다.
  • 경로에 담긴 job + 라벨들이 그대로 grouping key 이자, 푸시된 모든 메트릭에 붙는 라벨이 됩니다.

예를 들어 /metrics/job/backup/instance/host1 로 보내면, 그 그룹의 모든 메트릭에 job="backup", instance="host1" 라벨이 붙습니다. 이후 PUT/POST/DELETE 는 모두 이 grouping key 가 가리키는 그룹에 대해 동작합니다 — 이게 5장의 핵심 전제입니다.

라벨 값에 / 가 들어가야 하면 URL 경로에 그대로 못 넣습니다. base64 변형 인코딩(/<label>@base64/<value>)을 써야 하며, 클라이언트 라이브러리는 이를 자동 처리합니다.

3. 클라이언트 라이브러리로 송신

Python — prometheus-client

배치 잡이 끝나는 시점에 별도 CollectorRegistry 를 만들어 그 잡의 메트릭만 담아 보내는 것이 정석입니다. 전역 레지스트리를 쓰면 원하지 않는 메트릭까지 함께 보내지는 문제가 생깁니다.

pip install prometheus-client
from prometheus_client import CollectorRegistry, Gauge, Counter
from prometheus_client import push_to_gateway, pushadd_to_gateway, delete_from_gateway
 
GATEWAY = "localhost:9091"
 
def run_backup():
    registry = CollectorRegistry()              # 이 잡 전용 레지스트리
 
    last_success = Gauge(
        "backup_last_success_unixtime",
        "마지막 성공 시각", registry=registry,
    )
    processed = Counter(
        "backup_records_processed_total",
        "처리한 레코드 수", registry=registry,
    )
 
    # ... 실제 백업 작업 ...
    processed.inc(12345)
    last_success.set_to_current_time()
 
    # 그룹(job=backup, instance=host1) 전체를 이 값으로 교체 → PUT
    push_to_gateway(
        GATEWAY, job="backup",
        grouping_key={"instance": "host1"},
        registry=registry,
    )

세 가지 함수가 각각 다른 HTTP METHOD 로 매핑됩니다(5장에서 상술).

push_to_gateway(GATEWAY, job="backup", registry=registry)      # PUT  — 그룹 전체 교체
pushadd_to_gateway(GATEWAY, job="backup", registry=registry)   # POST — 같은 이름만 교체
delete_from_gateway(GATEWAY, job="backup")                     # DELETE — 그룹 삭제

인증이 필요한 Pushgateway 라면 handler 로 처리합니다.

from prometheus_client.exposition import basic_auth_handler
 
def auth_handler(url, method, timeout, headers, data):
    return basic_auth_handler(url, method, timeout, headers, data, "user", "secret")
 
push_to_gateway(GATEWAY, job="backup", registry=registry, handler=auth_handler)

Java — Micrometer / client_java (보너스)

Spring Boot 프로젝트라면 더 쉽습니다. PrometheusPushGatewayManager 가 주기적/종료 시 자동 송신을 처리합니다. 설정만으로 켜집니다.

management:
  prometheus:
    metrics:
      export:
        pushgateway:
          enabled: true
          base-url: http://localhost:9091
          job: my-batch-job
          push-rate: 1m
          shutdown-operation: push   # 종료 시 push (배치에 적합)

저수준으로 직접 보내려면 client_java 의 PushGateway 를 씁니다. 메서드 이름이 METHOD 매핑을 그대로 드러냅니다.

import io.prometheus.client.CollectorRegistry;
import io.prometheus.client.Gauge;
import io.prometheus.client.exporter.PushGateway;
 
CollectorRegistry registry = new CollectorRegistry();
Gauge duration = Gauge.build("backup_duration_seconds", "백업 소요 시간")
        .register(registry);
 
Gauge.Timer timer = duration.startTimer();
try {
    // ... 배치 작업 ...
} finally {
    timer.setDuration();
    PushGateway pg = new PushGateway("localhost:9091");
    pg.pushAdd(registry, "backup");   // POST  — 같은 이름만 교체
    // pg.push(registry, "backup");   // PUT   — 그룹 전체 교체
    // pg.delete("backup");           // DELETE — 그룹 삭제
}

4. 순수 HTTP로 송신 (curl)

클라이언트 라이브러리가 없는 환경이나 쉘 스크립트에서도 Pushgateway 로 바로 보낼 수 있습니다. 본문은 exposition format 텍스트면 되고, URL 에 grouping key 를 인코딩합니다. curl--data-binary 는 기본적으로 POST 로 전송됩니다.

# job=backup 그룹에 메트릭 하나 송신 (POST)
echo "backup_records_processed_total 12345" \
  | curl --data-binary @- http://localhost:9091/metrics/job/backup
 
# grouping key에 라벨 추가 (job=backup, instance=host1)
echo "backup_duration_seconds 42.3" \
  | curl --data-binary @- http://localhost:9091/metrics/job/backup/instance/host1

여러 메트릭은 줄바꿈으로 구분합니다. 한 가지 주의할 점은 본문이 반드시 개행으로 끝나야 한다는 것입니다. # TYPE 선언을 함께 보내면 타입이 보존됩니다.

printf '# TYPE backup_records_processed_total counter\nbackup_records_processed_total 12345\nbackup_duration_seconds 42.3\n' \
  | curl --data-binary @- http://localhost:9091/metrics/job/backup

METHOD 를 명시하면 동작이 달라집니다.

# PUT — 그룹 전체를 이 본문으로 교체
echo "backup_duration_seconds 42.3" \
  | curl -X PUT --data-binary @- http://localhost:9091/metrics/job/backup
 
# DELETE — 그룹 전체 삭제 (본문 불필요)
curl -X DELETE http://localhost:9091/metrics/job/backup

5. HTTP METHOD에 따른 내부 처리

같은 grouping key 로 보내도 어떤 HTTP METHOD 를 쓰느냐에 따라 결과가 완전히 달라집니다. Pushgateway 를 처음 쓸 때 가장 많이 헷갈리는 부분이니 꼭 이해하고 넘어가세요.

상황을 가정해 봅시다. job="backup" 그룹에 현재 메트릭 AB 가 저장돼 있고, 이번에 A(새 값)만 담아 보냅니다.

METHOD동작위 예시의 결과
POST본문에 있는 이름의 메트릭만 교체. 그룹 내 다른 이름은 보존A(새 값) + B 유지
PUT그룹 전체를 본문으로 교체. 본문에 없는 메트릭은 삭제A(새 값)만, B 삭제
DELETEgrouping key 의 그룹 전체 삭제그룹 비워짐(A·B 모두 삭제)

즉,

  • POST(=pushadd/pushAdd) — "이 메트릭들만 갱신해 줘." 같은 그룹에 다른 잡 단계가 따로 푸시하는 메트릭이 있을 때 안전합니다.
  • PUT(=push) — "이 그룹의 상태는 이게 전부야." 매 실행마다 그룹을 깨끗이 덮고 싶을 때.
  • DELETE(=delete) — 잡이 끝나 더는 노출하고 싶지 않을 때 정리용.

주의: PUT/POST 의 교체 단위는 메트릭 이름(metric family) 입니다. 같은 이름이면 라벨이 달라도 그 이름 전체가 한 번에 교체됩니다. 또한 어느 METHOD든 grouping key 가 다르면 서로 다른 그룹이라 영향을 주지 않습니다.

6. Pushgateway가 스스로 만드는 메트릭

Pushgateway 는 직접 만든 것 외에도 그룹마다 푸시 상태 메트릭을 자동으로 덧붙여 노출합니다. "배치가 제때 돌았는가"를 감시하는 데 매우 유용합니다.

  • push_time_seconds{job="backup",...} — 그 그룹에 마지막으로 성공한 푸시 시각
  • push_failure_time_seconds{...} — 마지막으로 실패한 푸시 시각

배치가 제때 푸시했는지(=신선도)를 이 값으로 감시할 수 있습니다.

# 1시간 넘게 새 푸시가 없으면 배치가 멈춘 것
time() - push_time_seconds{job="backup"} > 3600

7. Prometheus 설정 — honor_labels

Pushgateway 를 등록할 때 반드시 설정해야 할 옵션이 있습니다. 빠뜨리면 메트릭이 어느 잡에서 온 것인지 알 수 없게 됩니다.

scrape_configs:
  - job_name: "pushgateway"
    honor_labels: true                 # 푸시된 job/instance 라벨을 보존
    static_configs:
      - targets: ["localhost:9091"]

왜 필요할까요? Prometheus 는 보통 scrape 시 job/instance 라벨을 자기 설정값으로 덮어씌웁니다(앞 글에서 본 타깃 라벨). 그대로 두면 Pushgateway 로 들어온 job="backup" 이 전부 job="pushgateway" 로 바뀌어, 어느 잡에서 온 메트릭인지 사라집니다. honor_labels: true노출된 메트릭의 라벨을 우선하게 해서, 푸시할 때 지정한 job/instance 를 그대로 유지시킵니다.

8. 운영 주의점 — staleness와 정리

Pushgateway 를 쓰면서 빠지기 쉬운 함정이 있습니다. 바로 "절대 잊지 않는다" 는 점입니다.

  • 한 번 푸시된 값은 DELETE 하거나 Pushgateway 가 재시작될 때까지 영원히 /metrics 에 남습니다. 끝난 일회성 잡의 마지막 값이 계속 노출되어, 대시보드가 "오래된 값"을 현재처럼 보여줄 수 있습니다 → 잡 종료 시 DELETE 로 정리하거나, push_time_seconds 로 신선도를 함께 보세요.
  • Pushgateway 는 메트릭에 타임스탬프를 저장하지 않습니다. 노출 메트릭은 Prometheus 의 scrape 시각을 갖게 되므로, "언제 푸시됐는지"는 값이 아니라 push_time_seconds 로 판단합니다.
  • 모든 배치 메트릭이 한 곳을 거치므로 단일 장애점입니다. 다중화·재시작 시 데이터 유실(영속화 옵션 --persistence.file 미설정 시)을 고려하세요.
  • grouping key 가 무한정 늘어나지 않도록(예: 매 실행마다 고유 run_id 를 라벨로) 카디널리티를 통제하세요.

마무리

Pushgateway 는 "pull 로는 닿지 않는 짧은 잡"을 위한 임시 보관소입니다. 송신 자체는 단순합니다 — 클라이언트 라이브러리(push/pushadd/delete)든 순수 HTTP(PUT/POST/DELETE)든, 결국 grouping key 가 가리키는 그룹을 METHOD 규칙대로 갱신하는 일입니다. 진짜 중요한 건 사용 판단입니다: 상시 서비스엔 exporter 를, 합산이 필요하면 다른 설계를 쓰고, Pushgateway 는 배치 잡에만 쓰며 honor_labels 와 staleness 정리를 잊지 마세요.

다음 단계로는 push_time_seconds 기반 신선도 알림과, 배치 성공/소요 시간을 Grafana 패널로 묶어 "어젯밤 배치가 제대로 돌았는가"를 한눈에 보는 대시보드를 만들어 보길 권합니다.

마치며 — 핵심 요약

  • Pushgateway 는 짧게 살다 사라지는 배치·크론 잡의 메트릭을 위한 임시 보관소입니다. 상시 서비스에는 쓰지 마세요.
  • 모든 송신·삭제는 grouping key 단위로 일어납니다. URL 경로의 job + 추가 라벨이 grouping key 입니다.
  • PUT 은 그룹 전체 교체, POST 는 같은 이름만 교체, DELETE 는 그룹 전체 삭제입니다.
  • Prometheus scrape_configshonor_labels: true 를 반드시 붙이세요. 빠뜨리면 job 이 덮어씌워집니다.
  • Pushgateway 는 절대 잊지 않습니다. 잡이 끝나면 DELETE 로 정리하거나 push_time_seconds 로 신선도를 감시하세요.
  • --persistence.file 옵션으로 재시작 시 데이터 유실을 방지할 수 있습니다.