본문 바로가기
회사

1. 레전드 이슈 발생

by 진득한진드기 2026. 4. 28.

압축파일 손상 관련 해결 해보자~~


1. 배경

TPS 1,000 이상 나올시 해당 데이터들을 압축하고 전송하는 쓰레드에서 문제가 생김.


2. 첫 증상

2-1. 상황

  • 조건: TPS 500 × 60s (트래픽 body size = 4.3kb)
  • Loader 결과: 29,761 요청 전송, 100% 성공

2-2. 관측

  • 클라이언트(loader) 정상, 서버상태는 극히 정상
  • 손상은 agent 단일 파일. 같은 run 의 다른 파일은 정상
  • gzip 자체는 decompress 가 일부 가능 — 앞부분은 valid gzip stream, 뒷부분이 이상한 상태 ->? 뭐임 압축파일 자체의 문제

2-3. 이 시점에 세운 가설 (나중에 틀렸음을 확인)

"파일이 특정 크기를 넘으면 뭔가 터진다"

이 가설에 기반해 duration 을 60s → 30s → 20s 로 축소 + profile 별 U 가중치 조정 으로 우회 가능한 것처럼 보였고, 일정 기간 "우회 성공" 판정으로 Phase B 실험을 진행했다.

 

3  테스트 후 결론

트래픽 자체를 저장하는 부분에서 문제가 생긴다. 즉 

  • hcap 손상 버그는 여전히 존재
  • 재현 프로토콜을 고쳐야 정확한 현상 관측 가능

4. 재현 프로토콜 재설계 — robust_v2

4-1. 문제 정의

트래픽 자체가 모이고 그거를 잘 확인하고 있는지 부터가 문제

 

4-2. 재검증 매트릭스

robust_v2 프로토콜로 재실행한 결과:

medium_r1 small 1000 30s ✅ 정상 0%
xlarge_v2r1 xlarge 1000 120s ❌ 2 파일 손상 94%
medium_v2r1 medium 1000 120s ❌ 2 파일 손상 94%
small_v2r1 small 1000 120s ❌ 2 파일 손상 90%
small_tps300 small 300 120s ❌ 손상
 

이 매트릭스가 보여주는 것:

  • body profile 독립적 — small(95KB) 에서도 재현
  • TPS 독립적 — TPS 300 에서도 재현
  • duration 독립적이 아님 — 짧으면(30s) 파일이 특정 크기에 못 미쳐서 우연히 안 깨지는 것뿐

즉 "body/TPS/duration 특정 조합" 이 아니라 "한 minute 누적 파일이 ~19 MB 에 도달" 이라는 단일 조건 이 트리거. 이전의 인과 모델은 틀렸고 새 인과 모델은 단순.


5. Clean binary 검증 — 배포/빌드 문제 기각

5-1. 의심

테스트 중인 agent 가 진짜로 commit 964dafc 에서 빌드된 것인지 확신할 수 없는 상태. dirty flag 가 붙어있거나, 다른 branch 에서 나온 바이너리일 가능성도 있음.

5-2. 조치

5-3. 재테스트 결과

small × TPS 300 × 120s 로 재현 → 동일 증상. Clean binary (964dafc_clean) 에서도 파일이 정확히 같은 방식으로 손상됨.

5-4. 이 단계의 결론

  • 배포된 바이너리와 소스의 불일치 아님
  • dirty build 아님
  • 버그는 commit 964dafc 의 develop branch 에 실재

6. 포렌식 샘플 분석 — 3-region 패턴

이전 회사에서 간단히 했던 포렌식(hex 파일 분석)

6-1. 샘플 확보

재현에 성공한 손상 파일 3 개 + 대조군 1 개를 로컬에 보존:

 
sample1_xlarge_3pct_30s_dirty_agent.gz xlarge × 30s 20.9 MB 손상
sample2_small_3pct_tps300_120s_dirty_agent.gz small × TPS300 × 120s 17.9 MB 손상
sample3_small_3pct_tps300_120s_clean_agent.gz small × TPS300 × 120s × clean binary 18.5 MB 손상
reference-healthy/healthy_tail_from_same_run_as_sample3.gz sample3 와 같은 run 의 다음 minute 파일 8.05 MB 완전 정상
 

reference-healthy/ 는 분석의 핵심 대조군이다. 같은 설정으로 생성됐는데 한 파일은 깨지고 한 파일은 멀쩡. 이 비대칭이 "하드웨어/OS/라이브러리 통째 문제" 가설을 곧바로 기각한다.

6-2. 구조 분석 스크립트

각 파일의 바이트 레벨 구조 스캔. 표준 zlib.decompressobj 로 첫 gzip stream 을 디코드하고 unused_data 의 시작점을 찾아 Region 분할.

6-3. 3-region 패턴

모든 손상 파일이 정확히 동일한 3-region 구조:

