안녕하세요. 팀 하루들입니다.
추석 연휴를 하루 앞둔 수요일 저녁, 팀 카톡방에 운영 서버에서 만든 그림일기 이미지가 보이지 않는다는 소식이 올라왔습니다. 실제 사용자가 있는 서비스를 운영하며 처음 맞닥뜨린 긴급 상황이었습니다.
팀원 모두 프로젝트 경험은 있었지만, 실사용자가 있는 서비스에 문제가 생긴 것은 처음이었습니다. 무엇부터 확인하고 어떻게 알려야 하는지는 직접 겪어본 적이 없었습니다. 저희 팀은 우선 어떤 이미지가 보이지 않는지, 문제가 어디까지 영향을 주고 있는지부터 살펴보기 시작했습니다.
원인과 복구 방법을 확인하는 동안, 저희는 사용자들에게 현재 상황을 먼저 알리기로 했습니다. 기존 그림일기가 보이지 않는 점과 새로 생성하는 이미지에는 문제가 없다는 점, 복구 방법을 확인하고 있다는 내용을 슬랙과 하루들 서비스 내 모달 그리고 인스타그램 스토리에 1차로 안내했습니다.
슬랙, 서비스, 인스타그램 1차 긴급 공지
원인을 살펴보니 개발 환경과 운영 환경이 같은 S3 버킷을 사용하고 있었습니다. 최근 개발 환경에 반영된 코드에는 주기적으로 실행되는 이미지 정리 작업이 포함돼 있었습니다. 이 작업은 개발 데이터베이스에서 참조하지 않는 S3 객체를 삭제하도록 동작했습니다. 운영 환경에서 사용 중인 이미지라도 개발 데이터베이스에 참조 기록이 없으면 정리 대상으로 분류됐고, 그 결과 운영 환경의 이미지까지 삭제됐습니다.
저희는 S3에서 삭제된 원본 이미지를 되살릴 방법도 찾아봤습니다. 하지만 버킷 버전 관리가 꺼져 있었고, 별도 백업이나 다른 버킷으로의 복제도 설정되어 있지 않았습니다. S3에서 삭제 전 상태로 되돌릴 방법은 찾지 못했습니다.
복구가 어려운 상황이라는 걸 알게 되자, 그동안 서비스를 이용해준 사용자들이 가장 먼저 걱정됐습니다. 사용자들이 남겨준 그림일기를 다시 볼 수 없다는 생각에 마음이 무거웠습니다. 기능을 만들고 서비스를 알려온 시간도 함께 떠올랐습니다.
카톡방에는 코드를 작성한 팀원이 여러 차례 미안하다는 말을 남겼습니다. 팀원들은 자책하지 말라고 답했고, 리뷰 시스템과 인프라 작업 과정을 함께 돌아보자는 이야기도 나눴습니다. 공지부터 잘하고 무리하지 말고 천천히 해결하자는 말도 이어졌습니다.
“자책할 필요 없어!”
“리뷰 시스템을 꼼꼼하게 구축하지 못한 우리 모두의 책임이야”
“공지부터 해두면 되니까, 무리하지 말고 천천히 해결하자.””
“사용자가 있기에 이런 경험도 해보는 거야”
삭제된 S3 원본을 그대로 되살리는 방법은 찾지 못했지만, 저장된 일기 내용을 바탕으로 이미지를 다시 생성하는 방안을 마련할 수 있었습니다. 이 방향을 정한 뒤 사용자들에게는 원본 복원이 어렵다는 점과 재생성 방식에 대해 2차로 안내했습니다.
슬랙, 서비스, 인스타그램 2차 긴급 공지
확인한 상황과 다음에 할 일을 사용자들에게 알리고 나니, 막연했던 조급함이 조금 가라앉았습니다. 모든 답을 한 번에 찾기보다 지금 할 수 있는 일을 차례로 정리할 수 있었습니다.
다행히도 스토리를 만드는 스토리보드는 데이터베이스에 저장되어 있었습니다. 일부 이미지의 원본 파일은 남아 있는 사본을 찾아 다시 사용하고, 원본을 찾을 수 없는 그림일기는 새로 생성하였습니다.
기존 서버에서는 스토리보드를 이미지 생성용 프롬프트로 바꾸는 작업을 Java 코드가 담당하고 있었습니다. 복구를 위해 해당로직을 Python으로 옮긴 뒤, 기존 방식과 같은 내용의 프롬프트가 만들어지는지 확인했습니다.
그림마다 스타일이 크게 달라지지 않도록 테스트를 거쳐 하나의 공통 스타일 프롬프트와 캐릭터 참조 이미지 한 장을 정했습니다. 여기에 데이터베이스에서 추출한 스토리보드와 장면 배경, 색을 넣을 주요 소품에 대한 설명을 더해 생성 요청을 만들었습니다. 이렇게 준비한 프롬프트와 참조 이미지를 Codex의 imagegen, GPT image-2에 전달해 그림일기를 다시 생성했습니다.
새로 만들어진 그림은 원본과 달라질 수 있었습니다. 그래서 사용자들에게 원본을 그대로 되살리는 방식이 아니라, 저장된 일기 내용을 바탕으로 그림을 다시 만드는 작업이라고 미리 안내한 것입니다. 생성한 이미지와 확보한 원본 사본을 S3에 다시 올리고 나서야 그림일기를 서비스에서 다시 확인할 수 있게 됐습니다.
유실된 모든 이미지를 다시 재생성하여 올린 뒤에도 이번 일을 돌아보며 논의할 과제는 여전히 우리에게 남아있습니다. 다가오는 팀 회의에서 같은 문제가 반복되지 않도록 다음 항목들을 함께 논의할 예정입니다.
개발 환경과 운영 환경의 리소스를 정확히 분리하기
인프라 관련 코드는 작업 전에 팀에 공유하고, 서로 꼼꼼히 리뷰하기
프론트엔드와 백엔드가 함께 긴급 공지 체계 마련하기
자동/수동 백업과 이중화 방안을 비롯해 백업 파일 관리 및 장애 복구 절차 정리하기
긴급 상황에서 확인할 내용과 공지 대상을 담은 대응 가이드라인 만들기
다음 날이 주말이나 휴일이면 사소한 수정도 배포하지 않는 원칙 세우기
서비스 장애 시 점검 중임을 빠르게 알릴 수 있는 장애 대응 API 도입 방안 검토하기
이번 일을 겪으며 위기 상황일수록 팀이 하나로 뭉쳐야 한다는 점과 실시간으로 상황을 공유하고 다음에 할 일을 함께 찾아가는 과정이 중요하다는 걸 느꼈습니다. 또한 철저한 리뷰 체계와 백업, 위기 대응 가이드라인을 평소에 마련해 두어야 한다는 점도 배웠습니다.
다가오는 팀 회의에서 후속 과제의 우선순위와 실행 방법을 논의하고, 하나씩 실천해 사용자들의 기록을 더 책임 있게 돌보는 하루들이 되겠습니다. 감사합니다.