[Monitoring] zabbix 3편: zabbix DB 파티셔닝 적용 가이드

Zabbix를 운영하면서 반드시 마주하게 되면 'DB 부하 및 용량 관리' 문제를 해결하기 위한 DB 파티셔닝(Partitioning)에 대해 알아보겠습니다.

Zabbix는 수천, 수만 개의 아이템 데이터를 실시간으로 수집하여 DB에 저장합니다. 시간이 흐를수록 데이터는 기하급수적으로 쌓이고, 이를 삭제하는 과정에서 시스템 성능이 급격히 저하될 수 있습니다. 이를 우아하게 해결하는 방법이 바로 파티셔닝 입니다.

DB 파티셔닝이 왜 필요하지?

Zabbix에는 Housekeeper라는 프로세스가 있습니다. 설정된 보관 주기(History storage period)가 지는 데이터를 자동으로 삭제해 주는 고마운 존재 입니다.

  • Housekeeper의 한계 : 데이터 삭제시 DELETE쿼리를 사용합니다. 데이터가 많을수록 인덱스 재구성 및 트랜젝션 로그 발생으로 인해 DB에 큰 부하를 줍니다.
  • 파티셔닝의 장점 : 데이터를 날짜별 ""으로 나누어 저장합니다. 삭제 기한이 지나면 DELETE대신 DROP PARTITION 명령을 사용합니다. 이는 테이블 전체를 건드리지 않고 파일 자체를 삭제하는 방식이라 DB부하가 거의 없으며 속도가 압도적으로 빠릅니다.

Zabbix 주요 테이블을 이해해 봅시다.

파티셔닝을 적용하기 전, 어떤 테이블이 데이터를 많이 사용하는지 알아야 합니다.

테이블 분류

주요 테이블명

저장 데이터 유형

관리 방식

History (상세 데이터)

history, history_uint, history_str, history_log, history_text

CPU 사용률, 로그 메시지 수집된 원시 (Raw Data)

일별(Daily) 파티셔닝 권장

Trends (통계 데이터)

trends, trends_uint

시간당 최소/최대/평균값 집계 데이터

월별(Monthly) 파티셔닝 권장


단계별 파티셔닝 적용 방법

주의! 파티셔닝 작업은 테이블 구조를 변경하는 대규모 작업입니다. 반드시 Zabbix Server를 중단하고 진행하세요.

systemctl stop zabbix-server

기존 데이터 날짜 확인

먼저 각 테이블에 저장된 가장 오래된 데이터의 날짜를 확인하여 파티션 시작점을 잡습니다.

SELECT FROM_UNIXTIME(MIN(clock)) FROM `history`;

일별 파티셔닝 적용(History 테이블 예시)

history 테이블을 현재 날짜를 기준으로 파티셔닝합니다. (아래 쿼리는 예시 날짜이므로 실제 환경에 맞춰 조정하세요.)

ALTER TABLE `history` PARTITION BY RANGE (clock)
(
    PARTITION p2025_03_11 VALUES LESS THAN (UNIX_TIMESTAMP('2025-03-12 00:00:00')) ENGINE = InnoDB,
    PARTITION p2025_03_12 VALUES LESS THAN (UNIX_TIMESTAMP('2025-03-13 00:00:00')) ENGINE = InnoDB,
    -- ... 중략 ...
    PARTITION p2025_04_11 VALUES LESS THAN (UNIX_TIMESTAMP('2025-04-12 00:00:00')) ENGINE = InnoDB
);

월별 파티셔닝 적용(Trends 테이블 예시)

통계 데이터는 데이터 양이 상대적으로 적으므로 월 단위로 관리 합니다.

ALTER TABLE `trends` PARTITION BY RANGE (clock)
(
    PARTITION p2025_02 VALUES LESS THAN (UNIX_TIMESTAMP('2025-03-01 00:00:00')) ENGINE = InnoDB,
    PARTITION p2025_03 VALUES LESS THAN (UNIX_TIMESTAMP('2025-04-01 00:00:00')) ENGINE = InnoDB
);

