使用 Cloud Functions 進行無伺服器網頁效能監控

本教學課程說明如何使用 Google Cloud Platform (GCP) 無伺服器技術建立網頁效能監控應用程式。

任何網頁應用程式若要成功,效能都是極為重要的因素。如果您的網站效能不佳,則註冊的人數可能會減少、使用者留存率也會降低,就可能會影響您的業務目標。在設計、建構和測試網頁應用程式時,效能應該是一項關鍵的成功標準。

不過,隨著您的應用程式發展,網頁效能也可能隨著時間而改變,因為開發人員可能會新增或更新映像檔和指令碼,或者基礎應用程式提供基礎架構本身也可能會改變。因此,定期監控網頁效能很重要。通常,您可以儲存效能指標,以便進行歷史記錄分析。如果網頁效能低於某些定義的門檻,則產生快訊也是一種常見的做法。

目標

  • 建立使用無頭 Chrome 來收集網頁效能指標的 Cloud 函式
  • 將指標儲存在 Cloud Storage 中。
  • 建立另一個 Cloud 函式,這個函式由 Cloud Storage 建立事件觸發,以分析網頁指標。
  • 將分析結果儲存在 Cloud Firestore 中。
  • 建立另一個 Cloud 函式,這個函式由 Cloud Firestore 建立事件觸發,以在網頁效能不佳時發布快訊至 Cloud Pub/Sub
  • 建立一個 Cloud Scheduler 工作,以定期觸發第一個 Cloud 函式。
  • 驗證成功和失敗情況下的輸出內容。

費用

本教學課程使用的 Google Cloud Platform 收費元件包括:

  • Cloud Functions
  • Cloud Scheduler
  • Cloud Storage
  • Cloud Firestore
  • Cloud Pub/Sub

使用 Pricing Calculator 可根據您的預測使用量來產生預估費用。

事前準備

  1. 登入您的 Google 帳戶。

    如果您沒有帳戶,請申請新帳戶

  2. 選取或建立 Google Cloud Platform 專案。

    前往「Manage resources」(管理資源) 頁面

  3. 請確認您已啟用 Google Cloud Platform 專案的計費功能。

    瞭解如何啟用計費功能

  4. 啟用Cloud Functions, Cloud Scheduler, and Cloud Pub/Sub API。

    啟用 API

架構

網頁效能監控作業通常是無狀態的短期作業。它們也經常是事件導向,既可以按時間表進行,也可以做為某些其他程序 (例如自動化測試管道) 的一部分觸發。這些特性使得無伺服器架構成為實作網頁分析應用程式的理想選擇。

在本教學課程中,您將使用 GCP 無伺服器堆疊的不同部分,包括 Cloud Functions、Cloud Firestore、Cloud Scheduler 和 Cloud Pub/Sub。您無需管理以上任何服務的基礎架構,而且只需用多少付多少即可。該應用程式的核心是使用 Cloud Functions 進行實作,可提供事件導向且可擴充的無伺服器執行環境。透過 Cloud Functions,您可以使用鬆散連結的獨立邏輯來建立和連結應用程式。

下圖顯示您將在本教學課程中建立的無伺服器解決方案的架構。

無伺服器網頁分析解決方案的架構

準備環境

在建立無伺服器環境之前,您必須先從 GitHub 取得程式碼、設定變數,以及準備稍後進行分析和儲存時所需的資源。

取得程式碼和設定環境變數

  1. 在 GCP Console 中,開啟 Cloud Shell。

    開啟 Cloud Shell

  2. 複製包含本教學課程中使用的 Cloud Functions 程式碼的存放區:

    git clone https://github.com/GoogleCloudPlatform/solutions-serverless-web-monitoring.git
    
  3. 變更為 functions 目錄:

    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 值區的名稱匯出殼層變數。值區名稱必須是全域不重複的,因此以下指令會使用您的 GCP 專案編號做為值區名稱的後置字串。

    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
    

建立 Cloud Firestore 集合

在後續章節中,您將分析網頁效能指標。在本節中,您將建立 Cloud Firestore 集合以儲存每個分析的結果。

  1. 前往 GCP Console 的「Cloud Firestore」頁面。

    前往「Cloud Firestore」頁面

  2. 如果您以前從未建立過 Cloud Firestore 資料庫,請執行以下步驟:

    1. 按一下 [Select Native mode] (選取原生模式) 以啟用 Cloud Firestore。
    2. 選取靠近您的 Cloud Functions 將執行的地區的地區位置。
    3. 按一下 [Create Database] (建立資料庫)。

    完成設定需要一些時間。

  3. 按一下 [Start Collection] (新增集合),然後將集合 ID 設為 page-metrics

  4. 按一下 [Save] (儲存)

