Amazon RDS 또는 Amazon Aurora PostgreSQL의 높은 CPU 사용률 문제를 해결하려면 어떻게 해야 하나요?

8분 분량
0

Amazon Relational Database Service(Amazon RDS) 또는 Amazon Aurora PostgreSQL-Compatible Edition에서 CPU 사용률이 높은 원인을 식별하고 해결하려고 합니다.

간략한 설명

로드의 CPU 사용량이 높은 경우 다음 도구를 조합하여 원인을 식별하세요.

해결 방법

Amazon CloudWatch 지표

CloudWatch 지표를 사용하여 장기간에 걸친 CPU 패턴을 식별할 수 있습니다. WriteIOPs, ReadIOPs, ReadThroughputWriteThroughput 그래프를 CPU 사용률과 비교하여 워크로드로 인해 높은 CPU가 발생한 시간을 확인할 수 있습니다.

기간을 확인한 후 DB 인스턴스와 연결된 향상된 모니터링 데이터를 검토하세요. 1, 5, 10, 15, 30 또는 60초 간격으로 데이터를 수집하도록 향상된 모니터링을 설정할 수 있습니다. 그러면 CloudWatch보다 더 세분화된 수준에서 데이터를 수집할 수 있습니다.

향상된 모니터링

향상된 모니터링은 운영 체제(OS) 수준의 뷰를 제공합니다. 이 뷰는 높은 CPU 의 원인을 세부적인 수준에서 식별하는 데 도움이 될 수 있습니다. 예를 들어 평균 로드, CPU 분포(System% 또는 Nice%) 및 OS 프로세스 목록을 검토할 수 있습니다.

향상된 모니터링을 사용하면 1, 5, 15분 간격으로 loadAverageMinute 데이터를 확인할 수 있습니다. 평균 로드가 vCPU 수보다 크면 인스턴스에 과부하가 걸렸다는 것을 나타냅니다. 평균 로드가 DB 인스턴스 클래스의 vCPU 수보다 적을 경우 CPU 제한으로 인해 애플리케이션 지연 시간이 발생하지 않을 수 있습니다. CPU 사용의 원인을 진단할 때는 평균 로드를 확인하여 오탐이 발생하지 않도록 하세요.

예를 들어, 프로비저닝된 IOPS가 3000인 db.m5.2xlarge 인스턴스 클래스를 사용하는 DB 인스턴스가 CPU 제한에 도달했다고 가정해 보겠습니다. 다음 예제에서 인스턴스 클래스에는 8개의 vCPU가 연결되어 있습니다. 동일한 평균 로드에서 170을 초과하면 측정된 기간 동안 기계에 과부하가 걸린다는 의미입니다.

평균 로드 시간(분)

15170.25
5391.31
1596.74

CPU 사용률

사용자(%)0.71
시스템(%)4.9
양호함(%)93.92
합계(%)99.97

참고: 향상된 모니터링에서 **Nice%**는 워크로드가 데이터베이스에 대해 사용하는 CPU의 양을 나타냅니다.

향상된 모니터링을 활성화한 후 DB 인스턴스와 연결된 OS 프로세스 목록도 확인할 수 있습니다. 향상된 모니터링은 최대 100개의 프로세스를 보여 주므로 성능에 가장 큰 영향을 미치는 프로세스를 식별하는 데 도움이 될 수 있습니다. 향상된 모니터링 결과를 pg_stat_activity 결과와 결합하여 쿼리의 리소스 사용량을 식별하는 데 도움이 될 수 있습니다.

성능 인사이트

Amazon RDS 성능 개선 도우미를 사용하여 데이터베이스 로드의 원인이 되는 쿼리를 식별하세요. 특정 기간에 해당하는 SQL 탭을 확인합니다.

네이티브 PostgreSQL 뷰 및 카탈로그