파티셔닝 자동화 관리(Bash Script)

매일 수동으로 파티션을 생성할 수는 없겠죠? 아래 스크립트를 활용해 신규 파티션 생성(Add)과 오래된 파티션 삭제(Drop)를 자동화할 수 있습니다.

#!/bin/bash

# set -ex
# 파티션 생성 : 
# - 일별 : 매일 오후 11시에 다음날 파티션 생성 (00 23 * * * root zabbix_db_partitioning.sh add daily) 
# - 월별 : 매월 말일 오후 11시에 다음달 파티션 생성 (00 23 * * * root [ $(date +\%d) = 01 ] && zabbix_db_partitioning.sh add monthly) 
# 파티션 삭제 :
# - 일별 : 매일 오전 00시 이후 실행 되고 현재 일 기준 365일 이전 파티션 삭제 (00 00 * * * root zabbix_db_partitioning.sh drop daily)
# - 월별 : 매월 1일 오전 00시 이후 실행 되고 현재 월 기준 12개월 이전 파티션 삭제(00 00 1 * * root [ $(date +\%d) = 01 ] && zabbix_db_partitioning.sh drop monthly)

DB="zabbix"
MYSQL="mysql"

if [ "$2" == "daily" ]; then
    TABLES="history history_log history_str history_uint history_text"
    KEEP=365
    NEXT=$(date -d "+1 day" +"%Y-%m-%d")
    # NEXT_TIMESTAMP=$(date -d "$NEXT" +%s)
    NEXT_PARTITION="p$(date -d "$NEXT" +"%Y_%m_%d")"
    LESS_THEN=$(date -d "+2 day" +"%Y-%m-%d")
    DROP_DATE=$(date -d "-$KEEP day" +"%Y-%m-%d")
    DROP_PARTITION="p$(date -d "$DROP_DATE" +"%Y_%m_%d")"
elif [ "$2" == "monthly" ]; then
    TABLES="trends trends_uint"
    KEEP=12
    NEXT=$(date -d "+1 month" +"%Y-%m-01")
    # NEXT_TIMESTAMP=$(date -d "$NEXT" +%s)
    NEXT_PARTITION="p$(date -d "$NEXT" +"%Y_%m")"
    LESS_THEN=$(date -d "+2 month" +"%Y-%m-01")
    DROP_DATE=$(date -d "-$(($KEEP - 1)) month" +"%Y-%m-01")
    DROP_PARTITION="p$(date -d "$DROP_DATE" +"%Y_%m")"
else
    echo "Usage: $0 {daily|monthly}"
    exit 1
fi

for table in $TABLES
do
  if [ "$1" == "add" ]; then
    # 파티션 생성 SQL
    ADD_PARTITION_SQL="ALTER TABLE $DB.$table ADD PARTITION (PARTITION $NEXT_PARTITION VALUES LESS THAN (UNIX_TIMESTAMP('${LESS_THEN}')));"
    # echo $ADD_PARTITION_SQL
    echo "Adding partition: $NEXT_PARTITION"
    $MYSQL $DB -e "$ADD_PARTITION_SQL"

    VALIDATION_QUERY="SELECT TABLE_SCHEMA, TABLE_NAME, PARTITION_NAME, PARTITION_ORDINAL_POSITION, TABLE_ROWS FROM information_schema.PARTITIONS WHERE TABLE_NAME = '${table}' AND PARTITION_NAME = '${NEXT_PARTITION}';"
    $MYSQL $DB -e "$VALIDATION_QUERY" > /root/logs/${table}_$(date +%Y-%m-%d)_validation.log
 elif [ "$1" == "drop" ]; then
    # 파티션 삭제 SQL
    DROP_PARTITION_SQL="ALTER TABLE $DB.$table DROP PARTITION $DROP_PARTITION;"
    # echo $DROP_PARTITION_SQL
    echo "Dropping old partition: $DROP_PARTITION"
    $MYSQL $DB -e "$DROP_PARTITION_SQL"
  else
    echo "Usage: $0 {add|drop} {daily|monthly}"
    exit 1
  fi
