Cloud Functions를 사용하여 서버리스 웹 성능 모니터링


이 가이드에서는 Google Cloud 서버리스 기술을 사용하여 웹 성능 모니터링 앱을 만드는 방법을 설명합니다.

성능은 모든 웹 앱의 성공에 있어 중요한 역할을 수행합니다. 사이트 성능이 좋지 않은 경우 회원 가입이 저조하고 사용자 유지율이 낮아져서 비즈니스 목표 달성에 영향을 미칠 수 있습니다. 성능은 웹 앱을 설계, 구축, 테스트할 때 주요 성공 기준이 되어야 합니다.

하지만 추후 앱이 발전하면서 페이지 성능이 변경될 수도 있습니다. 개발자가 이미지와 스크립트를 추가하거나 업데이트할 수도 있고 기본 앱 제공 인프라 자체가 변경될 수도 있습니다. 따라서 페이지 성능을 정기적으로 모니터링하는 것이 좋습니다. 일반적으로 이전 기록의 분석을 위해 성능 측정항목을 저장합니다. 또한 페이지 성능이 정의된 임계값 미만이면 알림을 생성하는 것도 일반적인 방법입니다.

목표

  • 헤드리스 Chrome을 사용하여 웹페이지 성능 측정항목을 수집하는 Cloud 함수를 만듭니다.
  • Cloud Storage에 측정항목을 저장합니다.
  • Cloud Storage 생성 이벤트에 의해 트리거되는 다른 Cloud 함수를 만들어 페이지 측정항목을 분석합니다.
  • Firestore에 분석 결과를 저장합니다.
  • Firestore 생성 이벤트에 의해 트리거되는 다른 Cloud 함수를 만들어 페이지 성능이 좋지 않은 경우 Pub/Sub에 알림을 게시합니다.
  • Cloud Scheduler 작업을 만들어 첫 번째 Cloud 함수를 주기적으로 트리거합니다.
  • 성공 및 실패 시나리오의 출력을 확인합니다.

비용

이 튜토리얼에서는 비용이 청구될 수 있는 다음과 같은 Google Cloud 구성요소를 사용합니다.

  • Cloud Functions
  • Cloud Scheduler
  • Cloud Storage
  • Firestore
  • Pub/Sub
  • Container Registry
  • Cloud Build

가격 계산기를 사용하면 예상 사용량을 기준으로 예상 비용을 산출할 수 있습니다.

시작하기 전에

  1. Google Cloud 계정에 로그인합니다. Google Cloud를 처음 사용하는 경우 계정을 만들고 Google 제품의 실제 성능을 평가해 보세요. 신규 고객에게는 워크로드를 실행, 테스트, 배포하는 데 사용할 수 있는 $300의 무료 크레딧이 제공됩니다.
  2. Google Cloud Console의 프로젝트 선택기 페이지에서 Google Cloud 프로젝트를 선택하거나 만듭니다.

    프로젝트 선택기로 이동

  3. Google Cloud 프로젝트에 결제가 사용 설정되어 있는지 확인합니다.

  4. API Cloud Functions, Cloud Scheduler, Pub/Sub, and Cloud Build 사용 설정

    API 사용 설정

  5. Google Cloud Console의 프로젝트 선택기 페이지에서 Google Cloud 프로젝트를 선택하거나 만듭니다.

    프로젝트 선택기로 이동

  6. Google Cloud 프로젝트에 결제가 사용 설정되어 있는지 확인합니다.

  7. API Cloud Functions, Cloud Scheduler, Pub/Sub, and Cloud Build 사용 설정

    API 사용 설정

아키텍처

웹 성능 모니터링 작업은 일반적으로 스테이트리스(Stateless)이며 짧게 사용됩니다. 또한 종종 이벤트 기반으로 수행하므로 일정에 따라 발생하거나 자동 테스트 파이프라인과 같은 다른 프로세스의 일부로 트리거됩니다. 이러한 특성으로 인해 분석 앱을 구현하는 데 서버리스 아키텍처가 적합합니다.