建立 Cloud Pub/Sub 主題和訂閱項目

當分析結果指出網頁效能不佳時,通常您會希望通知相關的系統和各方。在本節中,您將建立 Cloud Pub/Sub 主題,其中包含說明任何效能不佳情形的訊息。 我們 1. 在 Cloud Shell 中,建立一個名為 performance-alerts 的 Cloud Pub/Sub 主題:

```none
gcloud pubsub topics create performance-alerts
```
  1. 為該主題建立訂閱項目。您可以使用訂閱來確認系統是否正在將快訊訊息發布至該主題。

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

收集網頁效能指標

許多網站都會使用 JavaScript 來動態呈現網頁內容。而這樣會使得效能分析作業變得更加複雜,因為用戶端必須模擬瀏覽器才能完全載入網頁。適用於 Cloud Functions 的 Node.js 8 執行階段支援無頭 Chrome,可在無伺服器環境中提供完整的網路瀏覽器功能。

Puppeteer 是一個由 Chrome DevTools 團隊建構的 Node.js 程式庫,可提供一個高階 API 以控制無頭 Chrome。根據預設,Puppeteer 會隨程式庫一起安裝最新版的瀏覽器。因此,您可以將 Puppeteer 以依附元件的形式加入 Cloud 函式,這是在該函式中使用無頭 Chrome 的簡便方法。

