포스트

고객사 RDS 통합 모니터링 플랫폼 구축 — Part 5: EOS 추적과 정기점검 보고서

고객사 RDS 통합 모니터링 플랫폼 구축 — Part 5: EOS 추적과 정기점검 보고서

고객사 내 EOS 관리 및 월 정기점검 보고서에 대한 자동화를 고민한 내용을 다룹니다.

이전까지의 글들은 실시간 모니터링 에 가까운 기능들이었습니다. 이번에는 매주 또는 매월 한 번 사람이 손으로 정리해야 했던 작업, 그래서 결국 안 하게 되는 작업을 포털이 대신 해 주는 영역을 고민하고 자동화한 내용에 대해서 다루었습니다.

이번에는 각 고객사 모든 인스턴스에 대한 두 가지 체크 방안에 대한 고민을 풀어낸 과정을 기록합니다. DB 버전이 언제 지원 종료되는지 추적하는 EOS 화면, 그리고 지난 한 달의 운영 보고서를 자동으로 합성 하는 정기점검 보고서입니다.

EOS 버전 현황

DBA 운영에서 가장 조용히 위험 한 게 지원 종료 (End-of-Support) 가 임박한 DB 버전 입니다. 평소엔 잘 돌아가는데, 어느 날 갑자기 AWS 가 이 버전은 다음 주에 강제 업그레이드됩니다 라고 통보하면 그 주에 모든 일을 멈추고 업그레이드 준비를 해야 합니다. 그래서 최소 몇 달 전부터 알고 있어야 합니다.

포털의 EOS 버전 현황 메뉴는 한 화면에 그 답을 모아 줍니다.

색으로 한눈에 보는 위험도

각 인스턴스가 사용 중인 DB 버전을 남은 일수 기준으로 다섯 단계 색상으로 표시합니다.

색상의미
🔴 빨강이미 EOS 만료 또는 30일 이내
🟠 주황90일 이내 만료
🟡 노랑180일 이내 만료
🟢 초록180일 이상 여유
⚪ 회색EOS 정보 없음

초록 색 (180일 이상) 일 때는 상관이 없지만, 이후 시기부터는 고객사에 알림 메일을 보내며 준비에 대한 Noti 를 합니다. 사실 이 부분도 자동 메일 발송 등에 대해 추가적인 자동화를 고민 중입니다. 회색AWS 가 아직 EOS 일정을 공개하지 않은 신버전 또는 Oracle 처럼 별도 채널로 일정이 나오는 엔진 에 해당합니다.

화면에 보이는 정보

화면은 두 묶음으로 나뉘어 있습니다.

  • 위험 인스턴스 Top 10: 남은 일수가 가장 적은 인스턴스 10개를 한 표에 모아 둡니다. 지금 가장 급한 게 무엇인지 한눈에 잡힙니다.
  • 버전별 EOS 현황: 같은 버전을 쓰는 인스턴스를 묶어서 해당 버전을 운영 중인 인스턴스 수, 만료까지 남은 일수, Extended Support 일정 을 표시합니다. MySQL 8.0.28 을 쓰는 인스턴스가 우리 운영에 몇 개 있는지 같은 질문에 바로 답이 나옵니다.

메인 대시보드의 인스턴스 EOS 관리 패널 (1편 hero 사진의 4색 박스) 도 이 화면의 요약입니다. 빨강 / 주황 / 노랑 / 초록 각 색상의 인스턴스 개수가 한눈에 보이고, 박스를 누르면 이 EOS 화면으로 이동합니다.

매주 월요일 자동 갱신

이 화면에 표시되는 EOS 날짜는 매주 월요일 새벽에 자동으로 한 번씩 갱신됩니다. AWS 가 공식 문서로 공개하는 RDS 엔진별 지원 일정 페이지를 포털이 직접 들여다보고 새 정보를 가져옵니다. 지원하는 엔진은 다섯 가지입니다.

  • MySQL
  • Aurora MySQL
  • PostgreSQL
  • Aurora PostgreSQL
  • MariaDB

Oracle 은 빠져 있습니다. Oracle 의 지원 일정이 AWS 가 아닌 Oracle 본사 의 공식 문서에 있어서 파싱 경로가 다르고, 우리가 운영하는 Oracle 인스턴스 수가 많지 않아 우선순위에서 뒤로 미뤘습니다. 이쪽은 AWS 공식 문서가 아닌 별도 입력 으로 처리해 두었고, 화면에서는 회색 (정보 없음) 으로 표시되거나 수동으로 등록한 일정 이 보입니다.