이 가이드에서는 Cloud Functions, Firestore, Cloud Scheduler, Pub/Sub 등 Google Cloud 서버리스 스택의 다양한 부분을 사용합니다. 이러한 서비스를 위해 인프라를 관리할 필요가 없으며 사용한 만큼만 비용을 지불하면 됩니다. 앱의 핵심은 Cloud Functions를 사용하여 구현되므로 이벤트 기반의 확장 가능한 서버리스 실행 환경을 제공합니다. Cloud Functions를 사용하면 연결성이 적고 독립적인 로직을 사용하여 앱을 만들고 연결할 수 있습니다.

다음 다이어그램은 이 가이드에서 만든 서버리스 솔루션의 아키텍처를 보여줍니다.

서버리스 웹 분석 솔루선 아키텍처

환경 준비

서버리스 환경을 만들기 전에 GitHub에서 코드를 가져오고 변수를 설정하며 나중에 분석 및 저장에 필요한 리소스를 준비합니다.

코드 가져오기 및 환경 변수 설정

  1. Google Cloud 콘솔에서 Cloud Shell을 엽니다.

    Cloud Shell 열기

  2. 이 가이드에서 사용된 Cloud Functions의 코드가 포함된 저장소를 클론합니다.

    git clone https://github.com/GoogleCloudPlatform/solutions-serverless-web-monitoring.git
    
  3. 함수 디렉터리로 변경합니다.

    cd solutions-serverless-web-monitoring/functions
    
  4. 현재 프로젝트 ID 및 프로젝트 번호를 셸 변수로 설정합니다.

    export PROJECT=$DEVSHELL_PROJECT_ID
    export PROJECT_NUM=$(gcloud projects list \
        --filter="$PROJECT" \
        --format="value(PROJECT_NUMBER)")
    
  5. Cloud Functions의 기본 배포 리전을 설정합니다. 다음 예시에서는 리전을 us-east1로 설정하지만 Cloud Functions를 사용할 수 있는 리전으로 이를 변경할 수 있습니다.

    export REGION=us-east1
    gcloud config set functions/region $REGION
    

Cloud Storage 버킷 만들기

이 섹션에서는 수집된 페이지 성능 데이터를 저장하기 위해 Cloud Storage 버킷을 만듭니다. 위치 또는 스토리지 클래스를 선택할 수 있지만 버킷을 사용하는 Cloud Functions와 동일한 위치에 버킷을 만드는 것이 좋습니다.

  1. Cloud Shell에서 모든 측정항목을 저장하는 Cloud Storage 버킷의 이름에 대한 셸 변수를 내보냅니다. 버킷 이름은 전역에서 고유해야 하므로 다음 명령어는 Google Cloud 프로젝트 번호를 버킷 이름의 서픽스로 사용합니다.

    export METRICS_BUCKET=page-metrics-$PROJECT_NUM
    
  2. gsutil 도구를 사용하여 버킷을 만듭니다.

    gsutil mb -l $REGION gs://$METRICS_BUCKET
    
  3. env-vars.yaml 파일을 버킷 이름으로 업데이트합니다. 이 파일에는 나중에 Cloud Functions에 전달할 환경 변수가 포함됩니다.

    sed -i "s/\[YOUR_METRICS_BUCKET\]/$METRICS_BUCKET/" env-vars.yaml
    

Firestore 컬렉션 만들기

페이지 성능 측정항목은 뒤에 나오는 섹션에서 분석합니다. 이 섹션에서는 각 분석 결과를 저장할 Firestore 컬렉션을 만듭니다.

  1. Google Cloud 콘솔에서 Firestore 페이지로 이동합니다.

    Firestore 페이지로 이동

  2. 전에 Firestore 데이터베이스를 만들어본 적이 없는 경우 다음 단계를 수행합니다.

    1. 기본 모드 선택을 클릭하여 Firestore를 활성화합니다.
    2. Cloud Functions가 실행되는 리전에 가장 근접한 리전 위치를 선택합니다.
    3. 데이터베이스 만들기를 클릭합니다.

    잠시 후에 구성이 완료됩니다.

  3. 컬렉션 시작을 클릭하고 컬렉션 ID를 page-metrics로 설정합니다.

  4. 저장을 클릭합니다.

Pub/Sub 주제 및 구독 만들기

