k8s 환경에서 프로세스등의 로그를 수집(collector pod) > json stdout(/var/log/pods/.../0.log) > filebeat > kafka cluster 로 흐름이 구축되어 있다.
그런데 자정(0시)에 가끔 collector CPU 90% 이 넘어가고 해소가 되지 않는다.
kafka(4.0.2) server.log 를 보면 다음과 같이 invalid timestamp 로 거부가 됐다.
kafka 디폴트로 메시지 1시간까지 허용하고 넘어가면 거부된다.
org.apache.kafka.common.errors.InvalidTimestampException: One or more records have been rejected due to invalid timestamp
collector 는 pidstat 커맨드로 수집을 하는데 pidstat 는 Time=HH:MM:SS 으로 날짜가 출력되지 않는다.
# -h : 한 줄 가로 출력, 평균 행 없음 (파싱용)
# -u : CPU
# -r : 메모리
# -d : 디스크 I/O
# -l : Command 에 전체 커맨드라인
# -I : CPU 사용률을 전체 코어 수로 나눔 (SMP 정규화)
# -T : TASK + CHILD 통계 모두
# -p : 대상 PID (discover 가 찾은 프로세스들)
pidstat -hurdl -I -T ALL -p <PIDs> <interval> <count>
# Time UID PID %usr %system %guest %wait %CPU CPU minflt/s majflt/s VSZ RSS %MEM kB_rd/s kB_wr/s kB_ccwr/s iodelay Command
05:04:08 0 630 0.00 0.00 0.00 0.00 0.00 9 0.00 0.00 2228 1024 0.01 0.00 0.00 0.00 0 sleep 300
이 Time을 collector 에서 파싱해서 @timestamp 필드값을 설정한다.
# 파싱 과정
# local_to_utc() python 로직
dt = datetime.strptime(local_timestamp, "%H:%M:%S")
return datetime.now().replace(hour=dt.hour, minute=dt.minute, second=dt.second).astimezone(tz=timezone.utc)
# timestamp 필드 설정
obj["@timestamp"] = local_to_utc(obj.pop("Time")).strftime("%Y-%m-%dT%H:%M:%SZ")
# 문제가 되는 상황 예시
pidstat 출력 23:59:59.6 (8/15) -> Time="23:59:59"
파서 처리 시점 00:00:00.2 (8/16) -> now().date = 8/16 -> timestamp = 2026-0816T23:59:59Z
실제 측정 시각 8/15 23:59:59 대비 +24h이 지난 상태의 timestamp 가 된다.
+24h 메시지는 kafka 에서 거부하는데, collector 는 계속 재시도를 해 cpu 리소스가 높게 유지 된 것이다.
# 해결 시도
# pidstat 와 1초 정도밖에 차이 안나서 이렇게 파싱시 now 를 timestamp 로 사용할 수 있겠지만
# pidstat 이 한 주기에 프로세스 n개를 측정하고 있어 원래는 n개의 라인이 전부 Time 이 같아야 한다. 매번 now 로 조금씩 달라지면 배치 동일성이 깨진다.
obj["@timestamp"] = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
# 해결 방법1
# +24(12시간 차이 정도로 하자)시간이 지난 경우 -1day 한다.
now = datetime.now()
ts = now.replace(hour=dt.hour, minute=dt.minute, second=dt.second, microsecond=0)
if ts - now > timedelta(hours=12):
ts -= timedelta(days=1)
logger.info(f"midnight rollover: Time={local_timestamp} -> {ts}")
return ts.astimezone(tz=timezone.utc)
# 해결 방법2
# pidstat 사용 안 하고 k8s 환경이면 이미 cAdvisor(ContainerAdvisor, kubelet 내장, 실행 중인 컨테이너들의 리소스 사용량과 성능 메트릭을 수집,처리,노출하는 도구)로 prometheus 에 메트릭이 있으니 이 값을 조회해서 사용한다.
# 메트릭들은 이미 같은 timestamp 로 저장되어 있다.
{"@timestamp": "2026-08-16T05:23:44Z", "%CPU": "0.88", "%usr": "35.59", "%system": "6.81",
"RSS": "571528", "container": "ysoftman1-container", "pod": "ysoftman1-aaa"}
{"@timestamp": "2026-08-16T05:23:44Z", "%CPU": "0.88", "%usr": "35.59", "%system": "6.81",
"RSS": "571528", "container": "ysoftman2-container", "pod": "ysoftman2-bbb"}
# 현재시각을 고정하고 이 값으로 prometheus 메트릭을 조회 하고 그대로 @timestamp 로 설정한다.
at = datetime.now(timezone.utc).timestamp()
ts = datetime.fromtimestamp(at, timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
# 어쩌다 발생해서 신경쓰였는데 원인 파악 돼서 개비스콘 짤로 남긴다.ㅎ