MySQL 운영 대시보드: 핵심 지표와 알림 임계값
대시보드가 필요한 이유
MySQL 장애는 대부분 예고 없이 오지 않는다. 버퍼 풀 히트율이 서서히 떨어지고, Threads_running이 점점 쌓이고, 복제 지연이 수십 초로 늘어나다 연결 폭주로 이어지는 패턴이 반복된다. 대시보드는 이 전조 증상을 잡아내는 도구다.
운영 대시보드의 목표는 두 가지다.
- 이상 징후를 사람이 인지하기 전에 알림으로 전달한다.
- 장애 발생 시 근거 있는 진단을 위한 타임라인을 제공한다.
모니터링 스택 아키텍처
Prometheus + mysqld_exporter 조합이 사실상 표준이다. mysqld_exporter는 SHOW GLOBAL STATUS, SHOW GLOBAL VARIABLES, SHOW REPLICA STATUS, performance_schema 등을 스크레이핑해 200개 이상의 메트릭을 Prometheus 텍스트 포맷으로 노출한다.
지표 범주와 핵심 항목
1. 연결 지표 (Connection)
연결 포화가 임박하면 새 연결이 Too many connections 오류로 거부된다. Threads_running은 포화도의 가장 민감한 신호다.
| 지표 | 의미 |
|---|---|
Threads_connected | 현재 열린 연결 수 |
Threads_running | 실제로 쿼리 실행 중인 스레드 수 |
Max_used_connections | 서버 시작 이래 최대 동시 연결 수 |
Connection_errors_max_connections | 최대 연결 수 초과로 거부된 횟수 (0이어야 함) |
-- 연결 상태 빠른 조회
SELECT VARIABLE_NAME, VARIABLE_VALUE
FROM performance_schema.global_status
WHERE VARIABLE_NAME IN (
'Threads_connected', 'Threads_running',
'Max_used_connections', 'Connection_errors_max_connections'
);
-- 현재 연결 포화도 (%)
SELECT
ROUND(
(SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Threads_connected')
/ (SELECT VARIABLE_VALUE FROM performance_schema.global_variables WHERE VARIABLE_NAME = 'max_connections')
* 100, 1
) AS connection_saturation_pct;# PromQL: 연결 포화도
mysql_global_status_threads_connected
/ mysql_global_variables_max_connections
# PromQL: 실행 중 스레드
mysql_global_status_threads_running2. 쿼리 처리량 지표 (Query Throughput)
-- QPS 추이용 기준값 (snapshot 두 번 찍어서 차분 계산)
SELECT VARIABLE_NAME, VARIABLE_VALUE
FROM performance_schema.global_status
WHERE VARIABLE_NAME IN (
'Questions', 'Slow_queries',
'Com_select', 'Com_insert', 'Com_update', 'Com_delete'
);# PromQL: 초당 쿼리 수
rate(mysql_global_status_questions[5m])
# PromQL: 슬로우 쿼리 발생률
rate(mysql_global_status_slow_queries[5m])
# PromQL: 읽기/쓰기 비율
rate(mysql_global_status_commands_total{command="select"}[5m])
/ rate(mysql_global_status_questions[5m])슬로우 쿼리의 rate가 평상시 대비 급증하면 인덱스 누락, 잠금 경합, 데이터 증가 등을 의심한다. long_query_time은 기본값 10초가 너무 관대하므로 1~2초로 낮춰 운영하는 것이 일반적이다.
3. InnoDB 버퍼 풀 지표 (Buffer Pool)
버퍼 풀 히트율은 MySQL 성능 지표 중 가장 직접적으로 인스턴스 건강도를 나타낸다.
히트율 공식: 1 − Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests
- 99% 이상: 정상. 작업 세트가 메모리에 잘 올라와 있다.
- 95~99%: 주의. 버퍼 풀 크기 증설 검토.
- 95% 미만: 긴급. 디스크 I/O 급증, 쿼리 지연 심화 구간.
SELECT
s1.VARIABLE_VALUE AS pool_reads,
s2.VARIABLE_VALUE AS read_requests,
ROUND(
(1 - s1.VARIABLE_VALUE / s2.VARIABLE_VALUE) * 100, 2
) AS hit_rate_pct
FROM
(SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_reads') s1,
(SELECT VARIABLE_VALUE FROM performance_schema.global_status WHERE VARIABLE_NAME = 'Innodb_buffer_pool_read_requests') s2;
-- 더티 페이지 비율 (< 75% 권장)
SELECT
ROUND(
pages_dirty / pages_data * 100, 1
) AS dirty_pct
FROM information_schema.INNODB_BUFFER_POOL_STATS;# PromQL: 버퍼 풀 히트율
1 - rate(mysql_global_status_innodb_buffer_pool_reads[5m])
/ rate(mysql_global_status_innodb_buffer_pool_read_requests[5m])
# PromQL: 더티 페이지 비율
mysql_global_status_innodb_buffer_pool_pages_dirty
/ mysql_global_status_innodb_buffer_pool_pages_total4. InnoDB Redo Log 지표
SELECT VARIABLE_NAME, VARIABLE_VALUE
FROM performance_schema.global_status
WHERE VARIABLE_NAME IN (
'Innodb_os_log_written', -- redo log 쓰기 바이트 (rate)
'Innodb_log_waits', -- 로그 버퍼 부족 대기 (0이어야 함)
'Innodb_log_write_requests', -- 로그 쓰기 요청 수
'Innodb_log_writes' -- 실제 디스크 쓰기 수
);Innodb_log_waits가 0이 아니면 innodb_log_buffer_size가 너무 작은 것이다. 기본값 16MB를 64MB 이상으로 늘리면 개선된다.
5. 잠금 지표 (Row Lock)
SELECT VARIABLE_NAME, VARIABLE_VALUE
FROM performance_schema.global_status
WHERE VARIABLE_NAME IN (
'Innodb_row_lock_current_waits', -- 현재 대기 중인 행 잠금 수
'Innodb_row_lock_time_avg', -- 평균 대기 시간 (ms)
'Innodb_row_lock_waits' -- 잠금 대기 발생 누적 횟수
);
-- 현재 잠금 대기 세부 정보 (MySQL 8.0+)
SELECT
r.trx_id AS waiting_trx,
r.trx_mysql_thread_id AS waiting_thread,
b.trx_id AS blocking_trx,
b.trx_mysql_thread_id AS blocking_thread,
b.trx_query AS blocking_query,
TIMESTAMPDIFF(SECOND, r.trx_wait_started, NOW()) AS wait_seconds
FROM information_schema.INNODB_TRX r
JOIN information_schema.INNODB_TRX b
ON r.trx_wait_started IS NOT NULL
AND b.trx_id = (
SELECT blocking_trx_id
FROM performance_schema.data_lock_waits
WHERE requesting_engine_transaction_id = r.trx_id
LIMIT 1
)
ORDER BY wait_seconds DESC;# PromQL: 현재 행 잠금 대기 수
mysql_global_status_innodb_row_lock_current_waits
# PromQL: 평균 행 잠금 대기 시간 (ms)
mysql_global_status_innodb_row_lock_time_avg6. 복제 지표 (Replication)
-- Replica에서 실행
SHOW REPLICA STATUS\G
-- 주요 항목:
-- Seconds_Behind_Source: 복제 지연 (초)
-- Replica_SQL_Running: Yes여야 함
-- Replica_IO_Running: Yes여야 함
-- Last_SQL_Errno: 0이어야 함# PromQL: 복제 지연 (collect.heartbeat 또는 SHOW REPLICA STATUS 기반)
mysql_slave_status_seconds_behind_master
# 복제 스레드 실행 여부 (1=정상, 0=중단)
mysql_slave_status_slave_sql_running
mysql_slave_status_slave_io_runningcollect.heartbeat를 활성화하면 binlog 이벤트 기반이 아닌 실제 헤드비트 쓰기/읽기 타임스탬프로 지연을 측정해 더 정확한 lag 값을 얻을 수 있다.
7. 임시 테이블 지표
SELECT VARIABLE_NAME, VARIABLE_VALUE
FROM performance_schema.global_status
WHERE VARIABLE_NAME IN (
'Created_tmp_tables', -- 총 임시 테이블 생성 수
'Created_tmp_disk_tables' -- 디스크 임시 테이블 생성 수
);
-- 디스크 임시 테이블 비율 (< 10% 권장)
-- Created_tmp_disk_tables / Created_tmp_tables디스크 임시 테이블이 많으면 tmp_table_size와 max_heap_table_size를 높이거나, 해당 쿼리에 인덱스를 추가한다.
알림 임계값 기준표
경고 > 80% / 긴급 > 90%
경고 > 30 / 긴급 > 50
0 초과 즉시 알림
경고 < 99% / 긴급 < 95%
경고 > 50% / 긴급 > 75%
> 0 즉시 알림
경고 > 30초 / 긴급 > 300초
0 = 즉시 알림
0 이외 즉시 알림
경고 > 5 / 긴급 > 20
경고 > 50ms / 긴급 > 200ms
평상시 2배 이상 급증
대시보드 구성 권고안
운영 대시보드를 처음 만들 때 가장 흔한 실수는 패널을 너무 많이 넣는 것이다. 한 화면에 30개 패널은 아무것도 안 본 것과 같다. 권고 레이아웃은 5개 행으로 구성한다.
행 1: 가용성 요약 (신호등)
- Primary 복제 스레드 상태 | Replica 지연 | Connection_errors_max_connections | Innodb_log_waits
행 2: 연결 · 처리량
- Threads_running (time series) | 연결 포화도 (gauge) | QPS (time series)
행 3: InnoDB 버퍼 풀
- 히트율 (time series + stat) | 더티 페이지 비율 | buffer pool 사용량
행 4: 잠금 · 느린 쿼리
- row_lock_current_waits | row_lock_time_avg | 슬로우 쿼리 rate
행 5: 복제
- Seconds_Behind_Source (time series, 복수 replica) | IO/SQL Thread 상태Grafana ID 7362(MySQL Overview) 또는 ID 11323(MySQL Exporter Quickstart) 대시보드를 기본으로 불러온 후 위 패널 구조로 정리하면 빠르게 시작할 수 있다.
Alertmanager 규칙 예시
groups:
- name: mysql
rules:
- alert: MySQLBufferPoolHitRateLow
expr: |
1 - rate(mysql_global_status_innodb_buffer_pool_reads[5m])
/ rate(mysql_global_status_innodb_buffer_pool_read_requests[5m]) < 0.95
for: 5m
labels:
severity: critical
annotations:
summary: "MySQL 버퍼 풀 히트율 {{ $value | humanizePercentage }} — 디스크 I/O 급증 가능"
- alert: MySQLConnectionSaturation
expr: |
mysql_global_status_threads_connected
/ mysql_global_variables_max_connections > 0.8
for: 2m
labels:
severity: warning
annotations:
summary: "MySQL 연결 포화도 {{ $value | humanizePercentage }}"
- alert: MySQLReplicationLagHigh
expr: mysql_slave_status_seconds_behind_master > 30
for: 1m
labels:
severity: warning
annotations:
summary: "MySQL 복제 지연 {{ $value }}초"
- alert: MySQLReplicationLagCritical
expr: mysql_slave_status_seconds_behind_master > 300
for: 1m
labels:
severity: critical
annotations:
summary: "MySQL 복제 지연 {{ $value }}초 — 복제 상태 즉시 확인"
- alert: MySQLRowLockWaitsHigh
expr: mysql_global_status_innodb_row_lock_current_waits > 5
for: 2m
labels:
severity: warning
annotations:
summary: "MySQL 행 잠금 대기 {{ $value }}건"
- alert: MySQLInnoDBLogWaits
expr: rate(mysql_global_status_innodb_log_waits[5m]) > 0
for: 1m
labels:
severity: critical
annotations:
summary: "InnoDB 로그 버퍼 대기 발생 — innodb_log_buffer_size 증설 필요"for 절을 두어 일시적 스파이크는 알림을 보내지 않도록 한다. 연결 포화도 같은 지표는 2분, 복제 지연은 1분으로 설정해 대응 속도와 알림 피로도의 균형을 잡는다.
References
- Datadog Blog, "Monitoring MySQL performance metrics": https://www.datadoghq.com/blog/monitoring-mysql-performance-metrics/
- Prometheus mysqld_exporter GitHub: https://github.com/prometheus/mysqld_exporter
- Percona, "MySQL Performance Monitoring: Best Practices": https://www.percona.com/blog/mysql-performance-monitoring-best-practices/
- Sysdig, "Top key metrics for monitoring MySQL": https://www.sysdig.com/blog/mysql-monitoring
- MySQL 8.4 Reference Manual, "Performance Schema Status Variable Tables": https://dev.mysql.com/doc/refman/8.4/en/performance-schema-status-variable-tables.html
- MySQL 8.4 Reference Manual, "InnoDB Metrics Table": https://dev.mysql.com/doc/refman/8.4/en/information-schema-innodb-metrics-table.html
- Grafana Labs, "MySQL Query Performance Troubleshooting Dashboard": https://grafana.com/grafana/dashboards/12630-mysql-query-performance-troubleshooting/
- oneuptime Blog, "How to Monitor MySQL InnoDB Buffer Pool, Slow Query Rate, and Thread State": https://oneuptime.com/blog/post/2026-02-06-mysql-innodb-buffer-pool-slow-query/view