반응형

2021년 7월, DB 장애가 발생했다.
현 회사의 DB는 Writer 인스턴스 1대와 N개의 Reader 인스턴스로 이루어져있는 Master/Slave 구조인데, Writer에 허용량 이상의 세션이 물리면서 DB가 죽게 됐다.
다음부터는 동일한 원인으로 DB 장애가 쉽게 발생하지 않도록 단기적, 장기적으로 개선해나가는 과정을 정리한다.

👉 장애 원인과 즉각적인 조치

원인 : Writer 인스턴스에 느린 조회 쿼리를 동시 허용량보다 많이 시도했는데, 사용중인 언어에 풀링이 안되고, 사용중인 AWS Aurora 버전에 버그가 있었음

조치 내용 :

  • Writer 인스턴스에서 조회하는 쿼리 일부 → Reader 인스턴스에서 조회하도록 변경
  • 느린 조회 쿼리 → full-scan 타는 느린 조회 쿼리에 인덱스 적용함
  • 허용량보다 많은 연결 → AWS RDS Proxy 적용하여 Connection Pooling 하도록 변경
  • 그 외 후속처리(마케팅팀에게 마케팅 시 사전 예고 부탁, 장애 리포트 작성 등)

처음에는 DB 장애가 발생했는데 원인 파악에 시간을 좀 썼다. 다음부터는 Writer 세션이 허용량 이상 물려있고, CPU 사용량은 높은데 메모리 사용량이 적다면 느린 조회 쿼리를 확인하고, 이 쿼리들이 사용되는 지점을 조사해서 Reader 인스턴스에 접속하는 지, 인덱스는 잘 타는 지 플랜을 조회해봐야겠다.

해당 장애에 즉각적이고 큰 효과를 볼 수 있는 조치를 취했는데, 이번 장애를 기회로 점진적으로 해결해나가야 하는 장기적인 개선 방향에 대해 생각해보게 됐다.

👉 휴먼에러 발견, 이를 방지하기 위한 DB 공통 클래스 작성

인프라 구성에 빈틈도 있었지만, 휴먼 에러도 발견했다.

사용중인 언어에 풀링이 안된다던가, AWS Aurora 버전에 버그가 있다던가 하는 것은 즉각적으로 조치가 가능하고 인프라 차원의 이슈였다. 하지만 DB 아키텍처가 Master/Slave인 이상 하나뿐인 소중한 Master 인스턴스에게 불필요한 세션이 많이 물린다면 좋지 않다. 이번 장애를 유발했던 느린 쿼리를 가진 프로세스는 db read만 하는 작업들로 이루어져있어서 순수하게 개발자의 휴먼에러로 Writer 세션에 붙게 됐다. (물론 풀링이 됐다면 장애로 번지지는 않았겠지만!)

팀원들의 휴먼 에러를 어떻게 줄일 수 있을까?

생각을 해보니 DB 접속용 공통 클래스를 만들어서 지금보다 개발자들이 편하게 DB 접속을 할 수 있게 하되, Writer/Reader 인스턴스에 붙는 세션은 내부적으로 관리하면 좋을 것 같았다. 기존에는 조회 시에는 Reader 세션을 맺고, CUD 쿼리에는 Writer 인스턴스에 세션을 맺고 있었는데 슬프게도 두 세션을 동시에 맺으면 오류가 발생하는 상황이었다. 그래서 DB 접속용 클래스 내에 조회용 메서드와 실행용 메서드를 제공했다. 그리고 지연전파를 피하기 위해 실행용 메서드 실행 시 바라보고 있는 조회용 메서드의 세션을 Writer로 바라보게 내부적으로 처리했다(이 부분에 대해서는 추가 피드백 받은 내용이 있다).

발생했던 DB 장애와 이에 대한 조치, 휴먼에러 방지를 위한 DB 접속용 클래스 사용법에 대해 사내 세미나를 진행했고, 앞으로 어떻게 개선시켜야할지 피드백과 개선방향을 잡을 수 있었다.

👉 장애 회고 겸 세미나

사내 세미나에서는 아래 내용에 대해 발표했다. 희희! 첫 사내 세미나였는데 첫 발표자였다.

  • Master/Slave DB 구조의 장단점
  • 발생했던 DB 장애와 조치내용 공유
  • DB 접속용 클래스를 만든 이유와 사용법 (CQRS 느낌)
  • DB 접속용 클래스의 한계와 개선방향
  • Q&A (다함께 개선 방향에 대해 논의)

https://prohannah.tistory.com/190

 

2021.10.06 첫 사내 세미나

사내에서 처음으로 세미나를 진행했다. 다행히 온라인이라 스크립트 작성해서 보면서 읽을 수 있어서 자연스럽게 말하려고 연습하느라 죽을 뻔 😇 세미나 주제는 7월에 발생했던 DB 장애의 원

prohannah.tistory.com

👉 한계와 장기적인 개선 방향

프레임워크가 적용되지 않은 서비스라 DB를 바라보는 프로세스를 하나씩 점검해야한다.
CQRS 패턴을 제대로 도입한다고 하더라도 지연전파를 피하기 위해 Writer 세션에 조회 쿼리가 많이 물리게 된다면 Writer 인스턴스에 부하가 발생하게 된다.

위 한계를 정리하면 아래 내용들을 꾸준히 진행해야 한다.

  • 카테고라이징을 하여 Wrtier 인스턴스 부하 낮추기 (레이첼님 의견)
    • 실시간으로 바로 적용되야하는 도메인(로그인, 결제)을 구분하여 CUD→R 해야하는 경우 Writer 인스턴스를 바라봄 
    • 1~2초의 지연전파가 허용되는 도메인들은 CUD 후에 조회 시 Reader 인스턴스를 바라봄
    • 추후 더 나아가서 로그인처럼! 라이터 인스턴스를 무는 도메인의 요청이 엄청 많이 들어올 경우는 DB 자체를 분리할 수 있다. 예를들어 로그인 같은 경우는 인증/인가에 관련된 영역이니까 인증 서버와 회원 DB를 별도로 분리해서 로그인이 장애가 나도 세션이 몰려도 다른 도메인에는 영향이 가지 않도록 한다!
  • DB 접속용 공통 클래스를 사용해서 휴먼에러 발생하지 않도록 방지
  • 느린 쿼리 튜닝

참고하면 좋은 글

반응형