내 손으로 데이터베이스를 날린, 그 후 5일간의 이야기

2025. 5. 14. 23:42·CI&CD

교내 알고리즘 학회에서 solved.ac의 api를 이용하여 소속 학회원들의 레이팅을 매겨주는 웹 서비스를 운영중이다.

지난 주말 새벽에 원인 미상의 오류로 서버가 터지고, 그 이후 있었던 일에 대한 회고를 적어보고자 한다.

 

2025-05-10 (토)

[02:30] EC2 인스턴스 접속 불가

새벽에 서버가 터졌다는 연락을 받고 AWS 콘솔을 확인했는데, 어떤 이유로 터진 건지 로그도 출력이 안되고 EC2 내부 접속조차 되지 않았다. 일단 DB가 살아있는지의 여부가 매우 중요했는데, RDS 콘솔에서 DB는 정상으로 확인되었기 때문에 안심했다.

 

우리 서비스 서버는 Elastic Beanstalk를 통해 배포되어 있는데, 애초에 내가 AWS 서비스에 대해서 깊게 알지 못하다 보니 이런 상황에 대해 잘 몰랐다. 그래서 열심히 찾아본 결과 Elastic Beanstalk 환경을 다시 빌드하면 대부분 해결된다고 해서 환경 다시 빌드를 하고자 했더니 다음과 같은 알림이 떴다.

환경을 다시 빌드하는 데 몇 분 정도 걸릴 수 있습니다. 이 기간에는 애플리케이션 및 연결된 Amazon RDS DB 인스턴스가 삭제됨을 사용할 수 없습니다.

서비스에 장애가 났지만 DB는 살아있었고, 설마 DB도 환경 다시 빌드할 때 날아가겠어? 싶었는데 다음과 같은 확인을 받으니 조금 더 안심됐다. 다시 말하지만 분명 "연결된 Amazon RDS DB 인스턴스가 삭제됨을 사용할 수 없습니다." 라고 써있었다.

[04:00] DB 접속 불가

환경을 다시 빌드했는데도 콘솔에서 서비스 상태는 오류를 던지고 있었고, DB도 분명 살아있다고 확인되는데 접속이 되지 않았다. 내 얕은 AWS 경험으로는 도저히 해결이 불가능해서 일단 자고 일어나서 생각하기로 했다. "이참에 Docker를 사용하는 컨테이너 기반 배포로 전환하면 되지 않을까?" 라고 생각해서, 팀원들에게 상황 전달을 하고 마무리했다.

[19:00] DB 초기화 인지

낮에 팀장님이 학회원들에게 서비스 오류에 대해서 사과 공지를 올려주셨다. 서비스 자체가 우리 학회에서 백준 스트릭을 재해석하여 구현한 것이라, 스트릭이 날아가거나 점수가 반영되지 않으면 큰일이기 때문에 하루빨리 안정화시켜야 하는 상황이었다.

 

일단 나는 DB 접속부터 해결하고 서버를 손보려 했다. 무슨 이유인지 DB에 인바운드 규칙 설정이 바뀌어 있어서 로컬에서 접속이 불가능했음을 알아냈다. 그런데 그렇게 들어간 DB에는 존재하는 테이블이 없었다. 현실을 부정했다. 남아있는 스냅샷도 들어가봤는데, 거기에도 아무것도 존재하지 않았다. 모든 테이블이 날아간 것이다.

 

찾아보니까, 환경 다시 빌드 버튼을 누를 때 떴던 "연결된 Amazon RDS DB 인스턴스가 삭제됨을 사용할 수 없습니다." 알림이, 번역투 문장이라 내가 잘못 이해했던 것이다. 즉, 연결된 Amazon RDS DB 인스턴스가 삭제되는 것이었다.

 

2025-05-11 (일)

[19:00] 서버 재배포

Docker 기반으로 EC2에 배포해보려 했는데, 나 자신이 Docker를 써본 적 없기도 하고, 처음에 Elastic Beanstalk로 배포하신 팀원분이 저장해놓으신 환경변수나 세팅들을 짧은 시간 내에 Docker 기반 배포로 전환하기 힘들 것 같았다. 서비스를 신속히 복구하는 게 우선이 되어야 한다고 생각했다.

 

그래서 다시 Elastic Beanstalk 환경으로 배포하고, 이참에 기존 코드에서 github에 노출되면 안되는 정보들을 삭제했다. (이전에는 서버 실행 파일이 깃허브에 올라가 있었다.) 새로운 EC2 인스턴스에 대해서 가비아에 DNS 연결을 해주고, Https가 적용될 수 있도록 인증서도 발급 해주었다.

 