자동 갱신은 매번 AWS 문서 페이지가 응답하지 않거나 표 구조가 살짝 바뀌는 경우에 대비해서 직전에 받아 둔 정보를 그대로 보존 합니다. AWS 문서가 잠시 흔들려도 EOS 화면 자체는 직전 일정 으로 계속 동작하고, DBA 가 “오, EOS 일정이 갑자기 안 보이네!” 라며 당황할 일이 없도록 했습니다. 그리고 긴급한 일정이 알려진 경우엔 JSON 파일을 직접 편집 해서 새 일정을 즉시 반영할 수도 있게 해 두었습니다.

DB 별 Release Note Crawling

자동 갱신이 AWS 문서를 파싱하는 부분을 발췌하면, 날짜 포맷을 다루는 핵심 로직은 이렇게 생겼습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
DATE_PATTERNS = [
    ("%d %B %Y",  r"\d{1,2}\s+[A-Za-z]+\s+\d{4}"),     # 14 November 2025
    ("%B %d, %Y", r"[A-Za-z]+\s+\d{1,2},\s*\d{4}"),    # November 14, 2025
    ("%Y-%m-%d",  r"\d{4}-\d{2}-\d{2}"),                # 2025-11-14
    ("%m/%d/%Y",  r"\d{1,2}/\d{1,2}/\d{4}"),            # 11/14/2025
    ("%B %Y",     r"[A-Za-z]+\s+\d{4}"),                # November 2025 → 말일 처리
]

def parse_date(text: str) -> date | None:
    text = text.strip()
    if not text or re.match(r'^(n/a|tbd|to be determined|-+)$', text, re.IGNORECASE):
        return None
    for fmt, pattern in DATE_PATTERNS:
        m = re.search(pattern, text)
        if m:
            try:
                d = datetime.strptime(m.group(), fmt).date()
                if fmt == "%B %Y":
                    last_day = calendar.monthrange(d.year, d.month)[1]
                    d = d.replace(day=last_day)
                return d
            except ValueError:
                continue
    return None

AWS 는 같은 EOS 일정을 14 November 2025, November 14, 2025, 2025-11-14 같은 여러 포맷으로 표기합니다. 다섯 가지 정규식을 순서대로 시도해서 첫 번째 매칭을 쓰는 방식이고, November 2025 처럼 일자가 빠진 표기는 해당 월의 마지막 날을 자동으로 채웁니다.

마이너 / 메이저 두 가지 시점

DB 엔진 버전은 보통 마이너 (예: MySQL 8.0.32)메이저 (예: MySQL 8.0) 두 가지 시점에서 EOS 일정이 다릅니다. 마이너 버전은 몇 달 단위로 빠르게 EOS 가 도는 편이고, 메이저 버전은 몇 년 단위로 도는 게 일반적입니다. AWS RDS 는 마이너 자동 업그레이드 옵션이 있어서 마이너 EOS 가 임박해도 비교적 부드럽게 처리되지만, 메이저는 직접 계획해서 업그레이드 해야 하는 영역이라 시야가 다릅니다.

화면에서는 두 시점을 나란히 보여 줍니다. 한 인스턴스가 마이너는 빨강 인데 메이저는 초록 이면 마이너 자동 업그레이드만 적용하면 된다 는 판단이 가능합니다. 두 시점이 모두 빨강이면 메이저 업그레이드 계획 까지 필요한 케이스입니다.

마이너버전 & 메이저버전

화면에서 두 시점을 나란히 보여 주는 백엔드 로직의 발췌입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
eos_key = extract_eos_key(inst.engine, inst.engine_version)
minor_ver = None
major_ver = None

if eos_key:
    # 마이너 정확 매칭
    res = await db.execute(
        select(EosVersion).where(
            and_(EosVersion.engine_name == inst.engine,
                 EosVersion.version_string == eos_key,
                 EosVersion.version_level == "minor")
        )
    )
    minor_ver = res.scalar_one_or_none()

    # 메이저 버전 조회 (항상 수행)
    major_key = eos_key.rsplit(".", 1)[0] if "." in eos_key else eos_key
    res = await db.execute(
        select(EosVersion).where(
            and_(EosVersion.engine_name == inst.engine,
                 EosVersion.version_string == major_key,
                 EosVersion.version_level == "major")
        )
    )
    major_ver = res.scalar_one_or_none()

# 유효 EOS = 마이너 우선 (마이너 없으면 메이저)
effective_ver = minor_ver or major_ver

