Cloud SQL Insights 소개

Cloud SQL Insights는 Cloud SQL 데이터베이스의 쿼리 성능 문제를 감지하고 진단하고 방지하는 데 도움이 됩니다. 감지뿐 아니라 셀프서비스, 직관적인 모니터링, 진단 정보를 제공하여 문제의 근본 원인을 식별하는 데 도움이 됩니다.

이 Codelab에서는 PostgreSQL용 Cloud SQL 인스턴스를 설정하고, Cloud SQL 인스턴스를 백엔드 저장소로 사용하는 Node.js 앱을 배포한 후 Cloud SQL 통계를 사용하여 쿼리를 확인 및 모니터링하는 방법을 알아봅니다.

기본 요건

  • Node.js 프로그래밍 언어 및 도구에 대한 기본 지식

실습할 내용

  • Node.js 앱에서 Cloud SQL을 사용합니다.
  • Node.js 앱에서 SQL Commenter를 사용 설정합니다.
  • Cloud SQL Insights를 사용하여 쿼리 성능을 모니터링하고 조사합니다.

필요한 사항

  • API를 사용 설정하고 서비스를 만들 수 있는 권한이 있는 Google Cloud 계정

자습형 환경 설정

  1. Cloud Console에 로그인하고 새 프로젝트를 만들거나 기존 프로젝트를 다시 사용합니다. (아직 Gmail이나 Google Workspace 계정이 없는 경우 계정을 만들어야 합니다.)

사용 중인 프로젝트의 프로젝트 ID를 기억해 둡니다. 이 ID는 나중에 이 Codelab에서 PROJECT-ID라고 부릅니다.

  1. 그런 후 Google Cloud 리소스를 사용할 수 있도록 Cloud Console에서 결제를 사용 설정해야 합니다.

이 Codelab 실행에는 많은 비용이 들지 않습니다. 이 가이드를 마친 후 비용이 결제되지 않도록 리소스 종료 방법을 알려주는 '삭제 및 자세히 알아보기' 섹션의 안내를 따르세요. Google Cloud 새 사용자에게는 $300USD 상당의 무료 평가판 프로그램 참여 자격이 부여됩니다.

Cloud Shell 활성화

  1. Cloud Console에서 Cloud Shell 활성화를 클릭합니다.

Cloud Shell 활성화

이전에 Cloud Shell을 시작하지 않았으면 설명이 포함된 중간 화면(스크롤해야 볼 수 있는 부분)이 제공됩니다. 이 경우 계속을 클릭합니다(이후 다시 표시되지 않음). 이 일회성 화면은 다음과 같습니다.

Cloud Shell 대화상자 창

Cloud Shell을 프로비저닝하고 연결하는 데 몇 분 정도만 걸립니다.

Cloud Shell 터미널

가상 머신은 필요한 모든 개발 도구와 함께 로드됩니다. 영구적인 5GB 홈 디렉터리를 제공하고 Google Cloud에서 실행되므로 네트워크 성능과 인증이 크게 개선됩니다.

  1. Cloud Shell에서 다음 명령어를 실행하여 올바른 프로젝트를 사용하고 있는지 확인합니다.

Cloud Shell에 연결되면 인증이 완료되었고 프로젝트가 해당 프로젝트 ID로 이미 설정된 것을 볼 수 있습니다.

다음 명령어를 실행하여 올바른 프로젝트를 사용하고 있는지 확인합니다.

gcloud config list project

Cloud Shell을 열 때 선택한 프로젝트가 아닌 다른 프로젝트를 사용하려면 다음을 실행하여 새 프로젝트를 설정할 수 있습니다.

gcloud config set project <PROJECT-ID>;
  1. Cloud Shell이 실행되면 명령줄을 사용하여 Cloud SQL Insights가 사용 설정된 상태에서 my-instance라는 새 Cloud SQL 인스턴스를 만들 수 있습니다.
gcloud sql instances create my-instance --tier db-f1-micro --database-version=POSTGRES_12 --region=us-central --root-password=<PASSWORD> --insights-config-query-insights-enabled --insights-config-record-application-tags --insights-config-record-client-address

