기술

외부 시스템이 흘려보낸 로그를 어떻게 받을까?

2026.05.2012분 읽기

신호 수집 인프라를 어떻게 설계할까

AI 운영 플랫폼에서 외부 시스템이 흘려보낸 로그를 받는 인프라가 필요했습니다. 외부 에이전트가 작업 결과·이벤트·메트릭을 떨궈주면, 플랫폼이 그걸 받아서 적재하고 검색 가능하게 만드는 구조입니다.

처음에는 Push 모델(외부 에이전트가 API 호출)이 자연스러워 보였습니다. 외부 시스템이 새 로그 발생 시 즉시 API를 호출하면, 플랫폼은 받는 쪽에서 단순히 적재만 하면 됩니다. 데이터 흐름이 명확하고 실시간성도 보장됩니다.

그런데 검토할수록 다른 그림이 보였습니다. Pull 모델(플랫폼이 폴더를 주기적으로 스캔)이 종종 더 단순합니다. 외부 시스템 구성 부담은 줄어들고, 플랫폼 측에서 timing과 페이로드를 통제할 수 있기 때문입니다.

이번 글은 그 결정 과정과 구현 디테일을 정리한 회고입니다.


3가지 신호 수집 모델 비교

신호 수집 인프라의 모델은 보통 세 가지입니다.

모델

흐름

장점

단점

Push

외부 → API 호출 → 플랫폼 적재

실시간성 보장

외부 구성 부담, 인증·재시도 비용

Pull

외부 → 파일 떨굼 → 플랫폼 스캔 → 적재

외부 측 단순함, 플랫폼 통제

실시간성 손실

Hybrid

Push + 폴백 cron

양쪽 장점

복잡, 작은 시스템에 과다

각 모델의 본질을 정리하면 이렇습니다.

Push 모델

외부 시스템이 우리 API를 호출합니다. 외부 시스템에 인증 정보를 심어야 하고, 우리 API 스펙을 외부 시스템이 따라야 합니다. 실패 시 재시도 로직도 외부 시스템에 들어가야 합니다.

외부 시스템 입장에서 부담이 큽니다. 새 시스템이 추가될 때마다 같은 구성을 반복해야 하고, 우리 API가 바뀌면 외부 시스템도 같이 업데이트가 필요합니다.

Pull 모델

외부 시스템은 약속된 폴더에 파일만 떨굽니다. 인증도 없고, API 스펙도 모릅니다. 그저 파일 쓰기만 알면 됩니다.

플랫폼은 cron으로 주기적으로 폴더를 스캔합니다. 새 파일이 있으면 적재, 없으면 패스. 외부 시스템과 플랫폼이 파일 시스템이라는 단순한 인터페이스로만 연결됩니다.

Hybrid 모델

둘 다 깔아둡니다. Push가 정상 동작하면 그걸 쓰고, 실패하면 cron 폴백이 잡습니다. 안전하지만 운영 복잡도가 두 배입니다. 작은 시스템에는 과다한 설계입니다.

선택은 Pull 모델이었습니다. 이유는 세 가지였습니다.

첫째, 외부 시스템 구성 부담을 최소화하고 싶었습니다. 새 시스템이 추가될 때마다 인증·재시도 로직을 만들지 않아도 되는 게 큰 이득이었습니다.

둘째, 플랫폼 측에서 timing을 통제하고 싶었습니다. 외부 시스템이 일제히 API를 호출하면 우리 측 부하가 폭발할 수 있는데, Pull 모델은 우리가 스캔 주기를 정합니다.

셋째, 실시간성이 핵심이 아니었습니다. 로그 수집은 분 단위 지연이 허용되는 작업이에요. 초 단위 즉시 처리가 필요하면 다른 결정이 됐을 것입니다.

1.jpeg


watch_paths + APScheduler — 구현 흐름

Pull 모델을 어떻게 구현했는지 정리해보겠습니다.

스키마 추가

로그 시스템 테이블에 두 컬럼을 추가했습니다.

watch_paths (JSON, 절대경로 배열) — 어느 폴더를 스캔할지

scan_cron (VARCHAR(64)) — 시스템별 cron 표현식

로그 적재 테이블에는 file_mtime 컬럼을 추가했습니다. 변경 감지를 size+mtime 기반으로 하기 위함입니다. 이 결정은 뒤에서 더 자세히 다루겠습니다.

스케줄러 — APScheduler

