Cowork
[잡학상식] Postmortem, 포스트모템
너드나무
2024. 11. 29. 07:20
반응형
포스트모템이란?
포스트모템(Postmortem)은 라틴어로 "사후(Post) + 죽음(Mortem)"을 의미하며,
IT 및 비즈니스 분야에서는 프로젝트나 시스템에서 발생한 문제나 실패를 철저히 분석하고,
이를 통해 교훈을 얻는 프로세스를 의미합니다.
포스트모템의 목적
- 문제 원인 파악
- 문제의 근본 원인(Root Cause)을 식별하여 같은 문제가 다시 발생하지 않도록 합니다.
- 지식 공유
- 팀 전체가 문제 해결 과정과 교훈을 공유해 조직 전반의 역량을 향상시킵니다.
- 책임 전가 방지
- 비난 대신 개선에 집중하며, 건설적인 문화를 조성합니다.
- 미래 실패 방지
- 교훈을 반영하여 더 나은 시스템, 프로세스를 설계합니다.
포스트모템의 주요 과정
- 사건 기록(Event Documentation)
- 문제가 발생한 시점부터 종료까지의 과정을 상세히 기록합니다.
- 사건 발생 시간
- 주요 이벤트 타임라인
- 관련된 시스템/서비스
- 문제를 감지한 방법과 첫 대응 조치
- 문제가 발생한 시점부터 종료까지의 과정을 상세히 기록합니다.
- 원인 분석(Root Cause Analysis)
- 발생한 문제의 근본 원인을 찾습니다.
- 이를 위해 5 Whys(왜를 다섯 번 묻기), Ishikawa 다이어그램 등을 활용할 수 있습니다.
- 문제: 서버 다운
- 왜? → 요청 수 증가로 서버 과부하.
- 왜? → 부하 분산 설정이 잘못됨.
- 왜? → 설정 변경 과정에서 테스트 미흡.
- 문제: 서버 다운
- 대응 평가(Response Evaluation)
- 문제 해결을 위해 취했던 대응 조치를 분석하고, 개선점을 찾습니다.
- 무엇이 효과적이었는가?
- 어떤 부분이 미흡했는가?
- 문제 해결을 위해 취했던 대응 조치를 분석하고, 개선점을 찾습니다.
- 교훈 도출(Lessons Learned)
- 이 사건에서 얻을 수 있는 교훈을 명확히 정의하고, 이를 조직에 반영할 방법을 모색합니다.
- 액션 아이템(Action Items) 정의
- 미래의 실패를 방지하기 위해 필요한 구체적인 개선 작업을 정의합니다.
사례: FastAPI 응답 지연 및 500 오류 발생
- 사건 개요
- 발생 일시
- 2024-11-22, 10:00 AM
- 해결 일시
- 2024-11-22, 11:30 AM
- 문제 현상
- 클라이언트가 특정 API를 호출했을 때 응답 시간이 10초 이상으로 증가.
- 일부 요청에서 500 Internal Server Error 발생.
- 영향 범위
- api/v1/users/{user_id}/details 엔드포인트 사용 불가.
- 사용자 데이터 요청의 70%가 실패
- 발생 일시
- 타임라인
시간 | 이벤트 |
10:00 AM | /api/v1/users/{user_id}/details에서 응답 지연 및 500 오류 발생 시작. |
10:15 AM | 장애 보고 후 긴급 대응팀 소집. |
10:30 AM | FastAPI 애플리케이션의 로그에서 DB 연결 문제 확인. |
10:50 AM | 문제 원인으로 SQLAlchemy 세션 누수 파악. |
11:15 AM | SQLAlchemy 세션 관리 코드 수정 및 배포. |
11:30 AM | 서비스 정상화 및 로그 모니터링 완료. |
- 원인 분석
- SQLAlchemy 세션 누수
- get_db 함수가 제대로 종료되지 않아 데이터베이스 연결이 지속적으로 열려 있었음.
- 일정 시간이 지나면서 데이터베이스 연결이 포화 상태에 도달.
- DB 풀 부족
- PostgreSQL 데이터베이스 풀 크기 초과로 인해 요청 대기열이 증가.
- SQLAlchemy 세션 누수
from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session
from app.database import get_db
from app.models import User
router = APIRouter()
@router.get("/users/{user_id}/details")
def get_user_details(user_id: int, db: Session = Depends(get_db)):
user = db.query(User).filter(User.id == user_id).first()
if not user:
return {"error": "User not found"}
return {"id": user.id, "name": user.name}
- 대응 평가
- get_db 함수에서 yield를 사용하여 요청이 종료되면 세션이 자동으로 닫히도록 설정.
- 잘한 점
- 로그를 신속히 분석하여 원인을 SQLAlchemy 세션 누수로 좁힘.
- 문제 해결 후 즉시 배포 및 서비스 복구 성공.
- 개선할 점
- get_db 함수가 세션 종료를 보장하지 않음.
- 테스트 환경에서 대규모 트래픽 시뮬레이션 부족.
- SQLAlchemy 세션 관리 문제를 사전에 탐지하지 못함.
from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session
from app.database import SessionLocal
router = APIRouter()
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
@router.get("/users/{user_id}/details")
def get_user_details(user_id: int, db: Session = Depends(get_db)):
user = db.query(User).filter(User.id == user_id).first()
if not user:
return {"error": "User not found"}
return {"id": user.id, "name": user.name}
- 교훈
- DB 세션 관리를 철저히 하라
- FastAPI에서 Depends로 의존성을 주입할 때, 세션의 열고 닫는 과정을 명시적으로 관리해야 한다.
- 로드 테스트의 중요성:
- 실제 트래픽 수준을 시뮬레이션하여 데이터베이스 연결 문제가 발생할 가능성을 조기에 발견해야 한다.
- 프로덕션 로그 모니터링
- 로그를 실시간으로 모니터링하여 데이터베이스 풀 부족과 같은 징후를 빠르게 감지.
- DB 세션 관리를 철저히 하라
- 액션 아이템
작업 항목 | 마감일 | 담당자 |
get_db 함수에 세션 종료 로직 추가. | 완료 | 개발 팀 |
대규모 트래픽 로드 테스트 진행. | 2024-11-25 | QA 팀 |
데이터베이스 연결 풀 모니터링 도구 설정. | 2024-11-28 | DevOps 팀 |
728x90
반응형