분석 결과 페이지 성능이 좋지 않으면 일반적으로 관심 시스템과 당사자에게 알리려고 합니다. 이 섹션에서는 좋지 않은 성능을 설명하는 메시지가 포함된 Pub/Sub 주제를 만듭니다.

  1. Cloud Shell에서 performance-alerts라는 Pub/Sub 주제를 만듭니다.

    gcloud pubsub topics create performance-alerts
    
  2. 주제에 대한 구독을 만듭니다. 구독을 사용하여 알림 메시지가 주제에 게시되고 있는지 확인합니다.

    gcloud pubsub subscriptions create performance-alerts-sub \
        --topic performance-alerts
    

페이지 성능 측정항목 수집

많은 웹사이트에서는 자바스크립트를 사용하여 페이지 콘텐츠를 동적으로 렌더링합니다. 이렇게 하면 클라이언트가 웹페이지를 완전히 로드하기 위해 브라우저를 에뮬레이션해야 하므로 성능 분석이 더 복잡해집니다. Cloud Functions용 Node.js 런타임은 헤드리스 Chrome을 지원하므로 서버리스 환경에서 완전한 웹브라우저 기능을 제공합니다.

Puppeteer는 Chrome DevTools 팀에서 개발한 Node.js 라이브러리로, 헤드리스 Chrome을 제어하는 고급 API를 제공합니다. 기본적으로 Puppeteer는 라이브러리와 함께 최신 버전의 브라우저를 설치합니다. 따라서 함수 내에서 헤드리스 Chrome을 사용하는 간단한 방법으로 Puppeteer를 종속 항목으로 Cloud 함수에 추가할 수 있습니다.

웹페이지 성능을 측정하고 분석하는 것은 크고 복잡한 분야입니다. 편의를 위해 이 가이드에서는 Puppeteer를 사용하여 최상위 페이지 성능 측정항목을 수집합니다. 그러나 Puppeteer 및 CDP(Chrome DevTools Protocol)를 사용하여 타임라인 trace와 같은 보다 자세한 정보를 수집할 수도 있습니다. 또한 네트워크 정체를 에뮬레이션하고 CPU 제한을 수행하여 최종 사용자 환경을 보다 정확하게 표현할 수 있습니다. 웹페이지 성능 분석에 대한 소개는 Chrome 웹 개발자 사이트를 참조하세요.

클라이언트의 성능 특성을 비롯하여 웹페이지 로드 시간에 영향을 주는 많은 요소가 있습니다. Cloud 함수의 CPU 및 RAM 구성을 사용하여 기준을 설정하는 것이 중요합니다.

tracer/index.js 파일의 다음 스니펫은 Puppeteer를 사용하여 웹페이지를 로드하는 방법을 보여줍니다.

// launch Puppeteer and start a Chrome DevTools Protocol (CDP) session
// with performance tracking enabled.
browser = await puppeteer.launch({
  headless: true,
  args: ['--no-sandbox']
});
const page = await browser.newPage();
const client = await page.target().createCDPSession();
await client.send('Performance.enable');

// browse to the page, capture and write the performance metrics
console.log('Fetching url: '+url.href);
await page.goto(url.href, {
  'waitUntil' : 'networkidle0'
});
const performanceMetrics = await client.send('Performance.getMetrics');
options = createUploadOptions('application/json', page.url());
await writeToGcs(metricsBucket, filename, JSON.stringify(performanceMetrics), options);
  • Cloud Shell에서 trace Cloud 함수를 배포합니다.

    gcloud functions deploy trace \
        --trigger-http \
        --runtime nodejs10 \
        --memory 1GB \
        --source tracer \
        --env-vars-file env-vars.yaml \
        --quiet
    

    Cloud 함수를 배포하는 데 몇 분이 걸릴 수 있습니다.

    배포 매개변수는 함수에 HTTP 트리거가 있어야 하고 Node.js 10 런타임을 사용해야 하며 1GB 메모리가 있어야 한다는 것을 지정합니다. 헤드리스 Chrome을 실행하려면 이 메모리 양이 필요합니다. 환경 변수는 env-vars.yaml 파일을 통해 함수에 제공됩니다.

기본적으로 HTTP 트리거 Cloud Functions는 인증되지 않은 호출을 허용합니다. 따라서 trace 함수에 보안을 설정해야 합니다.

  • allUserscloudfunctions.invoker IAM 역할을 삭제합니다.

    gcloud beta functions remove-iam-policy-binding trace \
        --member allUsers \
        --role roles/cloudfunctions.invoker
    