플래그와 그 의미에 대한 간략한 설명은 다음과 같습니다.

  • --tier db-f1-micro 플래그는 개발 목적으로 하기 때문에 최소한의 리소스가 포함된 머신 유형을 지정합니다. Codelab에는 많은 리소스가 필요하지 않습니다. 등급에 대한 자세한 내용은 여기를 참조하세요.
  • --database-version=POSTGRES_12 플래그는 PostgreSQL 버전 12인 인스턴스를 만듭니다.
  • --region=us-central 플래그는 인스턴스를 생성할 리전을 지정합니다.
  • --root-password=<PASSWORD> 플래그를 사용하면 루트 postgres 사용자의 비밀번호를 지정할 수 있습니다. <PASSWORD>를 원하는 비밀번호로 대체합니다.
  • --insights-config-query-insights-enabled 플래그는 인스턴스에서 Cloud SQL Insights를 사용 설정합니다.
  • --insights-config-record-application-tags 플래그를 사용하면 애플리케이션 태그를 기록할 수 있습니다. 애플리케이션 태그에 대한 자세한 내용은 뒷부분에서 설명합니다.
  • --insights-config-record-client-address 플래그를 사용하면 Cloud SQL Insights에서 클라이언트 IP 주소를 기록할 수 있습니다.

프로젝트에 API sqladmin.googleapis.com을 사용 설정하라는 메시지가 표시될 수 있습니다. 메시지가 표시되면 y를 선택하여 API를 사용 설정합니다.

인스턴스를 만드는 데 몇 분 정도 걸립니다. 이 작업이 완료되면 인스턴스를 사용할 수 있습니다.

  1. 이제 샘플 앱에 사용할 데이터베이스를 만듭니다.
gcloud sql databases create votesdb --instance my-instance

Cloud Console을 통해 인스턴스에 액세스하고 구성할 수도 있습니다.

  1. 다음 명령어를 실행하여 PROJECT-ID:ZONE-ID:INSTANCE-ID 형식으로 인스턴스 연결 이름을 가져옵니다. 이 명령어는 나중에 Node.js 앱을 구성할 때 사용합니다.
gcloud sql instances describe my-instance | grep connectionName

서비스 계정은 GCP 프로젝트 내에서 다른 서비스를 사용할 수 있는 권한을 부여하는 데 사용됩니다. 이 Codelab의 경우 Cloud SQL 인스턴스에 연결할 수 있는 권한을 Cloud SQL 프록시에 부여하려면 서비스 계정이 하나 필요합니다.

Console에서 서비스 계정 만들기

  1. IAM 서비스 계정 페이지로 이동하여 페이지 상단의 -PCvKR3aQ2zKaUcml8w9lW4JNlmYtN5-r2--mC6kMUp6HOXW8wT1wUvLoYEPU-aA-oGskT3XkAqfNwRAKkZkllwTe6ugdrUVFwaeKT0M9Y1RwHA8JPZeGmCWYBfr8d9TSycNMIRsLw 버튼을 클릭합니다.
  2. 서비스 계정에 고유한 이름과 ID를 지정하고 만들기를 클릭합니다.
  3. 다음 페이지에서 역할 선택을 클릭합니다. 'Cloud SQL'을 필터링하고 Cloud SQL 클라이언트 역할을 선택합니다. 계속을 클릭한 다음 완료를 클릭합니다.
  4. 서비스 계정이 생성되면 새 서비스 계정의 작업 아래에 있는 점 3개를 클릭하고 키 만들기를 선택합니다. JSON이 선택됩니다. 이 기본값을 그대로 두고 만들기를 클릭합니다. 그러면 .json 비공개 키 파일이 다운로드됩니다. 닫기를 클릭합니다.
  5. Cloud Shell에서 더보기 메뉴의 점 3개를 클릭하고 파일 업로드를 선택합니다. 로컬 머신에 다운로드한 .json 파일을 찾아 선택합니다. .json 파일이 Cloud Shell의 홈 디렉터리에 업로드됩니다.