APScheduler(BackgroundScheduler, Asia/Seoul 타임존)를 사용했습니다. 시스템별로 cron job을 등록하는 방식입니다.

시스템 A: 0 */5 * * * (5분마다)
시스템 B: 0 0 * * * (매시 정각)
시스템 C: */10 * * * * (10분마다)

각 시스템이 자기 스캔 주기를 갖습니다. 한 글로벌 cron으로 모든 시스템을 처리하지 않은 이유는 운영 유연성이었습니다. 어떤 시스템은 자주 스캔이 필요하고, 어떤 시스템은 하루 한 번이면 충분합니다.

시스템 정보가 변경되면(예: 운영자가 UI에서 cron 주기 수정), reload(db)로 스케줄러가 즉시 새 설정을 반영합니다. 재시작 없이 운영 중 변경이 가능합니다.

스캔 로직 — scan_watched_paths()

스캔 함수는 다음 단계로 동작합니다.

1. 시스템별 watch_paths 목록 조회
2. 각 경로의 파일 목록 가져오기
3. in-memory 인덱스로 dedup (같은 파일 중복 처리 방지)
4. size+mtime 비교로 신규/변경 판단
5. 신규/변경 파일만 절대경로로 적재
6. 콘솔 진행 로그 출력 (시스템별·파일별 new·changed·ERROR)

콘솔 진행 로그가 중요합니다. cron이 백그라운드에서 도는 작업이라 사용자가 직접 보기 어렵습니다. 어떤 파일이 적재됐는지, 어떤 게 실패했는지가 로그로 남아야 디버깅이 가능합니다.


size+mtime이면 hash 없이 멱등성 보장

변경 감지를 어떻게 할지가 한 가지 고민거리였습니다. 같은 파일이 두 번 적재되면 데이터가 중복됩니다. 멱등성을 어떻게 보장할까요.

선택지

방식

정확도

비용

size+mtime

높음 (실무에서 충분)

매우 낮음

hash (MD5/SHA-256)

매우 높음

큰 파일에서 비쌈

선택은 size+mtime이었습니다.

왜 hash가 아닌가

hash는 파일 전체를 읽어서 계산합니다. 1MB 파일이면 별것 아니지만, 100MB 파일을 매 스캔마다 hash 계산하면 부하가 큽니다. 수백 개 파일이 폴더에 있으면 스캔 자체가 무거워집니다.

size+mtime은 파일 메타데이터만 봅니다. OS가 이미 캐시하고 있는 정보라 거의 비용이 없습니다.

size+mtime의 정확도

이론적으로 size와 mtime이 같은데 내용이 다른 파일이 존재할 수 있습니다. 그런데 실무에서 이런 경우는 거의 없습니다. 외부 시스템이 파일을 수정하면 mtime이 바뀌고, 내용이 바뀌면 보통 size도 바뀝니다. 일부러 동일 size로 변조하지 않는 한 충돌 가능성은 무시할 수 있는 수준입니다.

신호 수집 인프라에서 size+mtime이면 충분했습니다.


Take-over 패턴 — 같은 콘텐츠가 다른 경로로 들어왔을 때

추가로 고려한 패턴이 있습니다. 같은 콘텐츠가 다른 경로로 들어오는 경우를 어떻게 처리할까요.

예를 들면 이런 상황입니다.

1. 외부 시스템 A가 /path/old/log.json에 파일을 떨굼 → 플랫폼이 적재
2. 외부 시스템 A가 폴더 구조를 변경 → /path/new/log.json으로 같은 파일이 다시 들어옴
3. 플랫폼은 신규 경로로 인식해서 다시 적재 → 중복 발생

이를 막기 위해 _ingest_full_path() 함수에 file_hash 기반 take-over 로직을 추가했습니다.

새 파일이 들어오면 hash 계산

같은 hash를 가진 기존 row가 있는지 확인

있으면 그 row의 경로를 새 경로로 업데이트 (흡수)

없으면 신규 row 생성

여기서 흥미로운 점은 변경 감지는 size+mtime, take-over는 hash라는 점입니다. 두 작업의 비용 특성이 달라서 다른 방식을 썼습니다.

변경 감지: 매 스캔마다 모든 파일에 대해 수행 → 가벼워야 함 → size+mtime

take-over: 새 파일이 들어올 때만 수행 → 1회성이라 hash 비용 감수 가능

2.jpeg


수동 트리거 버튼이 운영 신뢰도를 보강합니다

cron 자동 스캔만으로는 부족했습니다. 운영 화면에 [지금 스캔] 버튼을 추가했습니다.

이유는 단순합니다. 자동 외에 즉시 실행 동선이 운영 신뢰도를 만듭니다.

"방금 외부 시스템에서 파일 떨어졌는데 안 보여요" → [지금 스캔] 누르면 즉시 확인

"cron이 정상 동작하는지 확인하고 싶어요" → [지금 스캔] 누르고 결과 확인

"신규 시스템 등록 후 첫 스캔 보고 싶어요" → 다음 cron 기다리지 않고 즉시 실행

자동만 깔아두면 운영자는 "정상 동작 중이겠지" 하고 믿을 수밖에 없습니다. 수동 트리거가 있으면 운영자가 직접 확인할 수 있고, 자동에 대한 의심이 줄어듭니다.

UI 구성:

시스템 모달에 watch_paths 텍스트영역 + scan_cron 패널 + [지금 스캔] 버튼

시스템 목록에 자동 스캔 컬럼 + 행별 [지금 스캔] 버튼

결과 모달: 신규/변경/실패 파일 전체 나열 + 복사 가능, 스캔 중 로딩 표시

수동 트리거 엔드포인트는 /api/ops/ingestions/scan으로 분리했습니다. 자동 스케줄러와 같은 함수를 호출하지만, API 경로는 별도입니다.


신호 수집 인프라 검토 체크리스트

신호 수집 인프라를 설계하거나 솔루션을 도입하실 때 점검할 일반 체크리스트입니다.

1. 실시간성이 정말 핵심인지 확인합니다

"실시간이면 좋다"는 막연한 느낌이 아니라, "분 단위 지연이 비즈니스에 어떤 영향을 주는가"로 구체화합니다. 분 단위 허용이면 Pull 모델이 충분합니다. 초 단위 즉시 처리가 필수면 Push 모델이 맞습니다.

2. 외부 시스템 구성 부담을 측정합니다

외부 시스템이 몇 개인지, 각각이 어떤 환경인지, 우리 API에 인증·재시도 로직을 심는 게 가능한지 확인합니다. 외부 측 부담이 크면 Pull 모델이 안전합니다.

3. 변경 감지 비용을 봅니다

파일이 작고 적으면 hash 계산이 비용 문제가 안 됩니다. 파일이 크거나 많으면 size+mtime 비교가 훨씬 효율적입니다. 정확도와 비용의 균형을 봅니다.

4. 수동 트리거 동선을 만듭니다

자동만 깔면 운영자가 의심하고 직접 확인할 방법이 없습니다. [지금 스캔] 같은 버튼이 운영 신뢰도를 만듭니다. 자동과 수동을 같이 깔아두는 게 인프라의 기본기입니다.

비슷한 발상이 다른 인프라 결정에서도 흐릅니다. 자연스러워 보이는 첫 선택지를 의심하는 것, 비용 특성에 따라 다른 메커니즘을 조합하는 것, 자동과 수동을 같이 까는 것. 인프라 설계의 핵심 기준입니다.


마무리

외부 시스템이 흘려보낸 로그를 받는 인프라를 Pull 모델로 구축했습니다. watch_paths에 외부 에이전트가 파일을 떨구면, APScheduler 기반 cron이 시스템별 주기로 깨어나 스캔합니다. 변경 감지는 size+mtime으로, take-over는 hash로 분리해서 비용 특성에 맞춘 메커니즘을 조합했습니다.

핵심 교훈은 세 가지입니다.

Pull 모델이 종종 더 단순하다 — Push가 자연스러워 보여도 외부 구성 부담을 보면 Pull이 답일 때가 많음

변경 감지와 take-over는 비용 특성이 다르다 — 매번 수행하는 변경 감지는 가볍게, 1회성 take-over는 정확하게

수동 트리거 버튼이 운영 신뢰도를 만든다 — 자동만 깔면 운영자가 의심할 방법이 없음

신호 수집 인프라·로그 적재·외부 시스템 연동을 검토하신다면, 이번 글의 4가지 체크리스트(실시간성 필요성 / 외부 구성 부담 / 변경 감지 비용 / 수동 트리거 동선)를 한 번 살펴보시길 추천합니다. 자연스러워 보이는 첫 선택지를 의심하면 더 단순한 답이 보일 때가 많았습니다.

#로그수집#Pull모델#APScheduler#cron#멱등성#신호수집#AI전환기