Serverless 的內存配置與超時時間

當我們使用 Serverless 架構的時候,如何設置運行內存和超時時間呢?

在上一篇文章《Serverless 的資源評估與成本探索》中,我們對性能和成本探索進行了些思考,在此就引出一個新的問題:當我們使用 Serverless 架構的時候,如何設置運行內存和超時時間呢?這裡分享下我的評估方法供大家參考。

首先在函數上線時,選擇一個稍微大一點的內存。例如,這裡執行一次函數,得到下圖結果:

Serverless 的內存配置與超時時間

那麼將我的函數設置為 128M 或者 256M,超時時間設置成 3S。

讓函數跑一段時間,例如該接口每天觸發約為 4000 次:

Serverless 的內存配置與超時時間

將這個函數的日誌撈出來寫成腳本,做統計:

<code>    import json, time, numpy, base64
import matplotlib.pyplot as plt
from matplotlib import font_manager
from tencentcloud.common import credential
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from tencentcloud.scf.v20180416 import scf_client, models

secretId = ""
secretKey = ""
region = "ap-guangzhou"
namespace = "default"
functionName = "course"

font = font_manager.FontProperties(fname="./fdbsjw.ttf")

try:
cred = credential.Credential(secretId, secretKey)
httpProfile = HttpProfile()
httpProfile.endpoint = "scf.tencentcloudapi.com"

clientProfile = ClientProfile()
clientProfile.httpProfile = httpProfile
client = scf_client.ScfClient(cred, region, clientProfile)

req = models.GetFunctionLogsRequest()

strTimeNow = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(int(time.time())))
strTimeLast = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(int(time.time()) - 86400))
params = {
"FunctionName": functionName,
"Limit": 500,
"StartTime": strTimeLast,
"EndTime": strTimeNow,
"Namespace": namespace
}
req.from_json_string(json.dumps(params))

resp = client.GetFunctionLogs(req)

durationList = []
memUsageList = []

for eveItem in json.loads(resp.to_json_string())["Data"]:
durationList.append(eveItem['Duration'])
memUsageList.append(eveItem['MemUsage'] / 1024 / 1024)

durationDict = {
"min": min(durationList), # 運行最小時間
"max": max(durationList), # 運行最大時間
"mean": numpy.mean(durationList) # 運行平均時間
}
memUsageDict = {
"min": min(memUsageList), # 內存最小使用
"max": max(memUsageList), # 內存最大使用
"mean": numpy.mean(memUsageList) # 內存平均使用
}

plt.figure(figsize=(10, 15))
plt.subplot(4, 1, 1)
plt.title('運行次數與運行時間圖', fontproperties=font)
x_data = range(0, len(durationList))
plt.plot(x_data, durationList)
plt.subplot(4, 1, 2)
plt.title('運行時間直方分佈圖', fontproperties=font)
plt.hist(durationList, bins=20)
plt.subplot(4, 1, 3)
plt.title('運行次數與內存使用圖', fontproperties=font)
x_data = range(0, len(memUsageList))
plt.plot(x_data, memUsageList)
plt.subplot(4, 1, 4)
plt.title('內存使用直方分佈圖', fontproperties=font)
plt.hist(memUsageList, bins=20)


​ with open("/tmp/result.png", "rb") as f:
​ base64_data = base64.b64encode(f.read())


print("-" * 10 + "運行時間相關數據" + "-" * 10)
print("運行最小時間:\\t", durationDict["min"], "ms")
print("運行最大時間:\\t", durationDict["max"], "ms")
print("運行平均時間:\\t", durationDict["mean"], "ms")


print("\\n")

print("-" * 10 + "內存使用相關數據" + "-" * 10)
print("內存最小使用:\\t", memUsageDict["min"], "MB")
print("內存最大使用:\\t", memUsageDict["max"], "MB")
print("內存平均使用:\\t", memUsageDict["mean"], "MB")

print("\\n")

plt.show(dpi=200)
​ except TencentCloudSDKException as err:
​ print(err)/<code>

運行結果:

<code>    ----------運行時間相關數據----------
運行最小時間: 6.02 ms
運行最大時間: 211.22 ms
運行平均時間: 54.79572 ms

----------內存使用相關數據----------
內存最小使用: 17.94921875 MB
內存最大使用: 37.21875190734863 MB
內存平均使用: 24.83201559448242 MB/<code>
Serverless 的內存配置與超時時間

通過該結果可以清楚看出,近 500 次,每次函數的時間消耗和內存使用。

可以看到時間消耗基本在 1S 以下,所以此處「超時時間」設置成 1S 比較合理;而內存使用基本是 64M 以下,所以此時內存設置成 64M 就可以。

再舉個例子,對於另外一個函數:

<code>    ----------運行時間相關數據----------
運行最小時間: 63445.13 ms
運行最大時間: 442629.12 ms
運行平均時間: 91032.31301886792 ms


​ ----------內存使用相關數據----------
​ 內存最小使用: 26.875 MB
​ 內存最大使用: 58.69140625 MB
​ 內存平均使用: 36.270415755937684 MB/<code>
Serverless 的內存配置與超時時間

假如說上一個函數,是一個非常平穩和光滑的函數,很容易預估資源使用率,那麼這個函數則可以很明顯看出波動。

運行時間絕大部分在 150S 以下,部分不到 200S,最高峰值近 450S。這個時候,我們就可以業務需求來判定,450S 的請求波峰是否可以被中止。此時,我推薦將這個函數的超時時間設置為 200S。

至於內存部分,可以看到絕大部分都在 40MB 以內,部分出現在 45-55MB,最高未超過 60MB,所以此時可以將函數設置為 64MB。

就目前來說,雲函數在執行時可能會有一定的波動。因此內存使用或超時時間在範圍內波動是很正常的,我們可以根據業務需求來做一些設置,將資源使用量壓到最低,節約成本。

我的做法基本就是分為兩步走:

  1. 簡單運行兩次,評估一下基礎資源使用量,然後設置一個較高的值;
  2. 函數運行一段時間後,獲取樣本,再進行基本的數據分析和數據可視化,優化得到一個相對穩定的新數值。


分享到:


相關文章: