

# Amazon Aurora MySQL 데이터베이스 성능 문제 해결
<a name="aurora-mysql-troubleshooting"></a>

이 주제에서는 몇 가지 일반적인 Aurora MySQL DB 성능 문제와 문제를 해결하거나 정보를 수집하여 이러한 문제를 신속하게 해결하는 방법을 중점적으로 다룹니다. 데이터베이스 성능은 다음 두 가지 범주로 나뉩니다.
+ 서버 성능 - 전체 데이터베이스 서버가 느리게 실행됩니다.
+ 쿼리 성능 - 하나 이상의 쿼리를 실행하는 데 시간이 더 오래 걸립니다.

## AWS 모니터링 옵션
<a name="aurora-mysql-troubleshooting.monitoring"></a>

문제 해결에 도움이 되는 다음 AWS 모니터링 옵션을 사용하는 것이 좋습니다.
+ Amazon CloudWatch – Amazon CloudWatch는 AWS 리소스와 AWS에서 실행 중인 애플리케이션을 실시간으로 모니터링합니다. CloudWatch를 사용하여 리소스 및 애플리케이션에 대해 측정할 수 있는 변수인 지표를 수집하고 추적할 수 있습니다. 자세한 내용은 [Amazon CloudWatch란 무엇인가요?](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/WhatIsCloudWatch.html)를 참조하세요.

  AWS Management Console에서 DB 인스턴스에 대한 모든 시스템 지표 및 프로세스 정보를 볼 수 있습니다. 일반, 느린, 감사, 오류 로그 데이터를 Amazon CloudWatch Logs의 로그 그룹에 게시하도록 Aurora MySQL DB 클러스터를 구성할 수 있습니다. 이를 통해 추세를 확인하고, 호스트가 영향을 받는 경우 로그를 유지 관리하고, 이상 또는 변경 사항을 쉽게 식별할 수 있도록 '정상' 성능에 대한 기준을 만들 수 있습니다. 자세한 내용은 [Amazon CloudWatch Logs에 Amazon Aurora MySQL 로그 게시](AuroraMySQL.Integrating.CloudWatch.md) 단원을 참조하십시오.