직접 Elastic Beanstalk 설정을 하면서 알게 된 사실은, RDS 자동 연결 구성을 할 때, 환경 다시 배포 시 DB를 어떻게 할 지 설정 가능하다는 점이었다. 아마 이전 환경을 만드신 팀원분이 RDS도 같이 삭제 옵션을 준 것 같았는데, DB를 내 손으로 날린 나는 이 옵션을 체크하지 않았다. 무서워서 RDS 콘솔에서 DB 삭제 방지 옵션도 켜줬다.

[21:30] DB 복구 정책 논의

이제 서버가 배포되었으니 DB를 복구해야 할 차례다. 앞서 말했듯이 DB 스냅샷에 저장된 백업 데이터가 아무것도 없었고, 따라서 원본 데이터를 전혀 복구할 수 없었다. 이미 날아간 DB이니 서버가 터진 시점의 학회원들의 점수 및 스트릭을 알지 못했고, 다음과 같은 방법을 고려했다.

  1. 시즌 1 데이터를 날리고, 시작한 지 일주일 된 시즌 2 데이터만 백준에서 학회원 및 문제 티어별로 역추적해서 복구하자.
  2. 시즌 1 데이터, 시즌 2 데이터 모두 백준에서 역추적해서 복구하자.

선택지에서 알 수 있듯, 일단 시즌 2 데이터는 복구하는 편이 맞다고 보았다. 시즌이 끝날 때 운영진들이 디비전 별 상위 랭킹에 있는 학회원들에게 상품을 주기 때문에, 이 데이터를 무효로 하면 일주일간 열심히 문제를 푼 학생들에게 공정하지 않다고 생각했다.

 

문제는 시즌 1 데이터인데, 내 경험에 입각했을 때 이것도 최대한 복구하는 편이 맞다고 생각했다. 한창 백준을 풀 때, 쌓여가는 solved.ac 점수와 스트릭을 보면서 다음날 문제를 푸는 원동력이 되었다. 우리 서비스에서도, 서비스 시작일부터 하루도 빠짐없이 문제를 푸신 분들이 있고, 점수도 많이 쌓으신 분들이 있는데, 이걸 전부 다 무효로 하기에는 그동안의 노력을 없던 일로 만드는 것 같아 꺼려졌다.

 

그래서 이전의 모든 데이터를 복구하기로 결정하고, 복구할 데이터가 늘어나지 않도록 DB에 학생 데이터부터 넣기로 했다. 그래야 solved.ac의 각 학생별로 API를 호출해서, 서비스 시작 시점 이후에 값들이 DB에 저장되게 할 수 있기 때문이다.

 

2025-05-12 (월)

[16:30] DB 테이블 생성 및 초기 데이터 삽입

프론트엔드 팀원과 함께 잘 되길 빌면서 DB에 학생 데이터를 넣었는데, 서버가 한번 더 터졌다. 이쯤되면 우리 서비스가 문제가 있는게 아닐까 조금 고민되어서, 방학 기간 중에 코드 개선을 해야겠다고 강한 마음가짐을 갖게 되었다.

 

아무튼 서버가 터진건 터진거고, DB에 학생 데이터가 잘 들어갔는지 먼저 확인했다. MySQL workbench에서 solved 테이블(티어별로 학생이 푼 문제 수를 저장하는 row)을 확인하니, 어느 순간부터 끊겨있어서 학생 데이터가 잘 안들어갔다고 생각했다. 일단 DB는 서버를 다시 복구하고 다시 확인해보기로 했다.

 

지난 번과 같은 실수를 반복하지 않기 위해, 이번에는 EC2 인스턴스만 삭제해보았다. Elastic Beanstalk 설정에서 EC2 개수를 항상 하나로 맞추도록 설정했기 때문에, 현재 멈춘 EC2 인스턴스를 삭제했더니 다시 새로운 EC2 인스턴스를 만들어주었다. 이번에는 안전하게 배포를 마칠 수 있었다.

 

학생 데이터를 다시 넣어보았는데, 아까와 workbench에서 보았던 테이블과 동일하게 row가 끊겨있었다. 클라이언트에서 전달받는 데이터도, 존재하지 않을 row를 잘 불러오고 있었다. 그래서 이건 내 문제라고 생각하고 다시 보니, MySQL workbench의 테이블 보기 설정에 'LIMIT TO 1000' 옵션이 기본적으로 세팅되어 있었다. 한도를 10000까지로 바꿔주니 그제야 전체 행이 보이기 시작했다.

[18:30] 서버 정상화

서비스는 이제 잘 동작하도록 마무리가 되었고, 이제 남은건 5/12 18:33 이전의 유실된 데이터 복구였다. 마침 22:30에 개발 팀 회의가 예정되어 있어서, 이때 이야기를 나눠보기로 했다.

[22:30] DB 복구 절차 논의