마이너와 메이저를 둘 다 조회한 뒤, 마지막 한 줄 effective_ver = minor_ver or major_ver마이너 우선, 없으면 메이저 폴백 규칙이 결정됩니다. UI 에서 두 시점 나란히 보이는 것이 이 한 줄에서 갈리는 구조입니다.

정기점검 보고서

DBA 운영에서 해야 하는 걸 알지만 자꾸 미루게 되는 작업이 있습니다. 지난 한 달 운영 보고서를 정리해서 고객사에 전달하는 일입니다. 이벤트 카운트, CPU 평균과 최댓값, 메모리·스토리지 추이, Top SQL, Wait Event, 백업 현황을 직접 모으고 표로 정리하고 PDF 로 출력하는 일이 한 사람당 서너 시간 씩 듭니다. 인스턴스가 30개 고객사 100여 대인 환경에서 매월 그 작업을 손으로 하기는 사실상 불가능에 가까웠습니다.

포털의 정기 점검 메뉴는 이 작업을 한 번의 조회 로 끝낼 수 있게 합니다. 고객사를 고르고, 점검 기간을 고르고, 조회 버튼을 누르면 지난 한 달 보고서 가 한 화면에 자동으로 합성되어 나옵니다. (사실 이 부분은 크리티컬한 장애가 발생하지 않은 고객사에 한해서 Claude API 를 통해 메일 자동발송까지의 과정을 자동화하는 고민을 진행 중인 영역입니다.)

전월 비교

DB 운영 보고서를 쓰다 보면 지난달 평균 CPU 가 얼마였더라 가 매번 다음으로 미루게 되는 질문이 됩니다. 답을 찾으려면 옛 보고서를 펴거나 CloudWatch 콘솔에서 기간을 한 달 전으로 다시 잡고 다시 그래프를 보고 메모해야 합니다. 그래서 보통 당월 숫자만 적고 전월 대비 는 빠지는 보고서가 됩니다.

이걸 자동 으로 해결하려고, 사용자가 점검 기간을 3월 1일 ~ 3월 27일 로 선택하면 포털은 자동으로 2월 1일 ~ 2월 27일 의 같은 데이터를 같이 가져와서 나란히 표시 합니다.

  • CW 메트릭의 평균·최대·최소 → 당월 / 전월 / 변화율 한 행
  • DB Load → 당월 평균 / 전월 평균 / 변화율 한 행
  • Top SQL → 당월 SQL 옆에 전월 동일 SQL 의 Load 가 같이 표시되고, 전월에는 없던 SQL 에는 신규 배지
  • CW 월간 추이 차트 → 당월은 실선, 전월은 점선 으로 겹쳐서 한 차트에 표시

신규 배지를 판별하는 로직은 정기점검 보고서의 Top SQL 비교 부분에 있습니다.

1
2
3
4
5
6
7
8
9
10
11
prev_top5 = set(sorted(sql_p, key=lambda s: sql_p[s]["load"], reverse=True)[:5])
items = []
for sid in sorted(sql_t, key=lambda s: sql_t[s]["load"], reverse=True)[:5]:
    tl = round(sql_t[sid]["load"], 3)
    pl = round(sql_p[sid]["load"], 3) if sid in sql_p else None
    items.append(InspectionTopSqlItem(
        sql_id=sid, sql_text=sql_t[sid].get("text"),
        current_load=tl, prev_load=pl,
        change_pct=round((tl - pl) / pl * 100, 1) if pl else None,
        is_new=sid not in prev_top5,
    ))

is_new=sid not in prev_top5 한 줄이 전월에 없던 SQL 을 잡아냅니다. 전월 Top 5 의 SQL ID 를 set 으로 만들어 두고, 당월 SQL 이 거기에 없으면 신규 가 됩니다.

여기에 작은 디테일 하나가 들어 있습니다. 점검 기간이 3월 31일 까지인데 전월 2월 에는 31일이 없으면 어떻게 매핑하느냐 입니다. 포털은 그 달의 마지막 날 로 자동 매핑합니다. 3/31 → 2/28 (윤년이면 2/29) 식입니다. 사람이 2월 31일이 없어서 어쩌지 라고 잠깐이라도 멈출 일이 없도록 한 처리입니다.

그 월말 매핑을 처리하는 함수는 세 줄입니다.

1
2
3
def _prev_month(d: date) -> date:
    y, m = (d.year - 1, 12) if d.month == 1 else (d.year, d.month - 1)
    return date(y, m, min(d.day, _calendar.monthrange(y, m)[1]))