측정항목 분석

웹-성능-모니터링 실습의 일반적인 목표는 정의된 일부 벤치마크를 기준으로 성능을 추적하는 것입니다. 특정 측정항목이 예상 임곗값을 초과하는 경우 최신 소프트웨어 출시 버전에 문제가 있거나 기본 인프라에 문제가 있는 것일 수 있습니다.

이 섹션에서는 페이지 측정항목을 파싱하고 Firestore 컬렉션에 대한 결과를 유지하기 위해 Python에서 Cloud 함수를 만듭니다. 이 함수는 예상 임계값을 기준으로 FirstMeaningfulPaint 측정항목을 평가한 후 임계값을 초과하면 분석 결과를 문제가 있는 것으로 표시합니다. FirstMeaningfulPaint는 페이지가 사용자에게 유용해지는 시기를 자세히 설명하는 사용자 중심 측정항목입니다. Cloud Storage 트리거를 사용하여 새 파일이 측정항목을 포함하는 버킷에 기록될 때마다 분석 함수를 실행합니다.

analyzer/main.py 파일의 다음 스니펫은 함수 로직을 보여줍니다.

def analyze(data, context):
  """Function entry point, triggered by creation of an object in a GCS bucket.

  The function reads the content of the triggering file, analyses its contents,
  and persists the results of the analysis to a new Firestore document.

  Args:
    data (dict): The trigger event payload.
    context (google.cloud.functions.Context): Metadata for the event.
  """
  page_metrics = get_gcs_file_contents(data)
  max_time_meaningful_paint = int(os.environ.get('MAX_TIME_MEANINGFUL_PAINT'))
  analysis_result = analyze_metrics(data, page_metrics,
                                    max_time_meaningful_paint)
  docref = persist(analysis_result, data['name'])
  logging.info('Created new Firestore document %s/%s describing analysis of %s',
               docref.parent.id, docref.id, analysis_result['input_file'])
  • analyze Cloud 함수를 배포합니다.

    gcloud functions deploy analyze \
        --trigger-resource gs://$METRICS_BUCKET \
        --trigger-event google.storage.object.finalize \
        --runtime python37 \
        --source analyzer \
        --env-vars-file env-vars.yaml
    

    이 함수는 측정항목 버킷에서 finalize 이벤트에 의해 트리거되어 객체가 버킷에 생성될 때마다 전송됩니다. 이 함수는 Python 3.7 런타임을 사용합니다.

실패 알림

측정항목 분석 결과 페이지 성능이 좋지 않은 경우 일반적으로 조치를 취하려고 합니다.

이 섹션에서는 페이지 성능이 만족스럽지 못한 경우 메시지를 Pub/Sub 주제에 전송하기 위해 Cloud 함수를 만듭니다. 이 함수는 문서가 Firestore 컬렉션에서 생성될 때마다 트리거됩니다. 관심 당사자는 Pub/Sub 주제를 구독하고 적절한 조치를 취할 수 있습니다. 예를 들어 지원 앱은 Pub/Sub 메시지를 구독한 후 이메일을 전송하거나 지원 페이저를 트리거하거나 버그를 열 수 있습니다.

alerter/main.py 파일의 다음 스니펫은 함수 로직을 보여줍니다.

def generate_alert(data, context):
  """Cloud Function entry point, triggered by a change to a Firestore document.

  If the triggering document indicates a Failed status, send the document to
  configured PubSub topic.

  Args:
    data (dict): The event payload.
    context (google.cloud.functions.Context): Metadata for the event.
  """
  doc_fields = data['value']['fields']
  status = doc_fields['status']['stringValue']
  if 'FAIL' in status:
    global publish_client
    if not publish_client:
      publish_client = pubsub.PublisherClient()

    logging.info('Sending alert in response to %s status in document %s',
                 status, context.resource)
    project = os.environ.get('GCP_PROJECT')
    topic = os.environ.get('ALERT_TOPIC')
    fqtn = 'projects/{}/topics/{}'.format(project, topic)
    msg = json.dumps(data['value']).encode('utf-8')
    publish_client.publish(fqtn, msg)

