創新推出 | Serverless 場景排查問題利器:函式例項命令列操作

語言: CN / TW / HK

作者:叢霄(阿里雲函式計算研發工程師)

背景介紹

全託管的 Serverless 計算平臺能給使用者帶來更少的運維代價、更強的穩定性和更快的彈效能力,在 Serverless 落地的過程中,遇到的一個很大的挑戰是 Serverless 平臺如何給予開發者足夠的安全感。讓開發者們無負擔地使用並信任 Serverless,是我們一直追求的目標。

全託管的初衷是為了減小開發者的使用和運維複雜度,但這一定程度上削減了使用者對自身服務的控制權力。比如在很多場景中,使用者會想知道,如何能夠掌握自己應用的實際執行情況?應用出現問題時如何能快速確認是自身問題還是雲平臺問題?如果是雲平臺的問題,如何能快速恢復服務,及時止損?

這些問題的根本原因,都是使用者對雲平臺無法做到完全的信任,這也進一步阻礙了他們遷移應用和擴充套件業務場景。所以我們也在思考,如何打破這種不信任局面,讓使用者擁有更多資源層面上的掌控力,但又能遠離資源層的複雜運維。

在這樣的背景和需求下,阿里雲函式計算創新推出了 Serverless 場景下的函式例項命令列操作功能,支援使用者在控制檯介面登入進函式例項內部,或者使用工具對例項執行指定的命令。 本文將具體介紹這個功能的使用方式和使用場景。

實現 Exec 功能定位及使用方式

例項命令列操作功能提供和 K8s Pod Exec 與 Docker Container Exec 一致的使用體驗,支援在函式例項的真實執行環境中執行具體命令。

同時,由於 Serverless 極致彈性、按量收費等特性,在 Serverless 場景下的例項 Exec 功能又與 K8s 和 Docker 有著一些本質的區別:

  1. 只能對還存活著的例項(包括預留常駐例項和按量活躍例項) 執行 Exec 操作,如果按量例項空閒超時被釋放,則無法再執行;

  2. InstanceExec 請求不佔用例項的併發度。因此即使函式的例項併發度設定為 1,也可以同時執行 InvokeFunction 和 InstanceExec 操作;

  3. InstanceExec 的一次操作被視作一次 InvokeFunction 請求呼叫。只要 InstanceExec 請求建立的 websocket 連線沒有和函式例項斷開,那麼函式例項將一直處於活躍狀態,和 InvokeFunction 採用同樣的計費規則。使用者可以設定 InstantceExec 的 idleTimeout 引數讓客戶端在空閒指定時間後主動斷開連線。

例項命令列操作功能支援在控制檯上登入例項、使用 Serverless Devs 工具執行命令,或者 SDK 呼叫介面,執行命令。

控制檯登入例項

在函式計算官網控制檯上在函式詳情-監控指標-例項指標頁面,在最右側可以對例項執行登陸操作。

點選“登入例項”,介面將會調到一個終端介面,即可馬上登入進例項,執行命令進行問題排查。

在函式詳情-監控指標-例項指標頁面,點選例項 ID 可以進入到函式的例項詳情頁面,介面右上方有登入例項的按鈕,點選即可進入例項。

SDK 呼叫

以 golang SDK 為例,其它 SDK 的呼叫方式大都類似。

SDK 對 InstanceExec API 進行了封裝,在呼叫介面的時候需要使用建 OnStdout、OnStderr 傳入兩個回撥函式,回撥函式定義了處理 Exec 通道返回資料的具體邏輯 ;同時可以使用返回的 execConn 輸入 stdin 訊息以傳輸給遠端的 Exec 通道。

command := []string{"/bin/bash"}

execConn, err := client.InstanceExec(
      fc.NewInstanceExecInput(
        serviceName, functionName, instanceID, command,
      ).WithStdin(true)
             .WithStdout(true)
             .WithStderr(true)
             .WithTTY(true)
             .WithIdleTimeout(120)
             .OnStdout(
        func(data []byte) { fmt.Printf("STDOUT: %s\n", data) },
      ).OnStderr(
        func(data []byte) { fmt.Printf("STDERR: %s\n", data) },
      ))