min(d.day, monthrange(y, m)[1])해당 월에 그 날짜가 존재하면 그대로, 없으면 그 달의 마지막 날 로 잘라 줍니다.

주차별 분할

같은 지난 한 달 안에서도 어느 주에 이상이 있었는지 가 보고서 가독성에 큰 영향을 줍니다. 3월 평균 CPU 60% 라고만 적으면 전반적으로 그랬다 처럼 들리지만, 3주차에 평균 85% 까지 올라갔다 라고 적으면 그 주에 무슨 일이 있었구나 가 명확해집니다.

그래서 정기점검 보고서는 4개 주차로 분할 한 표를 같이 보여 줍니다. 1주차는 1~7일, 2주차는 8~14일, 3주차는 15~21일, 4주차는 22~말일. 이벤트 건수도 주차별로 따로 카운트하고, CW 메트릭 6종도 주차별 평균·최대·최소 를 각자 칸에 표시합니다. 임계치를 초과한 칸에는 색이 들어가서, 어느 주의 어떤 지표가 어떻게 안 좋았는지 가 한눈에 보입니다.

DBA 종합 의견 + PDF 출력

자동으로 모인 숫자만으로는 보고서가 안 끝납니다. DBA 의 종합 의견 이 마지막에 들어가야 사람이 검토한 보고서 가 됩니다. 화면 최하단에 텍스트 입력란이 있고, 거기에 점검 결과, 권고사항, 그 다음 달에 할 조치 같은 사람의 해석 을 적으면, 그게 그대로 PDF 의 마지막 섹션으로 들어갑니다.

PDF 출력은 화면 우상단 PDF 출력 버튼 한 번입니다. 브라우저 인쇄 다이얼로그가 열리고 PDF 로 저장 을 누르면 됩니다. 인쇄 전용 레이아웃 이 자동으로 적용되어서, 포털의 사이드바·헤더는 빠지고 표지 + 본문 15섹션 만 깔끔하게 정리된 PDF 가 나옵니다.

손으로 매월 서너 시간씩 들여서 만들던 보고서가 조회 → 의견 작성 → PDF 출력 세 동작으로 끝나는 셈입니다. 그리고 그 안에 전월 비교가 자동으로 들어가니, 사람이 손으로 쓸 때는 보통 빠지던 추세 정보 가 매월 보고서마다 자연스럽게 포함됩니다.

마무리

EOS 추적과 정기점검 보고서는 두 가지 모두 원래 사람이 하기로 되어 있던 일 입니다. 다만 매주 / 매월 한 번 만 하면 되는 일이라서, 바쁘면 다음으로 미루기 쉬운 종류였습니다. 그래서 결국 안 하게 되고, 결국 EOS 임박 직전에야 알게 되거나, 정기점검 보고서가 매월 일관성 없이 작성되는 결과가 따라옵니다.

이 두 영역을 자동화하는 게 시간을 줄이는 것 이상이라고 느꼈습니다. 정기적으로 같은 형태로 쌓이는 데이터전월 / 분기 / 연간 비교 의 기반이 되고, 그게 결국 운영의 시야 를 만들어 줍니다. 1편에서 4편까지의 모든 작업이 이 비교 가능한 시야 를 만들기 위한 준비 작업이었다는 생각도 듭니다.

다섯 편의 시리즈가 여기서 마무리됩니다. 1편의 처음부터 다시 만든 이유 부터 시작해서, 2편의 9개 잡과 알림 매커니즘, 3편의 세 가지 모니터링 화면, 4편의 알림 다듬기와 운영 도구, 그리고 5편의 정기 자동화 까지 한 바퀴를 돌았습니다. 다섯 주 동안 만든 시스템을 다섯 편의 글로 풀어 보니, 직접 만들고 직접 쓰는 시스템 의 의외의 즐거움이 있었다는 걸 글을 쓰면서 한 번 더 느꼈습니다. 읽어 주신 분들께도 직접 만들어 써볼 만한 가치를 창출해 내시는 데에 영감이 닿았으면 좋겠습니다. 저도 DBA 로서 AI Agent 를 도구 삼아 운영의 빈틈을 하나씩 메워 나가는 시도를 멈추지 않으려 합니다. 만들 수 있는 것이 아직 많이 남아 있다는 감각이, 이 시리즈를 쓰면서 오히려 더 선명해졌습니다.

×
×
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.