+ 향상된 모니터링 - Aurora MySQL 데이터베이스에 대해 Amazon CloudWatch 지표를 추가로 활성화하려면 향상된 모니터링을 켜세요. Aurora DB 클러스터를 생성하거나 수정할 때 **향상된 모니터링 활성화**를 선택합니다. 이를 통해 Aurora는 성능 지표를 CloudWatch에 게시할 수 있습니다. 사용 가능한 주요 지표로는 CPU 사용량, 데이터베이스 연결, 스토리지 사용량, 쿼리 지연 시간 등이 있습니다. 이러한 지표는 성능 병목 현상을 파악하는 데 도움이 됩니다.

  DB 인스턴스에 대해 전송되는 정보의 양은 확장 모니터링에 대해 정의된 세부 단위에 직접적으로 비례합니다. 모니터링 간격이 작을수록 OS 측정치가 더 자주 보고되고 모니터링 비용이 증가합니다. 비용을 관리하려면 AWS 계정의 여러 인스턴스에 대해 서로 다른 세부 단위를 설정합니다. 인스턴스 생성 시 기본 시간 세부 단위는 60초입니다. 자세한 내용은 [Enhanced Monitoring 비용](USER_Monitoring.OS.md#USER_Monitoring.OS.cost) 단원을 참조하십시오.
+ 성능 개선 도우미 - 모든 데이터베이스 직접 호출 지표를 볼 수 있습니다. 여기에는 DB 잠금, 대기, 처리된 행 수가 포함되며, 이 모든 정보를 문제 해결에 사용할 수 있습니다. Aurora DB 클러스터를 만들거나 수정할 때 **성능 개선 도우미 활성화**를 선택합니다. 기본적으로 성능 개선 도우미의 데이터 보존 기간은 7일이지만 장기적인 성능 추세를 분석하도록 사용자 지정할 수 있습니다. 7일 넘게 보존하려면 유료 티어로 업그레이드해야 합니다. 자세한 내용은 [성능 개선 도우미 요금](https://aws.amazon.com/rds/performance-insights/pricing/)을 참조하세요. 각 Aurora DB 인스턴스의 데이터 보존 기간을 개별적으로 설정할 수 있습니다. 자세한 내용은 [성능 개선 도우미를 통한 Amazon Aurora 모니터링](USER_PerfInsights.md) 단원을 참조하십시오.

## Aurora MySQL 데이터베이스 성능 문제의 가장 일반적인 원인
<a name="aurora-mysql-troubleshooting-common"></a>

다음 단계를 사용하여 Aurora MySQL 데이터베이스의 성능 문제를 해결할 수 있습니다. 이러한 단계는 논리적인 조사 순서로 나열되어 있지만 순서대로 따라야 하는 것은 아닙니다. 하나의 발견으로 여러 단계를 건너뛸 수 있으며 일련의 조사 경로가 가능해집니다.

1. [워크로드](aurora-mysql-troubleshooting-workload.md) - 데이터베이스 워크로드를 이해합니다.

1. [로깅](aurora-mysql-troubleshooting-logging.md) - 모든 데이터베이스 로그를 검토합니다.

1. [데이터베이스 연결](mysql-troubleshooting-dbconn.md) - 애플리케이션과 데이터베이스 간의 연결이 안정적인지 확인합니다.

1. [쿼리 성능](aurora-mysql-troubleshooting-query.md) - 쿼리 실행 계획을 검토하여 변경되었는지 확인합니다. 코드 변경으로 인해 계획이 변경될 수 있습니다.

# Aurora MySQL 데이터베이스의 워크로드 문제 해결
<a name="aurora-mysql-troubleshooting-workload"></a>

데이터베이스 워크로드는 읽기 및 쓰기로 볼 수 있습니다. '일반적인' 데이터베이스 워크로드를 이해하면 변화하는 수요에 맞춰 쿼리와 데이터베이스 서버를 튜닝할 수 있습니다. 성능이 변경될 수 있는 이유는 다양하므로 먼저 무엇이 변경되었는지 파악해야 합니다.
+ 메이저 버전 또는 마이너 버전 업그레이드가 있었나요?

  메이저 버전 업그레이드에는 쿼리 실행 계획을 변경할 수 있는 엔진 코드, 특히 최적화 프로그램의 변경 사항이 포함됩니다. 데이터베이스 버전, 특히 메이저 버전을 업그레이드할 때는 데이터베이스 워크로드를 분석하고 그에 따라 튜닝하는 것이 매우 중요합니다. 튜닝에는 테스트 결과에 따라 쿼리를 최적화 및 재작성하거나 파라미터 설정을 추가 및 업데이트하는 작업이 포함될 수 있습니다. 영향을 미치는 원인을 이해하면 해당 영역에 집중할 수 있습니다.

  자세한 내용은 MySQL 설명서의 [What is new in MySQL 8.0](https://dev.mysql.com/doc/refman/8.0/en/mysql-nutshell.html)과 [Server and status variables and options added, deprecated, or removed in MySQL 8.0](https://dev.mysql.com/doc/refman/8.0/en/added-deprecated-removed.html) 및 [Aurora MySQL 버전 2와 Aurora MySQL 버전 3의 비교](AuroraMySQL.Compare-v2-v3.md) 섹션을 참조하세요.
+ 처리 중인 데이터(행 수)가 증가했나요?
+ 동시에 실행되는 쿼리가 더 많나요?
+ 스키마 또는 데이터베이스 변경 사항이 있나요?
+ 코드 결함이나 수정이 있었나요?

**Contents**
+ [인스턴스 호스트 지표](#ams-workload-instance)
  + [CPU 사용량](#ams-workload-cpu)
  + [메모리 사용량](#ams-workload-instance-memory)
  + [네트워크 처리량](#ams-workload-network)
+ [데이터베이스 지표](#ams-workload-db)
+ [Aurora MySQL 데이터베이스의 메모리 사용량 문제 해결](ams-workload-memory.md)
  + [예제 1: 지속적인 높은 메모리 사용량](ams-workload-memory.md#ams-workload-memory.example1)
  + [예제 2: 일시적인 메모리 급증](ams-workload-memory.md#ams-workload-memory.example2)
  + [예시 3: 여유 메모리가 지속적으로 삭제되고 회수되지 않음](ams-workload-memory.md#ams-workload-memory.example3)
+ [Aurora MySQL 데이터베이스의 메모리 부족 문제 해결](AuroraMySQLOOM.md)

## 인스턴스 호스트 지표
<a name="ams-workload-instance"></a>

CPU, 메모리, 네트워크 활동과 같은 인스턴스 호스트 지표를 모니터링하면 워크로드 변경 여부를 이해하는 데 도움이 됩니다. 워크로드 변화를 이해하는 데는 두 가지 주요 개념이 있습니다.
+ 사용률 - CPU 또는 디스크와 같은 디바이스의 사용량. 시간 기반 또는 용량 기반일 수 있습니다.
  + 시간 기반 - 특정 관찰 기간 동안 리소스가 많이 사용된 시간
  + 용량 기반 - 시스템 또는 구성 요소가 제공할 수 있는 처리량(용량의 백분율)
+ 포화도 - 리소스에 처리할 수 있는 것보다 더 많은 작업이 필요한 정도. 용량 기준 사용량이 100%에 도달하면 추가 작업을 처리할 수 없으므로 대기열에 추가되어야 합니다.

### CPU 사용량
<a name="ams-workload-cpu"></a>

다음 도구를 사용하여 CPU 사용량 및 포화도를 파악할 수 있습니다.
+ CloudWatch는 `CPUUtilization` 지표를 제공합니다. 이 수치가 100%에 도달하면 인스턴스가 포화 상태입니다. 하지만 CloudWatch 지표는 1분 단위로 평균을 낸 값이며 세분성이 부족합니다.

  CloudWatch 지표에 대한 자세한 내용은 [Amazon Aurora에 대한 인스턴스 수준 지표](Aurora.AuroraMonitoring.Metrics.md#Aurora.AuroraMySQL.Monitoring.Metrics.instances) 섹션을 참조하세요.
+ 향상된 모니터링은 운영 체제 `top` 명령으로 반환된 지표를 제공합니다. 로드 평균과 다음 CPU 상태를 1초 단위로 보여줍니다.
  + `Idle (%)` = 유휴 시간
  + `IRQ (%)` = 소프트웨어 중단
  + `Nice (%)` = [Niced](https://en.wikipedia.org/wiki/Nice_(Unix)) 우선순위가 있는 프로세스의 Nice 시간
  + `Steal (%)` = 다른 테넌트에게 서비스를 제공하는 데 소요된 시간(가상화 관련)
  + `System (%)` = 시스템 시간
  + `User (%)` = 사용자 시간
  + `Wait (%)` = I/O 대기

  향상된 모니터링 지표에 대한 자세한 내용은 [Aurora​의 지표](USER_Monitoring-Available-OS-Metrics.md#USER_Monitoring-Available-OS-Metrics-RDS) 섹션을 참조하세요.

### 메모리 사용량
<a name="ams-workload-instance-memory"></a>

시스템이 메모리 부족 상태이고 리소스 사용량이 포화 상태에 이르면 페이지 스캔, 페이징, 교체 및 메모리 부족 오류가 많이 발생합니다.

다음 도구를 사용하여 메모리 사용량 및 포화도를 파악할 수 있습니다.

CloudWatch는 일부 OS 캐시와 현재 사용 가능한 메모리를 비워서 회수할 수 있는 메모리 양을 보여주는 `FreeableMemory` 지표를 제공합니다.

CloudWatch 지표에 대한 자세한 내용은 [Amazon Aurora에 대한 인스턴스 수준 지표](Aurora.AuroraMonitoring.Metrics.md#Aurora.AuroraMySQL.Monitoring.Metrics.instances) 섹션을 참조하세요.

향상된 모니터링은 메모리 사용 문제를 식별하는 데 도움이 되는 다음과 같은 지표를 제공합니다.
+ `Buffers (KB)` - 스토리지 디바이스에 쓰기 전에 I/O 요청을 버퍼링하는 데 사용되는 메모리의 양(KB)
+ `Cached (KB)` - 파일 시스템 기반 I/O를 캐시하는 데 사용된 메모리의 양
+ `Free (KB)` - 할당되지 않은 메모리의 양(KB)
+ `Swap` - 캐시됨, 사용할 수 있음, 합계

예를 들어 DB 인스턴스에서 `Swap` 메모리를 사용하는 경우 워크로드의 총 메모리 용량은 현재 인스턴스에서 사용할 수 있는 양보다 큽니다. DB 인스턴스의 크기를 늘리거나 메모리 사용량을 줄이도록 워크로드를 튜닝하는 것이 좋습니다.

향상된 모니터링 지표에 대한 자세한 내용은 [Aurora​의 지표](USER_Monitoring-Available-OS-Metrics.md#USER_Monitoring-Available-OS-Metrics-RDS) 섹션을 참조하세요.

성능 스키마 및 `sys` 스키마를 사용하여 메모리를 사용하는 연결 및 구성 요소를 확인하는 방법에 대한 자세한 내용은 [Aurora MySQL 데이터베이스의 메모리 사용량 문제 해결](ams-workload-memory.md) 섹션을 참조하세요.

### 네트워크 처리량
<a name="ams-workload-network"></a>

CloudWatch는 총 네트워크 처리량에 대해 다음과 같은 지표를 제공하며, 모두 1분 단위로 평균을 낸 값입니다.
+ `NetworkReceiveThroughput` - Aurora DB 클러스터의 각 인스턴스가 클라이언트에서 수신하는 네트워크 처리량
+ `NetworkTransmitThroughput` - Aurora DB 클러스터의 각 인스턴스가 클라이언트로 전송하는 네트워크 처리량
+ `NetworkThroughput` - Aurora DB 클러스터의 각 인스턴스가 클라이언트에서 수신하고 클라이언트로 전송하는 네트워크 처리량
+ `StorageNetworkReceiveThroughput` - DB 클러스터의 각 인스턴스가 Aurora 스토리지 하위 시스템에서 수신하는 네트워크 처리량
+ `StorageNetworkTransmitThroughput` - Aurora DB 클러스터의 각 인스턴스가 Aurora 스토리지 하위 시스템으로 전송하는 네트워크 처리량
+ `StorageNetworkThroughput` - Aurora DB 클러스터의 각 인스턴스가 Aurora 스토리지 하위 시스템과 송수신하는 네트워크 처리량

CloudWatch 지표에 대한 자세한 내용은 [Amazon Aurora에 대한 인스턴스 수준 지표](Aurora.AuroraMonitoring.Metrics.md#Aurora.AuroraMySQL.Monitoring.Metrics.instances) 섹션을 참조하세요.

향상된 모니터링은 `network` 수신(**RX**) 및 전송(**TX**) 그래프를 최대 1초의 세부 단위로 제공합니다.

향상된 모니터링 지표에 대한 자세한 내용은 [Aurora​의 지표](USER_Monitoring-Available-OS-Metrics.md#USER_Monitoring-Available-OS-Metrics-RDS) 섹션을 참조하세요.

## 데이터베이스 지표
<a name="ams-workload-db"></a>

워크로드 변화에 대한 다음 CloudWatch 지표를 살펴보세요.
+ `BlockedTransactions` - 데이터베이스에서 1초마다 차단되는 평균 트랜잭션 수
+ `BufferCacheHitRatio` - 버퍼 캐시에서 처리하는 요청 비율
+ `CommitThroughput` - 초당 커밋 작업의 평균 수
+ `DatabaseConnections` - 데이터베이스 인스턴스에 대한 클라이언트 네트워크 연결 수
+ `Deadlocks` - 데이터베이스 1초마다 발생하는 평균 교착 수
+ `DMLThroughput` - 초당 평균 삽입, 업데이트 및 삭제 수
+ `ResultSetCacheHitRatio` - 쿼리 캐시에서 처리하는 요청 비율
+ `RollbackSegmentHistoryListLength` - 삭제 표시 레코드로 커밋된 트랜잭션을 기록하는 실행 취소 로그
+ `RowLockTime` - InnoDB 테이블에 대한 행 잠금을 획득하는 데 걸린 총 시간
+ `SelectThroughput` - 초당 평균 선택 쿼리 수

CloudWatch 지표에 대한 자세한 내용은 [Amazon Aurora에 대한 인스턴스 수준 지표](Aurora.AuroraMonitoring.Metrics.md#Aurora.AuroraMySQL.Monitoring.Metrics.instances) 섹션을 참조하세요.

워크로드를 검토할 때는 다음 질문을 고려해 보세요.

1. 인스턴스 크기를 8xlarge에서 4xlarge로 줄이거나 db.r5에서 db.r6으로 변경하는 등 최근에 DB 인스턴스 클래스를 변경했나요?

1. 클론을 생성하여 문제를 재현할 수 있나요? 아니면 해당 인스턴스에서만 발생하나요?

1. 서버 리소스 고갈, 높은 CPU 또는 메모리 고갈이 있나요? 그렇다면 추가 하드웨어가 필요할 수 있습니다.

1. 하나 이상의 쿼리가 더 오래 걸리나요?

1. 변경 사항이 업그레이드, 특히 메이저 버전 업그레이드로 인해 발생했나요? 그렇다면 업그레이드 전후 지표를 비교하세요.

1. 리더 DB 인스턴스 수에 변화가 있나요?

1. 일반, 감사 또는 바이너리 로깅을 활성화했나요? 자세한 내용은 [Aurora MySQL 데이터베이스에 대한 로깅](aurora-mysql-troubleshooting-logging.md) 단원을 참조하십시오.

1. 바이너리 로그(binlog) 복제 사용을 활성화, 비활성화 또는 변경나요?

1. 다수의 행 잠금이 있는 장기 실행 트랜잭션이 있나요? InnoDB 기록 목록 길이(HLL)에서 장기 실행 트랜잭션의 징후를 확인하세요.

   자세한 내용은 [InnoDB 기록 목록 길이가 크게 늘어남](proactive-insights.history-list.md) 및 [Amazon Aurora MySQL DB 클러스터에서 SELECT 쿼리가 느리게 실행되는 이유는 무엇인가요?](https://repost.aws/knowledge-center/aurora-mysql-slow-select-query) 블로그 게시물을 참조하세요.

   1. 쓰기 트랜잭션으로 인해 큰 HLL이 발생한 경우 `UNDO` 로그가 누적되고 있다는 의미입니다(정기적으로 정리되지 않음). 대규모 쓰기 트랜잭션의 경우 이 누적이 빠르게 증가할 수 있습니다. MySQL에서는 `UNDO`가 [SYSTEM 테이블스페이스](https://dev.mysql.com/doc/refman/5.7/en/innodb-system-tablespace.html)에 저장됩니다. `SYSTEM` 테이블스페이스는 축소할 수 없습니다. `UNDO` 로그로 인해 `SYSTEM` 테이블스페이스가 몇 GB, 심지어는 몇 TB까지 증가할 수 있습니다. 삭제 후에는 데이터를 논리적으로 백업(덤프)하여 할당된 공간을 해제한 다음 덤프를 새 DB 인스턴스로 가져오세요.

   1. 읽기 트랜잭션(장기 실행 쿼리)으로 인해 큰 HLL이 발생하는 경우 쿼리가 많은 양의 임시 공간을 사용하고 있다는 의미일 수 있습니다. 재부팅하여 임시 공간을 해제하세요. 성능 개선 도우미 DB 지표를 검토하여 `Temp` 섹션의 변경 사항(예: `created_tmp_tables`)이 있는지 확인하세요. 자세한 내용은 [성능 개선 도우미를 통한 Amazon Aurora 모니터링](USER_PerfInsights.md) 단원을 참조하십시오.

1. 장기 실행 트랜잭션을 더 적은 행을 수정하는 더 작은 트랜잭션으로 분할할 수 있나요?

1. 차단된 트랜잭션에 변경 사항이 있거나 교착 상태가 증가했나요? 성능 개선 도우미 DB 지표를 검토하여 `Locks` 섹션의 상태 변수 변경 사항(예: `innodb_row_lock_time`, ` innodb_row_lock_waits`, ` innodb_dead_locks`)이 있는지 확인하세요. 1분 또는 5분의 간격을 사용하세요.

1. 대기 이벤트가 늘어났나요? 1분 또는 5분 간격을 사용하여 성능 개선 도우미의 대기 이벤트와 대기 유형을 검사하세요. 상위 대기 이벤트를 분석하고 이러한 이벤트가 워크로드 변경 또는 데이터베이스 경합과 상관관계가 있는지 확인하세요. 예를 들어, `buf_pool mutex`는 버퍼 풀 경합을 나타냅니다. 자세한 내용은 [대기 이벤트로 Aurora MySQL 튜닝](AuroraMySQL.Managing.Tuning.wait-events.md) 단원을 참조하십시오.

# Aurora MySQL 데이터베이스의 메모리 사용량 문제 해결
<a name="ams-workload-memory"></a>

CloudWatch, 향상된 모니터링 및 성능 개선 도우미는 운영 체제 수준에서 데이터베이스 프로세스에서 사용하는 메모리 양 등의 메모리 사용량에 대한 유용한 개요를 제공하지만, 이러한 메모리 사용량을 유발할 수 있는 엔진 내 연결 또는 구성 요소를 분석할 수는 없습니다.

이 문제를 해결하기 위해 성능 스키마와 `sys` 스키마를 사용할 수 있습니다. Aurora MySQL 버전 3에서 메모리 계측은 성능 스키마가 사용 설정되면 기본적으로 활성화됩니다. Aurora MySQL 버전 2에서는 성능 스키마 메모리 사용량의 메모리 계측만 기본적으로 사용 설정됩니다. 성능 스키마에서 메모리 사용량을 추적하고 성능 스키마 메모리 계측을 사용 설정하는 데 사용할 수 있는 테이블에 대한 자세한 내용은 MySQL 설명서의 [메모리 요약 테이블](https://dev.mysql.com/doc/refman/8.3/en/performance-schema-memory-summary-tables.html)을 참조하시기 바랍니다. 성능 개선 도우미에서 성능 스키마를 사용하는 것에 대한 자세한 내용은 [Aurora MySQL에서 성능 개선 도우미의 성능 스키마 개요](USER_PerfInsights.EnableMySQL.md) 섹션을 참조하세요.

성능 스키마에서 현재 메모리 사용량을 추적할 수 있는 자세한 정보가 나와 있지만, MySQL [sys 스키마](https://dev.mysql.com/doc/refman/8.0/en/sys-schema.html)에는 메모리 사용 위치를 빠르게 찾아내는 데 사용할 수 있는 성능 스키마 테이블 상단에 뷰가 제공됩니다.

`sys` 스키마에서 다음 뷰를 사용하여 연결, 구성 요소 및 쿼리별로 메모리 사용량을 추적할 수 있습니다.


| 보기 | 설명 | 
| --- | --- | 
|  [memory\$1by\$1host\$1by\$1current\$1bytes](https://dev.mysql.com/doc/refman/8.0/en/sys-memory-by-host-by-current-bytes.html)  |  호스트별 엔진 메모리 사용량에 대한 정보를 제공합니다. 이 정보를 통해 메모리를 사용하는 애플리케이션 서버 또는 클라이언트 호스트를 식별할 수 있습니다.  | 
|  [memory\$1by\$1thread\$1by\$1current\$1bytes](https://dev.mysql.com/doc/refman/8.0/en/sys-memory-by-thread-by-current-bytes.html)  |  스레드 ID별 엔진 메모리 사용량에 대한 정보를 제공합니다. MySQL의 스레드 ID는 클라이언트 연결 또는 백그라운드 스레드일 수 있습니다. [sys.processlist](https://dev.mysql.com/doc/refman/8.0/en/sys-processlist.html) 뷰 또는 [performance\$1schema.threads](https://dev.mysql.com/doc/refman/8.0/en/performance-schema-threads-table.html) 테이블을 사용하여 스레드 ID를 MySQL 연결 ID에 매핑할 수 있습니다.  | 
|  [memory\$1by\$1user\$1by\$1current\$1bytes](https://dev.mysql.com/doc/refman/8.0/en/sys-memory-by-user-by-current-bytes.html)  |  사용자별 엔진 메모리 사용량에 대한 정보를 제공합니다. 이 정보를 통해 메모리를 사용하는 사용자 계정 또는 클라이언트를 식별할 수 있습니다.  | 
|  [memory\$1global\$1by\$1current\$1bytes](https://dev.mysql.com/doc/refman/8.0/en/sys-memory-global-by-current-bytes.html)  |  엔진 구성 요소별 엔진 메모리 사용량에 대한 정보를 제공합니다. 이 정보를 통해 엔진 버퍼 또는 구성 요소별 메모리 사용량을 전체적으로 식별할 수 있습니다. 예를 들어 InnoDB 버퍼 풀의 `memory/innodb/buf_buf_pool` 이벤트 또는 준비된 문에 대한 `memory/sql/Prepared_statement::main_mem_root` 이벤트를 볼 수 있습니다.  | 
|  [memory\$1global\$1total](https://dev.mysql.com/doc/refman/8.0/en/sys-memory-global-total.html)  |  데이터베이스 엔진에서 추적된 총 메모리 사용량에 대한 개요를 제공합니다.  | 

Aurora MySQL 버전 3.05 이상에서는 [성능 스키마 문 요약 테이블](https://dev.mysql.com/doc/refman/8.0/en/performance-schema-statement-summary-tables.html)에서 문 다이제스트를 통해 최대 메모리 사용량을 추적할 수도 있습니다. 문 요약 테이블에는 정규화된 문 요약과 실행에 대한 집계된 통계가 포함되어 있습니다. 이 `MAX_TOTAL_MEMORY` 열을 통해 통계가 마지막으로 재설정된 이후 또는 데이터베이스 인스턴스가 재시작된 이후 쿼리 다이제스트에서 사용된 최대 메모리를 식별할 수 있습니다. 이를 통해 메모리를 많이 사용할 수 있는 특정 쿼리를 식별할 수 있습니다.

**참고**  
성능 스키마와 `sys` 스키마는 서버의 현재 메모리 사용량과 연결 및 엔진 구성 요소당 사용된 메모리의 상한선을 보여줍니다. 성능 스키마는 메모리에 유지 관리되므로 DB 인스턴스가 다시 시작될 때 정보가 재설정됩니다. 시간이 지나도 기록을 계속해서 유지하려면 성능 스키마 외부에서 이 데이터를 검색 및 저장하도록 구성하는 것이 좋습니다.

**Topics**
+ [예제 1: 지속적인 높은 메모리 사용량](#ams-workload-memory.example1)
+ [예제 2: 일시적인 메모리 급증](#ams-workload-memory.example2)
+ [예시 3: 여유 메모리가 지속적으로 삭제되고 회수되지 않음](#ams-workload-memory.example3)

## 예제 1: 지속적인 높은 메모리 사용량
<a name="ams-workload-memory.example1"></a>

전반적으로 CloudWatch에서 `FreeableMemory`를 살펴보면 2024-03-26 02:59 UTC를 기준으로 메모리 사용량이 크게 증가한 것을 확인할 수 있습니다.

![\[높은 메모리 사용량을 보여주는 FreeableMemory 그래프입니다.\]](http://docs.aws.amazon.com/ko_kr/AmazonRDS/latest/AuroraUserGuide/images/ams-freeable-memory.png)


이것이 전부는 아닙니다. 어떤 구성 요소가 메모리를 가장 많이 사용하고 있는지 확인하려면 데이터베이스에 로그인하여 `sys.memory_global_by_current_bytes`를 살펴보시기 바랍니다. 이 표에는 MySQL이 추적하는 메모리 이벤트 목록과 이벤트별 메모리 할당 정보가 포함되어 있습니다. 각 메모리 추적 이벤트는 `memory/%`로 시작되며 이벤트와 관련된 엔진 구성 요소/특성에 대한 기타 정보가 뒤따릅니다.

예를 들어 `memory/performance_schema/%`는 성능 스키마와 관련된 메모리 이벤트용이고 `memory/innodb/%`는 InnoDB용 등입니다. 이벤트 이름 지정 규칙에 대한 자세한 내용은 MySQL 설명서의 [성능 스키마 계측 이름 지정 규칙](https://dev.mysql.com/doc/refman/8.0/en/performance-schema-instrument-naming.html)을 참조하세요.

다음 쿼리에서는 `current_alloc`을 기반으로 유력한 원인을 찾을 수 있지만 많은 `memory/performance_schema/%` 이벤트도 확인할 수 있습니다.

```
mysql> SELECT * FROM sys.memory_global_by_current_bytes LIMIT 10;

+-----------------------------------------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
| event_name                                                                  | current_count | current_alloc | current_avg_alloc | high_count | high_alloc | high_avg_alloc |
+-----------------------------------------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
| memory/sql/Prepared_statement::main_mem_root                                |        512817 | 4.91 GiB      | 10.04 KiB         |     512823 | 4.91 GiB   | 10.04 KiB      |
| memory/performance_schema/prepared_statements_instances                     |           252 | 488.25 MiB    | 1.94 MiB          |        252 | 488.25 MiB | 1.94 MiB       |
| memory/innodb/hash0hash                                                     |             4 | 79.07 MiB     | 19.77 MiB         |          4 | 79.07 MiB  | 19.77 MiB      |
| memory/performance_schema/events_errors_summary_by_thread_by_error          |          1028 | 52.27 MiB     | 52.06 KiB         |       1028 | 52.27 MiB  | 52.06 KiB      |
| memory/performance_schema/events_statements_summary_by_thread_by_event_name |             4 | 47.25 MiB     | 11.81 MiB         |          4 | 47.25 MiB  | 11.81 MiB      |
| memory/performance_schema/events_statements_summary_by_digest               |             1 | 40.28 MiB     | 40.28 MiB         |          1 | 40.28 MiB  | 40.28 MiB      |
| memory/performance_schema/memory_summary_by_thread_by_event_name            |             4 | 31.64 MiB     | 7.91 MiB          |          4 | 31.64 MiB  | 7.91 MiB       |
| memory/innodb/memory                                                        |         15227 | 27.44 MiB     | 1.85 KiB          |      20619 | 33.33 MiB  | 1.66 KiB       |
| memory/sql/String::value                                                    |         74411 | 21.85 MiB     |  307 bytes        |      76867 | 25.54 MiB  |  348 bytes     |
| memory/sql/TABLE                                                            |          8381 | 21.03 MiB     | 2.57 KiB          |       8381 | 21.03 MiB  | 2.57 KiB       |
+-----------------------------------------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
10 rows in set (0.02 sec)
```

앞서 설명했듯이 성능 스키마는 메모리에 저장됩니다. 즉, `performance_schema` 메모리 계측에서 추적할 수도 있습니다.

**참고**  
성능 스키마가 메모리를 많이 사용하고 있고 메모리 사용량을 제한하려는 경우 요구 사항에 따라 데이터베이스 파라미터를 조정할 수 있습니다. 자세한 내용은 MySQL 설명서의 [성능 스키마 메모리 할당 모델](https://dev.mysql.com/doc/refman/8.0/en/performance-schema-memory-model.html)을 참조하세요.

가독성을 위해 동일한 쿼리를 다시 실행하되 성능 스키마 이벤트는 제외할 수 있습니다. 출력은 다음과 같이 표시됩니다.
+ `memory/sql/Prepared_statement::main_mem_root`에서 주로 메모리가 사용됩니다.
+ `current_alloc` 열에는 MySQL이 현재 이 이벤트에 4.91GiB를 할당하고 있음이 나와 있습니다.
+ `high_alloc column`에는 통계가 마지막으로 재설정된 이후 또는 서버가 다시 시작된 이후 4.91GiB가 최고 `current_alloc` 수치임이 나와 있습니다. 즉, `memory/sql/Prepared_statement::main_mem_root`가 현재 해당 최대치에 있다는 의미입니다.

```
mysql> SELECT * FROM sys.memory_global_by_current_bytes WHERE event_name NOT LIKE 'memory/performance_schema/%' LIMIT 10;

+-----------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
| event_name                                    | current_count | current_alloc | current_avg_alloc | high_count | high_alloc | high_avg_alloc |
+-----------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
| memory/sql/Prepared_statement::main_mem_root  |        512817 | 4.91 GiB      | 10.04 KiB         |     512823 | 4.91 GiB   | 10.04 KiB      |
| memory/innodb/hash0hash                       |             4 | 79.07 MiB     | 19.77 MiB         |          4 | 79.07 MiB  | 19.77 MiB      |
| memory/innodb/memory                          |         17096 | 31.68 MiB     | 1.90 KiB          |      22498 | 37.60 MiB  | 1.71 KiB       |
| memory/sql/String::value                      |        122277 | 27.94 MiB     |  239 bytes        |     124699 | 29.47 MiB  |  247 bytes     |
| memory/sql/TABLE                              |          9927 | 24.67 MiB     | 2.55 KiB          |       9929 | 24.68 MiB  | 2.55 KiB       |
| memory/innodb/lock0lock                       |          8888 | 19.71 MiB     | 2.27 KiB          |       8888 | 19.71 MiB  | 2.27 KiB       |
| memory/sql/Prepared_statement::infrastructure |        257623 | 16.24 MiB     |   66 bytes        |     257631 | 16.24 MiB  |   66 bytes     |
| memory/mysys/KEY_CACHE                        |             3 | 16.00 MiB     | 5.33 MiB          |          3 | 16.00 MiB  | 5.33 MiB       |
| memory/innodb/sync0arr                        |             3 | 7.03 MiB      | 2.34 MiB          |          3 | 7.03 MiB   | 2.34 MiB       |
| memory/sql/THD::main_mem_root                 |           815 | 6.56 MiB      | 8.24 KiB          |        849 | 7.19 MiB   | 8.67 KiB       |
+-----------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
10 rows in set (0.06 sec)
```

이벤트 이름을 보면 이 메모리가 준비된 문에 사용되고 있음을 알 수 있습니다. 어떤 연결이 이 메모리를 사용하고 있는지 알아보려면 [memory\$1by\$1thread\$1by\$1current\$1bytes](https://dev.mysql.com/doc/refman/8.0/en/sys-memory-by-thread-by-current-bytes.html)를 확인하시기 바랍니다.

다음 예제에서 각 연결에는 약 7MiB가 할당되어 있으며 최고 수치는 약 6.29MiB(`current_max_alloc`)입니다. 이 예제에서는 준비된 문을 포함하는 80개의 테이블과 800개의 연결을 가진 `sysbench`를 사용하고 있으므로 납득 가능한 수치입니다. 이 시나리오에서 메모리 사용량을 줄이려면 준비된 문의 애플리케이션 사용량을 최적화하여 메모리 사용량을 줄일 수 있습니다.

```
mysql> SELECT * FROM sys.memory_by_thread_by_current_bytes;

+-----------+-------------------------------------------+--------------------+-------------------+-------------------+-------------------+-----------------+
| thread_id | user                                      | current_count_used | current_allocated | current_avg_alloc | current_max_alloc | total_allocated |
+-----------+-------------------------------------------+--------------------+-------------------+-------------------+-------------------+-----------------+
|        46 | rdsadmin@localhost                        |                405 | 8.47 MiB          | 21.42 KiB         | 8.00 MiB          | 155.86 MiB      |
|        61 | reinvent@10.0.4.4                         |               1749 | 6.72 MiB          | 3.93 KiB          | 6.29 MiB          | 14.24 MiB       |
|       101 | reinvent@10.0.4.4                         |               1845 | 6.71 MiB          | 3.72 KiB          | 6.29 MiB          | 14.50 MiB       |
|        55 | reinvent@10.0.4.4                         |               1674 | 6.68 MiB          | 4.09 KiB          | 6.29 MiB          | 14.13 MiB       |
|        57 | reinvent@10.0.4.4                         |               1416 | 6.66 MiB          | 4.82 KiB          | 6.29 MiB          | 13.52 MiB       |
|       112 | reinvent@10.0.4.4                         |               1759 | 6.66 MiB          | 3.88 KiB          | 6.29 MiB          | 14.17 MiB       |
|        66 | reinvent@10.0.4.4                         |               1428 | 6.64 MiB          | 4.76 KiB          | 6.29 MiB          | 13.47 MiB       |
|        75 | reinvent@10.0.4.4                         |               1389 | 6.62 MiB          | 4.88 KiB          | 6.29 MiB          | 13.40 MiB       |
|       116 | reinvent@10.0.4.4                         |               1333 | 6.61 MiB          | 5.08 KiB          | 6.29 MiB          | 13.21 MiB       |
|        90 | reinvent@10.0.4.4                         |               1448 | 6.59 MiB          | 4.66 KiB          | 6.29 MiB          | 13.58 MiB       |
|        98 | reinvent@10.0.4.4                         |               1440 | 6.57 MiB          | 4.67 KiB          | 6.29 MiB          | 13.52 MiB       |
|        94 | reinvent@10.0.4.4                         |               1433 | 6.57 MiB          | 4.69 KiB          | 6.29 MiB          | 13.49 MiB       |
|        62 | reinvent@10.0.4.4                         |               1323 | 6.55 MiB          | 5.07 KiB          | 6.29 MiB          | 13.48 MiB       |
|        87 | reinvent@10.0.4.4                         |               1323 | 6.55 MiB          | 5.07 KiB          | 6.29 MiB          | 13.25 MiB       |
|        99 | reinvent@10.0.4.4                         |               1346 | 6.54 MiB          | 4.98 KiB          | 6.29 MiB          | 13.24 MiB       |
|       105 | reinvent@10.0.4.4                         |               1347 | 6.54 MiB          | 4.97 KiB          | 6.29 MiB          | 13.34 MiB       |
|        73 | reinvent@10.0.4.4                         |               1335 | 6.54 MiB          | 5.02 KiB          | 6.29 MiB          | 13.23 MiB       |
|        54 | reinvent@10.0.4.4                         |               1510 | 6.53 MiB          | 4.43 KiB          | 6.29 MiB          | 13.49 MiB       |
.                                                                                                                                                          .
.                                                                                                                                                          .
.                                                                                                                                                          .
|       812 | reinvent@10.0.4.4                         |               1259 | 6.38 MiB          | 5.19 KiB          | 6.29 MiB          | 13.05 MiB       |
|       214 | reinvent@10.0.4.4                         |               1279 | 6.38 MiB          | 5.10 KiB          | 6.29 MiB          | 12.90 MiB       |
|       325 | reinvent@10.0.4.4                         |               1254 | 6.38 MiB          | 5.21 KiB          | 6.29 MiB          | 12.99 MiB       |
|       705 | reinvent@10.0.4.4                         |               1273 | 6.37 MiB          | 5.13 KiB          | 6.29 MiB          | 13.03 MiB       |
|       530 | reinvent@10.0.4.4                         |               1268 | 6.37 MiB          | 5.15 KiB          | 6.29 MiB          | 12.92 MiB       |
|       307 | reinvent@10.0.4.4                         |               1263 | 6.37 MiB          | 5.17 KiB          | 6.29 MiB          | 12.87 MiB       |
|       738 | reinvent@10.0.4.4                         |               1260 | 6.37 MiB          | 5.18 KiB          | 6.29 MiB          | 13.00 MiB       |
|       819 | reinvent@10.0.4.4                         |               1252 | 6.37 MiB          | 5.21 KiB          | 6.29 MiB          | 13.01 MiB       |
|        31 | innodb/srv_purge_thread                   |              17810 | 3.14 MiB          |  184 bytes        | 2.40 MiB          | 205.69 MiB      |
|        38 | rdsadmin@localhost                        |                599 | 1.76 MiB          | 3.01 KiB          | 1.00 MiB          | 25.58 MiB       |
|         1 | sql/main                                  |               3756 | 1.32 MiB          |  367 bytes        | 355.78 KiB        | 6.19 MiB        |
|       854 | rdsadmin@localhost                        |                 46 | 1.08 MiB          | 23.98 KiB         | 1.00 MiB          | 5.10 MiB        |
|        30 | innodb/clone_gtid_thread                  |               1596 | 573.14 KiB        |  367 bytes        | 254.91 KiB        | 970.69 KiB      |
|        40 | rdsadmin@localhost                        |                235 | 245.19 KiB        | 1.04 KiB          | 128.88 KiB        | 808.64 KiB      |
|       853 | rdsadmin@localhost                        |                 96 | 94.63 KiB         | 1009 bytes        | 29.73 KiB         | 422.45 KiB      |
|        36 | rdsadmin@localhost                        |                 33 | 36.29 KiB         | 1.10 KiB          | 16.08 KiB         | 74.15 MiB       |
|        33 | sql/event_scheduler                       |                  3 | 16.27 KiB         | 5.42 KiB          | 16.04 KiB         | 16.27 KiB       |
|        35 | sql/compress_gtid_table                   |                  8 | 14.20 KiB         | 1.77 KiB          | 8.05 KiB          | 18.62 KiB       |
|        25 | innodb/fts_optimize_thread                |                 12 | 1.86 KiB          |  158 bytes        |  648 bytes        | 1.98 KiB        |
|        23 | innodb/srv_master_thread                  |                 11 | 1.23 KiB          |  114 bytes        |  361 bytes        | 24.40 KiB       |
|        24 | innodb/dict_stats_thread                  |                 11 | 1.23 KiB          |  114 bytes        |  361 bytes        | 1.35 KiB        |
|         5 | innodb/io_read_thread                     |                  1 |  144 bytes        |  144 bytes        |  144 bytes        |  144 bytes      |
|         6 | innodb/io_read_thread                     |                  1 |  144 bytes        |  144 bytes        |  144 bytes        |  144 bytes      |
|         2 | sql/aws_oscar_log_level_monitor           |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |    0 bytes      |
|         4 | innodb/io_ibuf_thread                     |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |    0 bytes      |
|         7 | innodb/io_write_thread                    |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |    0 bytes      |
|         8 | innodb/io_write_thread                    |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |    0 bytes      |
|         9 | innodb/io_write_thread                    |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |    0 bytes      |
|        10 | innodb/io_write_thread                    |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |    0 bytes      |
|        11 | innodb/srv_lra_thread                     |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |    0 bytes      |
|        12 | innodb/srv_akp_thread                     |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |    0 bytes      |
|        18 | innodb/srv_lock_timeout_thread            |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |  248 bytes      |
|        19 | innodb/srv_error_monitor_thread           |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |    0 bytes      |
|        20 | innodb/srv_monitor_thread                 |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |    0 bytes      |
|        21 | innodb/buf_resize_thread                  |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |    0 bytes      |
|        22 | innodb/btr_search_sys_toggle_thread       |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |    0 bytes      |
|        32 | innodb/dict_persist_metadata_table_thread |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |    0 bytes      |
|        34 | sql/signal_handler                        |                  0 |    0 bytes        |    0 bytes        |    0 bytes        |    0 bytes      |
+-----------+-------------------------------------------+--------------------+-------------------+-------------------+-------------------+-----------------+
831 rows in set (2.48 sec)
```

앞서 설명한 것처럼 여기서 스레드 ID(`thd_id`) 값은 서버 백그라운드 스레드 또는 데이터베이스 연결을 참조할 수 있습니다. 스레드 ID 값을 데이터베이스 연결 ID에 매핑하려면 `performance_schema.threads` 테이블 또는 `sys.processlist` 뷰를 사용할 수 있으며, 연결 ID는 `conn_id`입니다.

```
mysql> SELECT thd_id,conn_id,user,db,command,state,time,last_wait FROM sys.processlist WHERE user='reinvent@10.0.4.4';

+--------+---------+-------------------+----------+---------+----------------+------+-------------------------------------------------+
| thd_id | conn_id | user              | db       | command | state          | time | last_wait                                       |
+--------+---------+-------------------+----------+---------+----------------+------+-------------------------------------------------+
|    590 |     562 | reinvent@10.0.4.4 | sysbench | Execute | closing tables |    0 | wait/io/redo_log_flush                          |
|    578 |     550 | reinvent@10.0.4.4 | sysbench | Sleep   | NULL           |    0 | idle                                            |
|    579 |     551 | reinvent@10.0.4.4 | sysbench | Execute | closing tables |    0 | wait/io/redo_log_flush                          |
|    580 |     552 | reinvent@10.0.4.4 | sysbench | Execute | updating       |    0 | wait/io/table/sql/handler                       |
|    581 |     553 | reinvent@10.0.4.4 | sysbench | Execute | updating       |    0 | wait/io/table/sql/handler                       |
|    582 |     554 | reinvent@10.0.4.4 | sysbench | Sleep   | NULL           |    0 | idle                                            |
|    583 |     555 | reinvent@10.0.4.4 | sysbench | Sleep   | NULL           |    0 | idle                                            |
|    584 |     556 | reinvent@10.0.4.4 | sysbench | Execute | updating       |    0 | wait/io/table/sql/handler                       |
|    585 |     557 | reinvent@10.0.4.4 | sysbench | Execute | closing tables |    0 | wait/io/redo_log_flush                          |
|    586 |     558 | reinvent@10.0.4.4 | sysbench | Execute | updating       |    0 | wait/io/table/sql/handler                       |
|    587 |     559 | reinvent@10.0.4.4 | sysbench | Execute | closing tables |    0 | wait/io/redo_log_flush                          |
.                                                                                                                                     .
.                                                                                                                                     .
.                                                                                                                                     .
|    323 |     295 | reinvent@10.0.4.4 | sysbench | Sleep   | NULL           |    0 | idle                                            |
|    324 |     296 | reinvent@10.0.4.4 | sysbench | Execute | updating       |    0 | wait/io/table/sql/handler                       |
|    325 |     297 | reinvent@10.0.4.4 | sysbench | Execute | closing tables |    0 | wait/io/redo_log_flush                          |
|    326 |     298 | reinvent@10.0.4.4 | sysbench | Execute | updating       |    0 | wait/io/table/sql/handler                       |
|    438 |     410 | reinvent@10.0.4.4 | sysbench | Execute | System lock    |    0 | wait/lock/table/sql/handler                     |
|    280 |     252 | reinvent@10.0.4.4 | sysbench | Sleep   | starting       |    0 | wait/io/socket/sql/client_connection            |
|     98 |      70 | reinvent@10.0.4.4 | sysbench | Query   | freeing items  |    0 | NULL                                            |
+--------+---------+-------------------+----------+---------+----------------+------+-------------------------------------------------+
804 rows in set (5.51 sec)
```

이제 `sysbench` 워크로드를 중지하여 연결을 닫고 메모리를 해제합니다. 이벤트를 다시 확인해 보면 메모리가 해제된 것을 확인할 수 있지만, `high_alloc`을 통해 최고 수치를 계속 확인할 수 있습니다. `high_alloc` 열은 현재 할당된 메모리만 보여주는 `current_alloc`의 메모리 사용량을 즉시 식별하지 못할 수도 있는 단기 메모리 사용량 급증을 식별하는 데 매우 유용할 수 있습니다.

```
mysql> SELECT * FROM sys.memory_global_by_current_bytes WHERE event_name='memory/sql/Prepared_statement::main_mem_root' LIMIT 10;

+----------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
| event_name                                   | current_count | current_alloc | current_avg_alloc | high_count | high_alloc | high_avg_alloc |
+----------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
| memory/sql/Prepared_statement::main_mem_root |            17 | 253.80 KiB    | 14.93 KiB         |     512823 | 4.91 GiB   | 10.04 KiB      |
+----------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
1 row in set (0.00 sec)
```

`high_alloc`을 재설정하려는 경우 `performance_schema` 메모리 요약 테이블을 잘라낼 수 있지만 이렇게 하면 모든 메모리 계측이 재설정됩니다. 자세한 내용은 MySQL 설명서의 [성능 스키마 일반 테이블 특성](https://dev.mysql.com/doc/refman/8.0/en/performance-schema-table-characteristics.html)을 참조하세요.

다음 예제에서는 잘린 후 `high_alloc`이 재설정되는 것을 볼 수 있습니다.

```
mysql> TRUNCATE `performance_schema`.`memory_summary_global_by_event_name`;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM sys.memory_global_by_current_bytes WHERE event_name='memory/sql/Prepared_statement::main_mem_root' LIMIT 10;

+----------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
| event_name                                   | current_count | current_alloc | current_avg_alloc | high_count | high_alloc | high_avg_alloc |
+----------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
| memory/sql/Prepared_statement::main_mem_root |            17 | 253.80 KiB    | 14.93 KiB         |         17 | 253.80 KiB | 14.93 KiB      |
+----------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
1 row in set (0.00 sec)
```

## 예제 2: 일시적인 메모리 급증
<a name="ams-workload-memory.example2"></a>

또 다른 일반적인 현상은 데이터베이스 서버의 메모리 사용량이 일시적으로 급증하는 것입니다. 사용 가능한 메모리가 주기적으로 떨어지면 메모리가 이미 비워졌기 때문에 `sys.memory_global_by_current_bytes`에서 `current_alloc`을 사용할 때 문제를 해결하기가 어려울 수 있습니다.

**참고**  
성능 스키마 통계를 재설정하거나 데이터베이스 인스턴스를 다시 시작한 경우 `sys` 또는 p`erformance_schema`에서 이 정보를 사용할 수 없습니다. 이 정보를 유지하려면 외부 지표 수집을 구성하는 것이 좋습니다.

향상된 모니터링의 다음 `os.memory.free` 지표 그래프는 7초간의 단기 메모리 사용량 급증을 보여줍니다. 향상된 모니터링을 통해 1초 정도의 짧은 간격으로 모니터링할 수 있어 이와 같은 일시적 급증을 포착하는 데 적합합니다.

![\[시간 경과에 따른 일시적 메모리 사용량 급증과 잠재적 메모리 관리 문제를 나타내는 주기적 패턴을 보여주는 그래프입니다.\]](http://docs.aws.amazon.com/ko_kr/AmazonRDS/latest/AuroraUserGuide/images/ams-free-memory-spikes.png)


여기서 메모리 사용량의 원인을 진단하는 데 도움이 되도록 `sys` 메모리 요약 뷰의 `high_alloc`과 [성능 스키마 문 요약 테이블](https://dev.mysql.com/doc/refman/8.0/en/performance-schema-statement-summary-tables.html)을 함께 사용하여 문제가 되는 세션 및 연결을 식별할 수 있습니다.

예상한 바와 같이 현재 메모리 사용량이 많지 않으므로 `current_alloc`의 `sys` 스키마 뷰에서 주요 문제 인자를 확인할 수 없습니다.

```
mysql> SELECT * FROM sys.memory_global_by_current_bytes LIMIT 10;

+-----------------------------------------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
| event_name                                                                  | current_count | current_alloc | current_avg_alloc | high_count | high_alloc | high_avg_alloc |
+-----------------------------------------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
| memory/innodb/hash0hash                                                     |             4 | 79.07 MiB     | 19.77 MiB         |          4 | 79.07 MiB  | 19.77 MiB      |
| memory/innodb/os0event                                                      |        439372 | 60.34 MiB     |  144 bytes        |     439372 | 60.34 MiB  |  144 bytes     |
| memory/performance_schema/events_statements_summary_by_digest               |             1 | 40.28 MiB     | 40.28 MiB         |          1 | 40.28 MiB  | 40.28 MiB      |
| memory/mysys/KEY_CACHE                                                      |             3 | 16.00 MiB     | 5.33 MiB          |          3 | 16.00 MiB  | 5.33 MiB       |
| memory/performance_schema/events_statements_history_long                    |             1 | 14.34 MiB     | 14.34 MiB         |          1 | 14.34 MiB  | 14.34 MiB      |
| memory/performance_schema/events_errors_summary_by_thread_by_error          |           257 | 13.07 MiB     | 52.06 KiB         |        257 | 13.07 MiB  | 52.06 KiB      |
| memory/performance_schema/events_statements_summary_by_thread_by_event_name |             1 | 11.81 MiB     | 11.81 MiB         |          1 | 11.81 MiB  | 11.81 MiB      |
| memory/performance_schema/events_statements_summary_by_digest.digest_text   |             1 | 9.77 MiB      | 9.77 MiB          |          1 | 9.77 MiB   | 9.77 MiB       |
| memory/performance_schema/events_statements_history_long.digest_text        |             1 | 9.77 MiB      | 9.77 MiB          |          1 | 9.77 MiB   | 9.77 MiB       |
| memory/performance_schema/events_statements_history_long.sql_text           |             1 | 9.77 MiB      | 9.77 MiB          |          1 | 9.77 MiB   | 9.77 MiB       |
+-----------------------------------------------------------------------------+---------------+---------------+-------------------+------------+------------+----------------+
10 rows in set (0.01 sec)
```

뷰를 `high_alloc` 기준으로 정렬하여 펼치면 이제 `memory/temptable/physical_ram` 구성 요소가 매우 적합한 후보임을 알 수 있습니다. 최대 용량으로는 515.00MiB를 소비했습니다.

이름에서 알 수 있듯이 `memory/temptable/physical_ram`은 MySQL 8.0에 도입된 MySQL의 `TEMP` 스토리지 엔진의 메모리 사용량을 측정합니다. MySQL에서 임시 테이블을 사용하는 방법에 대한 자세한 내용은 MySQL 설명서의 [MySQL의 내부 임시 테이블 사용](https://dev.mysql.com/doc/refman/8.0/en/internal-temporary-tables.html)을 참조하세요.

**참고**  
이 예제에서는 `sys.x$memory_global_by_current_bytes` 뷰를 사용합니다.

```
mysql> SELECT event_name, format_bytes(current_alloc) AS "currently allocated", sys.format_bytes(high_alloc) AS "high-water mark"  
FROM sys.x$memory_global_by_current_bytes ORDER BY high_alloc DESC LIMIT 10;

+-----------------------------------------------------------------------------+---------------------+-----------------+
| event_name                                                                  | currently allocated | high-water mark |
+-----------------------------------------------------------------------------+---------------------+-----------------+
| memory/temptable/physical_ram                                               | 4.00 MiB            | 515.00 MiB      |
| memory/innodb/hash0hash                                                     | 79.07 MiB           | 79.07 MiB       |
| memory/innodb/os0event                                                      | 63.95 MiB           | 63.95 MiB       |
| memory/performance_schema/events_statements_summary_by_digest               | 40.28 MiB           | 40.28 MiB       |
| memory/mysys/KEY_CACHE                                                      | 16.00 MiB           | 16.00 MiB       |
| memory/performance_schema/events_statements_history_long                    | 14.34 MiB           | 14.34 MiB       |
| memory/performance_schema/events_errors_summary_by_thread_by_error          | 13.07 MiB           | 13.07 MiB       |
| memory/performance_schema/events_statements_summary_by_thread_by_event_name | 11.81 MiB           | 11.81 MiB       |
| memory/performance_schema/events_statements_summary_by_digest.digest_text   | 9.77 MiB            | 9.77 MiB        |
| memory/performance_schema/events_statements_history_long.sql_text           | 9.77 MiB            | 9.77 MiB        |
+-----------------------------------------------------------------------------+---------------------+-----------------+
10 rows in set (0.00 sec)
```

[예제 1: 지속적인 높은 메모리 사용량](#ams-workload-memory.example1)에서는 각 연결의 현재 메모리 사용량을 확인하여 문제의 메모리 사용을 담당하는 연결을 확인했습니다. 이 예제에서는 메모리가 이미 비워졌으므로 현재 연결의 메모리 사용량을 확인하는 것은 유용하지 않습니다.

더 자세히 알아보고 문제가 되는 문, 사용자, 호스트를 찾기 위해 성능 스키마를 사용합니다. 성능 스키마에는 이벤트 이름, 문 다이제스트, 호스트, 스레드, 사용자 등 다양한 차원으로 구분된 여러 문 요약 테이블이 포함되어 있습니다. 각 뷰를 통해 특정 문이 실행되는 위치와 수행하는 작업을 더 자세히 살펴볼 수 있습니다. 이 섹션은 `MAX_TOTAL_MEMORY`를 중점적으로 다루지만, 사용 가능한 모든 열에 대한 자세한 내용은 [성능 스키마 문 요약 테이블](https://dev.mysql.com/doc/refman/8.0/en/performance-schema-statement-summary-tables.html) 설명서에서 확인할 수 있습니다.

```
mysql> SHOW TABLES IN performance_schema LIKE 'events_statements_summary_%';

+------------------------------------------------------------+
| Tables_in_performance_schema (events_statements_summary_%) |
+------------------------------------------------------------+
| events_statements_summary_by_account_by_event_name         |
| events_statements_summary_by_digest                        |
| events_statements_summary_by_host_by_event_name            |
| events_statements_summary_by_program                       |
| events_statements_summary_by_thread_by_event_name          |
| events_statements_summary_by_user_by_event_name            |
| events_statements_summary_global_by_event_name             |
+------------------------------------------------------------+
7 rows in set (0.00 sec)
```

먼저 `events_statements_summary_by_digest`를 확인해 `MAX_TOTAL_MEMORY`를 살펴봅니다.

여기서 다음 내용을 확인할 수 있습니다.
+ 다이제스트 `20676ce4a690592ff05debcffcbc26faeb76f22005e7628364d7a498769d0c4a`가 포함된 쿼리가 이 메모리 사용량에 적합한 것으로 보입니다. `MAX_TOTAL_MEMORY`는 5537450710으로, `sys.x$memory_global_by_current_bytes`의 `memory/temptable/physical_ram` 이벤트에서 살펴본 최고 수치와 일치합니다.
+ 이는 4번(`COUNT_STAR`) 실행되었는데, 처음은 2024-03-26 04:08:34.943256에, 마지막은 2024-03-26 04:43:06.998310에 실행되었습니다.

```
mysql> SELECT SCHEMA_NAME,DIGEST,COUNT_STAR,MAX_TOTAL_MEMORY,FIRST_SEEN,LAST_SEEN
FROM performance_schema.events_statements_summary_by_digest ORDER BY MAX_TOTAL_MEMORY DESC LIMIT 5;

+-------------+------------------------------------------------------------------+------------+------------------+----------------------------+----------------------------+
| SCHEMA_NAME | DIGEST                                                           | COUNT_STAR | MAX_TOTAL_MEMORY | FIRST_SEEN                 | LAST_SEEN                  |
+-------------+------------------------------------------------------------------+------------+------------------+----------------------------+----------------------------+
| sysbench    | 20676ce4a690592ff05debcffcbc26faeb76f22005e7628364d7a498769d0c4a |          4 |        537450710 | 2024-03-26 04:08:34.943256 | 2024-03-26 04:43:06.998310 |
| NULL        | f158282ea0313fefd0a4778f6e9b92fc7d1e839af59ebd8c5eea35e12732c45d |          4 |          3636413 | 2024-03-26 04:29:32.712348 | 2024-03-26 04:36:26.269329 |
| NULL        | 0046bc5f642c586b8a9afd6ce1ab70612dc5b1fd2408fa8677f370c1b0ca3213 |          2 |          3459965 | 2024-03-26 04:31:37.674008 | 2024-03-26 04:32:09.410718 |
| NULL        | 8924f01bba3c55324701716c7b50071a60b9ceaf17108c71fd064c20c4ab14db |          1 |          3290981 | 2024-03-26 04:31:49.751506 | 2024-03-26 04:31:49.751506 |
| NULL        | 90142bbcb50a744fcec03a1aa336b2169761597ea06d85c7f6ab03b5a4e1d841 |          1 |          3131729 | 2024-03-26 04:15:09.719557 | 2024-03-26 04:15:09.719557 |
+-------------+------------------------------------------------------------------+------------+------------------+----------------------------+----------------------------+
5 rows in set (0.00 sec)
```

이제 문제가 되는 다이제스트를 알았으므로 쿼리 텍스트, 실행한 사용자, 실행 위치 등의 세부 정보를 더 자세히 확인할 수 있습니다. 반환된 다이제스트 텍스트를 바탕으로 이는 임시 테이블 4개를 만들고 테이블 스캔을 4회 수행하는 일반적인 테이블 표현식(CTE)이며, 매우 비효율적이라는 것을 알 수 있습니다.

```
mysql> SELECT SCHEMA_NAME,DIGEST_TEXT,QUERY_SAMPLE_TEXT,MAX_TOTAL_MEMORY,SUM_ROWS_SENT,SUM_ROWS_EXAMINED,SUM_CREATED_TMP_TABLES,SUM_NO_INDEX_USED
FROM performance_schema.events_statements_summary_by_digest
WHERE DIGEST='20676ce4a690592ff05debcffcbc26faeb76f22005e7628364d7a498769d0c4a'\G;

*************************** 1. row ***************************
           SCHEMA_NAME: sysbench
           DIGEST_TEXT: WITH RECURSIVE `cte` ( `n` ) AS ( SELECT ? FROM `sbtest1` UNION ALL SELECT `id` + ? FROM `sbtest1` ) SELECT * FROM `cte`
     QUERY_SAMPLE_TEXT: WITH RECURSIVE cte (n) AS (   SELECT 1  from sbtest1 UNION ALL   SELECT id + 1 FROM sbtest1) SELECT * FROM cte
      MAX_TOTAL_MEMORY: 537450710
         SUM_ROWS_SENT: 80000000
     SUM_ROWS_EXAMINED: 80000000
SUM_CREATED_TMP_TABLES: 4
     SUM_NO_INDEX_USED: 4
1 row in set (0.01 sec)
```

`events_statements_summary_by_digest` 테이블 및 기타 성능 스키마 문 요약 테이블에 대한 자세한 내용은 MySQL 설명서의 [문 요약 테이블](https://dev.mysql.com/doc/refman/8.0/en/performance-schema-statement-summary-tables.html)을 참조하세요.

[EXPLAIN](https://dev.mysql.com/doc/refman/8.0/en/explain.html) 또는 [EXPLAIN ANALYZE](https://dev.mysql.com/doc/refman/8.0/en/explain.html#explain-analyze) 문을 실행하여 자세한 내용을 확인할 수도 있습니다.

**참고**  
`EXPLAIN ANALYZE`는 `EXPLAIN`보다 많은 정보를 제공할 수 있지만 쿼리를 실행하기도 하므로 주의해야 합니다.

```
-- EXPLAIN
mysql> EXPLAIN WITH RECURSIVE cte (n) AS (SELECT 1  FROM sbtest1 UNION ALL SELECT id + 1 FROM sbtest1) SELECT * FROM cte;

+----+-------------+------------+------------+-------+---------------+------+---------+------+----------+----------+-------------+
| id | select_type | table      | partitions | type  | possible_keys | key  | key_len | ref  | rows     | filtered | Extra       |
+----+-------------+------------+------------+-------+---------------+------+---------+------+----------+----------+-------------+
|  1 | PRIMARY     | <derived2> | NULL       | ALL   | NULL          | NULL | NULL    | NULL | 19221520 |   100.00 | NULL        |
|  2 | DERIVED     | sbtest1    | NULL       | index | NULL          | k_1  | 4       | NULL |  9610760 |   100.00 | Using index |
|  3 | UNION       | sbtest1    | NULL       | index | NULL          | k_1  | 4       | NULL |  9610760 |   100.00 | Using index |
+----+-------------+------------+------------+-------+---------------+------+---------+------+----------+----------+-------------+
3 rows in set, 1 warning (0.00 sec)

-- EXPLAIN format=tree 
mysql> EXPLAIN format=tree WITH RECURSIVE cte (n) AS (SELECT 1 FROM sbtest1 UNION ALL SELECT id + 1 FROM sbtest1) SELECT * FROM cte\G;

*************************** 1. row ***************************
EXPLAIN: -> Table scan on cte  (cost=4.11e+6..4.35e+6 rows=19.2e+6)
    -> Materialize union CTE cte  (cost=4.11e+6..4.11e+6 rows=19.2e+6)
        -> Index scan on sbtest1 using k_1  (cost=1.09e+6 rows=9.61e+6)
        -> Index scan on sbtest1 using k_1  (cost=1.09e+6 rows=9.61e+6)
1 row in set (0.00 sec)

-- EXPLAIN ANALYZE 
mysql> EXPLAIN ANALYZE WITH RECURSIVE cte (n) AS (SELECT 1 from sbtest1 UNION ALL SELECT id + 1 FROM sbtest1) SELECT * FROM cte\G;

*************************** 1. row ***************************
EXPLAIN: -> Table scan on cte  (cost=4.11e+6..4.35e+6 rows=19.2e+6) (actual time=6666..9201 rows=20e+6 loops=1)
    -> Materialize union CTE cte  (cost=4.11e+6..4.11e+6 rows=19.2e+6) (actual time=6666..6666 rows=20e+6 loops=1)
        -> Covering index scan on sbtest1 using k_1  (cost=1.09e+6 rows=9.61e+6) (actual time=0.0365..2006 rows=10e+6 loops=1)
        -> Covering index scan on sbtest1 using k_1  (cost=1.09e+6 rows=9.61e+6) (actual time=0.0311..2494 rows=10e+6 loops=1)
1 row in set (10.53 sec)
```

하지만 누가 실행했을까요? 성능 스키마에서 `destructive_operator` 사용자가 537450710의 `MAX_TOTAL_MEMORY`를 보유한 것을 확인할 수 있는데, 이 역시 이전 결과와 일치합니다.

**참고**  
성능 스키마는 메모리에 저장되므로 감사의 유일한 소스로 사용해서는 안 됩니다. 문의 실행 내역과 사용자 기록을 관리해야 하는 경우 [Aurora 고급 감사](AuroraMySQL.Auditing.md)를 사용 설정하는 것이 좋습니다. 메모리 사용량에 대한 정보도 유지해야 하는 경우 이러한 값을 내보내고 저장하도록 모니터링을 구성하는 것이 좋습니다.

```
mysql> SELECT USER,EVENT_NAME,COUNT_STAR,MAX_TOTAL_MEMORY FROM performance_schema.events_statements_summary_by_user_by_event_name
ORDER BY MAX_CONTROLLED_MEMORY DESC LIMIT 5;

+----------------------+---------------------------+------------+------------------+
| USER                 | EVENT_NAME                | COUNT_STAR | MAX_TOTAL_MEMORY |
+----------------------+---------------------------+------------+------------------+
| destructive_operator | statement/sql/select      |          4 |        537450710 |
| rdsadmin             | statement/sql/select      |       4172 |          3290981 |
| rdsadmin             | statement/sql/show_tables |          2 |          3615821 |
| rdsadmin             | statement/sql/show_fields |          2 |          3459965 |
| rdsadmin             | statement/sql/show_status |         75 |          1914976 |
+----------------------+---------------------------+------------+------------------+
5 rows in set (0.00 sec)

mysql> SELECT HOST,EVENT_NAME,COUNT_STAR,MAX_TOTAL_MEMORY FROM performance_schema.events_statements_summary_by_host_by_event_name
WHERE HOST != 'localhost' AND COUNT_STAR>0 ORDER BY MAX_CONTROLLED_MEMORY DESC LIMIT 5;

+------------+----------------------+------------+------------------+
| HOST       | EVENT_NAME           | COUNT_STAR | MAX_TOTAL_MEMORY |
+------------+----------------------+------------+------------------+
| 10.0.8.231 | statement/sql/select |          4 |        537450710 |
+------------+----------------------+------------+------------------+
1 row in set (0.00 sec)
```

## 예시 3: 여유 메모리가 지속적으로 삭제되고 회수되지 않음
<a name="ams-workload-memory.example3"></a>

InnoDB 데이터베이스 엔진은 다양한 구성 요소에 대해 다양한 특수 메모리 추적 이벤트를 사용합니다. 이러한 특정 이벤트를 통해 주요 InnoDB 하위 시스템의 메모리 사용량을 세부적으로 추적할 수 있습니다. 예를 들면 다음과 같습니다.
+ `memory/innodb/buf0buf` - InnoDB 버퍼 풀에 대한 메모리 할당 모니터링을 전담합니다.
+ `memory/innodb/ibuf0ibuf` - 특히 InnoDB 변경 버퍼와 관련된 메모리 변경 사항을 추적합니다.

메모리의 상위 소비자를 식별하기 위해 `sys.memory_global_by_current_bytes`를 쿼리할 수 있습니다.

```
mysql> SELECT event_name,current_alloc FROM sys.memory_global_by_current_bytes LIMIT 10;

+-----------------------------------------------------------------+---------------+
| event_name                                                      | current_alloc |
+-----------------------------------------------------------------+---------------+
| memory/innodb/memory                                            | 5.28 GiB      |
| memory/performance_schema/table_io_waits_summary_by_index_usage | 495.00 MiB    |
| memory/performance_schema/table_shares                          | 488.00 MiB    |
| memory/sql/TABLE_SHARE::mem_root                                | 388.95 MiB    |
| memory/innodb/std                                               | 226.88 MiB    |
| memory/innodb/fil0fil                                           | 198.49 MiB    |
| memory/sql/binlog_io_cache                                      | 128.00 MiB    |
| memory/innodb/mem0mem                                           | 96.82 MiB     |
| memory/innodb/dict0dict                                         | 96.76 MiB     |
| memory/performance_schema/rwlock_instances                      | 88.00 MiB     |
+-----------------------------------------------------------------+---------------+
10 rows in set (0.00 sec)
```

결과는 `memory/innodb/memory`가 현재 할당된 메모리의 5.28GiB를 사용하는 상위 소비자임을 보여줍니다. 이 이벤트는 앞에서 언급한 `memory/innodb/buf0buf`와 같이 보다 구체적인 대기 이벤트와 관련이 없는 다양한 InnoDB 구성 요소에서 메모리 할당을 위한 범주 역할을 합니다.

InnoDB 구성 요소가 메모리의 기본 소비자임을 확인한 후 다음 MySQL 명령을 사용하여 세부 정보를 자세히 살펴볼 수 있습니다.

```
SHOW ENGINE INNODB STATUS \G;
```

[SHOW ENGINE INNODB STATUS](https://dev.mysql.com/doc/refman/8.4/en/show-engine.html) 명령은 다양한 InnoDB 구성 요소에 대한 자세한 메모리 사용량 통계를 포함하여 InnoDB 스토리지 엔진에 대한 포괄적인 상태 보고서를 제공합니다. 이를 통해 가장 많은 메모리를 소비하는 특정 InnoDB 구조 또는 작업을 식별할 수 있습니다. 자세한 내용은 MySQL 설명서에서 [InnoDB in-memory structures](https://dev.mysql.com/doc/refman/8.0/en/innodb-in-memory-structures.html)를 참조하세요.

InnoDB 상태 보고서의 `BUFFER POOL AND MEMORY` 섹션을 분석하면 `memory/innodb/memory`가 추적하는 메모리의 89%를 차지하는 5,051,647,748바이트(4.7GiB)가 [딕셔너리 객체 캐시](https://dev.mysql.com/doc/refman/8.0/en/data-dictionary-object-cache.html)에 할당되어 있는 것을 확인할 수 있습니다.

```
----------------------
BUFFER POOL AND MEMORY
----------------------
Total large memory allocated 0
Dictionary memory allocated 5051647748
Buffer pool size 170512
Free buffers 142568
Database pages 27944
Old database pages 10354
Modified db pages 6
Pending reads 0
```

딕셔너리 객체 캐시는 이전에 액세스한 데이터 딕셔너리 객체를 메모리에 저장하여 객체 재사용을 가능하게 하고 성능을 개선하는 공유 글로벌 캐시입니다. 딕셔너리 객체 캐시에 메모리가 많이 할당되어 있다는 것은 데이터 딕셔너리 캐시에 데이터베이스 객체가 많다는 것을 의미합니다.

데이터 딕셔너리 캐시가 주된 소비자임을 알았으므로 이제 데이터 딕셔너리 캐시에서 열린 테이블을 검사합니다. 테이블 정의 캐시에서 테이블 수를 찾으려면 글로벌 상태 변수 [open\$1table\$1definitions](https://dev.mysql.com/doc/refman/8.4/en/server-status-variables.html#statvar_Open_table_definitions)을 쿼리합니다.

```
mysql> show global status like 'open_table_definitions';

+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| Open_table_definitions | 20000 |
+------------------------+-------+
1 row in set (0.00 sec)
```

자세한 내용은 MySQL 설명서의 [MySQL에서 테이블을 열고 닫는 방법](https://dev.mysql.com/doc/refman/8.0/en/table-cache.html)을 참조하십시오.

DB 클러스터 또는 DB 인스턴스 파라미터 그룹에서 `table_definition_cache` 파라미터를 제한하여 데이터 딕셔너리 캐시의 테이블 정의 수를 제한할 수 있습니다. Aurora MySQL의 경우 이 값은 테이블 정의 캐시의 테이블 수에 대한 소프트 제한 역할을 합니다. 기본값은 인스턴스 클래스에 따라 달라지며 다음과 같이 설정됩니다.

```
LEAST({DBInstanceClassMemory/393040}, 20000)
```

테이블 수가 `table_definition_cache` 한도를 초과하면 가장 오래전에 사용됨(LRU) 메커니즘이 캐시에서 테이블을 없애고 제거합니다. 그러나 외래 키 관계와 관련된 테이블은 LRU 목록에 배치되지 않으므로 제거가 불가능합니다.

현재 시나리오에서는 [FLUSH TABLES](https://dev.mysql.com/doc/refman/8.4/en/flush.html)을 실행하여 테이블 정의 캐시를 지웁니다. 이 작업을 수행하면 다음과 같이 [Open\$1table\$1definitions](https://dev.mysql.com/doc/refman/8.0/en/server-status-variables.html#statvar_Open_table_definitions) 글로벌 상태 변수가 2만에서 12로 크게 감소합니다.

```
mysql> show global status like 'open_table_definitions';

+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| Open_table_definitions | 12    |
+------------------------+-------+
1 row in set (0.00 sec)
```

이러한 감소에도 불구하고 `memory/innodb/memory`에 대한 메모리 할당은 5.18GiB로 높게 유지되고 할당된 딕셔너리 메모리도 변경되지 않는 것으로 관찰됩니다. 이는 다음 쿼리 결과에서 확실히 알 수 있습니다.

```
mysql> SELECT event_name,current_alloc FROM sys.memory_global_by_current_bytes LIMIT 10;

+-----------------------------------------------------------------+---------------+
| event_name                                                      | current_alloc |
+-----------------------------------------------------------------+---------------+
| memory/innodb/memory                                            | 5.18 GiB      |
| memory/performance_schema/table_io_waits_summary_by_index_usage | 495.00 MiB    |
| memory/performance_schema/table_shares                          | 488.00 MiB    |
| memory/sql/TABLE_SHARE::mem_root                                | 388.95 MiB    |
| memory/innodb/std                                               | 226.88 MiB    |
| memory/innodb/fil0fil                                           | 198.49 MiB    |
| memory/sql/binlog_io_cache                                      | 128.00 MiB    |
| memory/innodb/mem0mem                                           | 96.82 MiB     |
| memory/innodb/dict0dict                                         | 96.76 MiB     |
| memory/performance_schema/rwlock_instances                      | 88.00 MiB     |
+-----------------------------------------------------------------+---------------+
10 rows in set (0.00 sec)
```

```
----------------------
BUFFER POOL AND MEMORY
----------------------
Total large memory allocated 0
Dictionary memory allocated 5001599639
Buffer pool size 170512
Free buffers 142568
Database pages 27944
Old database pages 10354
Modified db pages 6
Pending reads 0
```

이렇게 지속적으로 높은 메모리 사용량은 외래 키 관계와 관련된 테이블 때문일 수 있습니다. 이러한 테이블은 제거를 위해 LRU 목록에 배치되지 않으므로 테이블 정의 캐시를 플러싱한 후에도 메모리 할당이 높은 상태를 유지하는 이유가 설명됩니다.

이 문제를 해결하려면:

1. 데이터베이스 스키마, 특히 외래 키 관계를 검토하고 최적화하세요.

1. 딕셔너리 객체를 수용할 수 있는 메모리가 더 많은 더 큰 DB 인스턴스 클래스로 이동하는 것을 고려해 보세요.

다음 단계에 따라 메모리 할당 패턴을 이해하면 Aurora MySQL DB 인스턴스의 메모리 사용량을 더 잘 관리하고 메모리 압박으로 인한 잠재적 성능 문제를 방지할 수 있습니다.

# Aurora MySQL 데이터베이스의 메모리 부족 문제 해결
<a name="AuroraMySQLOOM"></a>

The Aurora MySQL `aurora_oom_response` 인스턴스 수준 파라미터를 사용하면 DB 인스턴스가 시스템 메모리를 모니터링하고 다양한 명령문 및 연결에서 소비되는 메모리를 예측할 수 있습니다. 시스템 메모리가 부족해지면 시스템은 이 메모리를 해제하려고 시도하는 작업 목록을 수행할 수 있습니다. 메모리 부족(OOM) 문제로 인한 데이터베이스 재시작을 피하려고 시도하는 과정에서 그러한 작업 목록을 수행합니다. 이 인스턴스 수준 파라미터는 메모리가 부족할 때 DB 인스턴스가 수행하는 쉼표로 구분된 작업 문자열을 사용합니다. `aurora_oom_response` 파라미터는 Aurora MySQL 버전 2 및 3에서 지원됩니다.

다음 값과 그 조합을 `aurora_oom_response` 파라미터에 사용할 수 있습니다. 문자열을 비워두면 어떠한 작업도 수행하지 않는다는 뜻이며 해당 기능이 사실상 해제되어 데이터베이스가 OOM으로 인해 재시작되기 쉽습니다.
+ `decline` – DB 인스턴스 메모리가 부족해지면 새 쿼리를 거부합니다.
+ `kill_connect` - 많은 양의 메모리를 사용하는 데이터베이스 연결을 닫고 현재 트랜잭션과 데이터 정의 언어(DDL) 문을 종료합니다. 이 응답은 Aurora MySQL 버전 2에서 지원되지 않습니다.

  자세한 내용은 MySQL 설명서의 [KILL statement](https://dev.mysql.com/doc/refman/8.0/en/kill.html)를 참조하세요.
+ `kill_query` – 인스턴스 메모리가 하한값 이상이 될 때까지 메모리 사용량이 많은 순서로 쿼리를 종료합니다. DDL 문이 종료되지 않습니다.

  자세한 내용은 MySQL 설명서의 [KILL statement](https://dev.mysql.com/doc/refman/8.0/en/kill.html)를 참조하세요.
+ `print` - 많은 양의 메모리를 사용하는 쿼리만 인쇄합니다.
+ `tune` – 내부 테이블 캐시를 조정하여 일부 메모리를 시스템으로 돌려줍니다. Aurora MySQL은 메모리가 부족해지면 `table_open_cache`, `table_definition_cache` 같은 캐시에 사용하는 메모리를 줄입니다. 그리고 시스템의 메모리가 부족해지지 않게 되면 이러한 캐시에 사용하는 메모리를 정상 수준으로 되돌립니다.

  자세한 내용은 MySQL 설명서의 [table\$1open\$1cache](https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_table_open_cache) 및 [table\$1definition\$1cache](https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_table_definition_cache)를 참조하세요.
+ `tune_buffer_pool` - 버퍼 풀의 크기를 줄여 일부 메모리를 확보하고 데이터베이스 서버가 연결을 처리하는 데 사용할 수 있도록 합니다. 이 응답은 Aurora MySQL 버전 3.06 이상에서 지원됩니다.

  `tune_buffer_pool`을 `aurora_oom_response` 파라미터 값 중 `kill_query` 또는 `kill_connect`와 짝지어야 합니다. 그러지 않으면 파라미터 값에 `tune_buffer_pool`을 포함하더라도 버퍼 풀 크기가 조정되지 않습니다.

3.06 미만의 Aurora MySQL 버전에서 메모리가 4GiB 이하인 DB 인스턴스 클래스의 경우, 인스턴스에 메모리 부족 현상이 발생하면 기본 작업에 `print`, `tune`, `decline`, `kill_query` 등이 포함됩니다. 메모리가 4GiB보다 큰 DB 인스턴스 클래스의 경우, 파라미터 값은 기본적으로 비어 있습니다(비활성화됨).

Aurora MySQL 버전 3.06 이상에서는 메모리가 4GiB 이하인 DB 인스턴스 클래스의 경우, Aurora MySQL은 메모리를 가장 많이 소비하는 연결도 종료합니다(`kill_connect`). 메모리가 4GiB보다 큰 DB 인스턴스 클래스의 경우, 기본 파라미터 값은 `print`입니다.

Aurora MySQL 버전 3.09 이상에서 메모리가 4GiB보다 큰 DB 인스턴스 클래스의 경우, 기본 파라미터 값은 `print,decline,kill_connect`입니다.

메모리 부족 문제가 자주 발생하는 경우, `performance_schema`가 활성화되면 [메모리 요약 테이블](https://dev.mysql.com/doc/refman/8.3/en/performance-schema-memory-summary-tables.html)을 사용하여 메모리 사용량을 모니터링할 수 있습니다.

OOM과 관련된 Amazon CloudWatch 지표에 대해서는 [Amazon Aurora에 대한 인스턴스 수준 지표](Aurora.AuroraMonitoring.Metrics.md#Aurora.AuroraMySQL.Monitoring.Metrics.instances)의 내용을 참조하세요. OOM과 관련된 글로벌 상태 변수는 [Aurora MySQL 글로벌 상태 변수](AuroraMySQL.Reference.GlobalStatusVars.md)의 내용을 참조하세요.

# Aurora MySQL 데이터베이스에 대한 로깅
<a name="aurora-mysql-troubleshooting-logging"></a>

Aurora MySQL 로그는 데이터베이스 활동 및 오류에 대한 필수 정보를 제공합니다. 이러한 로그를 활성화하면 문제를 식별 및 해결하고, 데이터베이스 성능을 이해하고, 데이터베이스 활동을 감사할 수 있습니다. 데이터베이스의 성능과 가용성을 최적화하려면 모든 Aurora MySQL DB 인스턴스에 대해 이러한 로그를 활성화하는 것이 좋습니다. 다음과 같은 유형의 로그를 활성화할 수 있습니다. 각 로그에는 데이터베이스 처리에 미치는 영향을 파악할 수 있는 특정 정보가 포함되어 있습니다.
+ 오류 - Aurora MySQL에서는 시작, 종료 및 오류 발생 시에만 오류 로그에 데이터가 로그됩니다. DB 인스턴스는 오류 로그에 새 항목이 기록되지 않는 상태로 몇 시간이나 며칠씩 작동할 수 있습니다. 최근 항목이 보이지 않으면 이는 서버에서 로그에 입력될 만한 오류가 발생하지 않았기 때문입니다. 오류 로깅은 기본적으로 활성화됩니다. 자세한 내용은 [Aurora MySQL 오류 로그](USER_LogAccess.MySQL.LogFileSize.md#USER_LogAccess.MySQL.Errorlog) 단원을 참조하십시오.
+ 일반 - 일반 로그는 데이터베이스 엔진에서 실행되는 모든 SQL 문을 포함하여 데이터베이스 활동에 대한 자세한 정보를 제공합니다. 일반 로깅을 활성화하고 로깅 파라미터를 설정하는 방법에 대한 자세한 내용은 MySQL 설명서의 [Aurora MySQL 느린 쿼리 로그 및 일반 로그](USER_LogAccess.MySQL.LogFileSize.md#USER_LogAccess.MySQL.Generallog) 및 [The general query log](https://dev.mysql.com/doc/refman/8.0/en/query-log.html)를 참조하세요.
**참고**  
일반 로그는 크기가 매우 커져 스토리지를 차지할 수 있습니다. 자세한 내용은 [Aurora MySQL용 로그 교체 및 보존](USER_LogAccess.MySQL.LogFileSize.md#USER_LogAccess.AMS.LogFileSize.retention) 단원을 참조하십시오.
+ 느린 쿼리 - 느린 쿼리 로그는 실행하는 데 [long\$1query\$1time](https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_long_query_time)초가 넘게 걸리고 검토할 행이 최소 [min\$1examined\$1row\$1limit](https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_min_examined_row_limit)개여야 하는 SQL 문으로 구성됩니다. 느린 쿼리 로그를 사용하면 실행 시간이 오래 걸리고 따라서 최적화가 필요한 쿼리를 찾을 수 있습니다.

  [`long_query_time`]의 기본값은 10초입니다. 먼저 높은 값으로 시작하여 가장 느린 쿼리를 식별한 다음 세부 튜닝을 위해 낮은 값으로 내려가는 것이 좋습니다.

  `log_slow_admin_statements` 및 `log_queries_not_using_indexes`와 같은 관련 파라미터를 사용할 수도 있습니다. `rows_examined`를 `rows_returned`에 비교하세요. `rows_examined`가 `rows_returned`보다 훨씬 크면 해당 쿼리가 잠재적으로 차단될 수 있습니다.

  Aurora MySQL 버전 3에서는 자세한 내용을 확인할 수 있도록 `log_slow_extra`를 설정할 수 있습니다. 자세한 내용은 MySQL 설명서의 [Slow query log contents](https://dev.mysql.com/doc/refman/8.0/en/slow-query-log.html#slow-query-log-contents)를 참조하세요. 대화식으로 쿼리 실행을 디버깅하기 위해 세션 수준에서 `long_query_time`을 수정할 수도 있는데, 이는 `log_slow_extra`가 전역적으로 활성화된 경우 특히 유용합니다.

  느린 쿼리 로깅을 활성화하고 로깅 파라미터를 설정하는 방법에 대한 자세한 내용은 MySQL 설명서의 [Aurora MySQL 느린 쿼리 로그 및 일반 로그](USER_LogAccess.MySQL.LogFileSize.md#USER_LogAccess.MySQL.Generallog) 및 [The slow query log](https://dev.mysql.com/doc/refman/8.0/en/slow-query-log.html)를 참조하세요.
+ 감사 - 감사 로그는 데이터베이스 활동을 모니터링하고 기록합니다. Aurora MySQL에 대한 감사 로깅을 고급 감사라고 합니다. 고급 감사를 활성화하려면 특정 DB 클러스터 파라미터를 설정합니다. 자세한 내용은 [Amazon Aurora MySQL DB 클러스터에서 고급 감사 사용](AuroraMySQL.Auditing.md) 단원을 참조하십시오.
+ 바이너리 - 바이너리 로그(binlog)에는 테이블 생성 작업 및 테이블 데이터 변경과 같은 데이터베이스 변경 사항을 설명하는 이벤트가 포함됩니다. 또한 행 기반 로깅을 사용하지 않는 한 잠재적으로 변경을 수행했을 수 있는 문(예: 일치하는 행이 없는 [DELETE](https://dev.mysql.com/doc/refman/8.0/en/delete.html))에 대한 이벤트도 포함됩니다. 또한 바이너리 로그에는 각 문이 업데이트된 데이터에 소요한 시간에 대한 정보도 포함됩니다.

  바이너리 로깅이 활성화된 상태에서 서버를 실행하면 성능이 약간 느려집니다. 그러나 복제를 설정하고 복원 작업을 수행할 수 있도록 하는 바이너리 로그의 이점은 일반적으로 이러한 사소한 성능 저하보다 큽니다.
**참고**  
Aurora MySQL은 복원 작업에 바이너리 로깅이 필요하지 않습니다.

  바이너리 로깅을 활성화하고 binlog 형식을 설정하는 방법에 대한 자세한 내용은 MySQL 설명서의 [단일 AZ 데이터베이스의 Aurora MySQL 이진 로깅 구성](USER_LogAccess.MySQL.BinaryFormat.md) 및 [The binary log](https://dev.mysql.com/doc/refman/8.0/en/binary-log.html)를 참조하세요.

오류, 일반, 느린 쿼리 및 감사 로그를 Amazon CloudWatch Logs에 게시할 수 있습니다. 자세한 내용은 [Amazon CloudWatch Logs에 데이터베이스 로그 게시](USER_LogAccess.Procedural.UploadtoCloudWatch.md) 단원을 참조하십시오.

느린 로그 파일, 일반 로그 파일, 바이너리 로그 파일을 요약하는 데 유용한 또 다른 도구는 [pt-query-digest](https://docs.percona.com/percona-toolkit/pt-query-digest.html)입니다.

# Aurora MySQL 데이터베이스의 연결 문제 해결
<a name="mysql-troubleshooting-dbconn"></a>

워크로드를 원활하게 운영하려면 애플리케이션과 RDS DB 인스턴스 간의 안정적인 연결을 보장하는 것이 중요합니다. 그러나 네트워크 구성, 인증 문제 또는 리소스 제약과 같은 다양한 요인으로 인해 연결 문제가 발생할 수 있습니다. 이 안내서는 Aurora MySQL의 연결 문제를 해결하기 위한 포괄적인 접근 방식을 제공하는 것을 목표로 합니다.

**Contents**
+ [Aurora MySQL의 데이터베이스 연결 문제 식별](#mysql-dbconn-identify)
+ [Aurora MySQL의 연결 문제에 대한 데이터 수집](#mysql-dbconn-gather)
+ [Aurora MySQL에 대한 데이터베이스 연결 모니터링](#mysql-dbconn-monitor)
  + [Aurora MySQL에 대한 추가 모니터링](#mysql-dbconn-monitor-ams)
+ [Aurora MySQL의 연결 오류 코드](#mysql-dbconn-errors)
+ [Aurora MySQL에 대한 파라미터 튜닝 권장 사항](#mysql-dbconn-params)
+ [Aurora MySQL에 대한 데이터베이스 연결 문제 해결 예제](#mysql-dbconn-examples)
  + [예제 1: 실패한 연결 시도 문제 해결](#mysql-dbconn-example1)
  + [예제 2: 비정상적인 클라이언트 연결 해제 문제 해결](#mysql-dbconn-example2)
  + [예제 3: IAM 실패한 연결 시도 문제 해결](#mysql-dbconn-example3)

## Aurora MySQL의 데이터베이스 연결 문제 식별
<a name="mysql-dbconn-identify"></a>

연결 문제의 특정 범주를 식별하면 잠재적 원인의 범위를 좁히고 문제 해결 프로세스에 도움이 될 수 있습니다. 각 범주에는 진단 및 해결을 위한 다양한 접근 방식과 기법이 필요할 수 있습니다. 데이터베이스 연결 문제는 크게 다음 범주로 분류할 수 있습니다.

**연결 오류 및 예외**  
연결 오류 및 예외는 잘못된 연결 문자열, 인증 실패, 네트워크 중단 또는 데이터베이스 서버 문제와 같은 다양한 이유로 발생할 수 있습니다. 잘못 구성된 연결 파라미터, 잘못된 자격 증명, 네트워크 중단 또는 데이터베이스 서버 충돌 또는 재시작이 원인일 수 있습니다. 잘못 구성된 보안 그룹, 가상 프라이빗 클라우드(VPC) 설정, 네트워크 액세스 제어 목록(ACL) 및 서브넷과 연결된 라우팅 테이블도 연결 문제로 이어질 수 있습니다.

**연결 한도 도달**  
이 문제는 데이터베이스 서버에 대한 동시 연결 수가 최대 허용 한도를 초과할 때 발생합니다. 데이터베이스 서버에는 일반적으로 클러스터 및 인스턴스 파라미터 그룹의 파라미터 max\$1connections로 정의된 구성 가능한 최대 연결 한도가 있습니다. 연결 한도를 적용하면 데이터베이스 서버가 기존 연결을 효율적으로 처리하고 허용 가능한 성능을 제공하기에 충분한 리소스(예: 메모리, CPU 및 파일 핸들)를 보유하게 됩니다. 원인에는 애플리케이션의 연결 유출, 비효율적인 연결 풀링 또는 연결 요청의 예상치 못한 급증 등이 포함될 수 있습니다.

**연결 시간 초과**  
연결 시간 초과는 클라이언트 애플리케이션이 지정된 제한 시간 내에 데이터베이스 서버와의 연결을 설정할 수 없는 경우에 발생합니다. 일반적인 원인에는 네트워크 문제, 서버 과부하, 방화벽 규칙 및 잘못 구성된 연결 설정이 포함됩니다.

**유휴 연결 제한 시간**  
장시간 비활성 상태로 유지되는 유휴 연결은 리소스를 절약하기 위해 데이터베이스 서버에서 자동으로 닫힐 수 있습니다. 이 제한 시간은 일반적으로 `wait_timeout` 및 `interactive_timeout parameters`를 사용하여 구성할 수 있으며 애플리케이션의 연결 사용 패턴에 따라 조정해야 합니다. 연결을 장시간 유휴 상태로 두는 애플리케이션 로직 또는 부적절한 연결 관리가 원인일 수 있습니다.

**기존 연결의 간헐적 연결 해제**  
이 오류 클래스는 클라이언트 애플리케이션과 데이터베이스 간에 설정된 연결이 활성 상태이고 사용 중임에도 불구하고 불규칙한 간격으로 예기치 않게 종료되거나 연결이 끊어지는 시나리오를 나타냅니다. 이러한 연결 해제는 간헐적으로 발생하므로 불규칙한 간격으로 발생하며 일관되게 발생하지 않습니다. 원인에는 다음이 포함될 수 있습니다.  
+ 재시작 또는 장애 조치와 같은 데이터베이스 서버 문제
+ 부적절한 애플리케이션 연결 처리
+ 로드 밸런싱 및 프록시 문제
+ 네트워크 불안정성
+ 연결 경로와 관련된 타사 구성 요소 또는 미들웨어 문제
+ 쿼리 실행 제한 시간
+ 서버 또는 클라이언트 측의 리소스 제약 조건
포괄적인 모니터링, 로깅 및 분석을 통해 근본 원인을 식별하는 것이 중요하며, 적절한 오류 처리, 연결 풀링 및 재시도 메커니즘을 구현하면 이러한 간헐적 연결 해제가 애플리케이션의 기능 및 사용자 경험에 미치는 영향을 완화하는 데 도움이 될 수 있습니다.

## Aurora MySQL의 연결 문제에 대한 데이터 수집
<a name="mysql-dbconn-gather"></a>

애플리케이션, 데이터베이스, 네트워크 및 인프라 구성 요소와 관련된 포괄적인 데이터를 수집하는 것은 애플리케이션과 Aurora MySQL 데이터베이스 간의 연결 문제를 효과적으로 해결하는 데 매우 중요합니다. 관련 로그, 구성 및 진단 정보를 수집하면 연결 문제의 근본 원인을 파악하고 적절한 해결 방법을 수행하는 데 도움이 되는 가치 있는 인사이트를 얻을 수 있습니다.

보안 그룹 규칙, VPC 설정 및 라우팅 테이블과 같은 네트워크 로그 및 구성은 애플리케이션이 데이터베이스와 성공적으로 연결되지 못하게 할 수 있는 잠재적인 네트워크 관련 병목 현상 또는 잘못된 구성을 식별하는 데 필수적입니다. 이러한 네트워크 구성 요소를 분석하여 필요한 포트가 열려 있고 IP 주소가 허용되며 라우팅 구성이 올바르게 설정되었는지 확인할 수 있습니다.

**타임스탬프**  
연결 문제가 발생할 때 정확한 타임스탬프를 기록합니다. 이를 통해 패턴을 식별하거나 문제를 다른 이벤트 또는 활동과 상호 연관시킬 수 있습니다.

**DB 엔진 로그**  
일반 데이터베이스 로그 외에도 데이터베이스 엔진 로그(예: MySQL 오류 로그 및 느린 쿼리 로그)에서 간헐적 연결 문제와 관련이 있을 수 있는 관련 정보 또는 오류를 검토합니다. 자세한 내용은 [Aurora MySQL 데이터베이스에 대한 로깅](aurora-mysql-troubleshooting-logging.md) 섹션을 참조하세요.

**클라이언트 애플리케이션 로그**  
데이터베이스에 연결하는 클라이언트 애플리케이션에서 세부 로그를 수집합니다. 애플리케이션 로그는 애플리케이션의 관점에서 연결 시도, 오류 및 관련 정보를 볼 수 있는 가시성을 제공하여 연결 문자열, 인증 자격 증명 또는 애플리케이션 수준 연결 처리와 관련된 문제를 드러낼 수 있습니다.  
반면 데이터베이스 로그는 데이터베이스 측 오류, 느린 쿼리 또는 연결 문제에 기여할 수 있는 이벤트에 대한 통찰력을 제공합니다. 자세한 내용은 [Aurora MySQL 데이터베이스에 대한 로깅](aurora-mysql-troubleshooting-logging.md) 섹션을 참조하세요.

**클라이언트 환경 변수**  
클라이언트 측의 환경 변수 또는 구성 설정이 프록시 설정, SSL/TLS 설정 또는 기타 관련 변수와 같은 데이터베이스 연결에 영향을 미칠 수 있는지 확인합니다.

**클라이언트 라이브러리 버전**  
클라이언트가 데이터베이스 연결에 사용되는 모든 데이터베이스 드라이버, 라이브러리 또는 프레임워크의 최신 버전을 사용하고 있는지 확인합니다. 오래된 버전에는 알려진 문제 또는 호환성 문제가 있을 수 있습니다.

**클라이언트 네트워크 캡처**  
연결 문제가 발생하는 동안 Wireshark 또는 `tcpdump`와 같은 도구를 사용하여 클라이언트 측에서 네트워크 캡처를 수행합니다. 이렇게 하면 클라이언트 측에서 네트워크 관련 문제 또는 이상을 식별하는 데 도움이 될 수 있습니다.

**클라이언트 네트워크 토폴로지**  
클라이언트가 직접 연결하는 대신 데이터베이스에 연결하는 방화벽, 로드 밸런서 또는 RDS 프록시 또는 프록시 SQL과 같은 기타 구성 요소를 포함하여 클라이언트의 네트워크 토폴로지를 이해합니다.

**클라이언트 운영 체제 설정**  
방화벽 규칙, 네트워크 어댑터 설정 및 기타 관련 설정과 같이 네트워크 연결에 영향을 미칠 수 있는 클라이언트의 운영 체제 설정을 확인합니다.

**연결 풀링 구성**  
애플리케이션에서 연결 풀링 메커니즘을 사용하는 경우 구성 설정을 검토하고 풀 지표(예: 활성 연결, 유휴 연결 및 연결 제한 시간)를 모니터링하여 풀이 올바르게 작동하는지 확인합니다. 또한 최대 풀 크기, 최소 풀 크기 및 연결 검증 설정과 같은 풀 설정을 검토하여 올바르게 구성되었는지 확인합니다.

**연결 문자열**  
연결 문자열에는 일반적으로 호스트 이름 또는 엔드포인트, 포트 번호, 데이터베이스 이름 및 인증 자격 증명과 같은 파라미터가 포함됩니다. 연결 문자열을 분석하면 연결 문제를 일으킬 수 있는 구성 오류 또는 잘못된 설정을 식별하는 데 도움이 될 수 있습니다. 예를 들어 호스트 이름이나 포트 번호가 올바르지 않으면 클라이언트가 데이터베이스 인스턴스에 도달하지 못할 수 있지만 잘못된 인증 자격 증명은 인증 실패 및 연결 거부로 이어질 수 있습니다. 또한 연결 문자열은 연결 풀링, 제한 시간 또는 연결 문제에 기여할 수 있는 기타 연결별 설정과 관련된 문제를 드러낼 수 있습니다. 클라이언트 애플리케이션에서 사용하는 전체 연결 문자열을 제공하면 클라이언트의 잘못된 구성을 정확히 파악하는 데 도움이 될 수 있습니다.

**데이터베이스 지표**  
연결 문제가 발생하는 동안 CPU 사용량, 메모리 사용량 및 디스크 I/O와 같은 데이터베이스 지표를 모니터링합니다. 이를 통해 DB 인스턴스에 리소스 경합 또는 성능 문제가 있는지 확인할 수 있습니다.

**DB 엔진 버전**  
Aurora MySQL DB 엔진 버전을 참조하세요. AWS는 알려진 문제, 보안 취약성을 해결하고 성능 향상을 도입하는 업데이트를 정기적으로 릴리스합니다. 따라서 이러한 업데이트에는 특히 연결, 성능 및 안정성과 관련된 버그 수정 및 개선 사항이 포함되어 있으므로 사용 가능한 최신 버전으로 업그레이드하는 것이 좋습니다. 데이터베이스 버전 정보를 다른 수집된 세부 정보와 함께 제공하면 지원가 연결 문제를 효과적으로 진단하고 해결하는 데 도움이 될 수 있습니다.

**네트워크 지표**  
연결 문제가 발생하는 동안 지연 시간, 패킷 손실 및 처리량과 같은 네트워크 지표를 수집합니다. `ping`, `traceroute` 및 네트워크 모니터링 도구와 같은 도구는 이 데이터를 수집하는 데 도움이 될 수 있습니다.

**소스 및 클라이언트 세부 정보**  
애플리케이션 서버, 로드 밸런서 또는 데이터베이스 연결을 시작하는 기타 구성 요소의 IP 주소를 확인합니다. 이는 단일 IP 주소 또는 IP 주소 범위(CIDR 표기법)일 수 있습니다. 소스가 Amazon EC2 인스턴스인 경우 인스턴스 유형, 가용 영역, 서브넷 ID 및 인스턴스와 연결된 보안 그룹, 프라이빗 IP 주소 및 퍼블릭 IP 주소와 같은 네트워크 인터페이스 세부 정보를 검토하는 것도 도움이 됩니다.

수집된 데이터를 철저히 분석하면 구성 오류, 리소스 제약, 네트워크 중단 또는 간헐적이거나 지속적인 연결 문제를 유발하는 기타 기본 문제를 식별할 수 있습니다. 이 정보를 사용하면 구성 조정, 네트워크 문제 해결 또는 애플리케이션 수준 연결 처리 처리와 같은 대상 작업을 수행할 수 있습니다.

## Aurora MySQL에 대한 데이터베이스 연결 모니터링
<a name="mysql-dbconn-monitor"></a>

연결 문제를 모니터링하고 해결하기 위해 다음 지표와 기능을 사용할 수 있습니다.

**CloudWatch 지표**  
+ `CPUUtilization` – DB 인스턴스에서 CPU 사용량이 높으면 쿼리 실행이 느려져 연결 시간 초과 또는 거부가 발생할 수 있습니다.
+ `DatabaseConnections` – DB 인스턴스에 대한 활성 연결 수를 모니터링합니다. 구성된 최댓값에 가까운 연결 수가 많으면 잠재적 연결 문제 또는 연결 풀 소진을 나타낼 수 있습니다.
+ `FreeableMemory` – 사용 가능한 메모리가 적으면 리소스 제약으로 인해 성능 문제와 연결 문제가 발생할 수 있습니다.
+ `NetworkReceiveThroughput` 및 `NetworkTransmitThroughput` - 비정상적인 네트워크 처리량 급증 또는 하락은 연결 문제 또는 네트워크 병목 현상을 나타낼 수 있습니다.

**성능 개선 도우미 지표**  
성능 개선 도우미를 사용하여 Aurora MySQL의 연결 문제를 해결하려면 다음과 같은 데이터베이스 지표를 분석합니다.  
+ Aborted\$1clients
+ Aborted\$1connects
+ 연결
+ max\$1connections
+ Threads\$1connected
+ Threads\$1created
+ Threads\$1running
이러한 지표는 연결 병목 현상을 식별하고, 네트워크 또는 인증 문제를 감지하며, 연결 풀링을 최적화하고, 효율적인 스레드 관리를 보장하는 데 도움이 될 수 있습니다. 자세한 내용은 [Aurora MySQL용 성능 개선 도우미 카운터](USER_PerfInsights_Counters.md#USER_PerfInsights_Counters.Aurora_MySQL) 섹션을 참조하세요.

**성능 개선 도우미 기능**  
+ **데이터베이스 로드** - 시간 경과에 따라 데이터베이스 로드를 시각화하고 연결 문제 또는 성능 저하와 상호 연관시킵니다.
+ **SQL 통계** - SQL 통계를 분석하여 연결 문제에 기여할 수 있는 비효율적인 쿼리 또는 데이터베이스 작업을 식별합니다.
+ **상위 쿼리** - 가장 리소스 집약적인 쿼리를 식별하고 분석하여 연결 문제를 일으킬 수 있는 잠재적 성능 병목 현상 또는 장기 실행 쿼리를 식별하는 데 도움이 될 수 있습니다.

이러한 지표를 모니터링하고 성능 개선 도우미를 활용하면 연결 문제를 일으킬 수 있는 데이터베이스 인스턴스의 성능, 리소스 사용량 및 잠재적 병목 현상을 파악할 수 있습니다. 예:
+ 최대 한도에 가까운 높은 `DatabaseConnections`는 연결 풀 소진 또는 부적절한 연결 처리로 인해 연결 문제가 발생함을 나타낼 수 있습니다.
+ 높은 `CPUUtilization` 또는 낮은 `FreeableMemory`은 리소스 제약을 나타낼 수 있으며, 이로 인해 쿼리 실행이 느려지고 연결 제한 시간이 초과되거나 거부될 수 있습니다.
+ **상위 쿼리** 및 **SQL 통계**를 분석하면 연결 문제에 기여할 수 있는 비효율적이거나 리소스 집약적인 쿼리를 식별하는 데 도움이 될 수 있습니다.

또한 CloudWatch Logs를 모니터링하고 경보를 설정하면 연결 문제가 에스컬레이션되기 전에 사전에 식별하고 대응하는 데 도움이 될 수 있습니다.

이러한 지표와 도구는 가치 있는 인사이트를 제공할 수 있지만 다른 문제 해결 단계와 함께 사용해야 합니다. 또한 네트워크 구성, 보안 그룹 규칙 및 애플리케이션 수준 연결 처리를 검토하여 Aurora MySQL DB 인스턴스의 연결 문제를 포괄적으로 진단하고 해결할 수 있습니다.

### Aurora MySQL에 대한 추가 모니터링
<a name="mysql-dbconn-monitor-ams"></a>

**CloudWatch 지표**  
+ `AbortedClients` - 제대로 종료되지 않은 클라이언트 연결 수를 추적합니다.
+ `AuroraSlowConnectionHandleCount` - 느린 연결 핸들 작업 수를 추적하여 잠재적 연결 문제 또는 성능 병목 현상을 나타냅니다.
+ `AuroraSlowHandshakeCount` - 느린 핸드셰이크 작업 수를 측정하며, 이는 연결 문제를 나타내는 지표일 수도 있습니다.
+ `ConnectionAttempts` - Aurora MySQL DB 인스턴스에 대한 연결 시도 횟수를 측정합니다.

**글로벌 상태 변수**  
`Aurora_external_connection_count` - DB 인스턴스에 대한 데이터베이스 연결 수를 나타내며, 데이터베이스 상태 확인에 사용되는 RDS 서비스 연결은 제외됩니다.

이러한 지표와 글로벌 상태 변수를 모니터링하면 Amazon Aurora MySQL 인스턴스에 연결 문제를 일으킬 수 있는 연결 패턴, 오류 및 잠재적 병목 현상을 파악할 수 있습니다.

예를 들어 `AbortedClients` 또는 `AuroraSlowConnectionHandleCount`의 수가 많으면 연결 문제를 나타낼 수 있습니다.

또한 CloudWatch 경보 및 알림을 설정하면 연결 문제가 에스컬레이션되고 애플리케이션 성능에 영향을 미치기 전에 사전에 식별하고 대응하는 데 도움이 될 수 있습니다.

## Aurora MySQL의 연결 오류 코드
<a name="mysql-dbconn-errors"></a>

다음은 Aurora MySQL 데이터베이스의 몇 가지 일반적인 연결 오류와 오류 코드 및 설명입니다.

**오류 코드 1040: 연결이 너무 많음**  
이 오류는 클라이언트가 데이터베이스 서버에서 허용하는 최댓값보다 많은 연결을 설정하려고 할 때 발생합니다. 가능한 값은 다음을 포함합니다.  
+ 연결 풀링 구성 오류 - 연결 풀링 메커니즘을 사용하는 경우 최대 풀 크기가 너무 높게 설정되지 않았는지, 연결이 풀로 다시 제대로 릴리스되고 있는지 확인합니다.
+ 데이터베이스 인스턴스 구성 - 데이터베이스 인스턴스에 허용되는 최대 연결 설정을 확인하고 필요한 경우 `max_connections` 파라미터를 설정하여 조정합니다.
+ 높은 동시성 - 여러 클라이언트 또는 애플리케이션이 데이터베이스에 동시에 연결하는 경우 허용되는 최대 연결 한도에 도달할 수 있습니다.

**오류 코드 1045: 사용자 '...'@'...'에 대한 액세스 거부됨(암호 사용: YES/NO)**  
이 오류는 데이터베이스에 연결을 시도할 때 인증 실패를 나타냅니다. 가능한 값은 다음을 포함합니다.  
+ 인증 플러그인 호환성 - 클라이언트에서 사용하는 인증 플러그인이 데이터베이스 서버의 인증 메커니즘과 호환되는지 확인합니다.
+ 잘못된 사용자 이름 또는 암호 - 연결 문자열 또는 인증 메커니즘에서 올바른 사용자 이름과 암호가 사용되고 있는지 확인합니다.
+ 사용자 권한 - 사용자에게 지정된 호스트 또는 네트워크에서 데이터베이스 인스턴스에 연결하는 데 필요한 권한이 있는지 확인합니다.

**오류 코드 1049: 알 수 없는 데이터베이스 '...'**  
이 오류는 클라이언트가 서버에 없는 데이터베이스에 연결을 시도하고 있음을 나타냅니다. 가능한 값은 다음을 포함합니다.  
+ 데이터베이스가 생성되지 않음 - 지정된 데이터베이스가 데이터베이스 서버에서 생성되었는지 확인합니다.
+ 잘못된 데이터베이스 이름 - 연결 문자열 또는 쿼리에 사용된 데이터베이스 이름이 정확한지 다시 확인합니다.
+ 사용자 권한 - 사용자에게 지정된 데이터베이스에 액세스하는 데 필요한 권한이 있는지 확인합니다.

**오류 코드 1153: 'max\$1allowed\$1packet' 바이트보다 큰 패킷을 가져옴**  
이 오류는 클라이언트가 데이터베이스 서버에서 허용하는 최대 패킷 크기를 초과하는 데이터를 보내거나 받으려고 할 때 발생합니다. 가능한 값은 다음을 포함합니다.  
+ 대규모 쿼리 또는 결과 세트 - 대량의 데이터가 포함된 쿼리를 실행하는 경우 패킷 크기 제한을 초과할 수 있습니다.
+ 잘못 구성된 패킷 크기 설정 - 데이터베이스 서버의 `max_allowed_packet` 설정을 확인하고 필요한 경우 조정합니다.
+ 네트워크 구성 문제 - 네트워크 구성(예: MTU 크기)이 필요한 패킷 크기를 허용하는지 확인합니다.

**오류 코드 1226: '...' 사용자가 'max\$1user\$1connections' 리소스를 초과했습니다(현재 값: ...).**  
이 오류는 사용자가 데이터베이스 서버에서 허용하는 최대 동시 연결 수를 초과했음을 나타냅니다. 가능한 값은 다음을 포함합니다.  
+ 연결 풀링 구성 오류 - 연결 풀링 메커니즘을 사용하는 경우 최대 풀 크기가 사용자의 연결 한도에 비해 너무 높게 설정되지 않았는지 확인합니다.
+ 데이터베이스 인스턴스 구성 - 데이터베이스 인스턴스의 `max_user_connections` 설정을 확인하고 필요한 경우 조정합니다.
+ 높은 동시성 - 여러 클라이언트 또는 애플리케이션이 동일한 사용자를 사용하여 데이터베이스에 동시에 연결하는 경우 사용자별 연결 한도에 도달할 수 있습니다.

**오류 코드 2003: '...'에서 MySQL 서버에 연결할 수 없음(10061)**  
이 오류는 일반적으로 클라이언트가 데이터베이스 서버와 TCP/IP 연결을 설정할 수 없을 때 발생합니다. 다음과 같은 다양한 문제로 인해 발생할 수 있습니다.  
+ 데이터베이스 인스턴스 상태 - 데이터베이스 인스턴스가 `available` 상태이고 유지 관리 또는 백업 작업을 수행하지 않는지 확인합니다.
+ 방화벽 규칙 - 방화벽(운영 체제, 네트워크 또는 보안 그룹)이 지정된 포트(일반적으로 MySQL의 경우 3306)에서 연결을 차단하고 있는지 확인합니다.
+ 잘못된 호스트 이름 또는 엔드포인트 - 연결 문자열에 사용된 호스트 이름 또는 엔드포인트가 올바르고 데이터베이스 인스턴스와 일치하는지 확인합니다.
+ 네트워크 연결 문제 - 클라이언트 시스템이 네트워크를 통해 데이터베이스 인스턴스에 도달할 수 있는지 확인합니다. 네트워크 중단, 라우팅 문제 또는 VPC 또는 서브넷 구성 오류가 있는지 확인합니다.

**오류 코드 2005: 알 수 없는 MySQL 서버 호스트 '...'(11001)**  
이 오류는 클라이언트가 데이터베이스 서버의 호스트 이름 또는 엔드포인트를 IP 주소로 확인할 수 없을 때 발생합니다. 가능한 값은 다음을 포함합니다.  
+ DNS 해결 문제 - 클라이언트 시스템이 DNS를 사용하여 호스트 이름을 올바르게 해결할 수 있는지 확인합니다. DNS 설정, DNS 캐시를 확인하고 호스트 이름 대신 IP 주소를 사용해 보세요.
+ 잘못된 호스트 이름 또는 엔드포인트 - 연결 문자열에 사용된 호스트 이름 또는 엔드포인트가 정확한지 다시 확인합니다.
+ 네트워크 구성 문제 - 클라이언트의 네트워크 구성(예: VPC, 서브넷 및 라우팅 테이블)이 DNS 확인 및 데이터베이스 인스턴스에 대한 연결을 허용하는지 확인합니다.

**오류 코드 2026: SSL 연결 오류**  
이 오류는 연결 시도 중에 SSL/TLS 구성 또는 인증서 검증에 문제가 있을 때 발생합니다. 가능한 값은 다음을 포함합니다.  
+ 인증서 만료 - 서버에서 사용하는 SSL/TLS 인증서가 만료되어 갱신해야 하는지 확인합니다.
+ 인증서 검증 문제 - 클라이언트가 서버의 SSL/TLS 인증서를 올바르게 검증할 수 있고 인증서가 신뢰할 수 있는지 확인합니다.
+ 네트워크 구성 문제 - 네트워크 구성이 SSL/TLS 연결을 허용하고 SSL/TLS 핸드셰이크 프로세스를 차단하거나 방해하지 않는지 확인합니다.
+ SSL/TLS 구성 불일치 - 클라이언트 및 서버의 SSL/TLS 설정(예: 암호 제품군 및 프로토콜 버전)이 호환되는지 확인합니다.

각 오류 코드에 대한 자세한 설명과 잠재적 원인을 이해하면 Aurora MySQL 데이터베이스 작업 시 연결 문제를 더 잘 해결할 수 있습니다.

## Aurora MySQL에 대한 파라미터 튜닝 권장 사항
<a name="mysql-dbconn-params"></a>

**최대 연결 수**  
이러한 파라미터를 조정하면 허용되는 최대 연결 한도에 도달하여 발생하는 연결 문제를 방지하는 데 도움이 될 수 있습니다. 애플리케이션의 동시성 요구 사항 및 리소스 제약 조건에 따라 이러한 값이 적절하게 설정되었는지 확인합니다.  
+ `max_connections` - 이 파라미터는 DB 인스턴스에 허용되는 최대 동시 연결 수를 지정합니다.
+ `max_user_connections` - 이 파라미터는 사용자 생성 및 수정 중에 지정할 수 있으며 특정 사용자 계정에 허용되는 최대 동시 연결 수를 설정합니다.

**네트워크 버퍼 크기**  
이러한 값을 늘리면 네트워크 성능이 향상될 수 있습니다. 특히 대규모 데이터 전송 또는 결과 세트가 포함된 워크로드의 경우 더욱 그렇습니다. 그러나 버퍼 크기가 클수록 메모리를 더 많이 사용할 수 있으므로 주의해야 합니다.  
+ `net_buffer_length` - 이 파라미터는 클라이언트 연결 및 결과 버퍼의 초기 크기를 설정하여 메모리 사용량과 쿼리 성능의 균형을 맞춥니다.
+ `max_allowed_packet` - 이 파라미터는 DB 인스턴스에서 전송하거나 수신할 수 있는 단일 네트워크 패킷의 최대 크기를 지정합니다.

**네트워크 압축(클라이언트 측)**  
네트워크 압축을 활성화하면 네트워크 대역폭 사용량이 줄어들 수 있지만 클라이언트와 서버 측 모두에서 CPU 오버헤드가 증가할 수 있습니다.  
+ `compress` – 이 파라미터는 클라이언트/서버 통신을 위한 네트워크 압축을 활성화하거나 비활성화합니다.
+ `compress_protocol` - 이 파라미터는 네트워크 통신에 사용할 압축 프로토콜을 지정합니다.

**네트워크 성능 튜닝**  
이러한 제한 시간을 조정하면 유휴 연결을 관리하고 리소스 소진을 방지하는 데 도움이 될 수 있지만 값이 낮으면 연결이 조기에 종료될 수 있으므로 주의해야 합니다.  
+ `interactive_timeout` - 이 파라미터는 서버가 대화형 연결을 닫기 전에 활동을 기다리는 초 수를 지정합니다.
+ `wait_timeout` - 이 파라미터는 서버가 비대화형 연결을 닫기 전에 활동을 기다리는 초 수를 정합니다.

**네트워크 제한 시간 설정**  
이러한 제한 시간을 조정하면 느리거나 응답하지 않는 연결과 관련된 문제를 해결하는 데 도움이 될 수 있습니다. 하지만 연결이 조기에 실패할 수 있으므로 너무 낮게 설정하지 않도록 주의하세요.  
+ `net_read_timeout` - 이 파라미터는 읽기 작업을 종료하기 전에 연결에서 더 많은 데이터를 기다리는 초 수를 지정합니다.
+ `net_write_timeout` - 이 파라미터는 쓰기 작업을 종료하기 전에 블록이 연결에 기록될 때까지 기다릴 초 수를 결정합니다.

## Aurora MySQL에 대한 데이터베이스 연결 문제 해결 예제
<a name="mysql-dbconn-examples"></a>

다음 예제에서는 Aurora MySQL에 대한 데이터베이스 연결 문제를 식별하고 해결하는 방법을 보여 줍니다.

### 예제 1: 실패한 연결 시도 문제 해결
<a name="mysql-dbconn-example1"></a>

연결 시도는 인증 실패, SSL/TLS 핸드셰이크 실패, `max_connections` 한도 도달, DB 인스턴스의 리소스 제약 등 여러 가지 이유로 실패할 수 있습니다.

성능 개선 도우미에서 또는 다음 명령을 사용하여 실패한 연결 수를 추적할 수 있습니다.

```
mysql> show global status like 'aborted_connects';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| Aborted_connects | 7     |
+------------------+-------+
1 row in set (0.00 sec)
```

시간이 지남에 따라 `Aborted_connects` 수가 증가하면 애플리케이션에 간헐적인 연결 문제가 발생할 수 있습니다.

[Aurora 고급 감사](AuroraMySQL.Auditing.md)를 사용하여 클라이언트 연결에서 연결 및 연결 해제를 로깅할 수 있습니다. DB 클러스터 파라미터 그룹에서 다음 파라미터를 설정하여 이 작업을 수행할 수 있습니다.
+ `server_audit_logging` = `1`
+ `server_audit_events` = `CONNECT`

 다음은 실패한 로그인에 대한 감사 로그에서 발췌한 것입니다.

```
1728498527380921,auora-mysql-node1,user_1,172.31.49.222,147189,0,FAILED_CONNECT,,,1045
1728498527380940,auora-mysql-node1,user_1,172.31.49.222,147189,0,DISCONNECT,,,0
```

위치:
+ `1728498527380921` - 실패한 로그인이 발생한 시점의 에포크 타임스탬프
+ `aurora-mysql-node1` - 연결이 실패한 Aurora MySQL 클러스터 노드의 인스턴스 식별자
+ `user_1` - 로그인에 실패한 데이터베이스 사용자의 이름
+ `172.31.49.222` – 연결이 설정된 클라이언트의 프라이빗 IP 주소
+ `147189` – 실패한 로그인의 연결 ID
+ `FAILED_CONNECT` - 연결이 실패했음을 나타냄.
+ `1045` - 반환 코드. 0이 아닌 값은 오류를 나타냅니다. 이 경우 `1045`는 액세스 거부에 해당합니다.

자세한 내용은 MySQL 설명서의 [서버 오류 코드](https://dev.mysql.com/doc/mysql-errors/5.7/en/server-error-reference.html) 및 [클라이언트 오류 코드](https://dev.mysql.com/doc/mysql-errors/5.7/en/client-error-reference.html)를 참조하세요.

 Aurora MySQL 오류 로그에서 다음과 같은 관련 오류 메시지를 검사할 수도 있습니다.

```
2024-10-09T19:26:59.310443Z 220 [Note] [MY-010926] [Server] Access denied for user 'user_1'@'172.31.49.222' (using password: YES) (sql_authentication.cc:1502)
```

### 예제 2: 비정상적인 클라이언트 연결 해제 문제 해결
<a name="mysql-dbconn-example2"></a>

성능 개선 도우미에서 또는 다음 명령을 사용하여 비정상적인 클라이언트 연결 해제 수를 추적할 수 있습니다.

```
mysql> show global status like 'aborted_clients';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| Aborted_clients | 9     |
+-----------------+-------+
1 row in set (0.01 sec)
```

시간이 지남에 따라 `Aborted_clients`의 수가 증가하면 애플리케이션이 데이터베이스에 대한 연결을 올바르게 닫지 않는 것입니다. 연결이 제대로 닫히지 않으면 리소스 누출과 잠재적인 성능 문제가 발생할 수 있습니다. 연결을 불필요하게 열어 두면 메모리 및 파일 설명자와 같은 시스템 리소스를 사용할 수 있으며, 이로 인해 애플리케이션 또는 서버가 응답하지 않거나 다시 시작될 수 있습니다.

다음 쿼리를 사용하여 연결을 제대로 종료하지 않는 계정을 식별할 수 있습니다. 사용자 계정 이름, 사용자가 연결하는 호스트, 종료되지 않은 연결 수, 종료되지 않은 연결 백분율을 검색합니다.

```
SELECT
    ess.user,
    ess.host,
    (a.total_connections - a.current_connections) - ess.count_star AS not_closed,
    (((a.total_connections - a.current_connections) - ess.count_star) * 100) / (a.total_connections - a.current_connections) AS pct_not_closed
FROM
    performance_schema.events_statements_summary_by_account_by_event_name AS ess
    JOIN performance_schema.accounts AS a ON (ess.user = a.user AND ess.host = a.host)
WHERE
    ess.event_name = 'statement/com/quit'
    AND (a.total_connections - a.current_connections) > ess.count_star;

+----------+---------------+------------+----------------+
| user     | host          | not_closed | pct_not_closed |
+----------+---------------+------------+----------------+
| user1    | 172.31.49.222 |          1 |        33.3333 |
| user1    | 172.31.93.250 |       1024 |        12.1021 |
| user2    | 172.31.93.250 |         10 |        12.8551 |
+----------+---------------+------------+----------------+
3 rows in set (0.00 sec)
```

연결이 종료되지 않은 사용자 계정과 호스트를 식별한 후 연결을 정상적으로 종료하지 않는 코드를 계속 확인할 수 있습니다.

예를 들어 Python의 MySQL 커넥터를 사용하여 연결 객체의 `close()` 메서드를 사용하여 연결을 닫습니다. 다음은 데이터베이스에 대한 연결을 설정하고, 쿼리를 수행하고, 연결을 닫는 함수의 예입니다.

```
import mysql.connector

def execute_query(query):
    # Establish a connection to the database
    connection = mysql.connector.connect(
        host="your_host",
        user="your_username",
        password="your_password",
        database="your_database"
    )

    try:
        # Create a cursor object
        cursor = connection.cursor()

        # Execute the query
        cursor.execute(query)

        # Fetch and process the results
        results = cursor.fetchall()
        for row in results:
            print(row)

    finally:
        # Close the cursor and connection
        cursor.close()
        connection.close()
```

이 예제에서는 예외 발생 여부에 관계없이 연결이 닫혀 있는지 확인하기 위해 `finally` 블록에서 `connection.close()` 메서드를 호출합니다.

### 예제 3: IAM 실패한 연결 시도 문제 해결
<a name="mysql-dbconn-example3"></a>

AWS Identity and Access Management(IAM) 사용자와의 연결은 다음과 같은 여러 가지 이유로 실패할 수 있습니다.
+ 잘못된 IAM 정책 구성
+ 만료된 보안 자격 증명
+ 네트워크 연결 이벤트
+ 데이터베이스 권한 불일치

이러한 인증 오류를 해결하려면 Amazon Relational Database Service(RDS) 또는 Aurora 데이터베이스에서 `iam-db-auth-error` 로그 내보내기 기능을 활성화합니다. 이렇게 하면 Amazon RDS 또는 Amazon Aurora 클러스터에 대한 CloudWatch Log 그룹의 자세한 인증 오류 메시지를 볼 수 있습니다.

활성화되면 이러한 로그를 검토하여 IAM 인증 실패의 특정 원인을 식별하고 해결할 수 있습니다.

예:

```
2025-09-22T12:02:30,806 [ERROR] Failed to authorize the connection request for user 'user_1' due to an internal IAM DB Auth error. (Status Code: 500, Error Code: InternalError)
```

and

```
2025-09-22T12:02:51,954 [ERROR] Failed to authenticate the connection request for user 'user_2' because the provided token is malformed or otherwise invalid. (Status Code: 400, Error Code: InvalidToken)
```

문제 해결 지침은 IAM DB 인증에 대한 [Aurora](UsingWithRDS.IAMDBAuth.Troubleshooting.md) 문제 해결 가이드를 참조하세요.

# Aurora MySQL 데이터베이스 쿼리 성능 문제 해결
<a name="aurora-mysql-troubleshooting-query"></a>

MySQL은 쿼리 계획 평가 방법에 영향을 미치는 시스템 변수, 전환 가능한 최적화, 최적화 프로그램 및 인덱스 힌트, 최적화 프로그램 비용 모델을 통해 [쿼리 최적화 프로그램 제어](https://dev.mysql.com/doc/refman/8.0/en/controlling-optimizer.html) 기능을 제공합니다. 이러한 데이터 포인트는 다양한 MySQL 환경을 비교할 때뿐만 아니라 이전 쿼리 실행 계획을 현재 실행 계획과 비교하고 언제든지 MySQL 쿼리의 전체 실행을 이해하는 데 유용할 수 있습니다.

쿼리 성능은 실행 계획, 테이블 스키마 및 크기, 통계, 리소스, 인덱스, 파라미터 구성 등 여러 요인에 따라 달라집니다. 쿼리를 튜닝하려면 병목 현상을 식별하고 실행 경로를 최적화해야 합니다.
+ 쿼리의 실행 계획을 찾고 쿼리가 적절한 인덱스를 사용하고 있는지 확인하세요. `EXPLAIN`을 사용하고 각 계획의 세부 정보를 검토하여 쿼리를 최적화할 수 있습니다.
+ Aurora MySQL 버전 3(MySQL 8.0 Community Edition과 호환)은 `EXPLAIN ANALYZE` 문을 사용합니다. `EXPLAIN ANALYZE` 문은 MySQL이 쿼리에 시간을 소비하는 위치와 그 이유를 보여주는 프로파일링 도구입니다. Aurora MySQL은 `EXPLAIN ANALYZE`를 사용하여 쿼리를 계획, 준비 및 실행하는 동시에 행 수를 세고 실행 계획의 다양한 시점에서 소요되는 시간을 측정합니다. 쿼리가 완료되면 `EXPLAIN ANALYZE`는 쿼리 결과 대신 계획과 측정값을 인쇄합니다.
+ `ANALYZE` 문을 사용하여 스키마 통계를 최신 상태로 유지하세요. 오래된 통계 때문에 쿼리 최적화 프로그램이 잘못된 실행 계획을 선택하는 경우가 있습니다. 이 경우 테이블과 인덱스 모두의 카디널리티 추정치가 부정확하기 때문에 쿼리 성능이 저하될 수 있습니다. [innodb\$1table\$1stats](https://dev.mysql.com/doc/refman/8.0/en/innodb-persistent-stats.html#innodb-persistent-stats-tables) 테이블의 `last_update` 열에는 스키마 통계가 마지막으로 업데이트된 시간이 표시되며, 이는 '무효함'을 나타내는 좋은 지표입니다.
+ 데이터 분포 편차와 같이 테이블 카디널리티에 고려되지 않는 다른 문제가 발생할 수 있습니다. 자세한 내용은 MySQL 설명서에서 [Estimating ANALYZE TABLE complexity for InnoDB tables](https://dev.mysql.com/doc/refman/8.0/en/innodb-analyze-table-complexity.html) 및 [Histogram statistics in MySQL](https://dev.mysql.com/blog-archive/histogram-statistics-in-mysql/)을 참조하세요.

## 쿼리에 소요되는 시간 이해
<a name="ams-query-time"></a>

쿼리에 소요되는 시간을 확인하는 방법은 다음과 같습니다.
+ [프로파일링](https://dev.mysql.com/doc/refman/8.0/en/show-profile.html)
+ [성능 스키마](https://dev.mysql.com/doc/refman/8.0/en/performance-schema.html)
+ [쿼리 최적화 프로그램](https://dev.mysql.com/doc/refman/8.0/en/controlling-optimizer.html)

**프로파일링**  
기본적으로 프로파일링은 비활성화되어 있습니다. 프로파일링을 활성화한 다음 느린 쿼리를 실행하고 해당 프로필을 검토하세요.  

```
SET profiling = 1;
Run your query.
SHOW PROFILE;
```

1. 시간이 가장 많이 소요되는 단계를 식별합니다. MySQL 설명서의 [General thread states](https://dev.mysql.com/doc/refman/8.0/en/general-thread-states.html)에 따르면 `SELECT` 문의 행 읽기 및 처리는 주어진 쿼리의 수명 동안 실행 상태가 가장 긴 경우가 많습니다. `EXPLAIN` 문을 사용하여 MySQL이 이 쿼리를 실행하는 방식을 이해할 수 있습니다.

1. 느린 쿼리 로그를 검토하여 각 환경의 워크로드가 비슷한지 확인하기 위해 `rows_examined` 및 `rows_sent`를 평가합니다. 자세한 내용은 [Aurora MySQL 데이터베이스에 대한 로깅](aurora-mysql-troubleshooting-logging.md) 섹션을 참조하세요.

1. 식별된 쿼리에 속하는 테이블에 대해 다음 명령을 실행합니다.

   ```
   SHOW TABLE STATUS\G;
   ```

1. 각 환경에서 쿼리를 실행하기 전과 후에 다음 출력을 캡처합니다.

   ```
   SHOW GLOBAL STATUS;
   ```

1. 각 환경에서 다음 명령을 실행하여 이 샘플 쿼리의 성능에 영향을 미치는 다른 쿼리/세션이 있는지 확인합니다.

   ```
   SHOW FULL PROCESSLIST;
   
   SHOW ENGINE INNODB STATUS\G;
   ```

   서버의 리소스가 사용량이 많으면 쿼리를 포함하여 서버의 다른 모든 작업에 영향을 미치는 경우가 있습니다. 또한 쿼리가 실행될 때 정기적으로 정보를 캡처하거나 적절한 간격으로 정보를 캡처하도록 `cron` 작업을 설정할 수 있습니다.

**성능 스키마**  
성능 스키마는 성능에 미치는 영향을 최소화하면서 서버 런타임 성능에 대한 유용한 정보를 제공합니다. 이는 DB 인스턴스에 대한 스키마 정보를 제공하는 `information_schema`와 다릅니다. 자세한 내용은 [Aurora MySQL에서 성능 개선 도우미의 성능 스키마 개요](USER_PerfInsights.EnableMySQL.md) 섹션을 참조하세요.

**쿼리 최적화 프로그램 트레이스**  
특정 [쿼리 계획을 실행하도록 선택](https://dev.mysql.com/doc/refman/8.0/en/execution-plan-information.html)한 이유를 이해하려면 MySQL 쿼리 최적화 프로그램에 액세스하도록 `optimizer_trace`를 설정할 수 있습니다.  
최적화 프로그램 트레이스를 실행하여 최적화 프로그램이 사용할 수 있는 모든 경로와 선택에 대한 광범위한 정보를 표시합니다.  

```
SET SESSION OPTIMIZER_TRACE="enabled=on"; 
SET optimizer_trace_offset=-5, optimizer_trace_limit=5;

-- Run your query.
SELECT * FROM table WHERE x = 1 AND y = 'A';

-- After the query completes:
SELECT * FROM information_schema.OPTIMIZER_TRACE;
SET SESSION OPTIMIZER_TRACE="enabled=off";
```

## 쿼리 최적화 프로그램 설정 검토
<a name="ams-query-parameters"></a>

Aurora MySQL 버전 3(MySQL 8.0 Community Edition과 호환)은 Aurora MySQL 버전 2(MySQL 5.7 Community Edition과 호환)에 비해 최적화 프로그램 관련 변경 사항이 많습니다. `optimizer_switch`에 대한 사용자 지정 값이 있는 경우 기본값의 차이를 검토하고 워크로드에 가장 적합한 `optimizer_switch` 값을 설정하는 것이 좋습니다. 또한 Aurora MySQL 버전 3에서 사용할 수 있는 옵션을 테스트하여 쿼리가 어떻게 수행되는지 검사하는 것이 좋습니다.

**참고**  
Aurora MySQL 버전 3은 [innodb\$1stats\$1persistent\$1sample\$1pages](https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html#sysvar_innodb_stats_persistent_sample_pages) 파라미터에 커뮤니티 기본값인 20을 사용합니다.

이러한 명령을 사용하여 `optimizer_switch` 값을 표시할 수 있습니다.

```
SELECT @@optimizer_switch\G;
```

다음 테이블은 Aurora MySQL 버전 2와 3에 대한 `optimizer_switch` 기본값을 보여줍니다.


| 설정 | Aurora MySQL 버전 2 | Aurora MySQL 버전 3 | 
| --- | --- | --- | 
| batched\$1key\$1access | 끄기 | 끄기 | 
| block\$1nested\$1loop | on | on | 
| condition\$1fanout\$1filter | on | on | 
| derived\$1condition\$1pushdown | – | on | 
| derived\$1merge | on | on | 
| duplicateweedout | on | on | 
| engine\$1condition\$1pushdown | on | on | 
| firstmatch | on | on | 
| hash\$1join | 끄기 | on | 
| hash\$1join\$1cost\$1based | on | – | 
| hypergraph\$1optimizer | – | 끄기 | 
| index\$1condition\$1pushdown | on | on | 
| index\$1merge | on | on | 
| index\$1merge\$1intersection | on | on | 
| index\$1merge\$1sort\$1union | on | on | 
| index\$1merge\$1union | on | on | 
| loosescan | on | on | 
| materialization | on | on | 
| mrr | on | on | 
| mrr\$1cost\$1based | on | on | 
| prefer\$1ordering\$1index | on | on | 
| semijoin | on | on | 
| skip\$1scan | – | on | 
| subquery\$1materialization\$1cost\$1based | on | on | 
| subquery\$1to\$1derived | – | 끄기 | 
| use\$1index\$1extensions | on | on | 
| use\$1invisible\$1indexes | – | 끄기 | 

자세한 내용은 MySQL 설명서의 [Switchable optimizations (MySQL 5.7)](https://dev.mysql.com/doc/refman/5.7/en/switchable-optimizations.html) 및 [Switchable optimizations (MySQL 8.0)](https://dev.mysql.com/doc/refman/8.0/en/switchable-optimizations.html)를 참조하세요.