DogStatsD 란


DogStatsD = Datadog Agent 안의 metric aggregation 서버. application 이 보낸 metric 을 받아 10초 단위로 집계 → Datadog 백엔드로 flush.

  • 기본 listen = 127.0.0.1:8125 UDP
  • StatsD 프로토콜의 Datadog 확장 (tag 지원, histogram 추가 등)
  • Agent 가 같은 호스트에 떠 있을 때 = UDP (또는 UDS), 다른 호스트 = TCP·HTTP API 별도

동작 — UDP packet 흐름


application code:

statsd.Incr("api.requests", []string{"endpoint:users"}, 1)

내부적으로 StatsD wire format 텍스트로 변환:

api.requests:1|c|#endpoint:users

이 텍스트가 UDP packet payload 로 127.0.0.1:8125 에 전송. DogStatsD 가 받아서 in-memory 카운터·게이지에 누적, 10초 마다 flush.

특징

  • UDP fire-and-forget — application 은 sendto() 호출 후 곧장 리턴. 도달 여부 모름.
  • 한 packet 안에 여러 metric 묶을 수 있음 (\n 구분).
  • TCP 가 아니라 latency 거의 없음 — application 핫 패스에 metric 호출 박아도 안전.

메트릭 손실 메커니즘


UDP 의 본질

  • 신뢰성 없음. packet drop 시 sender 통보 없고 재전송도 없음.

손실 시나리오

  1. application 이 burst 로 많은 metric 전송 (request spike·batch job·캠페인 등).
  2. DD Agent 가 일시적으로 다른 작업(flush·aggregation·tag 평가) 으로 receive 못 따라감.
  3. 커널의 UDP receive buffer 가 채워짐.
  4. buffer 가득 차면 커널이 새 UDP packet 을 silent drop — sender 통보 없음, log 도 sender 쪽엔 안 남음.
  5. application 은 보냈다고 믿지만 실제 metric 누락. 대시보드에서 spike 가 누락된 채로 보임.

silent 라는 게 핵심 — 알아채기 어려움. 보통 “왜 메트릭이 띄엄띄엄 나오지?” 하다가 발견.

해결 — receive buffer 튜닝


DD Agent 가 자기 UDP 소켓에 더 큰 buffer 를 설정해 burst·일시 지연 흡수.

두 단 설정 (둘 다 해야 효과)

  • OS 레벨 = sysctl net.core.rmem_max=$VAL 로 상한 풀기. 이게 없으면 application 이 SO_RCVBUF 요청해도 OS 가 cap.
  • Agent 레벨 = datadog.yamldogstatsd_so_rcvbuf: $VAL — DD Agent 가 setsockopt(SO_RCVBUF, ...) 호출할 값.

권장값 = 환경마다 다르나 수십 MB. EKS Worker AMI 사례 = 25 MB (26214400).

UDP 가 TCP 와 다른 점

  • TCP = net.ipv4.tcp_rmem 으로 auto-tuning. application 이 SO_RCVBUF 안 호출해도 부하 따라 자동 조정.
  • UDP = auto-tuning 없음. application 이 setsockopt 으로 명시 설정해야 큰 buffer 사용.
  • 그래서 DogStatsD 같은 UDP receiver 는 OS·app 양쪽 모두 명시적 튜닝 필요.

net.core.rmem_max 는 모든 종류 소켓 (TCP·UDP·raw) 의 우산. 자세히 = 07. Linux Networking > rmem_max·tcp_rmem — TCP buffer 튜닝.

UDS (Unix Domain Socket) 대안


UDP 의 한계를 근본적으로 회피하는 방법 = UDS 로 전환. 같은 호스트 안에선 UDP 보다 우수.

설정 = datadog.yaml:

dogstatsd_socket: /var/run/datadog/dsd.socket

application 도 socket path 로 보내도록 변경 (Datadog client library 가 지원).

UDS 의 장점

  • 같은 호스트 내부 = 네트워크 스택 안 거치고 커널 IPC 로 직통 → 오버헤드 매우 작음
  • 신뢰성 모드 가능 = SOCK_DGRAM 으로 쓰면 UDP 비슷하지만 커널 queue 가 더 깊고, SOCK_STREAM 이면 손실 X
  • 메트릭 손실 거의 X (kernel queue 가 buffer 부족 시 sender 에 backpressure)
  • 권한 모델 = 파일 권한 (chmod) 으로 접근 제어

쓰임

  • DD Agent 가 DaemonSet 이고 같은 노드의 pod 들이 받음 → UDS 가 자연스러움
  • pod 가 /var/run/datadog/dsd.socket 를 hostPath volume 으로 마운트해서 사용

→ 사실 가장 깨끗한 해결. UDP buffer 튜닝은 차선책.

EKS DaemonSet 컨텍스트


EKS Worker 노드에 DD Agent 가 보통 DaemonSet 으로 떠 있다. 그 노드의 모든 pod 가 그 Agent 에 metric 보냄.

  • 노드 1 대 = 수십~수백 pod. 각 pod 의 application 이 metric 다수 전송.
  • DD Agent 의 UDP listener 1 개 = 노드 단위 throughput 의 모든 부하 흡수
  • 클러스터 단위 부하가 노드 단위로 집중되는 구조

→ 단일 인스턴스의 receive buffer 가 충분히 커야. OS·Agent 양쪽 튜닝 필요한 이유.

운영 사례 = 09. AL2023 EKS Worker AMI Migration > OS 튜닝 (sysctl·limits) — AMI 빌드 시 net.core.rmem_max=26214400 박은 배경.

진단 명령


# UDP socket 별 drop 카운터
cat /proc/net/udp
# Sl   local_address  rem_address  ...  drops
# 0:   0100007F:1F90  00000000:0000 ...  0       ← 8125 (0x1F90) drops 컬럼 봄
 
# 시스템 전체 UDP 통계
netstat -s | grep -iE 'udp|errors'
# Udp:
#     RcvbufErrors: ...   ← receive buffer 부족으로 drop 된 packet 수
#     packet receive errors: ...
 
# 특정 UDP 소켓의 buffer 상태
ss -munp | grep 8125
# UNCONN 0  0  127.0.0.1:8125  *:*  users:(("agent",pid=..., fd=N))
#   skmem:(r... rb...)  ← rb = receive buffer 크기
 
# DD Agent 자체 메트릭
# Agent 가 dogstatsd 의 drop·queue depth 통계를 자기 메트릭으로 노출
# Datadog UI 에서 datadog.dogstatsd.* 메트릭 확인

RcvbufErrors 가 증가하는 중이면 buffer 부족 신호 = rmem_max 또는 dogstatsd_so_rcvbuf 키울 시점.

References