데이터베이스 엔진 수준에서는 pg_stat_activitypg_stat_statements를 사용할 수 있습니다. 실시간으로 문제가 발생하는 경우 pg_stat_activity 또는 pg_stat_statements을 사용하여 가장 많은 트래픽을 보내는 시스템, 클라이언트 및 IP 주소를 그룹화하세요. 이 데이터를 사용하여 시간 경과에 따른 증가 또는 애플리케이션 서버의 증가를 확인할 수 있습니다. 애플리케이션 서버의 세션 중단이나 잠금 문제가 있는지도 확인할 수 있습니다. 자세한 내용을 보려면 PostgreSQL 웹 사이트의 페이지pg_stat_activitypg_stat_statements를 참조하세요.

기존 사용자 지정 파라미터 그룹을 수정하고 다음 값을 설정하여 pg_stat_statements를 활성화합니다.

  • shared_preload_libraries에 Add pg_stat_statements 추가
  • track_activity_query_size = 4096
  • pg_stat_statements.track = ALL
  • pg_stat_statements.max = 10000

즉시 적용을 선택한 다음 DB 인스턴스를 재부팅합니다. 그런 다음 모니터링하려는 데이터베이스에서 다음과 비슷한 명령을 실행합니다.

demo=> select current_database();current_database
------------------
demo
(1 row)     

demo=> CREATE EXTENSION IF NOT EXISTS pg_stat_statements;

참고: 앞의 명령은 데모 데이터베이스에 확장 프로그램을 설치합니다.

pg_stat_statements를 설정한 후 다음 방법 중 하나를 사용하여 출력을 모니터링합니다.

total_time쿼리를 나열하고 어떤 쿼리가 데이터베이스에서 가장 많은 시간을 소비하는지 확인하려면 다음 쿼리 중 하나를 실행합니다:

PostgreSQL 버전 12 이하

SELECT total_time, query
FROM pg_stat_statements
ORDER BY total_time DESC LIMIT 10;

PostgreSQL 버전 13 이상

SELECT total_plan_time+total_exec_time as total_time, query
FROM pg_stat_statements
ORDER BY 1 DESC LIMIT 10;

버퍼 캐시 적중률이 낮은 쿼리를 나열하려면 다음 쿼리 중 하나를 실행하세요.

PostgreSQL 버전 12 이하

SELECT query, calls, total_time, rows, 100.0 * shared_blks_hit / nullif(shared_blks_hit + shared_blks_read, 0) AS hit_percent
FROM pg_stat_statements
ORDER BY total_time DESC LIMIT 10;

PostgreSQL 버전 13 이상

SELECT query, calls, total_plan_time+total_exec_time as total_time, rows, 100.0 * shared_blks_hit / nullif(shared_blks_hit +shared_blks_read, 0) AS hit_percent
FROM pg_stat_statements
ORDER BY 3 DESC LIMIT 10;

실행별로 쿼리를 나열하여 시간 경과에 따른 쿼리를 샘플링하려면 다음 쿼리를 실행합니다.

PostgreSQL 버전 12 이하

SELECT query, calls, total_time/calls as avg_time_ms, rows/calls as avg_rows,temp_blks_read/calls as avg_tmp_read, temp_blks_written/calls as avg_temp_written
FROM pg_stat_statements
WHERE calls != 0
ORDER BY total_time DESC LIMIT 10;

PostgreSQL 버전 13 이상

SELECT query,
calls,
(total_plan_time+total_exec_time as total_time)/calls as avg_time_ms,
 rows/calls as avg_rows,
temp_blks_read/calls as avg_tmp_read,
 temp_blks_written/calls as avg_temp_written
FROM pg_stat_statements
WHERE calls != 0
ORDER BY 3 DESC LIMIT 10;

데이터베이스의 유휴 연결

데이터베이스의 유휴 연결은 메모리 및 CPU와 같은 컴퓨팅 리소스를 소비할 수 있습니다. 인스턴스의 CPU 사용률이 높으면 데이터베이스의 유휴 연결을 확인하세요. 자세한 내용을 보려면 유휴 PostgreSQL 연결이 성능에 미치는 영향을 참조하세요. 유휴 연결을 확인하려면 향상된 모니터링을 사용하여 OS 프로세스 목록을 검토하세요. 하지만 이 목록에는 최대 100개의 프로세스가 표시됩니다.

