부하 테스트와 동작 점검
Oracle과 PostgreSQL 모니터용 부하 테이블 생성, 공간 부족과 생성 실패 대응 및 데모와 실제 부하의 차이
#핵심 요약
실습 모니터는 숫자를 직접 움직이지 않음
부하 도구(load.py, bad_sql.py)가 부하 전용 계정의 테이블에 부하를 걸고 대시보드는 조회만 함
부하 데이터는 Oracle과 PostgreSQL 모두 같은 구성임
풀스캔용 big_sales 200만 건, 인덱스 컬럼 가공 실습용 날짜 인덱스, 락 경합 실습용 1건짜리 hot_row, 커밋 폭주 실습용 commit_log
Oracle에서 connect by level <= 2000000은 메모리가 작은 DB에서 ORA-30009로 실패했음
DB 없이 화면과 탐지 흐름을 먼저 보는 데모 모드가 있음
실습에서는 데모 모드에서 카테시안 조인을 넣고 10초 뒤 경보가 뜨는지 확인했음
#개념과 동작 원리
실제 데이터가 아닌 교육용 생성 데이터임
| 객체 | 용도 | Oracle 실습 결과 | PostgreSQL 실습 결과 |
|---|---|---|---|
big_sales |
풀스캔하면 읽기 그래프가 튐 | 2,000,000건, 288MB, 36,864블록 | 2,000,000건, 341MB |
| 날짜 인덱스 | 인덱스가 있는데도 못 타는 가공 실습 | 43MB | 수업 자료에 크기 기재 없음 |
hot_row |
락 경합 실습용 1건 | 1건 | 1건 |
commit_log |
커밋 폭주 실습 | 생성 | 생성 |
PostgreSQL 쪽 테이블은 shared_buffers 128MB보다 커서 풀스캔하면 디스크 읽기가 생긴다고 실습에서는 적었음
PostgreSQL판은 평상시 부하를 위해 id에 기본키를 둠
#데모 모드
| 확인 기준 | 실습 결과 |
|---|---|
| 데모 화면이 뜨는가 | KPI, CPU, Memory, SQL Elapsed, Alert Log, Reads 추이 모두 표시 |
| 카테시안 조인 버튼 → 경보 | 10초 뒤 악성 SQL 의심 세션 1개 감지 |
| 상세 패널 | SQL 전문, 진단(카테시안 곱, 풀 테이블 스캔), 실행계획의 MERGE JOIN CARTESIAN 빨강 |
경보 기준이 "10초 넘게 실행 중"이라 누른 직후에는 경보가 없음
데모의 악성 세션은 3분 뒤 자동으로 사라지고, 설명할 때는 자동 새로고침 멈춤을 켜면 화면이 고정됨
#필수 명령어 또는 SQL
#Oracle: 공간 먼저 확인
select tablespace_name, file_name, round(bytes/1024/1024) mb, autoextensible, round(maxbytes/1024/1024) max_mb
from dba_data_files where tablespace_name = 'USERS';
select round(sum(bytes)/1024/1024) free_mb from dba_free_space where tablespace_name = 'USERS';df -h /home결과 해석: 실습에서는 만들기 전 USERS 여유가 4MB로 작았지만 자동 확장(최대 32GB)이 켜져 있고 파일 시스템 여유가 25GB라 문제없다고 판단했음
자동 확장이 꺼져 있으면 먼저 alter database datafile '...' autoextend on maxsize 2g;를 함
실습 출력의 418MB, 21MB는 테이블을 만든 뒤 다시 조회한 값임
#Oracle: 부하 스키마(non-CDB용 스크립트)
create user <LOAD_USER> identified by <PASSWORD>
default tablespace users quota unlimited on users;
grant create session, create table, create procedure to <LOAD_USER>;
conn <LOAD_USER>/<PASSWORD>@//localhost:1521/<SERVICE_NAME>
create table big_sales nologging as
select rownum as id,
mod(rownum, 1000) as cust_id,
trunc(dbms_random.value(1,1e5)) as amount,
sysdate - mod(rownum, 3650) as sale_date,
rpad('x', 100, 'x') as filler
from (select level from dual connect by level <= 2000),
(select level from dual connect by level <= 1000);
create index big_sales_dt_ix on big_sales(sale_date);
create table hot_row (id number primary key, cnt number);
insert into hot_row values (1, 0);
create table commit_log (id number, ts timestamp default systimestamp);
commit;
exec dbms_stats.gather_table_stats(user, 'BIG_SALES');결과 해석: 실습 실행 시간은 테이블 생성 11.28초, 인덱스 9.82초로 전체 약 25초였음
확인은 count(*)로 2,000,000건, user_ind_columns로 인덱스가 SALE_DATE에 있는지, user_segments로 크기를 봄
#PostgreSQL: 부하 스키마
create role <LOAD_USER> login password '<PASSWORD>';
create database <LOAD_USER> owner <LOAD_USER>;
\c <LOAD_USER> <LOAD_USER> 127.0.0.1
create table big_sales as
select g as id,
g % 1000 as cust_id,
trunc(random() * 100000)::int as amount,
current_date - (g % 3650) as sale_date,
repeat('x', 100) as filler
from generate_series(1, 2000000) g;
alter table big_sales add primary key (id);
create index big_sales_dt_ix on big_sales(sale_date);
create table hot_row (id int primary key, cnt int);
insert into hot_row values (1, 0);
create table commit_log (id int, ts timestamptz default now());
analyze big_sales;결과 해석: 실습에서는 1분쯤 걸린다고 적었고 마지막 확인 조회에서 2,000,000건, 341MB가 나왔음
처음부터 다시 하려면 DB, 롤, 권한을 지운 뒤 스크립트를 다시 실행하며, 대시보드가 켜져 있으면 먼저 끔
#부하 도구
python load.py io --sessions 3 --seconds 45결과 해석: 세션 3개가 45초 동안 큰 테이블을 반복해 읽음
실습 결과는 세션마다 362~365회 실행임
대시보드의 Reads 추이선이 움직이는지 보는 용도임
악성 SQL 실행기는 문제 SQL 탐지와 세션 진단에서 다룸
#사용 조건과 주의사항
connect by level <= 2000000은 200만 단계 재귀를 한꺼번에 PGA에 올려, SGA 768MB로 작게 잡은 소스 DB에서 ORA-30009가 났음
뒤이어 인덱스는 ORA-00942, 통계 수집은 ORA-20000으로 실패했음
반쯤 만들어진 계정은 drop user ... cascade 후 다시 실행했음
실습에서는 행 생성기의 곱으로 바꿔도 level 대신 rownum을 쓰므로 id, cust_id, sale_date 값은 수업 자료와 같다고 적었음amount는 난수라 실행마다 다름
소스 PDB용 스크립트는 접속 서비스가 non-CDB에 없어 접속 문자열만 바꾼 non-CDB용 파일을 따로 만들었음
오라클 게이지 4단계의 읽기 부하는 5단계 테이블이 있어야 하므로, 실습에서는 4단계 일부를 건너뛰었다가 5단계 뒤에 돌아와 실행하게 했음