상태

 
sample1 (xlarge 30s) 19.97 MB 7.25 MB 13.05 MB 7,314 B
sample2 (small 120s dirty) 17.97 MB 3.21 MB 14.90 MB 880 B
sample3 (small 120s clean) 18.46 MB 1.01 MB 17.50 MB 4,297 B
healthy tail (same run as sample3) 8.06 MB 8.45 MB 0 0
 

6-4. 결정적 관찰 네 가지

  1. Region A 의 trailer 가 정상 — CRC32 와 ISIZE 가 맞음. 즉 gzip.Close() 가 성공적으로 완료 된 적이 있다.
  2. Region B 가 sparse hole — 파일시스템 (XFS) 관점에서 blocks * 512 << size 상태. 이건 특정 syscall(lseek, ftruncate, fallocate, pwrite) 중 하나가 호출돼야만 생길 수 있는 파일 형태.
  3. Region C 가 완전한 deflate fragment — gzip magic byte 없이 compressed data block 만 존재. 즉 "gzip writer 가 새로 열린 건 아니고, 어떤 컨텍스트에서 raw deflate 데이터가 일부 써진 것".
  4. 같은 run 에서 정상/손상 공존 — sample3 (minute N) 과 reference-healthy (minute N+1) 가 같은 agent 프로세스의 연속된 두 minute. 앞 minute 은 깨지고 뒤 minute 은 완전히 정상. 이건 전송 경계에서만 발동하는 code path 라는 강력한 증거.

6-5. 이 단계의 결론

  • 파일 포맷 레벨 손상이 확인됨 (capture 층 문제 아님)
  • 3-region 패턴이 일관됨 → 동일 원인
  • sparse hole 은 특정 syscall 이 호출돼야만 생김 → 어떤 syscall 이, 언제 호출됐는지 추적 필요
  • 일반 로그만으로는 syscall 레벨 원인을 잡을 수 없음 → 시스템콜 레벨 트레이싱 이 필수

7. 포렌식 단계에서 기각된 가설들 (중복 재현 방지용)

아래는 이 과정에서 한 번씩 의심해본 뒤 사실 확인으로 기각된 가설 목록. 이후 단계에서 다시 파지 않기 위해 정리.

기각 근거

 
1 "Loader 타이밍 문제" robust_v2 프로토콜 (capture 활성화 확증) 로도 재현
2 "Dirty build / 배포 이슈" 964dafc_clean 로컬 cross-compile 바이너리로도 재현
3 "Body 크기 때문" small profile (95 KB) 로도 재현
4 "고 TPS 때문" TPS 300 로도 재현
5 "test 서버 saveStore 블록" v2 서버 (throttled async) 이식 완료됨. 서버 측 병목 없음
6 "AF_PACKET 패킷 드롭" 파일 포맷 레벨 손상이므로 capture 층 아님. 드롭이라면 gzip format 은 valid 가 유지되어야 함
7 "Size-based rotation (128 MB) 오발동" 손상 파일 크기는 17~20 MB, 128 MB 임계 훨씬 아래
8 "하드웨어 / OS / 파일시스템 / 라이브러리 통째 문제" 같은 run 의 다음 minute 파일은 완전 정상 (reference-healthy)
 

8. 재현 가능성 확증

8-1. 재현율

  • robust_v2 프로토콜 적용 후 4 번 시도, 4 번 재현. 100%.
  • 재현 조건: hcap 파일이 한 minute 안에 ~19 MB 에 도달할 만큼의 트래픽.
  • 최소 재현 스펙: small profile × TPS 300 × 120s (낮은 부하에서도 120 초면 파일 깨짐)

8-2. 재현 비용

  • 테스트 1 회 ≈ 5 분 (trigger 30s + capture pickup 30s + loader 120s + buffer 150s)
  • 분석 1 회 ≈ 10 분 (파일 가져오기 + test 실행)
  • 합계 15 분 → root cause 탐색 사이클이 빠름

9. 포렌식 단계 결론

이 시점까지 확정된 것:

  1. 버그 실재 — 테스트 프로토콜 버그 아님. 코드 레벨 버그 확정.
  2. 재현율 100% — robust_v2 프로토콜 + 최소 스펙 (small × TPS 300 × 120s) 로 확정.
  3. 배포/빌드 이슈 아님 — clean binary 에서도 동일 재현.
  4. 파일 포맷 레벨 손상 — 3-region 패턴 (valid gzip + sparse hole + deflate fragment).
  5. sparse hole 존재 — XFS 의 blocks * 512 << size. 특정 syscall 이 호출됐다는 직접 증거.
  6. Rotation 경계 발동 — 같은 run 의 다음 minute 파일이 완전 정상이라는 대조군 증거.

아직 답하지 못한 것:

  • sparse hole 을 만든 syscall 이 정확히 무엇인가?
  • 어떤 코드 경로에서 그 syscall 이 호출됐는가?
  • Rotation 경계에서만 발동하는 이유는?

이 세 질문에 답하려면 syscall 레벨 실시간 추적 이 필요할듯함.