유휴 연결을 확인하려면 데이터베이스 수준에서 다음 쿼리를 실행합니다.

다음 쿼리를 실행하여 유휴 및 활성 상태인 현재 세션을 확인합니다:

SELECT pid, datname, state, current_timestamp-least(query_start,xact_start) age, application_name, usename, queryFROM pg_stat_activity
WHERE query != '<IDLE>
'AND query NOT ILIKE '%pg_stat_activity%'
AND usename!='rdsadmin'
ORDER BY query_start desc;

SELECT application_name,pid,wait_event_type,wait_event,current_timestamp-least(query_start,xact_start) AS runtime, query AS current_query
FROM pg_stat_activity
WHERE not pid=pg_backend_pid()
AND query NOT ILIKE '%pg_stat_activity%'
AND usename!='rdsadmin';

다음 쿼리를 실행하여 사용자 및 애플리케이션 이름별 연결 수를 가져옵니다.

postgres=> SELECT application_name,count(*) FROM pg_stat_activity GROUP BY application_name;
    application_name    | count
------------------------+-------
 psql                   |     1
 PostgreSQL JDBC Driver |     1
                        |     5
(3 rows)

postgres=> SELECT usename,count(*) FROM pg_stat_activity GROUP BY usename;
 usename  | count
----------+-------
 master   |     4
 user1    |     1
 rdsadmin |     2
(3 rows)

유휴 연결을 확인한 후 다음 쿼리 중 하나를 실행하여 연결을 종료합니다.

psql=> SELECT pg_terminate_backend(pid)
   FROM pg_stat_activity
   WHERE usename = 'example-username'
   AND pid <> pg_backend_pid()
   AND state in ('idle');

-또는-

SELECT pg\_terminate\_backend (example-pid);

애플리케이션에서 연결이 너무 많으면 메모리 및 CPU 리소스가 이러한 연결을 관리하는 데 소비되지 않도록 변경하세요. 애플리케이션을 변경하여 연결 수를 제한하거나 PgBouncer와 같은 연결 풀러를 사용할 수 있습니다. 연결 풀링을 설정할 수 있는 관리형 서비스인 Amazon RDS 프록시를 사용할 수도 있습니다.

ANALYZE 명령

ANALYZE 명령은 데이터베이스의 테이블 내용에 대한 통계를 수집하고 그 결과를 pg_statistic 시스템 카탈로그에 저장합니다. 그런 다음 쿼리 플래너는 이러한 통계를 사용하여 쿼리의 가장 효율적인 실행 계획을 결정하는 데 도움을 줍니다. 데이터베이스의 테이블에서 ANALYZE을 자주 실행하지 않는 경우, 쿼리에서 더 많은 컴퓨팅 리소스를 사용할 수 있습니다. 액세스하는 관계에 대해 시스템에 기한 경과 통계가 있기 때문에 쿼리는 더 많은 리소스를 소비합니다. 이러한 문제는 다음과 같은 상황에서 발생합니다.

  • Autovacuum이 자주 실행되지 않습니다.
  • 주요 버전 업그레이드 후 ANALYZE가 실행되지 않았습니다.

Autovacuum이 자주 실행되지 않습니다. Autovacuum은 VACUUM 및 ANALYZE 명령의 실행을 자동화하는 대몬입니다. Autovacuum은 데이터베이스에서 비대해진 테이블을 검사하고 재사용을 위한 공간을 확보합니다. autovacuum 대몬은 설정된 튜플 임계값이 초과될 때마다 ANALYZE 작업을 실행하여 테이블 통계가 정기적으로 업데이트되도록 합니다. 그러면 쿼리 플래너가 최근 통계를 기반하여 가장 효율적인 쿼리 계획을 사용할 수 있습니다. autovacuum이 실행되지 않는 경우 쿼리 플래너는 최적이 아닌 쿼리 플래너를 생성하여 쿼리의 리소스 사용량을 증가시킬 수 있습니다. 자세한 내용을 보려면 다음 문서를 참조하세요.

