場景:
現在需要開發一個前後端分離的應用,後端採用 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 服務案例的一個執行流程圖:
- 用戶將對象上傳到 S3 存儲桶(對象創建事件)。
- Amazon S3 檢測到對象創建事件。
- Amazon S3 調用在存儲桶通知配置中指定的 Lambda 函數。
- AWS Lambda 通過代入您在創建 Lambda 函數時指定的執行角色來執行 Lambda 函數。
- Lambda 函數執行。
這篇文章主要介紹 將 Lambda 作爲事件源用於 AWS 服務 和 配合 API Gateway 創建簡單的微服務。
如何使用 Lambda
接下來將使用一個案例介紹如何使用 Lambda。
將 AWS Lambda 與 Amazon API Gateway 結合使用(按需並通過 HTTPS)
步驟 1:設置 AWS 賬戶和 AWS CLI
步驟 2:創建 HelloWorld Lambda 函數和探索控制檯
創建 Hello World Lambda 函數
- 登錄 AWS 管理控制檯並打開 AWS Lambda 控制檯。
- 選擇 Get Started Now。(僅當未創建任何 Lambda 函數時,控制檯才顯示 Get Started Now 頁面。如果您已創建函數,則會看到 Lambda > Functions 頁面。在該列表頁面上,選擇 Create a Lambda function 轉到 Lambda > New function 頁面。下圖是這種情況
- 這裏選擇從頭開始創作,填寫函數名、選擇角色,點擊創建函數
- 配置創建好的Lambda函數
需要注意的是:處理程序填寫部分爲 代碼文件名+文件中函數名,這裏我們文件名lambda_function, 函數名是 lambda_handler,處理程序部分填寫爲 lambda_function.lambda_handler。
- 添加觸發器,這裏我們選擇API Gateway ,在配置部分選擇之前配置好的 API,點擊添加。然後保存函數
測試AWS Lambda + Amazon API Gateway
登錄 aws 控制檯,打開 API Gateway,選擇我們剛剛選用的 API,點擊測試,我們將會看到以下輸出
詳細信息可以參考 官方文檔(https://docs.aws.amazon.com/z...)
通過上面的步驟,我們瞭解瞭如何使用一個 Lambda 函數,現在我們看下如何構建 Lambda 函數。
如何構建Lambda
創建 Lambda 函數
在創建 Lambda 函數時,需要指定一個處理程序(此處理程序是代碼中的函數),AWS Lambda 可在服務執行代碼時調用它。在 Python 中創建處理程序函數時,使用以下一般語法結構。
def handler_name(event, context):
...
return some_value
在該語法中,需要注意以下方面:
-
event
- AWS Lambda 使用此參數將事件數據傳遞到處理程序。此參數通常是 Pythondict
類型。它也可以是list
、str
、int
、float
或NoneType
類型。 -
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.info
和logging.Logger.error
)。
print
和 logging.*
函數將日誌寫入 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.logGroupName
和context.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/z...
注意事項
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/z...
參考鏈接
最後,感謝女朋友支持。
歡迎關注(April_Louisa) | 請我喝芬達 |
---|---|