MogDB 데이터베이스의 ASP 기능을 이용한 성능 문제 진단

MogDB 데이터베이스의 ASP(Active Session Performance) 기능을 통해 성능 문제의 원인을 파악하는 방법에 대해 설명합니다.

local_active_session 뷰

메모리 내의 ASP 정보는 DBE_PERF.local_active_session 뷰에 저장됩니다. 이 뷰는 get_local_active_session() 함수를 호출하여 g_instance.stat_cxt.active_sess_hist_array->active_sess_hist_info에서 샘플링된 데이터를 가져와 생성됩니다. 이 정보는 실시간으로 메모리에 저장되며, 최근 활동 세션 정보를 보여줍니다.

ASP 시스템 테이블

ASP 시스템 테이블은 GS_ASP로, CATALOG 시스템 테이블의 일부이며 src/include/catalog/gs_asp.h 파일에 정의되어 있습니다(CATALOG(gs_asp,9534)). GS_ASP는 GUC 매개변수 asp_flush_rate에 의해 설정된 샘플링 값을 g_instance.stat_cxt.active_sess_hist_array->active_sess_hist_info에서 선택하여 디스크에 영속화됩니다. 이 테이블은 과거의 활동 세션 이력을 보관하며, 장기적인 통계 분석에 적합합니다.

ASP 로그 파일

GUC 매개변수 asp_flush_mode가 file로 설정되면, g_instance.stat_cxt.active_sess_hist_array의 일부 샘플링 정보는 GS_ASP 테이블이 아닌 ASP 로그 파일에 영속화됩니다. 로그 파일의 위치와 이름은 GUC 매개변수 asp_log_directory와 asp_log_filename에 지정되며, 기본값은 데이터베이스의 asp_data 디렉토리입니다.

ASP 로그 파일의 예시 내용:

{"sampleid":"350430","sample_time":"2023-07-27T23:59:35.558198+08:00","need_flush_sample":true,"databaseid":0,"thread_id":"139681843377920","sessionid":"139681843377920","global_sessionid":"0:0#0","start_time":"2023-07-07T16:39:56.969878+08:00","xact_start_time":null,"query_start_time":null,"state":"active","event":"none","waitstatus":"none","lwtid":23455,"psessionid":null,"tlevel":0,"smpid":0,"userid":0,"application_name":"Wal Writer","locktag":null,"lockmode":null,"block_sessionid":null,"client_addr":null,"client_hostname":null,"client_port":null,"query_id":"","unique_query_id":null,"user_id":null,"cn_id":null,"unique_query":null}

실전: 블로킹 원인 찾기

오류 시뮬레이션

세션1의 두 개의 문장을 실행한 후 세션2의 문장을 실행하면 세션2는 세션1의 잠금 해제를 기다리게 됩니다.

세션 1: 테이블 emp의 id가 3인 레코드의 필드 name 값을 c1로 업데이트합니다.

begin;
update emp SET name = 'c1' where id = 3;

세션 2: 테이블 emp의 id가 3인 레코드의 필드 name 값을 c2로 업데이트합니다.

update emp SET name = 'c2' where id = 3;

블로킹 확인

실시간 정보를 조회하려면 다음 SQL을 사용할 수 있습니다.

SELECT blocked_locks.pid     AS blocked_pid,
       blocked_activity.usename  AS blocked_user,
       blocking_locks.pid     AS blocking_pid,
       blocking_activity.usename AS blocking_user,
       blocked_activity.query    AS blocked_statement,
       blocking_activity.query   AS current_statement_in_blocking_process
  FROM  pg_catalog.pg_locks         blocked_locks
   JOIN pg_catalog.pg_stat_activity blocked_activity  ON blocked_activity.pid = blocked_locks.pid
   JOIN pg_catalog.pg_locks         blocking_locks
       ON blocking_locks.locktype = blocked_locks.locktype
       AND blocking_locks.database IS NOT DISTINCT FROM blocked_locks.database
       AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
       AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page
       AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple
       AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid
       AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid
       AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid
       AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid
       AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid
       AND blocking_locks.pid != blocked_locks.pid
   JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid
  WHERE NOT blocked_locks.granted;