상태 필드에 실패가 표시되는 경우에만 알림이 전송됩니다.

  • alert Cloud 함수를 배포합니다.

    gcloud functions deploy alert \
        --trigger-event providers/cloud.firestore/eventTypes/document.create \
        --trigger-resource "projects/$PROJECT/databases/(default)/documents/page-metrics/{any}" \
        --runtime python37 \
        --source alerter \
        --env-vars-file env-vars.yaml \
        --entry-point generate_alert
    

    이 함수는 page-metrics Firestore 컬렉션에서 document.create 이벤트에 의해 트리거됩니다. {any} 서픽스는 문서가 컬렉션에서 생성될 때마다 이 함수가 트리거되어야 함을 나타내는 와일드 카드입니다.

분석 일정 예약

페이지 성능을 정기적으로 모니터링하는 것이 좋습니다. 예를 들어 특정 페이지를 1시간마다, 매일, 매주 분석할 수 있습니다. 이 섹션에서는 trace 함수를 트리거하여 분석 파이프라인을 주기적으로 실행하기 위해 Cloud Scheduler 작업을 만듭니다.

Cloud Scheduler 작업은 trace 함수에 필요한 cloudfunctions.invoker IAM 역할이 부여된 서비스 계정을 사용하여 실행됩니다.

때때로 웹페이지가 올바르게 응답하지 않거나 타임아웃을 요청하므로 웹 분석 앱에서 재시도가 반드시 필요합니다. 따라서 앱에 재시도 로직이 있어야 합니다. Cloud Functions는 백그라운드 함수의 재시도를 지원합니다.

HTTP 트리거 Cloud Functions에는 재시도를 사용할 수 없으므로 Cloud Functions를 사용하여 trace 함수를 재시도할 수 없지만 Cloud Scheduler는 재시도를 지원합니다. 재시도 매개변수 구성에 대한 자세한 내용은 RetryConfig 문서를 참조하세요.

  1. 세 가지 Cloud Functions가 올바르게 배포되고 ACTIVE 상태를 표시하는지 확인합니다.

    gcloud functions list
    
  2. Cloud Scheduler 작업을 실행할 ID로 사용될 새 서비스 계정을 만듭니다.

    gcloud iam service-accounts create tracer-job-sa
    
  3. 새 서비스 계정에 trace 함수의 cloudfunctions.invoker IAM 역할을 부여합니다.

    gcloud beta functions add-iam-policy-binding trace \
        --role roles/cloudfunctions.invoker \
        --member "serviceAccount:tracer-job-sa@$PROJECT.iam.gserviceaccount.com"
    
  4. Cloud Scheduler 작업을 만듭니다.

    gcloud scheduler jobs create http traceWithRetry \
        --uri="https://$REGION-$PROJECT.cloudfunctions.net/trace" \
        --http-method=POST \
        --message-body="{\"url\":\"http://www.example.com\"}" \
        --headers="Content-Type=application/json" \
        --oidc-service-account-email="tracer-job-sa@$PROJECT.iam.gserviceaccount.com" \
        --schedule="0 3 * * *" \
        --time-zone="UTC" \
        --max-retry-attempts=3 \
        --min-backoff=30s
    

    작업이 HTTP 트리거 trace 함수를 호출하므로 명령어가 작업 유형을 http로 지정하고 함수 트리거 URL을 uri 값으로 제공합니다. 분석할 페이지(이 경우 www.example.com)는 message-body 플래그로 지정됩니다. oidc-service-account-email 플래그는 인증에 사용할 서비스 계정을 정의합니다. 명령어는 max-retry-attempts 플래그를 사용하여 시도할 재시도 횟수를 나타내고 schedule 플래그로 전달된 값은 실행 일정을 매일 오전 3시(UTC)로 설정합니다.

결과 확인

이 섹션에서는 성공 조건과 실패 조건 모두에 예상되는 동작을 얻는지 확인합니다.

성공 확인