애플리케이션과 데이터베이스 인스턴스 간의 통신을 위해 Cloud SQL 프록시를 사용합니다.

  1. Cloud SQL 프록시를 다운로드합니다. Cloud Shell에서 다음을 실행할 수 있습니다.
wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64 -O cloud_sql_proxy && chmod +x cloud_sql_proxy
  1. 프록시를 실행하려면 Cloud SQL 인스턴스 세부정보에서 복사한 인스턴스 연결 이름을 사용하여 <INSTANCE_CONNECTION_NAME>을 바꿉니다. 사용자 인증 정보 파일의 경우 마지막 단계에서 업로드한 파일의 경로를 입력합니다.
./cloud_sql_proxy -credential_file=/path/to/credential_file.json -instances=<INSTANCE_CONNECTION_NAME>=tcp:5432 &

성공하면 Ready for new connections 메시지와 함께 몇 줄의 출력이 표시됩니다.

  1. 샘플 애플리케이션의 저장소를 클론하고 앱을 실행하는 데 필요한 패키지를 설치합니다.
git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples/

cd nodejs-docs-samples/cloud-sql/postgres/knex

npm install
  1. 다음 환경 변수를 설정합니다.
export CLOUD_SQL_CONNECTION_NAME='<PROJECT-ID>:<ZONE-ID>:<INSTANCE-ID>'
export DB_HOST='127.0.0.1:5432'
export DB_USER='postgres>'
export DB_PASS='<PASSWORD>'
export DB_NAME='votesdb'
  1. createTable.js를 실행하여 앱에 필요한 데이터베이스 테이블을 만들고 데이터베이스가 올바르게 구성되었는지 확인한 후 샘플 앱을 시작합니다.
node createTable.js $DB_USER $DB_PASS $DB_NAME $CLOUD_SQL_CONNECTION_NAME votes $DB_HOST

npm start
  1. Cloud Shell에서 웹 미리보기웹 미리보기 아이콘를 클릭한 후 포트 8080에서 미리보기를 선택합니다.

포트 8080 메뉴 항목 미리보기

브라우저에 표시된 것과 같이 Tabs vs Spaces 투표 앱이 표시됩니다.

Tabs vs Spaces 투표 앱 스크린샷

  1. 버튼을 클릭하여 투표하고 데이터베이스에 일부 데이터를 저장합니다.

이 샘플 애플리케이션은 매우 간단하므로 모든 투표를 표시하는 추가 페이지를 추가합니다. 이렇게 하는 주된 이유는 나중에 Cloud SQL Insights를 사용할 때 고려할 데이터가 더 많아지기 때문입니다.

  1. Cloud Shell에 Ctrl+c를 입력하여 샘플 앱을 중지합니다.
  2. Cloud Shell에서 편집기 열기 버튼 버튼을 클릭하여 Cloud Shell 편집기를 실행합니다.
  3. 파일 탐색기에서 nodejs-docs-samples/cloud-sql/postgres/knex/server.js를 찾아 클릭하여 편집기에 server.js 파일을 로드합니다.

getVotes 함수가 정의된 후에 다음 코드를 추가합니다.

/**
 * Retrieve all vote records from the database.
 *
 * @param {object} pool The Knex connection object.
 * @returns {Promise}
 */
const getAllVotes = async pool => {
  return await pool
    .select('candidate', 'time_cast')
    .from('votes')
    .orderBy('time_cast', 'desc');
};
  1. 다른 경로가 정의된 아래 '/getAllVotes' 경로에 다음 코드를 추가합니다.
app.get('/getAllVotes', async (req, res) => {
  pool = pool || createPool();
  try {
    // Query all votes from the database.
    const votes = await getAllVotes(pool);

    res.render('allvotes.pug', {
      votes: votes,
    });
  } catch (err) {
    console.error(err);
    res
      .status(500)
      .send('Unable to load page; see logs for more details.')
      .end();
  }
});
  1. nodejs-docs-samples/cloud-sql/postgres/knex/views 디렉터리에 allvotes.pug라는 새 파일을 만듭니다. 다음 코드를 붙여넣습니다.
