"[260831~0906] 재발한 원장 오염과 자동화 함정을 뿌리부터 추적한 한 주"
이틀 연속 재발한 원장 오염 사고의 뿌리를 결국 찾아냈고, 그 사이 장중 관측 파이프라인과 GPU 확장으로 새 실험 트랙도 열었습니다
며칠씩 조용히 진행되던 문제들이 한꺼번에 드러났다
이번 주는 시작부터 무거웠습니다.
같은 날 안에 서로 다른 장애가 두 건 겹쳤습니다. 순위를 산출하는 상주 프로세스 하나가 코드 수정 이후 재시작되지 않은 채 며칠째 구버전으로 돌고 있었고, 같은 날 낮에는 모의계좌 완전자동 검증 트랙(새 창)의 라운드 하나가 통째로 빠졌습니다.
원인을 파고드니 증권사 API가 체결단가 필드 하나를 실제 값의 1000분의 1로 축소해서 보내고 있었습니다. 이 값이 원장에 그대로 쌓이면서 손익 기준점이 왜곡됐고, 실행 안전장치(새 창) 중 하나인 킬스위치가 허위로 발동해버렸습니다.
원장 정정은 되돌릴 수 없는 작업이라 다른 AI에게 정정 순서와 검증값을 미리 받아뒀고, 정정 후 계산된 수치가 그 예측값과 소수점까지 일치하는 걸로 검증을 마쳤습니다. 재발 방지책은 절반만 처리된 채로 다음 날로 넘어갔습니다.
이틀 연속 재발한 원장 오염, 결국 뿌리를 찾다
주 중반에는 또 다른 계열의 원장 오염이 이틀 연속 나타났습니다.
먼저 모의투자 계좌에서 정체불명의 유령 거래 기록이 발견됐는데, 처음엔 정확한 원인을 못 찾고 넘어갔습니다. 다음 날 같은 증상이 또 나타나자 재발 시점을 거꾸로 추적해서 뿌리를 찾아냈습니다.
범인은 회귀 테스트였습니다. 주문 체결을 기록하는 내부 함수의 실제 처리 경로를 가짜로 바꿔치기하지 않은 채 열어둔 테스트가 있어서, 전체 테스트를 돌릴 때마다 실제 운영 데이터베이스에 가짜 거래가 섞여 들어가고 있었습니다.
오염된 기록을 백업하고 정확히 골라 지운 뒤 실제 보유 내역과 맞췄습니다. 그런데 다음 날 같은 계열이지만 다른 함수를 대상으로 한 테스트에서 똑같은 문제가 또 나타났습니다.
이번엔 함수를 격리하도록 고치는 데서 그치지 않고, 그 데이터베이스 파일 자체를 테스트 격리 대상 목록에 정식으로 등록해 뒀습니다. 등록만 돼 있었어도 이틀 다 바로 잡혔을 문제였다는 게 이번 조사의 결론이었습니다.
우회로 막았던 문제를 근본원인까지 추적
같은 주 중반, 밤새 열 시간 동안 한 번도 못 끝난 배치 장애도 있었습니다.
모델을 고르는 함수 안의 코드 한 줄이 실수로 조건문 안에 들어가면서, 그 경로를 안 타는 프로덕션 배치가 밤새 백 번 가까이 재시도하다 매번 같은 자리에서 죽었습니다. 자체 경보 장치가 없어서 아침에 사람이 직접 확인하고서야 발견됐습니다.
복구 과정에서 수동으로 거래 라운드를 트리거하면 전부 무발주로 실패하는 문제도 튀어나왔습니다. 그날은 더 낮은 단계에서 직접 실행하는 우회 경로로 급한 불만 끄고 정식 수선은 미뤄뒀습니다.
다음 날 원인을 제대로 들여다보니, 실행 유닛 파일 안에 "이건 정기 자동 라운드다"라는 표식이 고정값으로 박혀 있어서 사람이 수동 실행해도 시스템이 무조건 정기 라운드로 착각하는 구조였습니다. AI 자문을 받아 systemd가 타이머 실행 시에만 주입하는 환경변수를 판별 근거로 쓰는 방식으로 근본 수정했습니다.
같은 날 실전 계좌에서도 비슷한 계열의 사고가 있었습니다. 잠깐 꺼뒀던 자동거래 타이머 하나가 사람이 모르던 별도의 자동 재기동 장치 때문에 조용히 다시 켜지면서, 이틀 전 기준으로 굳어 있던 매매 기준으로 거래가 몇 건 나갔습니다.
AI에게 안전성 검증을 맡긴 결과 안전장치들은 전부 정상 작동했고 손실 폭도 매우 작아서 이미 나간 주문은 되돌리지 않기로 했습니다. 다만 이 과정에서 비슷한 위험을 가진 두 번째 장치를 추가로 찾아냈고, 유지 여부는 사람에게 직접 확인해서 결정했습니다.
매일 밤 진행되는 모델 교체 작업을 감시하는 안전장치도 이 주에 다시 들여다봤습니다. 정상적으로 완주한 밤에도 매번 "멈춘 것 같다"고 오판하는 구조적인 문제가 있었는데, 원인을 거슬러 올라가 보니 감시 주기가 실제 작업 소요 시간보다 짧은 게 근본 원인이었습니다.
수선 방향도 "얼마나 오래 걸렸는지"가 아니라 "그 작업을 진행 중인 프로세스가 실제로 살아있는지"를 직접 확인하는 방식으로 바꿨습니다.
새 관측 트랙과 GPU 확장
장애 대응 사이사이에는 새 실험 트랙을 여는 작업도 진행됐습니다.
주 초반에는 AI에게 프로젝트 구조 전체를 점검받아 서빙 엔진 분리, 앙상블 결합 공식 통합, 체결 기록 공용 라이브러리 신설 같은 리팩터링을 순서대로 실행했습니다. 다 고친 뒤엔 다시 AI에게 통째로 코드리뷰를 맡겨 실제 결함 하나(정상성 판정 로직의 시각 비교 오류)를 추가로 찾아 고쳤습니다.
며칠 뒤에는 장이 열려 있는 시간대에 보조 모델을 별도 계통으로 돌려 성능만 관측하는 파이프라인을 처음 실가동했습니다. 발화하자마자 GPU 메모리 처리, 로깅 대상 착오, 종료 판단 로직의 예외창 누락까지 버그 세 개가 연달아 터졌지만 전부 잡고 나서 전 종목이 정상 처리되는 걸 확인했습니다. 같은 주에 코스피·코스닥 후보 종목 구성비도 재검증을 거쳐 조정했습니다.
주 후반에는 실험 전용으로 그래픽카드를 한 장 더 들였습니다. 메인 프로덕션 카드를 바꾸려는 목적이 아니라, 검증 중인 로컬 모델을 메인 작업과 완전히 분리된 환경에서 오프라인으로 돌려보기 위해서였습니다.
이 카드와 기존 카드를 함께 써서 로컬 대형모델로 "100종목을 10시간 안에" 처리하는 걸 목표로 서버 튜닝을 진행했습니다. 계산 일부를 보조 카드로 옮기는 방식이 단일 요청 벤치마크에서는 이겼지만 여러 요청을 동시에 처리하는 실전 조건에서는 오히려 손해라는 게 드러나 폐기했고, 결국 원래 쓰던 단순한 배분 방식으로 되돌아왔습니다. 목표에는 근접했지만 아직 소폭 못 미치는 상태로 한 주를 마쳤습니다.
같은 주 후반에 며칠째 재론 중이던 통계 경보 하나도 정리됐습니다. 비교 표본 자체가 늘었는데 경보 문턱은 예전 절대 건수 기준 그대로 남아 있던 게 원인이었고, 비율 기준으로 다시 계산해보니 평소 수준과 구분이 안 됐습니다. 조치 없이 종결하고 앞으로는 비율 기준으로 문턱을 다시 정의하기로 했습니다.
이번 주를 관통한 흐름은 하나였습니다. 겉으로는 조용해 보이던 문제들이 재발을 거듭하며 드러났고, 그때마다 당장의 증상만 막지 않고 재발 시점을 거꾸로 추적해서 근본 원인까지 파고들었습니다.
그 반복 속에서도 장중 관측 파이프라인과 GPU 확장처럼 새로 여는 작업은 계속 진행됐고, 다음 주는 이번 주에 새로 연 실험 트랙들이 실제로 얼마나 쌓이는지 지켜보는 데서 시작할 것 같습니다.