Cloud Scheduler 작업은 다음 예약 시간(이 경우 오전 3시(UTC))까지 실행되지 않습니다. 결과를 즉시 확인하려면 수동으로 실행을 트리거할 수 있습니다.

  1. 스케줄러 작업의 초기화가 완료될 때까지 90초 동안 기다립니다.
  2. Cloud Scheduler 작업을 수동으로 실행합니다.

    gcloud scheduler jobs run traceWithRetry
    
  3. 함수 파이프라인이 완료될 때까지 약 30초 동안 기다립니다.

  4. 해당 페이지 측정항목이 수집되었는지 나타내기 위해 측정항목 버킷의 콘텐츠를 나열합니다.

    gsutil ls -l gs://$METRICS_BUCKET
    
  5. Google Cloud 콘솔에서 Cloud Logging 뷰어 페이지를 엽니다.

    Logging 페이지로 이동

    세 가지 Cloud Functions, 즉 trace, analyze, alert 각각의 로그 메시지가 표시됩니다. 로그를 표시하는 데 잠시 시간이 걸릴 수 있으므로 로그 창을 새로 고쳐야 합니다.

    오류를 표시하지 않는 Logging 콘솔

  6. Created new Firestore document page-metrics/ 텍스트 다음에 나열되는 Firestore 문서 ID를 기록합니다.

  7. Google Cloud 콘솔에서 Firestore 페이지로 이동합니다.

    Firestore 페이지로 이동

  8. 분석 결과가 포함된 문서를 검사합니다. 문서 값은 PASS 상태를 나타내고 최신 페이지 성능 측정항목을 포함합니다.

  9. Cloud Shell에서 구독 메시지를 가져와서 알림 메시지가 Pub/Sub 주제에 전송되지 않았는지 확인합니다.

    gcloud pubsub subscriptions pull \
        projects/$PROJECT/subscriptions/performance-alerts-sub \
        --auto-ack
    

    나열된 항목이 없습니다.

실패 확인

  1. trace 함수를 수동으로 트리거합니다. 이번에는 Google Cloud 가이드 페이지를 URL로 제공합니다. 이 페이지에는 예상되는 최대 임곗값 이상으로 페이지 로드 시간을 증가시키는 동적 콘텐츠가 많이 있습니다.

    gcloud functions call trace \
        --data='{"url":"https://cloud.google.com/docs/tutorials"}'
    

    프로젝트에 Owner 또는 Editor IAM 역할이 있으므로 함수를 호출할 충분한 권한이 있습니다.

  2. 함수 파이프라인이 완료될 때까지 약 30초 동안 기다립니다.

  3. 측정항목 버킷의 콘텐츠를 나열하여 추가 측정항목이 수집되었는지 확인합니다.

    gsutil ls -l gs://$METRICS_BUCKET
    

    이제 각 버킷에 항목 두 개가 표시됩니다.

  4. Google Cloud 콘솔에서 Cloud Logging 뷰어 페이지로 이동하고 Cloud 함수 로그를 필터링합니다.

    Logging 페이지로 이동

    페이지가 허용된 최대 로드 시간을 초과했음을 나타내는 analyze 함수의 오류가 표시됩니다. 최신 메시지를 표시하기 위해 로그 창을 다시 새로 고쳐야 할 수도 있습니다.

    오류를 표시하는 Logging 콘솔

  5. Firestore 문서 ID를 기록합니다.

  6. Google Cloud 콘솔에서 Firestore 페이지로 이동합니다.

    Firestore 페이지로 이동

  7. 실패한 분석을 설명하는 문서를 찾습니다.

    상태 필드가 FAIL로 표시됩니다.

  8. Cloud Shell에서 구독 메시지를 가져와서 알림 메시지가 Pub/Sub 주제에 전송되었는지 확인합니다.

    gcloud pubsub subscriptions pull \
        projects/$PROJECT/subscriptions/performance-alerts-sub \
        --auto-ack
    

    이번에는 메시지 내용이 표시됩니다.

삭제

프로젝트 삭제

  1. Google Cloud 콘솔에서 리소스 관리 페이지로 이동합니다.

    리소스 관리로 이동

  2. 프로젝트 목록에서 삭제할 프로젝트를 선택하고 삭제를 클릭합니다.
  3. 대화상자에서 프로젝트 ID를 입력한 후 종료를 클릭하여 프로젝트를 삭제합니다.

다음 단계

  • Google Cloud 서버리스 기술 자세히 알아보기
  • 다른 Cloud Functions 가이드 살펴보기
  • Puppeteer 및 헤드리스 Chrome의 기타 용도를 설명하는 Google I/O '18의 동영상 보기
  • Google Cloud에 대한 참조 아키텍처, 다이어그램, 권장사항 살펴보기 Cloud 아키텍처 센터 살펴보기