doctype html
html(lang="en")
  head
    title Tabs VS Spaces

    link(rel="stylesheet", href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css")
    link(rel="stylesheet", href="https://fonts.googleapis.com/icon?family=Material+Icons")
    script(src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js")
  body

    nav(class="red lighten-1")
      div(class="nav-wrapper")
        a(href="#" class="brand-logo center") Tabs VS Spaces

    div(class="section")

      h4(class="header center") Recent Votes
      ul(class="container collection center")
        each vote in votes
          li(class="collection-item avatar")
            if vote.candidate.trim() === 'TABS'
              i(class="material-icons circle green") keyboard_tab
            else
              i(class="material-icons circle blue") space_bar
            span(class="title") A vote for <b>#{vote.candidate}</b>
            p was cast at #{vote.time_cast}.
  1. 터미널 열기 버튼 버튼을 클릭하여 Cloud Shell로 돌아가 실행합니다.
npm start
  1. 앱이 제대로 작동하는지 확인하려면 웹 미리보기에서 앱을 엽니다. 추가한 새 페이지를 보려면 브라우저의 URL에 /getAllVotes를 추가합니다.

이제 ORM이 실행 전에 주석을 사용하여 SQL 문을 보강할 수 있도록 하는 오픈소스 라이브러리인 SQL Commenter를 설치하고 사용 설정합니다. SQLcommenter는 샘플 앱에서 사용하는 .Knex.js를 포함한 여러 ORM 및 프레임워크를 지원합니다 Cloud SQL Insights는 이러한 주석의 정보를 사용하여 데이터베이스 성능에 대한 애플리케이션 중심의 보기를 제공하고 문제를 일으키는 애플리케이션 코드를 식별합니다. 성능 오버헤드는 매우 작으며 문서에서 성능에 대한 자세한 정보를 확인할 수 있습니다.

  1. Cloud Shell에 Ctrl+c를 입력하여 샘플 앱을 중지합니다.
  2. 다음 명령어를 실행하여 SQLcommenter에 필요한 패키지를 설치합니다.
  npm install @google-cloud/sqlcommenter-knex @opencensus/nodejs @opencensus/propagation-tracecontext @opentelemetry/api @opentelemetry/core --save
  1. Cloud Shell에서 편집기 열기 버튼 버튼을 클릭하여 Cloud Shell 편집기를 실행합니다.
  2. 파일 탐색기에서 nodejs-docs-samples/cloud-sql/postgres/knex/server.js를 찾아 클릭하여 편집기에 server.js 파일을 로드합니다.
  3. 파일에서 이 코드를 찾습니다.
const process = require('process');

아래에 다음 코드를 추가합니다.

const {wrapMainKnexAsMiddleware} = require('@google-cloud/sqlcommenter-knex');
  1. 파일에서 이 코드를 찾습니다.
// Set Content-Type for all responses for these routes.
app.use((req, res, next) => {
  res.set('Content-Type', 'text/html');
  next();
});

아래에 다음 코드를 추가합니다.

app.use(wrapMainKnexAsMiddleware(Knex, {
    traceparent: true,
    tracestate: true,
    route: true,
    db_driver: true
}));

완료되면 코드는 다음과 같이 표시됩니다.

...
// Require process, so we can mock environment variables.
const process = require('process');

const {wrapMainKnexAsMiddleware} = require('@google-cloud/sqlcommenter-knex');
const express = require('express');
const bodyParser = require('body-parser');
const Knex = require('knex');

const app = express();
app.set('view engine', 'pug');
app.enable('trust proxy');

// Automatically parse request body as form data.
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());

// Set Content-Type for all responses for these routes.
app.use((req, res, next) => {
  res.set('Content-Type', 'text/html');
  next();
});

app.use(wrapMainKnexAsMiddleware(Knex, {
    traceparent: true,
    tracestate: true,
    route: true,
    db_driver: true
}));
...
  1. 터미널 열기 버튼 버튼을 클릭하여 Cloud Shell로 돌아가 실행합니다.
npm start
  1. Tabs vs Spaces 애플리케이션에서 버튼을 클릭하여 데이터베이스에 추가 데이터를 추가하세요.

쿼리 통계 대시보드를 사용하면 Cloud SQL 쿼리 문제를 해결하여 성능 문제를 찾을 수 있습니다.

데이터베이스 부하 - 모든 쿼리 그래프

최상위 수준 쿼리 통계 대시보드에 데이터베이스 부하 - 모든 상위 쿼리 그래프가 표시됩니다.

모든 쿼리 그래프

그래프에 CPU 용량, CPU 및 CPU 대기, IO 대기, 잠금 대기에 대한 정보가 포함됩니다. 문서에서 이러한 측정항목이 의미하는 바와 측정항목이 저장된 위치, 이 그래프의 모양을 보여주는 예를 확인할 수 있습니다. 이 샘플 애플리케이션의 경우 데이터베이스 쿼리 부하가 낮으므로 그래프에 큰 폭이 급증하지 않습니다.

가장 많은 부하가 발생하는 쿼리는 무엇인가요?

그래프 아래에는 선택한 기간의 정규화된 쿼리가 포함된 쿼리 테이블이 있습니다. 테이블에 나오는 쿼리는 총 실행 시간을 기준으로 정렬됩니다.

인기 쿼리 테이블

개별 쿼리를 클릭하면 쿼리에 대한 데이터베이스 부하, 쿼리 지연 시간, 쿼리 계획 샘플, 상위 사용자에 대한 자세한 정보를 볼 수 있습니다. 샘플 애플리케이션의 경우와 마찬가지로 애플리케이션이 ORM을 사용하여 빌드된 경우, 애플리케이션의 어느 부분이 어느 쿼리에 대한 것인지 알 수 없습니다. 인기 태그 섹션을 보면 쉽게 알 수 있습니다.

애플리케이션에서 쿼리 부하가 발생하는 위치는 어디인가요?

쿼리 테이블에서 태그 테이블로 전환하여 비즈니스 로직으로 태그가 지정된 쿼리 목록을 보면 더 애플리케이션 중심의 보기가 제공됩니다.

인기 태그 테이블

태그 테이블에서 부하가 생성된 경로로 분할된 데이터베이스 부하를 볼 수 있습니다. 위 스크린샷에서는 '/getAllVotes' 경로의 평균 실행 시간이 더 길고 반환된 행이 평균적으로 더 많은 것을 확인할 수 있습니다. 이 경우 테이블에 표시된 실행 시간은 문제가 없지만, '/getAllVotes' 행을 계속 클릭하여 데이터를 더 자세히 살펴보겠습니다.

쿼리가 느리게 실행되는 이유는 무엇인가요?

쿼리 계획 샘플 그래프의 점을 클릭하여 쿼리 계획을 확인합니다.

샘플 쿼리 요금제

쿼리 계획은 PostgreSQL이 커버에서 쿼리를 실행하는 방식을 보여주므로, 속도가 느린 작업이 있는지 알 수 있습니다.

속도가 느려지는 것은 어떤 애플리케이션 코드 때문인가요?

Cloud SQL Insights에서는 또한 엔드 투 엔드 추적에 대한 컨텍스트 내 시각화를 통해 애플리케이션의 어떤 부분이 느린 쿼리를 생성하는지 더 자세히 조사하는 데 도움이 됩니다.

엔드 투 엔드 탭을 클릭하여 컨텍스트 내 추적을 확인합니다.

엔드 투 엔드 trace

지금까지 Cloud SQL Insights를 사용하여 Node.js 앱과 Cloud SQL PostgreSQL 데이터베이스의 쿼리 성능을 모니터링하고 조사하는 방법을 알아보았습니다.

삭제

Cloud SQL 인스턴스를 계속 실행하지 않으려면 지금 삭제할 수 있습니다.

gcloud sql instances delete my-instance

자세히 알아보기