테이블에서 autovacuum 및 autoanalyze를 마지막으로 실행한 시기에 대한 정보를 얻으려면 다음 쿼리를 실행하세요.

SELECT relname, last\_autovacuum, last\_autoanalyze FROM pg\_stat\_user\_tables;

**주요 버전 업그레이드 후 ANALYZE가 실행되지 않았습니다.**PostgreSQL 데이터베이스는 일반적으로 주요 엔진 버전 업그레이드 후에 성능 문제가 발생합니다. 이러한 문제의 일반적인 원인은 업그레이드 후 pg_statistic 테이블을 새로 고치기 위해 ANALYZE 작업이 수행되지 않기 때문입니다. PostgreSQL DB 인스턴스용 RDS의 모든 데이터베이스에 대해 ANALYZE 작업을 실행합니다. 주요 버전 업그레이드 중에는 옵티마이저 통계가 전송되지 않습니다. 따라서 리소스 사용률 증가로 인한 성능 문제를 방지하려면 모든 통계를 재생성하세요.

주요 버전 업그레이드 후 현재 데이터베이스의 모든 일반 테이블에 대한 통계를 생성하려면 파라미터 없이 다음 명령을 실행합니다.

ANALYZE VERBOSE

PostgreSQL 로깅 파라미터

쿼리 로깅을 사용하려면 Amazon RDS for PostgreSQL을 사용하세요. 그런 다음 PostgreSQL 오류 로그를 확인하여 log_min_duration_statementlog_statement 파라미터가 적절한 값으로 설정되어 있는지 확인합니다. 자세한 내용을 보려면 PostgreSQL 웹 사이트의 오류 보고 및 로깅을 참조하세요.

CPU 사용량 낮추기

높은 CPU를 유발하는 쿼리를 식별한 후 다음 방법을 사용하여 CPU 사용량을 더 낮추세요.

  • 튜닝할 기회를 찾으려면 EXPLAINEXPLAIN ANALYZE를 사용하여 주의 사항을 파악하세요. 자세한 내용을 보려면 PostgreSQL 웹 사이트의 EXPLAIN을 참조하세요.
  • 반복적으로 실행되는 쿼리가 있는 경우 준비된 명령문을 사용하여 CPU에 가해지는 부하를 줄이세요. 준비된 명령문을 반복해서 실행하면 쿼리 계획이 캐시됩니다. 계획은 추가 실행을 위해 이미 캐시에 저장되어 있으므로 계획에 소요되는 시간이 훨씬 줄어듭니다.

관련 정보

PostgreSQL 작업 모범 사례

AWS 공식
AWS 공식업데이트됨 3달 전
2 댓글

시간 경과에 따른 샘플 쿼리에 대해 실행별로 쿼리를 나열합니다. PostgreSQL 버전 13 이상의 경우:

아래 query는 PostgreSQL에서 실행해보면 오류가 발생합니다.

SELECT query, calls, (total_plan_time+total_exec_time as total_time)/calls as avg_time_ms, rows/calls as avg_rows,
temp_blks_read/calls as avg_tmp_read, temp_blks_written/calls as avg_temp_written
FROM pg_stat_statements
WHERE calls != 0
ORDER BY 3 DESC LIMIT 10;

SELECT 문에서 별칭을 지정할 때 괄호를 사용하면 문제가 발생합니다. as total_time를 괄호 밖으로 이동해야 합니다. 다음과 같이 수정하면 됩니다.

SELECT query, 
       calls, 
       (total_plan_time + total_exec_time) / calls as avg_time_ms, 
       rows / calls as avg_rows,
       temp_blks_read / calls as avg_tmp_read, 
       temp_blks_written / calls as avg_temp_written
FROM pg_stat_statements
WHERE calls != 0
ORDER BY avg_time_ms DESC 
LIMIT 10;
답글을 게시함 5달 전

의견을 작성해 주셔서 감사합니다. 필요에 따라 지식 센터 문서를 검토하고 업데이트하겠습니다.

profile pictureAWS
중재자
답글을 게시함 5달 전