InnoDB Metrics 활용: information_schema.INNODB_METRICS와 운영 대시보드
MySQL InnoDB Metrics의 계측 구조와 counter·gauge 해석, 수집·정규화·경보 설계 및 Aurora MySQL 운영 차이를 정리한다.
InnoDB Metrics 활용: information_schema.INNODB_METRICS와 운영 대시보드
MySQL 장애 대응에서는 “현재 연결이 몇 개인가”뿐 아니라 InnoDB 내부에서 잠금 충돌, Buffer Pool 읽기, redo 진행, purge 지연이 어떻게 변하고 있는지를 알아야 한다. information_schema.INNODB_METRICS는 이러한 내부 계측값을 한 테이블에서 조회하게 해 주는 관측 지점이다. 다만 이 테이블의 숫자는 그 자체로 장애 판정 기준이 아니다. 누적 counter와 현재 상태값을 구분하고, 활성화 상태와 reset 경계를 기록하며, 짧은 구간의 변화율을 계산해야 운영 가능한 지표가 된다.
이 글은 MySQL 8.0 이상을 기준으로 InnoDB Metrics의 구조를 설명하고, 읽기 전용 진단 SQL과 대시보드 설계 원칙을 제시한다. 특정 수치를 모든 시스템에 적용하는 고정 임계값은 만들지 않는다. 대신 지표가 어느 내부 경로에서 만들어지는지, 어떤 분모로 정규화해야 하는지, 이상 신호를 어떤 상세 자료로 좁혀야 하는지를 다룬다.
1. InnoDB Metrics가 필요한 이유
SHOW GLOBAL STATUS와 Performance Schema만으로도 많은 운영 상태를 볼 수 있다. 그럼에도 InnoDB Metrics가 유용한 이유는 스토리지 엔진 내부 활동을 lock, transaction, buffer, log, file_system 같은 하위 영역별로 정리해 제공하기 때문이다.
관측 계층은 서로 대체 관계가 아니라 역할 분담 관계다.
| 관측 계층 | 주로 답하는 질문 | 대표 자료 |
|---|---|---|
| 서버 상태 | 서버 전체 요청·연결·처리량이 어떻게 변했는가 | performance_schema.global_status, SHOW GLOBAL STATUS |
| InnoDB 내부 상태 | 잠금·트랜잭션·Buffer Pool·redo·purge 내부 활동이 어떻게 변했는가 | information_schema.INNODB_METRICS |
| 현재 실행과 대기 | 지금 어떤 thread와 SQL이 실행 또는 대기 중인가 | performance_schema.threads, statement·wait·lock 테이블 |
| SQL 패턴 | 어느 digest가 시간과 행 조사를 소비했는가 | events_statements_summary_by_digest, sys schema |
| 상세 원인 | 어떤 transaction·record·index·계획이 병목을 만드는가 | INNODB_TRX, data_locks, data_lock_waits, EXPLAIN |
따라서 InnoDB Metrics는 탐지와 범위 축소에 적합하다. 예를 들어 deadlock counter의 변화율이 증가했다면 이를 경보 신호로 사용하고, 실제 피해 SQL과 잠금 순서는 애플리케이션 오류, SHOW ENGINE INNODB STATUS, Performance Schema 자료로 내려가 확인한다.
2. 계측값이 대시보드가 되기까지
InnoDB 내부 코드 경로는 작업이 일어날 때 관련 metric을 갱신한다. 조회 시점의 INNODB_METRICS는 이 계측 상태를 표 형태로 노출한다. 운영 수집기는 일정 간격으로 snapshot을 저장하고, counter는 이전 표본과의 차이로 rate를 만들며, gauge 성격의 값은 현재값과 지속 시간을 보존한다.
flowchart LR
A[SQL과 background 작업] --> B[InnoDB 내부 경로]
B --> C[lock / trx / buffer / log / purge 계측]
C --> D[information_schema.INNODB_METRICS]
D --> E[주기 수집기]
E --> F[시계열 저장소]
F --> G[rate·ratio·gauge 계산]
G --> H[대시보드와 경보]
H --> I[Performance Schema·로그·EXPLAIN 상세 진단]
J[재시작·failover·metric reset] --> E
E --> K[baseline 분리]
이 흐름에서 자주 발생하는 실수는 네 가지다.
- 누적값을 현재 초당 발생량으로 표시한다.
- 서버 재시작이나 failover 전후 counter를 그대로 연결한다.
- 비활성 metric의
0을 “사건이 없었다”로 해석한다. - 하나의 metric만 보고 설정 변경이나 인덱스 추가를 결정한다.
대시보드는 원본 숫자를 보기 좋게 배치하는 화면이 아니라, metric의 수명 주기와 의미를 보존하는 해석 계층이어야 한다.
3. 먼저 스키마와 활성화 상태를 확인한다
MySQL minor version과 배포판에 따라 제공되는 metric 집합은 달라질 수 있다. 이름을 대시보드에 하드코딩하기 전에 대상 서버에서 목록, subsystem, type, status를 inventory로 수집해야 한다. 다음 SQL은 전체 규모와 subsystem별 활성화 상태를 읽기 전용으로 확인한다.
SELECT VERSION() AS mysql_version;
SELECT COUNT(*) AS total_metrics,
SUM(STATUS = 'enabled') AS enabled_metrics,
SUM(STATUS = 'disabled') AS disabled_metrics
FROM information_schema.INNODB_METRICS;
SELECT SUBSYSTEM,
COUNT(*) AS metric_count,
SUM(STATUS = 'enabled') AS enabled_count
FROM information_schema.INNODB_METRICS
GROUP BY SUBSYSTEM
ORDER BY metric_count DESC, SUBSYSTEM
LIMIT 12;
실행 결과(MySQL 8.0.x):
다음은 기본 설정으로 시작한 임시 MySQL 8.0 검증 인스턴스의 결과다. metric 수와 활성화 상태는 버전과 설정에 따라 달라질 수 있다.
mysql> SELECT VERSION() AS mysql_version;
+---------------+
| mysql_version |
+---------------+
| 8.0.46 |
+---------------+
1 row in set (0.00 sec)
mysql> SELECT COUNT(*) AS total_metrics,
-> SUM(STATUS = 'enabled') AS enabled_metrics,
-> SUM(STATUS = 'disabled') AS disabled_metrics
-> FROM information_schema.INNODB_METRICS;
+---------------+-----------------+------------------+
| total_metrics | enabled_metrics | disabled_metrics |
+---------------+-----------------+------------------+
| 314 | 74 | 240 |
+---------------+-----------------+------------------+
1 row in set (0.00 sec)
mysql> SELECT SUBSYSTEM, COUNT(*) AS metric_count,
-> SUM(STATUS = 'enabled') AS enabled_count
-> FROM information_schema.INNODB_METRICS
-> GROUP BY SUBSYSTEM
-> ORDER BY metric_count DESC, SUBSYSTEM
-> LIMIT 12;
+---------------------+--------------+---------------+
| SUBSYSTEM | metric_count | enabled_count |
+---------------------+--------------+---------------+
| buffer | 76 | 18 |
| log | 53 | 3 |
| buffer_page_io | 37 | 0 |
| server | 23 | 14 |
| lock | 22 | 13 |
| transaction | 16 | 1 |
| os | 9 | 7 |
| purge | 9 | 0 |
| adaptive_hash_index | 8 | 2 |
| change_buffer | 8 | 8 |
| dml | 8 | 7 |
| cpu | 6 | 0 |
+---------------------+--------------+---------------+
12 rows in set (0.01 sec)
STATUS='disabled'인 항목은 값이 0이더라도 “사건이 없었다”는 증거가 아니다. 먼저 해당 metric이 언제 활성화되었는지, 수집 구간 전체에서 활성 상태였는지 확인해야 한다. 반대로 모든 metric을 상시 활성화하는 것도 정답은 아니다. 계측 범위가 넓어질수록 CPU와 메모리 비용, 해석해야 할 시계열 수, dashboard cardinality가 늘어난다.
3.1 주요 열의 역할
INNODB_METRICS를 운영에 사용할 때는 NAME과 COUNT만 저장하지 말고 다음 metadata도 이해해야 한다.
| 열 | 운영 의미 |
|---|---|
NAME |
metric의 고유 이름이다. 수집 키로 사용하되 버전별 존재 여부를 검증한다. |
SUBSYSTEM |
lock, transaction, buffer 등 기능 영역이다. 대시보드 행과 담당 runbook을 나누는 기준이 된다. |
TYPE |
metric의 집계 성격을 해석하는 단서다. 이름만 보고 counter/gauge를 단정하지 않는다. |
STATUS |
현재 계측 활성화 여부다. 비활성 구간의 0을 정상값으로 처리하지 않는다. |
COUNT |
현재 노출되는 값이다. metric 의미에 따라 누적량 또는 상태값으로 해석한다. |
COUNT_RESET |
마지막 reset 이후 기준값을 확인하는 데 사용한다. reset 경계를 모르면 rate가 왜곡된다. |
TIME_ENABLED, TIME_DISABLED |
계측 수명 주기와 빈 관측 구간을 판별하는 데 사용한다. |
TIME_ELAPSED |
활성화 이후 경과 시간과 rate 계산의 보조 자료다. 실제 수집 간격은 수집 시각으로 계산하는 편이 안전하다. |
COMMENT |
metric 정의를 확인하는 1차 설명이다. 이름을 직관적으로만 번역해 의미를 확정하지 않는다. |
4. 운영 후보 metric을 좁혀 확인하는 SQL
다음 조회는 잠금, purge, Buffer Pool 영역에서 자주 살펴보는 후보를 제한된 열로 확인한다. metric이 존재하는지, 활성화되었는지, 값이 어떤 형태로 노출되는지를 함께 본다.
SELECT NAME,
SUBSYSTEM,
TYPE,
STATUS,
COUNT,
COUNT_RESET,
TIME_ELAPSED
FROM information_schema.INNODB_METRICS
WHERE NAME IN (
'lock_deadlocks',
'lock_timeouts',
'trx_rseg_history_len',
'buffer_pool_read_requests',
'buffer_pool_reads'
)
ORDER BY NAME;
실행 결과(MySQL 8.0.x):
mysql> SELECT NAME,
-> SUBSYSTEM,
-> TYPE,
-> STATUS,
-> COUNT,
-> COUNT_RESET,
-> TIME_ELAPSED
-> FROM information_schema.INNODB_METRICS
-> WHERE NAME IN (
-> 'lock_deadlocks',
-> 'lock_timeouts',
-> 'trx_rseg_history_len',
-> 'buffer_pool_read_requests',
-> 'buffer_pool_reads'
-> )
-> ORDER BY NAME;
+---------------------------+-------------+----------------+---------+-------+-------------+--------------+
| NAME | SUBSYSTEM | TYPE | STATUS | COUNT | COUNT_RESET | TIME_ELAPSED |
+---------------------------+-------------+----------------+---------+-------+-------------+--------------+
| buffer_pool_reads | buffer | status_counter | enabled | 1003 | 1003 | 5 |
| buffer_pool_read_requests | buffer | status_counter | enabled | 15276 | 15276 | 5 |
| lock_deadlocks | lock | counter | enabled | 0 | 0 | 5 |
| lock_timeouts | lock | counter | enabled | 0 | 0 | 5 |
| trx_rseg_history_len | transaction | value | enabled | 5 | 5 | 5 |
+---------------------------+-------------+----------------+---------+-------+-------------+--------------+
5 rows in set (0.00 sec)
이 다섯 항목도 동일한 방식으로 해석하면 안 된다.
lock_deadlocks,lock_timeouts는 누적 사건 수의 변화량과 발생률을 본다.buffer_pool_read_requests,buffer_pool_reads는 두 counter의 구간 delta로 논리 읽기 대비 물리 읽기 비율을 계산할 수 있다.trx_rseg_history_len은 시점의 backlog 성격으로 해석하며, 바이트나 undo row 수로 단정하지 않는다.COUNT_RESET과TIME_ELAPSED는 reset·활성화 경계를 확인하는 보조 정보다.
trx_rseg_history_len이 증가했다고 곧바로 purge thread 수를 늘려서는 안 된다. 오래된 consistent read, 큰 트랜잭션, 지속적인 변경량, purge 처리 여력, I/O 압력을 함께 봐야 한다. 또한 오래된 reader가 종료되어 purge 가능 경계가 열렸더라도 값이 즉시 감소한다는 보장은 없다.
5. counter, gauge, 파생 비율을 분리한다
5.1 누적 counter는 두 시점의 차이로 본다
누적 counter C를 시각 t1, t2에 수집했다면 다음처럼 계산한다.
delta_C = C(t2) - C(t1)
rate_C = delta_C / (t2 - t1의 실제 초)
다음 조건이면 해당 delta를 버리고 새 baseline을 시작한다.
C(t2) < C(t1)이다.- 서버 identity, 시작 시각, 역할 또는 process가 바뀌었다.
- metric의
STATUS가 수집 구간 중 변경되었다. - reset 명령이 실행되었거나
COUNT_RESET기준이 바뀌었다. - 수집 공백이 너무 길어 구간 평균이 운영 의미를 잃었다.
deadlock은 delta(lock_deadlocks)를 분당 또는 초당 rate로 만들 수 있다. 그러나 트래픽이 크게 다른 시스템을 비교하려면 transaction commit 수나 업무 요청 수로 한 번 더 정규화하는 것이 유용하다.
deadlocks_per_1000_transactions
= 1000 × delta(lock_deadlocks) / delta(committed_transactions)
분모가 0이거나 너무 작을 때 비율을 만들지 않아야 한다. 절대 발생량과 정규화 비율을 함께 표시하면 저부하 시간의 불안정한 비율과 고부하 시간의 실제 피해 규모를 구분하기 쉽다.
5.2 gauge 성격의 값은 현재값과 지속 시간을 본다
backlog나 현재 보유량을 나타내는 값은 단순 delta가 아니라 다음 관점으로 저장한다.
- 현재값
- 구간 최대값과 평균값
- 정상 baseline 대비 편차
- 특정 수준 이상이 지속된 시간
- workload와 처리 용량의 동시 변화
예를 들어 history list가 잠깐 증가했다가 회복되는 것은 batch 처리 중 자연스러운 현상일 수 있다. 반면 업무 변경량이 평소와 같은데 수십 분 동안 계속 상승하면 오래된 Read View나 purge 처리 지연을 조사할 근거가 된다.
5.3 ratio는 반드시 같은 구간의 delta로 계산한다
Buffer Pool의 논리 읽기 요청 대비 storage read 비율을 다음처럼 계산할 수 있다.
buffer_pool_read_miss_pct
= 100 × delta(buffer_pool_reads)
/ NULLIF(delta(buffer_pool_read_requests), 0)
서버 시작 이후 누적값끼리 나눈 장기 평균은 최근 5분의 변화가 아니다. 캐시가 충분히 예열된 오래된 서버와 재시작 직후 서버를 비교하면 누적 평균은 더 크게 왜곡된다. 대시보드에서는 원본 counter, 구간 delta, 파생 비율, reset 상태를 함께 추적한다.
6. 한 번의 snapshot을 안전하게 수집하는 예제
다음 SQL은 다섯 metric을 한 행으로 피벗한다. 이 결과는 수집기 입력에 적합하지만, 여기서 계산한 read_miss_pct_since_reset은 현재 구간 비율이 아니라 reset 이후 누적 비율이다. 실제 대시보드는 연속 snapshot을 저장한 뒤 두 표본의 delta로 비율을 다시 계산해야 한다.
WITH metric_snapshot AS (
SELECT NAME, COUNT
FROM information_schema.INNODB_METRICS
WHERE NAME IN (
'lock_deadlocks',
'lock_timeouts',
'trx_rseg_history_len',
'buffer_pool_read_requests',
'buffer_pool_reads'
)
), pivoted AS (
SELECT
MAX(CASE WHEN NAME = 'lock_deadlocks' THEN COUNT END) AS deadlocks_total,
MAX(CASE WHEN NAME = 'lock_timeouts' THEN COUNT END) AS lock_timeouts_total,
MAX(CASE WHEN NAME = 'trx_rseg_history_len' THEN COUNT END) AS history_list_length,
MAX(CASE WHEN NAME = 'buffer_pool_read_requests' THEN COUNT END) AS logical_read_requests_total,
MAX(CASE WHEN NAME = 'buffer_pool_reads' THEN COUNT END) AS physical_reads_total
FROM metric_snapshot
)
SELECT UTC_TIMESTAMP() AS observed_at,
deadlocks_total,
lock_timeouts_total,
history_list_length,
logical_read_requests_total,
physical_reads_total,
ROUND(
100 * physical_reads_total
/ NULLIF(logical_read_requests_total, 0),
4
) AS read_miss_pct_since_reset
FROM pivoted;
실행 결과(MySQL 8.0.x):
다음 값은 임시 검증 인스턴스를 시작한 직후의 한 번의 snapshot이다. 시각과 누적값은 실행마다 달라지며 운영 임계값으로 사용하지 않는다.
mysql> WITH metric_snapshot AS (...), pivoted AS (...)
-> SELECT UTC_TIMESTAMP() AS observed_at,
-> deadlocks_total, lock_timeouts_total, history_list_length,
-> logical_read_requests_total, physical_reads_total,
-> ROUND(100 * physical_reads_total
-> / NULLIF(logical_read_requests_total, 0), 4)
-> AS read_miss_pct_since_reset
-> FROM pivoted;
+---------------------+-----------------+---------------------+---------------------+-----------------------------+----------------------+---------------------------+
| observed_at | deadlocks_total | lock_timeouts_total | history_list_length | logical_read_requests_total | physical_reads_total | read_miss_pct_since_reset |
+---------------------+-----------------+---------------------+---------------------+-----------------------------+----------------------+---------------------------+
| 2026-08-24 00:04:53 | 0 | 0 | 5 | 15276 | 1003 | 6.5659 |
+---------------------+-----------------+---------------------+---------------------+-----------------------------+----------------------+---------------------------+
1 row in set (0.00 sec)
observed_at은 DB 서버의 UTC 시각이며 수집기의 실제 수신 시각과 지연을 함께 기록하는 것이 좋다. 여러 인스턴스를 수집한다면 결과 외부에 다음 label을 붙인다.
service
cluster
instance
role
engine_version
server_start_identity
collector_version
고객 ID, SQL 원문, session ID처럼 cardinality가 크거나 민감한 값은 metric label로 넣지 않는다. 시계열 비용이 폭증하고 운영 정보가 외부 모니터링 시스템에 불필요하게 노출될 수 있다.
7. metric 활성화와 reset은 변경 작업이다
일부 InnoDB metric은 기본으로 활성화되고, 일부는 필요할 때 명시적으로 활성화한다. MySQL은 innodb_monitor_enable, innodb_monitor_disable, innodb_monitor_reset, innodb_monitor_reset_all 계열 설정을 제공한다. 그러나 운영 서버에서 이 값을 바꾸는 것은 단순 조회가 아니다.
다음은 명령 형태를 설명하기 위한 예시 구조이며, 공개 운영 환경에 그대로 실행하기 전에 대상 버전의 허용 module 이름, 현재 설정, 계측 비용, 변경 절차를 확인해야 한다.
SET GLOBAL innodb_monitor_enable = '<검증된 metric 또는 module 이름>';
SET GLOBAL innodb_monitor_disable = '<검증된 metric 또는 module 이름>';
SET GLOBAL innodb_monitor_reset = '<검증된 metric 또는 module 이름>';
변경 절차는 다음 순서를 권장한다.
- 대상 metric 이름과 module 범위를 현재 서버의
INNODB_METRICS에서 확인한다. - 이미 활성화된 metric인지 확인한다.
- 대시보드와 수집기가 활성화 시각·reset 경계를 기록할 수 있는지 확인한다.
- 부하가 낮은 구간에서 제한된 범위만 활성화한다.
- CPU 사용률, latency, 계측 table 크기와 수집 시간을 비교한다.
- 필요성이 끝나면 원래 상태로 되돌리고 변경 시각을 기록한다.
all을 편의상 상시 활성화하는 접근은 피한다. 필요 지표를 선별하고, Performance Schema 계측 비용 관리와 동일하게 관측 자체의 비용을 측정해야 한다. reset은 incident 증거와 장기 기준선을 지우므로 공동 대시보드에서 임의로 실행하지 않는다.
8. 운영 대시보드의 계층 구조
좋은 대시보드는 metric 이름을 subsystem별로 나열하는 데서 끝나지 않는다. “현재 서비스 영향이 있는가”, “어느 내부 자원이 밀리는가”, “어디로 drill-down해야 하는가”를 화면 순서로 표현해야 한다.
8.1 1단: 수집과 기준선의 신뢰성
가장 위에는 다음 상태를 둔다.
- 수집 성공 여부와 마지막 성공 시각
- DB instance identity와 writer/reader 역할
- MySQL engine version과 시작 시각 또는
Uptime - metric 활성화 상태 변화
- counter reset 또는 failover 감지
- 수집 간격과 지연
이 행이 없으면 아래 그래프의 0이 “정상”인지 “수집 실패”인지 구분할 수 없다.
8.2 2단: 서비스 영향 신호
다음에는 사용자가 체감할 가능성이 큰 신호를 둔다.
- transaction 처리량과 오류율
- query latency와
Threads_running - lock wait timeout·deadlock 발생률
- connection 사용량과 실패
- replica lag 또는 commit 지연
InnoDB Metrics만으로 이 행을 완성하려 하지 않는다. 애플리케이션 SLI, Global Status, Performance Schema, replication 자료를 조합한다.
8.3 3단: InnoDB 내부 압력
세 번째 행에서 내부 원인을 영역별로 분리한다.
| 영역 | 표시할 관점 | 함께 볼 자료 |
|---|---|---|
| 잠금 | deadlock·timeout의 rate, 현재 wait 지속 시간 | data_lock_waits, data_locks, 오류 1205/1213 |
| 트랜잭션·purge | history backlog의 현재값·증가 기울기 | INNODB_TRX, 오래된 Read View, DML rate |
| Buffer Pool | 논리 요청과 물리 읽기의 구간 delta, dirty/free page 방향 | working set, storage latency, workload 변화 |
| redo·checkpoint | LSN 진행과 checkpoint 여유의 방향 | write throughput, fsync latency, log capacity |
| background I/O | flush/read/write 활동의 rate | 디스크 queue, latency, CPU, dirty page |
8.4 4단: 원인 SQL과 객체
마지막에는 바로 이동할 drill-down 링크나 runbook을 둔다.
- 현재 blocking/waiting transaction 관계
- total latency와 rows examined가 큰 statement digest
- table·index I/O wait
SHOW ENGINE INNODB STATUS의 최근 deadlock- 대표 SQL의
EXPLAIN또는 안전한 환경의EXPLAIN ANALYZE - 최근 배포, schema 변경, batch 실행 기록
이 구조는 “빨간 그래프를 보고 설정을 올리는” 대응을 막고, 영향 확인에서 원인 SQL까지 일관된 조사 경로를 제공한다.
9. 경보는 절대 임계값보다 증상 조합으로 만든다
모든 MySQL에 적용되는 history_list_length > N 같은 임계값은 만들기 어렵다. transaction 크기, 변경률, hardware, 스토리지, SLO가 서로 다르기 때문이다. 초기에는 baseline과 증상 조합을 사용한다.
| 경보 조합 | 가능한 해석 | 다음 조사 |
|---|---|---|
| deadlock rate 증가 + 1213 오류 증가 | transaction 접근 순서 또는 경쟁 범위 변화 | 최근 deadlock graph, digest, 배포 변경 |
| lock timeout rate 증가 + 현재 wait 증가 | 장기 transaction 또는 hot row 가능성 | data_lock_waits, transaction age, blocking SQL |
| history backlog 지속 상승 + 오래된 transaction 존재 | Read View 또는 큰 transaction이 purge 경계를 제한할 가능성 | INNODB_TRX, DML rate, purge 진행 |
| physical read 비율 상승 + query latency 상승 | working set 변화, scan 증가, cache 냉각 가능성 | digest rows examined, Buffer Pool 상태, storage latency |
| redo/checkpoint 여유 감소 + write latency 상승 | write burst 또는 flush 처리 여력 부족 가능성 | log·flush metric, I/O latency, batch 작업 |
| metric 전체가 갑자기 0 + collector gap | 정상화가 아니라 수집·활성화·reset 문제 가능성 | collector log, status, instance identity |
경보 조건에는 가능한 경우 다음 요소를 함께 둔다.
- 최소 지속 시간
- 최소 traffic 조건
- baseline 대비 변화율
- application error 또는 latency 조건
- reset/failover 억제 구간
- writer/reader 역할
예를 들어 deadlock은 한 번도 없어야 한다는 목표를 둘 수 있지만, 한 건 발생 즉시 모든 시간대에 긴급 호출을 보내는 것이 최선은 아니다. 결제처럼 피해가 큰 transaction인지, 애플리케이션이 안전하게 재시도했는지, 짧은 시간에 반복되는지에 따라 severity를 나눈다.
10. InnoDB Metrics에서 상세 원인으로 내려가는 절차
10.1 잠금과 deadlock
lock_deadlocks,lock_timeouts의 구간 delta가 실제로 증가했는지 확인한다.- 애플리케이션의 오류 1213, 1205 발생 시각과 맞춘다.
- 현재 대기라면
performance_schema.data_lock_waits와data_locks를 확인한다. - deadlock이라면
SHOW ENGINE INNODB STATUS의 최근 graph에서 transaction, SQL, index, lock mode를 확인한다. - transaction의 row 접근 순서, 범위 조건, 누락된 인덱스, 사용자 입력 대기 여부를 검토한다.
- 재시도는 전체 transaction 단위이며 멱등성을 보장하도록 설계한다.
counter는 deadlock이 있었다는 사실을 알려 줄 뿐 어느 transaction이 victim이었는지 보존하지 않는다. 사건 세부 정보는 별도의 로그와 추적 체계가 필요하다.
10.2 purge와 history backlog
trx_rseg_history_len의 현재값뿐 아니라 증가 기울기와 지속 시간을 본다.information_schema.INNODB_TRX에서 오래된 transaction과trx_rows_modified를 확인한다.- 변경이 없는 읽기 전용 transaction도 오래된 Read View를 유지할 수 있음을 고려한다.
- DML 처리량, undo 생성량, purge 관련 활동, storage latency를 함께 본다.
- 원인 session 종료는 영향과 rollback 비용을 평가한 뒤 수행한다.
- transaction 종료 뒤 purge 회복이 지연될 수 있으므로 즉시 하락을 성공 조건으로 삼지 않는다.
10.3 Buffer Pool 읽기 변화
- 같은 구간의
buffer_pool_reads와buffer_pool_read_requestsdelta를 구한다. - MySQL 재시작·failover·scale 이벤트로 cache가 냉각되었는지 확인한다.
- query mix와 rows examined가 변했는지 digest에서 확인한다.
- 새 index 또는 full scan이 working set을 밀어냈는지 조사한다.
- storage read latency와 throughput을 함께 본다.
- Buffer Pool을 키우기 전에 host memory, 동시성, 다른 cache와의 총량을 계산한다.
높은 hit ratio만으로 정상이라고 판단할 수 없다. 전체 논리 읽기가 매우 크면 작은 miss 비율도 상당한 physical I/O가 될 수 있다. 따라서 비율과 절대 read rate를 함께 표시해야 한다.
11. 수집기와 시계열 저장소 설계
11.1 수집 주기
수집 주기는 incident 탐지 속도와 DB 조회 비용 사이의 절충이다. 일반적인 운영 dashboard는 10~60초 구간에서 시작할 수 있지만 workload와 SLO에 맞게 검증해야 한다. 고빈도 수집이 필요하면 조회 시간과 CPU 비용을 측정하고, 모든 metric을 매번 읽기보다 필요한 이름만 제한한다.
수집기는 다음을 지켜야 한다.
- query timeout을 짧고 명시적으로 둔다.
- 실패를 0으로 저장하지 않고 missing sample로 기록한다.
- DB 서버 시각과 collector 수신 시각을 모두 기록한다.
- 동일 target에 수집기가 중복 실행되지 않도록 한다.
- counter 감소와 instance identity 변경을 reset으로 처리한다.
- metric이 사라지거나 새로 생기면 version inventory 경보를 만든다.
11.2 원본과 파생값을 분리한다
저장소에는 원본 COUNT, STATUS, 관측 시각을 먼저 보존한다. rate와 ratio는 query 또는 recording rule로 만든다. 그래야 수집기 계산 오류를 수정하거나 다른 구간으로 재계산할 수 있다.
권장 자료 모델은 다음과 같다.
raw_innodb_metric{
service,
cluster,
instance,
role,
engine_version,
metric_name,
subsystem,
status
} value
COMMENT 전체를 label로 넣지 않는다. 길고 변경 가능하며 cardinality 비용을 늘린다. metric 설명은 별도 metadata catalog로 관리한다.
11.3 reset과 failover 표기
그래프에는 재시작·failover·reset annotation을 표시한다. counter rate 함수가 감소를 자동 reset으로 처리하더라도, 역할이 바뀐 reader와 writer의 시계열을 하나로 섞으면 업무 의미가 달라진다. cluster-level 합계와 instance-level 원본을 분리하고 writer role을 명시한다.
12. Aurora MySQL에서 달라지는 운영 해석
Aurora MySQL은 MySQL 호환 계층을 제공하지만 compute instance와 분산 storage 계층이 분리되어 있다. 따라서 Community MySQL에서 익숙한 InnoDB metric을 그대로 물리 디스크 상태로 번역하면 안 된다.
12.1 InnoDB Metrics의 역할
Aurora MySQL에서도 engine version과 parameter 정책이 허용하는 범위에서 InnoDB 관측값을 활용할 수 있다. 그러나 제공 metric, 기본 활성화 상태, 내부 구현의 의미는 대상 Aurora MySQL 버전에서 직접 확인해야 한다. Community MySQL 8.0 검증 결과를 Aurora의 물리 I/O 구조에 그대로 적용하지 않는다.
12.2 CloudWatch·Performance Insights와 결합한다
Aurora 운영에서는 다음 계층을 결합한다.
- InnoDB Metrics: engine 내부의 lock, transaction, cache, purge 방향
- Performance Insights 또는 Database Insights: DB load, wait, SQL 차원
- CloudWatch: instance CPU·memory·connection과 Aurora storage·replication 관련 지표
- 애플리케이션 telemetry: 요청 latency, 오류, retry, 업무 transaction 결과
예를 들어 Buffer Pool physical read 증가를 곧바로 로컬 디스크 병목으로 단정하지 않는다. Aurora storage 지표, DB load wait, query pattern, cache warm-up 상태를 함께 확인한다.
12.3 failover와 scaling 경계
writer failover가 일어나면 instance identity와 role이 바뀌고 counter baseline이 달라질 수 있다. Aurora Serverless v2의 scaling이나 인스턴스 교체도 latency와 cache 상태에 영향을 줄 수 있다. 대시보드는 다음을 annotation으로 남겨야 한다.
- failover 시각과 이전·새 writer
- engine version 또는 parameter 변경
- instance class·capacity 변화
- 재시작과 maintenance
- 대규모 배포·batch·schema 변경
cluster 이름만으로 시계열을 이어 붙이지 말고 instance와 role 차원을 보존해야 reset을 정상화로 오인하지 않는다.
13. 흔한 오해와 실패 패턴
13.1 COUNT=0이면 사건이 없었다
metric이 disabled였거나 방금 reset되었을 수 있다. STATUS, 활성화 시각, 수집 공백을 함께 확인한다.
13.2 raw counter를 그래프에 그대로 표시한다
누적 counter는 대부분 계속 증가하므로 장애 구간이 보이지 않는다. raw 값은 증거로 보존하되 운영 화면은 rate와 구간 delta를 기본으로 표시한다.
13.3 모든 metric에 동일한 임계값을 적용한다
counter, gauge, backlog, high-water mark의 의미가 다르다. metric별 데이터 사전을 만들고 계산식·단위·reset 정책·runbook을 명시한다.
13.4 높은 Buffer Pool hit ratio면 성능이 정상이다
작은 miss 비율도 매우 큰 logical read workload에서는 많은 physical read를 만들 수 있다. latency, 절대 read rate, rows examined, storage 상태를 함께 본다.
13.5 history backlog 숫자만 보고 session을 종료한다
오래된 transaction이 원인인지, 지속적인 DML이 원인인지, purge 처리 여력이 부족한지 먼저 구분해야 한다. 강제 종료는 큰 rollback과 추가 I/O를 유발할 수 있다.
13.6 deadlock counter만으로 원인 SQL을 찾는다
counter에는 graph와 victim SQL이 없다. 최근 deadlock 자료, 오류 로그, statement telemetry를 별도로 수집해야 한다.
13.7 reset으로 그래프를 깨끗하게 만든다
reset은 문제 해결이 아니라 관측 기준선 삭제다. incident 중에는 특히 증거를 보존하고, reset이 꼭 필요하면 변경 승인과 시각을 기록한다.
13.8 계측 비용을 측정하지 않는다
관측 기능도 서버 자원을 사용한다. 활성화 전후 query latency, CPU, 메모리, 수집 query 시간을 비교하고 필요한 범위만 유지한다.
14. 운영 체크리스트
도입 전
수집기
대시보드와 경보
장애 대응
- 잠금은
data_lock_waits·data_locks
15. 결론
information_schema.INNODB_METRICS는 InnoDB 내부 활동을 운영 시계열로 연결하는 강력한 관측 지점이다. 그러나 신뢰할 수 있는 대시보드는 metric 이름과 숫자를 나열해서 만들어지지 않는다. 활성화 상태, counter와 gauge의 차이, reset·재시작·failover 경계, 구간 delta와 분모, 상세 진단으로 이어지는 절차를 함께 설계해야 한다.
운영의 기본 흐름은 inventory → raw snapshot → baseline 분리 → rate·ratio 계산 → 증상 조합 경보 → Performance Schema와 로그로 원인 축소다. 다음 기술노트에서는 이러한 engine 내부 지표를 실제 시계열 수집 구조와 연결할 때 필요한 exporter, 보존 주기, recording rule, 경보 평가 구간을 더 구체적으로 다룰 수 있다.