done

zabbix_db_partitioning.sh

Crontab에 등록하여 주기적으로 실행하세요.

  • 매일 23:00 : 다음날 파티션 미리 생성
  • 매일 00:01 : 보관 주기가 지난 과거 파티션 삭제
00 23 * * * /path/zabbix_db_partitioning.sh add daily
01 00 * * * /path/zabbix_db_partitioning.sh drop daily

00 23 * * * [ $(date +\%d) = 01 ] && /path/zabbix_db_partitioning.sh add monthly
01 00 * * * [ $(date +\%d) = 01 ] && /path/zabbix_db_partitioning.sh drop monthly

마무리 설정 : Housekeeper 비활성화

파티셔닝을 완료 했다면, 더 이상 Zabbix 내부의 Housekeeper가 historytrends 데이터를 건드를 필요가 없습니다.

  1. Zabbix 웹 GUI 접속 : Administration > Housekeeping
  2. HistoryTrendsEnable internal housekeeping 을 체크 해제합니다.
  3. 이제 DB관리는 파티셔닝 스크립트가 전담하게 됩니다.

요약하며

DB 파티셔닝은 초기 설정이 다소 번거로울 수 있지만, 대규모 모니터링 환경에서 DB안정성과 성능을 보장하는 유일한 방법입니다. Zabbix 서버가 느려지거나 DB용량 부족으로 고민중이라면 지금 바로 적용해 보세요!

Tip : 작업 전 DB백업은 필수 입니다. 예상치 못한 오류에 대비하세요.

Read more

매번 헷갈리는 RPO와 RTO

RPO와 RTO는 재해 복구(DR) 계획을 세울때 가장 핵심이 되는 지표 입니다. 용어가 비슷해서 헷갈리기 쉽지만, 어느 시점의 데이터로 돌아갈 것인가(RPO) 와 얼마나 빨리 복구할 것인가(RTO)의 차이로 이해하시면 쉽습니다. 백업 정책 예를 통해 살펴 봅시다. 운영중인 데이터베이스 서버가 있다고 가정합니다. 백업 정책은 아래와 같습니다. * 일 4회(6시간

By Onlab

[Monitoring] zabbix 2편: zabbix agent 설치하기

zabbix 서버는 zabbix agent, SNMP 등을 통해 원격 컴퓨터를 모니터링 합니다. 앞서 zabbix 서버 설치에 대해 다루어 보았는데 이번에는 zabbix-agent 설치에 대해서 다루어 보겠습니다. agent는 두가지 버전을 제공합니다. zabbix-agent와 zabbix-agent2 로 나뉘어 있습니다. agent2가 차세대 버전쯤으로 생각하면 됩니다. 자세한 내용은 아래 링크를 참고하세요. 15 Agent vs agent 2 comparisonDocs 이

By Onlab

[Monitoring] zabbix 1편: zabbix server 설치하기

엔터프라이즈급 오픈소스 모니터링 솔루션인 zabbix를 설치하고 초기 설정 하는 방법을 알아보겠습니다. 서버 대수가 늘어날수록 서비스 상태를 일일이 확인하는 것은 불가능에 가깝습니다. zabbix를 이용하면 서버의 CPU, 메모리, 트레픽 상태는 물론 장애 발생 시 실시간 알림까지 받을 수 있는 스마트한 환경을 구축할 수 있습니다. zabbix 란 무엇인가요? zabbix는 네트워크 서비스, 서버, 하드웨어

By Onlab

[Tip]터미널에서 AWS Profile 전환을 효율적으로 하는 방법

개요 aws cli를 사용할 때 profile 기능을 이용하면 여러개의 자격 증명을 등록하고 스위칭 해서 효율적으로 사용할 수 있다. default 프로파일을 사용하는 것은 human error 를 초래할 수 있어 권장되지 않아 cli를 사용할때 매번 --profile 옵션을 추가해야 하는 번거로움이 발생한다. 이 같은 번거로움을 조금이라도 회피해 보고자 합니다. AWS CLI의 default profile

By Onlab