회의를 하면서 새로 전달받은 사실은, 팀원분이 4/30 기준 우리 서비스의 점수, 스트릭 데이터의 백업본을 찾으셨다는 것이었다. 덕분에 우리는 5/1 ~ 5/12 18:33 만 역추적하면 되어서 일이 훨씬 줄었는데, 5/1~5/6은 시즌 중이 아니므로 이것도 점수 합산에서는 제외하기로 했다.

 

정리하면, 160명 가량의 학회원 각각에 대해서,

  1. 5/7 06:00 ~ 5/12 18:33 기간의 백준 기록을 역추적하여 티어에 따른 점수를 계산하고 (restore_season_score)
  2. 이 점수를 지금 서비스에서 계산중인 season_score에 더해서 점수를 업데이트 해주고,
  3. 4/30 기준 total_score에 이 season_score를 더해서 갱신해주자.

이렇게 결론이 났다.

 

팀원들과 Google 스프레드시트를 활용해서 나눠 작업을 했고, 양심상 나는 조금 더 많은 분량을 복구하겠다고 했다..

 

2025-05-13 (화)

[21:00] DB Update 쿼리 생성

내가 할당받은 분량에 대해서 점수 역추적을 마무리하고 160명의 값을 업데이트하는 쿼리를 만들었다. 운영 중에 바로 쿼리를 날리면 JPA에서 동시성 문제가 생길 수도 있을 것 같아서, 쿼리만 만들어놓고 새벽에 쿼리를 실행하기 위해 기다렸다.

 

2025-05-14 (수)

[01:00] DB 정상화

일단 쿼리를 날리기 전에 혹시 몰라서 DB 스냅샷을 만들어 두었다. 혹시 잘못된 쿼리라면 바로 되돌려야 하기 때문이다. 그렇게 쿼리를 날리고 160명의 값을 성공적으로 업데이트 할 수 있었다. 4/30~5/13에 대한 스트릭도 일괄 지급해서, 학회원들의 서비스에 대한 동기부여를 잃지 않도록 했다.

[11:30] 서비스 정상화

아침까지 서비스가 정상적으로 동작함을 확인하고, 점수 재검증도 마친 후, 마침내 학회원들에게 서비스 정상화가 완료되었다고 공지할 수 있었다.

 

회고

내가 내 손으로 DB를 날려버린 결과는 너무 참혹했다. 일단 소중한 팀원들의 시간을 할애하게 해야 했으며, 나 또한 개발에 투자해야 할 시간을 상당 부분 잃었다. 여기에 전부 담지는 못하지만, DB를 날렸다는 사실을 인지하고 나서 팀원들에게 몇번이고 사과했다.

 

그렇게 배운 점도 많았는데, DB는 무슨 일이 생기던 안전하게 백업을 한 후 작업하자는 점이다. 최소한의 백업 체계가 존재한다면 일이 이렇게까지 커지지는 않았을 것이라고 생각한다. 의도하진 않았지만 AWS 배포 인프라 이해도도 상당히 늘었다고 생각한다.

 

모쪼록 개발 팀 백엔드 파트로 혹여나 다른 팀원이 들어온다면, 이런 일을 최대한 겪지 않았으면 한다. 개발 팀 예산 할당이 어떻게 될 지는 모르겠으나, 가능하다면 방학 때 Elastic Beanstalk 인프라에서 ECS를 활용한 인프라로 바꿔보고 싶은 마음이 있다. 장애 대응에 훨씬 낫다고 생각하고, 배포 과정도 컨테이너 기반이라 신경 쓸 것도 훨씬 적기 때문이다. 그렇게 된다면, 꼭 인프라 구조도를 만들어서 다른 팀원들에게 인프라에 대해 설명하는 시간을 갖고, 나처럼 DB를 날려먹는 짓을 하지 않고, 서버 인프라에 대한 이해를 갖고 서비스를 개발했으면 한다.

'CI&CD' 카테고리의 다른 글

AWS CDK: AWS CloudFormation을 추상화하자  (0) 2025.11.11
Terraform으로 Infra를 Code로 관리하자!  (0) 2025.05.28
Amazon ECR/ECS 란 무엇일까?  (1) 2025.05.07
'CI&CD' 카테고리의 다른 글
  • AWS CDK: AWS CloudFormation을 추상화하자
  • Terraform으로 Infra를 Code로 관리하자!
  • Amazon ECR/ECS 란 무엇일까?
에싀
에싀
Dopamine-Driven-Develop
  • 에싀
    //comment
    에싀
  • 전체
    오늘
    어제
    • Programming (11)
      • Spring (1)
      • Algorithm (0)
      • CI&CD (4)
      • Project (1)
      • Network (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • GitHub
    • solved.ac
  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.1
에싀
내 손으로 데이터베이스를 날린, 그 후 5일간의 이야기
상단으로

티스토리툴바