
2025년 10월 ~ 2026년 3월
들어가며
6개월간 적지 않은 변화가 있었다.
먼저 판교의 작은 기업으로 이직하였다. 극장 시스템에서 전혀 다른 업무 도메인을 다루며 처음부터 시작하는 마음으로 업무를 해왔다. 아직도 새롭게 개발하거나 시스템을 수정할 때 헤매긴 하지만 1인분 이상을 하기 위해 노력 중이다.
AI의 흐름이 내가 생각한 것보다는 더 빠르게 일어나고 있다. 그 흐름을 타는 것은 내게 선택권이 있다고 생각했었지만 전혀 아니었다. 이 기간 동안 다양한 AI 서비스를 사용해보았고, 지금은 어느정도 정착하였다. 이젠 AI 서비스를 누가 더 얼마나 정확하게 다루고, 신뢰할 수 있는 결과를 만들어내는지가 중요한 시대 같다.
인생의 변화로는 붉은 말띠의 귀여운 딸이 태어났다. 조금 더 책임감을 가지고 살아야겠다.
요즘처럼 생성형 AI를 적극적으로 활용하는 시대에 잘 어울리지 않을 수 있지만, 문득 그러하니 활자 형태로 기록을 남겨야겠다는 생각이 들었다. 그래서 지난 기간 내가 기억해둘만한 일을 조금 정리해보았다.
더 자세히 기억할 일은 별도의 글로 분리할 계획이다.
1. 병목 개선
배경
실시간으로 대량의 메시지를 처리하는 파이프라인이 있었다. 오랫동안 크게 문제없이 운영되어 왔지만 처리해야 하는 디바이스가 점점 많아지면서 처리량 한계에 가까워지는 시점이 왔다. 더 이상 현행 구조로는 수요를 감당하기 어렵겠다고 판단했다.
문제
원인을 분석하니 하나의 메시지를 처리하는 과정에서 동일한 데이터를 여러 번 조회하고 있었다. 각 처리 단계가 독립적으로 동작하도록 설계되어 있었기 때문에, 앞 단계에서 이미 가져온 데이터를 다음 단계가 다시 가져오는 구조였다. 처리 건수가 적을 때는 문제가 되지 않았지만, 규모가 커질수록 이 중복 조회가 누적되어 병목이 되었다.
접근 방식
튜닝보다 구조를 바꾸는 쪽을 택했다. 메시지 하나를 처리하는 흐름 전체에서 공유되어야 할 데이터를 묶어 컨텍스트 객체로 정의하고, 처음 한 번만 조회한 뒤 이후 단계는 해당 객체를 참조하도록 바꿨다. 동시에 자주 반복 조회되는 데이터는 인메모리 캐시 레이어를 두어 외부 저장소 접근 자체를 줄였다.
변경 범위가 넓었기 때문에 기존 처리 흐름을 건드리지 않는 방향으로 점진적으로 적용했고, 캐시 구성 수와 만료 정책은 실제 데이터 특성을 분석해 결정했다.
결과
처리량이 약 2.5배 향상되었고, 시스템 리소스 사용률은 15~20% 낮아졌다. 캐시 적중률은 92~95% 수준을 유지했다.
회고
가장 잘한 선택은 증상이 아닌 원인을 찾으려 했다는 것이다. 설정 값 몇 개를 바꾸는 것으로도 단기적으로 버틸 수 있었겠지만, 그랬다면 이 구조적 문제는 더 크게 터졌을 것 같다.
아쉬운 점은 분명 사용률이 낮아지긴 했으나 기대만큼 크진 않았다는 점이다. 추후 추가로 개선지점을 찾아 가용성을 더 확보하고자 한다.
이후 모니터링의 필요성도 대두되어 모니터링 구축 작업으로 이어졌다.
2. 모니터링 구축
배경
시스템은 오랫동안 잘 돌아가고 있었지만, 모니터링이 조금 어려웠다. 사용 중인 프레임워크에서 별도의 Web UI를 제공해주지만, 매번 들어가서 보기도 불편하고, 조회 당시의 데이터만 볼 수 있는 점이 아쉬웠다.
문제
로그는 있었지만 직접 각 서버에 접근하여 파일을 일일이 열람해야 했다. 현재 시스템이 어떤 상태인지, 평소와 다른 이상이 있는지 감지할 수단이 없었다. 문제를 사후에 인지하는 구조였다.
접근 방식
로그에서 의미 있는 이벤트를 추출해 메트릭으로 변환하고, 이를 시각화하는 파이프라인을 구성했다. 도구 선택은 기존 인프라에 최소한의 변경으로 붙일 수 있는 방향을 우선했다.
어떤 지표를 볼 것인지 정의하는 과정이 가장 중요했다. 숫자를 많이 모으는 것보다, 실제로 운영 판단에 쓸 수 있는 지표 몇 개를 잘 정의하는 것이 낫다고 판단했다. 현재 처리량, 오류 발생 추이, 주요 이벤트 빈도 등 운영자가 바로 해석할 수 있는 지표를 중심으로 구성했다.
결과
단편적인 수치를 토대로 판단하던 것들을 추이로 판단할 수 있게 되었고, 성능 개선 작업의 효과도 모니터링을 통해 확인할 수 있었다. 무엇보다 이상 징후를 사전에 감지할 수 있는 기반이 생겼다.
회고
처음으로 직접 Prometheus와 Grafana를 구성하였다. 연차를 생각하면 늦은 감이 있지만 과거 다른 솔루션을 이용했던 경험이 있어 크게 어렵지 않게 구성할 수 있었다.
추후 사내에서 운영 중인 시스템의 지표를 점진적으로 추가하면서 각각이 실제로 활용되는지 확인하는 방식으로 발전시켜 나갈 것이다.
3. 덤프
배경
운영 중 메시지 처리 파이프라인에서 소비 지연이 발생했다. Kafka의 소비 지연 지표를 확인하였고, 재기동을 시도했지만 잠시 후 동일 증상이 반복되었다. 단순한 과부하나 일시적 오류가 아니라는 것을 직감했다.
문제
재기동 후에도 같은 현상이 반복된다는 것은 특정 메시지가 문제를 일으키고 있을 가능성을 시사했다. 처리 파이프라인의 특성상 메시지 하나가 ack되지 않으면 이후 메시지 전체의 offset이 전진하지 못한다. 겉으로는 처리가 멈춘 것처럼 보이지만, 실제로는 하나의 처리 단위가 특정 메시지에 갇혀 있는 상태였다.
어디서 막혔는지, 어떤 메시지가 원인인지 로그만으로는 알 수 없었다.
접근 방식
실행 중인 프로세스에서 Thread Dump를 수집하고 분석했다. WAITING 상태로 대기 중인 스레드들이 다수 확인되었고, 모두 동일한 데이터 조회 흐름에서 멈춰 있었다. 아직까지는 통신 지연이나 일시적 오류로도 볼 수 있는 단계였다.
특정 처리 단위의 처리량이 비정상적으로 낮은 것을 확인한 후 Heap Dump를 수집했다. 덤프 파일 크기가 수 GB에 달해 기존 도구로는 분석에 한계가 있었다. AI를 활용해 HPROF 바이너리 파일을 직접 파싱하는 스크립트를 작성했고, 문제가 된 메시지의 데이터를 추출하는 데 성공했다.
분석 결과, 외부 디바이스에서 전송된 특정 메시지의 날짜 필드에 비정상적으로 큰 값이 담겨 있었다. 이 값이 유효성 검사를 통과해 처리 흐름에 진입했고, 내부적으로 무한에 가까운 반복을 유발하며 해당 처리 단위를 점유하고 있었다.
결과
원인이 명확해지자 대응은 간단했다. 날짜 필드의 허용 범위를 제한하는 필터링 로직을 추가했고, 이후 동일 메시지가 들어와도 건너뛰고 정상 처리가 이어지도록 했다. 배포 후 처리가 재개되었다.
회고
이전 직장에서는 장애 시간이 서비스 레벨 지표였기 때문에 빠르게 복구하는 것을 최우선으로 삼았었다. 하지만 작년에 이직을 위해 면접을 보러 다니던 중 한 회사에서 이런 태도를 지적받았다. 그러면서 "문제가 발생하면 원인 파악을 위해 덤프를 뜨고, 서비스 복구를 진행하라"는 조언을 받았다.
이 장애를 조치하던 중 문득 그 때가 생각나서 Thread Dump와 Heap Dump를 생성했다. 수 GB짜리 바이너리 파일을 분석해야 하는 상황에서 AI가 실질적인 도움이 되었다. 직접 파서 스크립트를 작성하고, 중간에 발생한 오류를 수정해가며 결국 원인 데이터를 찾아냈다.
재기동이 증상을 해결하지 못한 이유, 특정 처리 단위만 처리량이 낮았던 이유 등 각 단서들을 찾아가는 과정이 상당히 즐거웠다. 시간은 걸렸지만 기억에 남는다.
마무리
새로운 환경에서 보낸 시기였다. 시스템을 이해하고, 보이지 않던 것을 보이게 만들고, 예상치 못한 문제를 끝까지 파고든 경험들이 쌓였다. 앞으로는 이 위에서 더 능동적으로, 단순히 주어진 일을 처리하는 것을 넘어 더 넓은 시각으로 시스템과 제품을 바라보고 싶다. 특히 지금처럼 빠르게 변모하는 시기일수록 코드를 잘 짜는 것만큼, 무엇을 왜 만드는지 아는 것이 중요해질 것 같다.
딸이 태어났다. 더 잘해야 할 이유가 하나 더 생겼다.