결과:

blocked_pidblocked_userblocking_pidblocking_userblocked_statementcurrent_statement_in_blocking_process
47810227406592omm47810357757696ommupdate emp SET name = 'MogDB' where id = 3;update emp SET name = 'MogDB' where id = 3;

ASP 데이터를 통한 블로킹 확인

SELECT sessionid, start_time, event, count
FROM (
SELECT sessionid, start_time, event, COUNT(*)
FROM dbe_perf.local_active_session
WHERE sample_time > now() - 10 / (24 * 60)
GROUP BY sessionid, start_time, event) as t ORDER BY SUM(t.count) OVER (PARTITION BY t.sessionid, start_time) DESC, t.event;

결과:

sessionidstart_timeeventcount
478103577576962024-04-21 21:07:23.08784+08wait cmd598
478103906526722024-04-21 21:12:03.224273+08HashJoin - build hash1
SELECT sessionid, start_time, event, wait_status, block_sessionid, final_block_sessionid 
FROM dbe_perf.local_active_session 
WHERE block_sessionid IN (47810357757696, 47810390652672);

세션 ID 47810357757696이 블로킹 소스이며, 세션 ID 47810390652672이 블로킹 대상임이 확인됩니다.

ASP 기능 향상

MogDB 기업 버전의 향상된 ASH 기능은 "SQL 실행 상태 관찰"이라고 하며, 주요히 샘플링 데이터에 SQL 실행 연산자의 샘플링을 추가하여 수행됩니다. dbe_perf.local_active_session 및 GS_ASP에 plan_node_id라는 열을 추가하여 각 SQL 문장의 연산자별 실행 상황을 기록합니다.

향상된 ASP 기능을 활성화하기 위한 매개변수: resource_track_level 매개변수가 operator로 설정되면 연산자 샘플링 기능이 활성화됩니다. 기본값은 query로 SQL 수준 샘플링만 기록합니다.

예시

테이블 test 생성:
MogDB=# create table test(c1 int);
CREATE TABLE
MogDB=# insert into test select generate_series(1, 1000000000);
해당 SQL의 query_id 조회:
MogDB=# select query, query_id from pg_stat_activity where query like 'insert into test select%';
                    query                                  |    query_id
-----------------------------------------------------------+-----------------
 insert into test select generate_series(1, 100000000000); | 562949953421368
(1 row)
plan_node_id 포함된 실행 계획 조회:
Set resource_track_cost=10;
MogDB=# select query_plan from dbe_perf.statement_complex_runtime where queryid = 562949953421368;
                                 query_plan
----------------------------------------------------------------------------
 Coordinator Name: datanode1                                               +
 1 | Insert on test  (cost=0.00..17.51 rows=1000 width=8)                         +
 2 |  ->  Subquery Scan on "*SELECT*"  (cost=0.00..17.51 rows=1000 width=8)    +
 3 |   ->  Result  (cost=0.00..5.01 rows=1000 width=0)                         +
                                                                        +
(1 row)
SQL 실행 상태 관찰:
MogDB=# select plan_node_id, count(plan_node_id) from dbe_perf.local_active_session where query_id = 562949953421368 group by plan_node_id;
 plan_node_id | count
--------------+-------
        3     |   12
        1     |   366
        2     |   2
(3 rows)

insert into test select generate_series(1, 1000000000) SQL이 성능 병목을 겪고 있음을 발견했으며, 해당 SQL 실행 과정에서 가장 많이 샘플링된 연산자는 insert 작업(plan_node_id = 1, count = 366)임을 확인할 수 있습니다. 이 부분을 최적화할 수 있습니다.

태그: MogDB ASP 성능분석 블로킹 SQL최적화

8월 26일 22:34에 게시됨