衡量和分析網頁效能是一個龐大且複雜的領域。為簡單起見,在本教學課程中,您將使用 Puppeteer 來收集一些頂層的網頁效能指標。不過,您也可以使用 Puppeteer 和 Chrome DevTools 通訊協定 (CDP) 來收集更詳細的資訊,例如時間軸追蹤記錄。您也可以透過模擬網路壅塞和執行 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);
await page.goto(url, {
  '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 nodejs8 \
        --memory 1GB \
        --source tracer \
        --env-vars-file env-vars.yaml \
        --quiet
    

    部署 Cloud 函式可能需要幾分鐘的時間。

    部署參數指定該函式應包含 HTTP 觸發條件、應使用 Node.js 8 執行階段,且應具有 1 GB 記憶體,因為必須具有這個記憶體大小才能執行無頭 Chrome。環境變數則可以透過 env-vars.yaml 檔案提供給該函式。

根據預設,HTTP 觸發的 Cloud 函式會允許未經驗證的叫用要求。因此,您必須將 trace 函式加密

  • 移除 allUserscloudfunctions.invoker IAM 角色:

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

分析指標

網路效能監控練習的一般目標是根據某些定義的基準來追蹤效能。如果某個特定指標超出了預期的門檻,則可能表示最新的軟體版本或基礎架構有問題。

在本節中,您將使用 Python 建立 Cloud 函式,以剖析網頁指標,並將結果保存至 Cloud Firestore 集合。該函式會根據預期的門檻評估 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 執行階段。

在發生失敗狀況時產生快訊

當指標分析結果指出網頁效能不佳時,您通常會希望採取某些行動。

在本節中,您將建立一個 Cloud 函式,以在網頁效能不佳時傳送訊息至 Cloud Pub/Sub 主題。每次在 Cloud Firestore 集合中建立文件時便會觸發該函式。相關的各方都可以訂閱 Cloud Pub/Sub 主題並採取適當的行動。例如,支援應用程式可以訂閱 Cloud 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 Cloud Firestore 集合中的 document.create 事件觸發。{any} 後置字串是一個萬用字元,指出每次在集合中建立文件時都應觸發該函式。

安排進行分析的時間

定期監控網頁效能是很好的做法。例如,您可以每小時、每天或每週分析一次某個網頁。在本節中,您將建立一個 Cloud Scheduler 工作,以透過觸發 trace 函式來定期執行分析管道。

系統會使用已獲授予 trace 函式所需的 cloudfunctions.invoker IAM 角色的服務帳戶來執行 Cloud Scheduler 工作。

有時候網頁無法正確回應,或要求逾時,因此網頁分析應用程式不可避免地需要進行重試。因此,在應用程式中包含重試邏輯很重要。Cloud Functions 支援背景函式的重試作業。

重試作業不適用於 HTTP 觸發的 Cloud 函式,因此您無法使用 Cloud Functions 來重試 trace 函式。不過,Cloud Scheduler 支援重試作業。如要進一步瞭解如何設定重試參數,請參閱 RetryConfig 說明文件。

  1. 確認三個 Cloud 函式已正確部署,並且正顯示 ACTIVE 狀態:

    gcloud functions list
    
  2. 建立新的服務帳戶,該帳戶將做為執行 Cloud Scheduler 工作的身分使用:

    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,並提供函式觸發網址做為 uri 值。而要分析的網頁 (在本例中為 www.example.com) 則在 message-body 標記中提供。oidc-service-account-email 標記定義要用於驗證的服務帳戶。以上指令使用 max-retry-attempts 標記來指示要嘗試的重試次數,而隨著 schedule 標記一起傳送的值會將執行時間表設為世界標準時間每天上午 3:00。

驗證結果

在本節中,您將驗證在成功和失敗的情況下是否都能產生預期的行為。

驗證成功狀況

Cloud Scheduler 工作要等到下一個排程時間 (在本例中為世界標準時間上午 3:00) 才會執行。如要立即查看結果,您可以手動觸發執行作業。

  1. 等待 90 秒,讓排程器工作完成初始化。
  2. 手動執行 Cloud Scheduler 工作:

    gcloud scheduler jobs run traceWithRetry
    
  3. 等待約 30 秒,讓函式管道完成作業。

  4. 列出指標值區的內容,以顯示是否已收集網頁指標:

    gsutil ls -l gs://$METRICS_BUCKET
    
  5. 在 GCP Console 中,開啟「Stackdriver Logging viewer」(Stackdriver Logging 檢視器) 頁面:

    前往「Logging」頁面

    您會看到來自以下三個 Cloud 函式的記錄檔訊息:traceanalyzealert。傳送記錄檔可能需要一些時間,因此您可能需要重新整理至記錄檔窗格。

    未顯示任何錯誤的 Logging 主控台

  6. 記下 Cloud Firestore 文件 ID,該 ID 會列在 Created new Firestore document page-metrics/ 文字之後。

  7. 前往 GCP Console 的「Cloud Firestore」頁面:

    前往「Cloud Firestore」頁面

  8. 檢查包含分析結果的文件。文件值會指出 PASS 狀態,並包含最新的網頁效能指標。

  9. 在 Cloud Shell 中,透過嘗試從訂閱中提取訊息,來確認是否沒有任何快訊訊息已傳送至 Cloud Pub/Sub 主題:

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

    您會看到未列出任何項目。

驗證失敗狀況

  1. 手動觸發 trace 函式。這次,您將提供 GCP 教學課程網頁做為網址。這個網頁包含許多動態內容,因此會使得網頁載入時間超過預期的門檻上限。

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

    由於您擁有專案的 OwnerEditor IAM 角色,因此有足夠的權限可以叫用該函式。

  2. 等待約 30 秒,讓函式管道完成作業。

  3. 列出指標值區的內容,以驗證是否已收集其他指標:

    gsutil ls -l gs://$METRICS_BUCKET
    

    現在,您會在每個值區中看到兩個項目。

  4. 前往 GCP Console 的「Stackdriver Logging viewer」(Stackdriver Logging 檢視器) 頁面,然後篩選 Cloud 函式記錄檔:

    前往「Logging」頁面

    您會在 analyze 函式中看到一個錯誤,指出該網頁超出了允許的載入時間上限。同樣地,您可能需要重新整理記錄檔窗格才能看到最新的訊息。

    顯示錯誤的 Logging 主控台

  5. 記下 Cloud Firestore 文件 ID。

  6. 前往 GCP Console 的「Cloud Firestore」頁面:

    前往「Cloud Firestore」頁面

  7. 尋找說明失敗分析的文件。

    狀態欄位會標示為 FAIL

  8. 在 Cloud Shell 中,透過從訂閱中提取訊息,來確認是否已有快訊訊息傳送至 Cloud Pub/Sub 主題。

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

    這次,您會看到訊息的內容。

清除所用資源

刪除專案

  1. 前往 GCP 主控台的「Projects」(專案) 頁面。

    前往專案頁面

  2. 在專案清單中選取要刪除的專案,然後按一下 [Delete] (刪除)
  3. 在對話方塊中輸入專案 ID,按一下 [Shut down] (關閉) 即可刪除專案。

後續步驟

  • 進一步瞭解 GCP 無伺服器技術。
  • 探索其他 Cloud Functions 教學課程
  • 閱讀介紹 App Engine 和 Cloud Functions 中對無頭 Chrome 的支援的網誌文章
  • 觀看 Google 2018 年 I/O 大會中說明 Puppeteer 和無頭 Chrome 的其他用途的影片
  • 自行試用其他 Google Cloud Platform 功能,並參考我們的教學課程
本頁內容對您是否有任何幫助?請提供意見:

傳送您對下列選項的寶貴意見...

這個網頁
解決方案