if err != nil {
  fmt.Printf("%v", err)
}

if err := execConn.WriteStdin([]byte("ls\r")); err != nil {
  fmt.Println("Write Stdin error", err)
}

適用場景

排查線上問題

在一些日常的場景下,例項命令列操作會帶來更符合使用者習慣、更高效便捷的排查問題方式。

使用者小王是 Serverless 小白使用者,寫完一個程式部署到函式計算後,發現函式中設定的環境變數不生效,如果進一步排查,則需要修改程式碼,列印日誌,重新部署,檢視日誌,使用這樣繁瑣的排查方式。現在藉助例項命令列操作,小王可以直接命令:s exec {instance_id} ENV,便能一步定位問題。

例項命令列操作提供了便捷的登入體驗,能幫助使用者解決複雜場景下的應用問題。 一些情況下,使用者已經無法通過函式日誌、監控指標來具體定位問題,需要藉助比如 coredump 、tcpdump、jmap 等工具進行深入排查。

比如,使用者小李發現自己的線上程式最近會出現一些函式錯誤,報錯內容都是連線遠端某服務超時。小李懷疑是函式例項與遠端服務的網路連結不穩定,想進入例項內部,調查分析下例項與遠端服務的網路情況。他可以按照這樣的步驟進行:

  • 登入進例項內部後,先安裝 tcpdump 工具,需要執行 apt-get update 和  apt-get install tcpdump 兩條命令:

  • 安裝完畢後,執行 tcpdump 命令,對遠端服務 IP 的請求進行抓包,並將抓包結果儲存在 tcpdump.cap 檔案中:

  • 抓包完畢,藉助 OSS 命令列工具 ossutil64 ,將 tcpdump.cap 檔案上傳到自己的 OSS ,然後下載到本地藉助分析工具 wireshark 可以進行分析。

程式效能優化

很多時候,開發者需要通過各種 profiling 工具來分析效能、資源使用等問題。比如應用例項 CPU、記憶體等資源使用不符合預期;應用效能低於預期,通過 profiling 工具找到瓶頸等等。通過例項命令列操作,開發者能夠方便的執行語言、框架提供的各種 profiling 工具,優化程式效能和資源使用。

以執行在函式計算上的高德自主出行為例,其峰值 TPS 會達到數十萬級別,作為實時線上應用,服務能接受的請求延遲在幾十毫秒級別。考慮到成本壓力,在上線前他們期望壓測出單例項最高能承受的 TPS 和對應的呼叫延遲,以此評估需要的例項數量。

但是高德在壓測中發現單例項的平均/長尾延時不符合預期,當單例項 TPS 達到 300 TPS 的時候,請求延遲會直線上升。他們想確定,是否是自己的應用程式哪裡存在效能瓶頸,或者是函式計算執行時的效能存在問題?藉助例項命令列操作,他們可以登入進例項內部,通過 profiling 深入分析後發現了效能問題,最後優化了程式效能達到了上線標準。

下面以 custom runtime 為例:demo 示例程式使用 golang 編寫並部署到函式計算上:

  • 登入進入例項後,下載 golang 安裝包 :

  • 並解壓安裝 go :

  • 執行 go tool pprof 命令,併產生分析檔案:/root/pprof/pprof.bootstrap.samples.cpu.001.pb.gz,

  • 最後藉助 OSS 命令列工具 ossutil64, 執行 ./ossutil64 cp 命令,將分析檔案上傳到自己的 OSS Bukcet 中 ,便可以下載到使用者本地進行視覺化分析。

總結

例項命令列功能的推出希望能消除使用者使用 Serverless 的“最後一公里”,直接將真實的函式執行環境展現給使用者,此後 Serverless 將不再是一個“黑盒”,使用者可以更加信任和依賴 Serverless 平臺來擴充套件更多的業務場景和規模。

作者簡介: 叢霄,阿里雲函式計算研發工程師,專注於雲原生 Serverless、分散式系統穩定性等領域。

戳​​此處​​,檢視函式計算更多詳情!