K6를 사용하여 데이터베이스 쿼리 성능을 테스트하는 방법
Source: Dev.to
번역할 텍스트를 제공해 주시면 한국어로 번역해 드리겠습니다.
전제 조건 📑
xk6-sql 모듈 알아보기 🧠
xk6-sql은 k6의 공식 확장으로, 성능 테스트에서 직접 SQL 쿼리를 실행할 수 있게 해줍니다. 이를 통해 MySQL, PostgreSQL, SQL Server, SQLite 등 다양한 관계형 데이터베이스에 연결하고 다음과 같은 작업을 수행할 수 있습니다:
- 테이블 생성
- 데이터 삽입
- 성능 테스트 사이클 중 쿼리 실행
사용하려면 선택한 데이터베이스에 맞는 드라이버와 함께 k6/x/sql 모듈을 import 해야 합니다. 예: xk6-sql-driver-postgres. import 후에는 다음을 할 수 있습니다:
- 데이터베이스 연결 열기;
- 설정 단계(
setup)에서 SQL 명령 실행; - 실행 단계에서 엔티티 데이터 조작;
- 해제 단계(
teardown)에서 연결 닫기.
사용된 애플리케이션 🛝
Padrinho – 구인 공고를 탐색하는 애플리케이션으로, 사용자가 프런트엔드에서 직접 각 기회의 상세 정보를 접근할 수 있는 공개 라우트를 가지고 있습니다. 이러한 라우트에 캐시가 활성화되어 있더라도, 상세 조회는 여러 엔터티 간의 조인을 포함하며 전체 애플리케이션에서 처리되는 요청의 **약 60 %에서 65 %**를 차지합니다.
반환되는 정보의 일관성을 보장하는 것 외에도, 우리는 Supabase의 단일 PostgreSQL 인스턴스 가용성을 처리해야 했습니다. 특히 트래픽이 가장 많은 시기(첫 방문)에는 구인 공고가 처음 조회될 때 아직 캐시에 존재하지 않기 때문입니다.
스크립트 설정 👷🏻♀️
임포트
import sql from "k6/x/sql";
import postgres from "k6/x/sql/driver/postgres";
import { SharedArray } from "k6/data";
import { check } from "k6";
import { QUERY_DETALHE_VAGA } from "./query.js";
참고: 버전 1.2.1부터 k6에 Automatic extension resolution 기능이 도입되었습니다. 이제 xk6 모듈이나 k6 코어에 포함되지 않은 모듈을 위해 커스텀 바이너리를 만들 필요가 없으며,
K6_ENABLE_COMMUNITY_EXTENSIONS플래그를true로 설정하기만 하면 됩니다. 로그 예시:
INFO[0000] Automatic extension resolution is enabled. The current k6 binary doesn't satisfy all dependencies, it's required to provision a custom binary. deps="k6/x/faker*"
INFO[0000] A new k6 binary has been provisioned with version(s): k6:v1.4.2 k6/x/faker:v0.4.4
테스트 옵션
export const options = {
vus: 10,
iterations: 100,
duration: "5s",
};
우리는 100 회 반복을 최대 5 s 동안 10 VU를 사용하여 수행하도록 정의하고 있습니다.
임계값 추가
export const options = {
vus: 5,
iterations: 100,
duration: "5s",
thresholds: {
iteration_duration: [
"p(90) **Importante:** Nunca defina valores sensíveis diretamente no código."
]
}
};
데이터베이스 연결 (setup)
export function setup() {
if (!host || !port || !dbname || !user || !password) {
throw new Error(
"Variáveis DB_HOST, DB_PORT, DB_NAME, DB_USER e DB_PASSWORD são obrigatórias."
);
}
const connectionString = `postgres://${user}:${password}@${host}:${port}/${dbname}?sslmode=${ssl}`;
const db = sql.open(postgres, connectionString);
return db;
}
2단계 – 조회용 데이터 세트 정의
두 번째 단계에서는 데이터베이스 조회에 사용할 데이터 세트를 정의합니다. .json 파일에 정의된 몇몇 조회 ID를 사용하며, 이를 SharedArray 구조로 읽어들여야 합니다:
const nanoIds = new SharedArray("nano_ids", () => {
return JSON.parse(open("./nanoids.json"));
});
3단계 – 쿼리 실행
정의된 데이터와 데이터베이스 연결이 열려 있으면 실행 단계에서 쿼리를 정의할 수 있습니다. 목적은 실행 시간 동안 계획된 모든 VU에 SharedArray에 로드된 ID를 분배하고, 데이터베이스에 쿼리를 수행한 뒤 쿼리 결과가 반환되었는지 확인하는 것입니다. 설정에 지연을 지정하지 않으므로 VU는 설정된 시간 간격 내에서 가능한 한 많은 요청을 수행합니다.
export default function (db) {
const nanoId = nanoIds[Math.floor(Math.random() * nanoIds.length)];
const result = db.query(QUERY_DETALHE_VAGA, nanoId);
check(result, {
"consulta executada": (rows) => rows.length >= 0,
});
}
4단계 – 해제
실행 후, 해제 단계에서 데이터베이스 연결을 닫으며 마무리합니다:
export function teardown(db) {
db.close();
}
스크립트 결과 🧑🔬
실행 후 출력 결과에서는 avg, min, med, max 및 퍼센트 **p(90)**와 **p(95)**를 포함한 주요 반복 지표를 확인할 수 있습니다.
█ THRESHOLDS
iteration_duration
✗ 'p(90) *Nosso experimento foi conduzido em execução única utilizando um banco de dados gratuito da ferramenta **Supabase**.*
결론 ❤️
데이터베이스 쿼리 성능은 사용자 경험과 애플리케이션 확장성에 직접적인 영향을 미치는 중요한 요소입니다.
이 글에서 보여준 바와 같이 **xk6-sql**을 사용하면 SQL 쿼리의 성능 병목을 개별적으로 식별하고, 명확한 기준선을 설정하며, 시간이 지남에 따라 성능 저하를 모니터링할 수 있었습니다.
데이터베이스 성능 테스트를 개발 주기에 통합하면 운영 환경에서의 문제를 예방할 뿐만 아니라, 최적화 우선순위를 정하고 개선 사항을 최종 사용자에게 영향을 주기 전에 검증할 수 있는 객관적인 지표를 제공합니다.
내용이 마음에 드시고 K6를 이용한 성능 테스트에 대해 더 알고 싶으신가요?
Udemy에서 제 강의를 확인해 보세요:
