AWS Lambda 使用入門

goodspeed發表於2019-03-04

場景:現在需要開發一個前後端分離的應用,後端採用 RESTful API 最為方便,但是如果這個後端服務會在一天中的某些時候有高併發的情況,使用什麼樣的架構最為簡單呢?

剛思考這個問題的時候我想到的解決方案可能有以下幾種:

  • 使用CDN內容分發網路,減少主伺服器的壓力

  • 使用LVS伺服器負載均衡

  • 使用快取

  • 硬體層 提高頻寬,使用SSD 硬碟,使用更好的伺服器

  • 程式碼層,優化程式碼(使用效能更好的語言等

但以上的幾個方法都需要關注伺服器的儲存和計算資源,以便隨時調整以滿足更高的效能,並且高併發的請求也是分時段的,配置了更高效能的伺服器在訪問量變低的時候也是資源浪費。

這個時候可以使用 FaaS(Functions as a Service) 架構,跟傳統架構不同在於,他們執行於無狀態的容器中,可以由事件觸發,短暫的,完全被第三方管理,功能上FaaS就是不需要關心後臺伺服器或者應用服務,只需關心自己的程式碼即可。其中AWS Lambda是目前最佳的FaaS實現之一。

AWS Lambda

AWS Lambda 是一項計算服務,使用時無需預配置或管理伺服器即可執行程式碼。AWS Lambda 只在需要時執行程式碼並自動縮放。藉助 AWS Lambda,幾乎可以為任何型別的應用程式或後端服務執行程式碼,而且無需執行任何管理。現在 AWS Lambda 支援 Node.js、Java、C# 和 Python。

使用場景

Lambda 常見的應用場景有以下幾種:

  • 將Lambda 作為事件源用於 AWS 服務(比如音訊上傳到 s3後,觸發 Lambda 音訊轉碼服務,轉碼音訊檔案
  • 通過 HTTPS (Amazon API Gateway) 實現的按需 Lambda 函式呼叫(配合 API Gateway建立簡單的微服務
  • 按需 Lambda 函式呼叫(使用自定義應用程式構建您自己的事件源)
  • 計劃的事件(比如每天晚上12點生成報表傳送到指定郵箱

下圖是將Lambda 作為事件源用於 AWS 服務案例的一個執行流程圖:

AWS Lambda 使用入門
  1. 使用者將物件上傳到 S3 儲存桶(物件建立事件)。
  2. Amazon S3 檢測到物件建立事件。
  3. Amazon S3 呼叫在儲存桶通知配置中指定的 Lambda 函式。
  4. AWS Lambda 通過代入您在建立 Lambda 函式時指定的執行角色來執行 Lambda 函式。
  5. Lambda 函式執行。

這篇文章主要介紹 將 Lambda 作為事件源用於 AWS 服務 和 配合 API Gateway 建立簡單的微服務。

如何使用 Lambda

接下來將使用一個案例介紹如何使用 Lambda。

將 AWS Lambda 與 Amazon API Gateway 結合使用(按需並通過 HTTPS)

步驟 1:設定 AWS 賬戶和 AWS CLI
步驟 2:建立 HelloWorld Lambda 函式和探索控制檯
建立 Hello World Lambda 函式
  1. 登入 AWS 管理控制檯並開啟 AWS Lambda 控制檯。
  2. 選擇 Get Started Now。(僅當未建立任何 Lambda 函式時,控制檯才顯示 Get Started Now 頁面。如果您已建立函式,則會看到 Lambda > Functions 頁面。在該列表頁面上,選擇 Create a Lambda function 轉到 Lambda > New function 頁面。下圖是這種情況
AWS Lambda 使用入門
  1. 這裡選擇從頭開始創作,填寫函式名、選擇角色,點選建立函式
  2. 配置建立好的Lambda函式
AWS Lambda 使用入門

需要注意的是:處理程式填寫部分為 程式碼檔名+檔案中函式名,這裡我們檔名lambda_function, 函式名是 lambda_handler,處理程式部分填寫為 lambda_function.lambda_handler。

  1. 新增觸發器,這裡我們選擇API Gateway ,在配置部分選擇之前配置好的 API,點選新增。然後儲存函式
AWS Lambda 使用入門
測試AWS Lambda + Amazon API Gateway

登入 aws 控制檯,開啟 API Gateway,選擇我們剛剛選用的 API,點選測試,我們將會看到以下輸出

AWS Lambda 使用入門

詳細資訊可以參考 官方文件(https://docs.aws.amazon.com/zh_cn/lambda/latest/dg/getting-started.html)

通過上面的步驟,我們瞭解瞭如何使用一個 Lambda 函式,現在我們看下如何構建 Lambda 函式。

如何構建Lambda

建立 Lambda 函式

在建立 Lambda 函式時,需要指定一個處理程式(此處理程式是程式碼中的函式),AWS Lambda 可在服務執行程式碼時呼叫它。在 Python 中建立處理程式函式時,使用以下一般語法結構。

def handler_name(event, context): 
    ...
    return some_value
複製程式碼

在該語法中,需要注意以下方面:

  • event – AWS Lambda 使用此引數將事件資料傳遞到處理程式。此引數通常是 Python dict 型別。它也可以是 liststrintfloatNoneType 型別。

  • context – AWS Lambda 使用此引數向處理程式提供執行時資訊。此引數為 LambdaContext 型別。

  • (可選)處理程式可返回值。返回的值所發生的狀況取決於呼叫 Lambda 函式時使用的呼叫型別:

    • 如果使用 RequestResponse 呼叫型別(同步執行),AWS Lambda 會將 Python 函式呼叫的結果返回到呼叫 Lambda 函式的客戶端(在對呼叫請求的 HTTP 響應中,序列化為 JSON)。例如,AWS Lambda 控制檯使用 RequestResponse 呼叫型別,因此當您使用控制檯呼叫函式時,控制檯將顯示返回的值。

      如果處理程式返回 NONE,AWS Lambda 將返回 null。

    • 如果使用 Event 呼叫型別(非同步執行),則丟棄該值。

context物件

在執行 Lambda 函式時,它可以與 AWS Lambda 服務進行互動以獲取有用的執行時資訊,例如:

  • AWS Lambda 終止您的 Lambda 函式之前的剩餘時間量(超時是 Lambda 函式配置屬性之一)。
  • 與正在執行的 Lambda 函式關聯的 CloudWatch 日誌組和日誌流。
  • 返回到呼叫了 Lambda 函式的客戶端的 AWS 請求 ID。可以使用此請求 ID 向 AWS Support 進行任何跟進查詢。
  • 如果通過 AWS 移動軟體開發工具包呼叫 Lambda 函式,則可瞭解有關呼叫 Lambda 函式的移動應用程式的更多資訊。
Context 物件方法 (Python)

context 物件提供了以下方法:

get_remaining_time_in_millis()

返回在 AWS Lambda 終止函式前剩餘的執行時間(以毫秒為單位)。

Context 物件屬性 (Python)

context 物件提供了以下屬性:

function_name

正在執行的 Lambda 函式的名稱。

function_version

正在執行的 Lambda 函式版本。如果別名用於呼叫函式,function_version 將為別名指向的版本。

invoked_function_arn

ARN 用於呼叫此函式。它可以是函式 ARN 或別名 ARN。非限定的 ARN 執行 $LATEST 版本,別名執行它指向的函式版本。

memory_limit_in_mb

為 Lambda 函式配置的記憶體限制(以 MB 為單位)。您在建立 Lambda 函式時設定記憶體限制,並且隨後可更改此限制。

aws_request_id

與請求關聯的 AWS 請求 ID。這是返回到呼叫了 invoke 方法的客戶端的 ID。 注意如果 AWS Lambda 重試呼叫(例如,在處理 Kinesis 記錄的 Lambda 函式引發異常的情況下)時,請求 ID 保持不變。

log_group_name

CloudWatch 日誌組的名稱,可從該日誌組中查詢由 Lambda 函式寫入的日誌。

log_stream_name

CloudWatch 日誌流的名稱,可從該日誌流中查詢由 Lambda 函式寫入的日誌。每次呼叫 Lambda 函式時,日誌流可能會更改,也可能不更改。如果 Lambda 函式無法建立日誌流,則該值為空。當向 Lambda 函式授予必要許可權的執行角色未包括針對 CloudWatch Logs 操作的許可權時,可能會發生這種情況。

identity

通過 AWS 移動軟體開發工具包進行呼叫時的 Amazon Cognito 身份提供商的相關資訊。它可以為空。identity.cognito_identity_ididentity.cognito_identity_pool_id

client_context

通過 AWS 移動軟體開發工具包進行呼叫時的客戶端應用程式和裝置的相關資訊。它可以為空。client_context.client.installation_idclient_context.client.app_titleclient_context.client.app_version_nameclient_context.client.app_version_codeclient_context.client.app_package_nameclient_context.custom由移動客戶端應用程式設定的自定義值的 dict。client_context.env由 AWS 移動軟體開發工具包提供的環境資訊的 dict

示例

檢視以下 Python 示例。它有一個函式,此函式也是處理程式。處理程式通過作為引數傳遞的 context 物件接收執行時資訊。

from __future__ import print_function

import time
def get_my_log_stream(event, context):       
    print("Log stream name:", context.log_stream_name)
    print("Log group name:",  context.log_group_name)
    print("Request ID:",context.aws_request_id)
    print("Mem. limits(MB):", context.memory_limit_in_mb)
    # Code will execute quickly, so we add a 1 second intentional delay so you can see that in time remaining value.
    time.sleep(1) 
    print("Time remaining (MS):", context.get_remaining_time_in_millis())
複製程式碼

此示例中的處理程式程式碼只列印部分執行時資訊。每個列印語句均在 CloudWatch 中建立一個日誌條目。如果您使用 Lambda 控制檯呼叫函式,則控制檯會顯示日誌。

日誌記錄

您的 Lambda 函式可包含日誌記錄語句。AWS Lambda 將這些日誌寫入 CloudWatch。如果您使用 Lambda 控制檯呼叫 Lambda 函式,控制檯將顯示相同的日誌。

以下 Python 語句生成日誌條目:

  • print 語句。
  • logging 模組中的 Logger 函式(例如,logging.Logger.infologging.Logger.error)。

printlogging.* 函式將日誌寫入 CloudWatch Logs 中,而 logging.* 函式將額外資訊寫入每個日誌條目中,例如時間戳和日誌級別。

查詢日誌

可查詢 Lambda 函式寫入的日誌,如下所示:

  • 在 AWS Lambda 控制檯中 – AWS Lambda 控制檯中的 ** Log output** 部分顯示這些日誌。

  • 在響應標頭中,當您以程式設計方式呼叫 Lambda 函式時 – 如果您以程式設計方式呼叫 Lambda 函式,則可新增 LogType引數以檢索已寫入 CloudWatch 日誌的最後 4 KB 的日誌資料。AWS Lambda 在響應的 x-amz-log-results 標頭中返回該日誌資訊。有關更多資訊,請參閱Invoke

    如果您使用 AWS CLI 呼叫該函式,則可指定帶有值 Tail--log-type parameter 來檢索相同資訊。

  • 在 CloudWatch 日誌中 – 要在 CloudWatch 中查詢您的日誌,您需要知道日誌組名稱和日誌流名稱。可以使用程式碼中的 context.logGroupNamecontext.logStreamName 屬性來獲取此資訊。在執行 Lambda 函式時,控制檯或 CLI 中生成的日誌將會向您顯示日誌組名稱和日誌流名稱。

函式錯誤

如果 Lambda 函式引發異常,AWS Lambda 會識別失敗,將異常資訊序列化為 JSON 並將其返回。考慮以下示例:

def always_failed_handler(event, context):
    raise Exception(`I failed!`)
複製程式碼

在呼叫此 Lambda 函式時,它將引發異常,並且 AWS Lambda 返回以下錯誤訊息:

{
  "errorMessage": "I failed!",
  "stackTrace": [
    [
      "/var/task/lambda_function.py",
      3,
      "my_always_fails_handler",
      "raise Exception(`I failed!`)"
    ]
  ],
  "errorType": "Exception"
}
複製程式碼

詳細資訊參考官方文件:https://docs.aws.amazon.com/zh_cn/lambda/latest/dg/lambda-app.html

注意事項

AWS Lambda 限制

AWS Lambda 在使用中會強加一些限制,例如,程式包的大小或 Lambda 函式在每次呼叫中分得的記憶體量。

每個呼叫的 AWS Lambda 資源限制

資源 限制
記憶體分配範圍 最小值 = 128 MB/最大值 = 1536 MB (增量為 64 MB). 如果超過最大記憶體使用量,則函式呼叫將會終止。
臨時磁碟容量(“/tmp”空間) 512MB
檔案描述符數 1024
過程和執行緒數(合併總數量) 1024
每個請求的最大執行時長 300 秒
Invoke 請求正文有效負載大小 (RequestResponse/同步呼叫) 6MB
Invoke 請求正文有效負載大小 (Event/非同步呼叫) 128 K

每個區域的 AWS Lambda 賬戶限制

資源 預設限制
併發執行數 1000

併發執行是指在任意指定時間對您的函式程式碼的執行數量。您可以估計併發執行計數,但是,根據 Lambda 函式是否處理來自基於流的事件源的事件,併發執行計數會有所不同。

  • 基於流的事件源 – 如果您建立 Lambda 函式處理來自基於流的服務(Amazon Kinesis Data Streams 或 DynamoDB 流)的事件,則每個流的分割槽數量是併發度單元。如果您的流有 100 個活動分割槽,則最多會有 100 個 Lambda 函式呼叫併發執行。然後,每個 Lambda 函式按照分割槽到達的順序處理事件。

  • 並非基於流的事件源 – 如果您建立 Lambda 函式處理來自並非基於流的事件源(例如,Amazon S3 或 API 閘道器)的事件,則每個釋出的事件是一個工作單元。因此,這些事件源釋出的事件數(或請求數)影響併發度。

    您可以使用以下公式來估算併發 Lambda 函式呼叫數。

    events (or requests) per second * function duration
    複製程式碼

    例如,考慮一個處理 API Gateway 的 Lambda 函式。假定 Lambda 函式平均用時 0.3 秒,API Gateway 每秒請求 1000 次。因此,Lambda 函式有 300 個併發執行。

具體資訊參考Lambda 函式並行執行

**AWS Lambda 部署限制 **

專案 預設限制
Lambda 函式部署程式包大小 (壓縮的 .zip/.jar 檔案) 50 MB
每個區域可以上傳的所有部署程式包的總大小 75GB
可壓縮到部署程式包中的程式碼/依賴項的大小 (未壓縮的 .zip/.jar 大小).注意每個 Lambda 函式都會在其的 /tmp 目錄中接收到額外的 500 MB 的非永續性磁碟空間。該 /tmp 目錄可用於在函式初始化期間載入額外的資源,如依賴關係庫或資料集。 250MB
環境變數集的總大小 4 KB

本文內容主要參考 AWS Lambda 官方文件,詳細資訊請訪問 https://docs.aws.amazon.com/zh_cn/lambda/latest/dg/welcome.html

參考連結

AWS Lambda 開發入門

建立部署程式包 (Python)

Lambda 函式並行執行

高併發解決方案

如何優化網站高併發訪問?

高併發的解決方案

Serverless開發程式設計思想

一個簡單的 Serverless 架構例子

使用lambda帶來的架構優勢


最後,感謝女朋友支援。

歡迎關注(April_Louisa) 請我喝芬達
歡迎關注
請我喝芬達

相關文章