Serverless 應用開發的 7 個經驗心得

Serverless發表於2022-04-25

預設標題_公眾號封面首圖_2022-04-20+20_07_18.png

Serverless 應用開發的 7 個經驗心得

作者說:Serverless 架構下的應用開發,與傳統架構的應用開發還是有比較大的區別點的,例如天然分散式架構會讓很多框架喪失一定的"便利性",無狀態的特點又讓很多"傳統架構下看起來再正常不過的操作"變得異常風險。所以本篇我會介紹一些在 Serverless 架構下,常見的應用開發注意事項,分享一些個人的實戰經驗心得。如果你在 Serverless 開發過程中遇到問題,不妨往下聽聽看吧。

1、如何上傳檔案

在傳統 Web 框架中,上傳檔案是非常簡單和便捷的,例如 Python 的 Flask 框架:

f = request.files['file']
f.save('my_file_path')

但是在 Serverless 架構下,卻不能直接上傳檔案,原因有以下幾點:

  • 一些雲平臺的 API 閘道器觸發器會將二進位制檔案轉換成字串;不便直接獲取和儲存;
  • 此外,API 閘道器與 FaaS 平臺之間傳遞的資料包有大小限制,很多平臺被限制在 6M;
  • FaaS 平臺大都是無狀態的,即使儲存到當前例項中,也會隨著例項釋放而導致檔案丟失;

因此,傳統框架中常用的上傳方案,是不太適合在 Serverless 架構中直接使用的。若是想在 Serverless 架構上傳檔案,可以嘗試以下兩種方法:

  • 一種是 BASE64 後上傳,持久化到物件儲存或者是 NAS 中,這種做法可能會觸及到 API 閘道器與 FaaS 平臺之間傳遞的資料包有大小限制,所以一般使用這種上傳方法的通常是上傳頭像等小檔案的業務場景;
  • 第二種上傳方法是,通過物件儲存等平臺來上傳,因為客戶端直接通過金鑰等資訊,來將檔案直傳到物件儲存是有一定風險的。所以通常情況是客戶端發起上傳請求,函式計算根據請求內容進行預簽名操作,並將預簽名地址返回給客戶端,客戶端再使用指定的方法進行上傳,上傳完成之後,可以通過物件儲存觸發器等來對上傳結果進行更新,詳情如下圖所示:

image.png

2、檔案讀寫與持久化方法

應用在執行過程中,可能會涉及到檔案的讀寫操作,或者是一些檔案的持久化操作。在傳統的雲主機模式下,通常情況下是可以直接讀寫檔案,或者將檔案持久化某個目錄下,但是在 Serverless 架構下卻並不是這樣的。

由於 FaaS 平臺是無狀態的,並且用過之後會被銷燬,所以檔案如果需要持久化並不能直接持久化在例項中,可以選擇持久化到其他的服務中,例如物件儲存、NAS 等。

同時,在不配置 NAS 的情況下,FaaS 平臺通常情況下之後 /tmp 目錄具有可寫許可權,所以部分臨時檔案可以快取在 /tmp 資料夾下。

3、慎用部分 Web 框架的特性

函式計算(FC)是請求級別的隔離,所以可以認為這個請求結束了,例項就有可能進入到一個“靜默”的狀態。在函式計算中,API 閘道器觸發器通常是同步呼叫_(以阿里雲函式計算為例,通常只在定時觸發器、OSS 事件觸發器、MNS 主題觸發器和 IoT 觸發器等幾種情況下是非同步觸發)_,這就意味著當 API 閘道器將結果返回給客戶端的時候,整個函式就會進入“靜默”狀態,或者被銷燬,而不是會繼續執行完非同步方法。

所以通常情況下像 Tornado 等框架就很難在 Serverless 架構下發揮其非同步的作用。當然,如果使用者需要非同步能力,可以參考雲廠商所提供非同步方法,以阿里雲函式計算為例,阿里雲函式計算為使用者提供了一種非同步呼叫能力,當函式的非同步呼叫被觸發後,函式計算會將觸發事件放入內部佇列中,並返回請求 ID,而具體的呼叫情況及函式執行狀態將不會返回。如果使用者希望獲得非同步呼叫的結果,可以通過配置非同步呼叫目標來實現,詳情如圖中所示:

image.png

Serverless 架構下,應用一旦完成當前請求,就會進入到“靜默”狀態,例項甚至都會被銷燬,所以這就導致一些自帶定時任務的框架沒有辦法正常執行定時任務。因為函式計算通常是由事件觸發,不會自主定時啟動。例如 Egg 專案中設定了一個定時任務,但是在實際的函式計算中如果沒有通過觸發器觸發該函式,那麼該函式是不會被觸發,函式也不會從內部自動啟動來執行定時任務,所以此時可以使用各個雲廠商為其 FaaS 平臺提供的定時觸發器,通過定時觸發器觸發指定方法,來替代定時任務。

4、要注意應用組成結構

在 Serverless 架構下,靜態資源更應該在物件儲存與 CDN 的加持下對外提供服務;否則所有的資源都在函式中,通過函式計算對外暴露,不僅僅會讓函式的真實業務邏輯併發度降低,也會造成更多的成本支出。尤其是將一些已有的程式遷移到 Serverless 架構上,如 Wordpress 等,更是要注意將靜態資源與業務邏輯進行拆分,不然在高併發的情況下,效能與成本都將會受到嚴格的考驗。

在眾多雲廠商中,函式的收費標準都是依靠執行時間和配置的記憶體,以及產生的流量進行收費的。如果一個函式的記憶體設定不合理,會導致成本翻倍增加。因此我們既要保證記憶體設定合理,更要保證業務邏輯結構的可靠性。

以阿里雲函式計算為例,當一個應用,有兩個對外的介面,其中有一個介面的記憶體消耗在 128MB 以下,另一個介面的記憶體消耗穩定在 3000MB 左右。這兩個介面,平均每天會被觸發 10000 次,並且時間消耗均在 100ms。如果兩個介面寫到一個函式中,那麼這個函式可能需要將記憶體設定在 3072MB,同時在使用者請求記憶體消耗較少的介面時,在冷啟動的情況下可能難以得到較好的效能表現;但是,如果兩個介面分別寫到兩個函式中,那麼兩個函式記憶體分別設定成 128MB 以及 3072MB 即可:

lQLPDhtZX6XDkeLNARDNBA2wl8BEPBQCAFgCYxpadoCIAA_1037_272.png

通過上表,我們可以明確看出,當合理的、適當地把業務進行拆分之後,會在一定程度上更節約成本,以上述例子來看,成本節約近 50%!

5、傳統框架遷移方案與策略

Serverless 的範圍越來越廣,它本質上來講更像是一種設計理念,一種新的程式設計正規化。在這種新的架構下,或者說新的程式設計正規化下,使用全新的思路來做 Serverless 應用是再好不過的了。但是原生的 Serverless 開發框架是非常少的,以 Web 框架為例,目前的主流的 Web 框架“均不支援 Serverless 模式部署”,一方面是要嘗試接觸 Serverless,一方面又沒辦法完全放棄傳統框架,所以如何將傳統框架更簡單、更快速、更科學地部署到 Serverless 架構上是一個值得探討的問題。下面我結合案例分享一下遷移思路:

  • 傳統框架遷移案例

請求整合方案實際上就是把真實的 API 閘道器請求,直接透傳給 FaaS 平臺,而不在中途增加任何轉換邏輯。以阿里雲函式計算的 HTTP 函式為例,當開發者想要把傳統框架(例如 Django,Flask,Express,Next.js 等)部署到阿里雲函式計算平臺上,並且體驗 Serverless 帶來的按量付費,彈性伸縮等便捷優勢。

得益於阿里雲函式計算的 HTTP 函式和 HTTP 觸發器,開發者不僅可以快速、簡單地將框架部署到阿里雲函式計算,更可以保持和傳統開發一樣的體驗。以 Python 的 Bottle 框架為例,當我們開發一個 Bottle 專案之後:

# index.pyp
import bottle

@bottle.route('/hello/<name>')
def index(name):
    return "Hello world"

if __name__ == '__main__':
    bottle.run(host='localhost', port=8080, debug=True)

可以直接在本地進行除錯。當想要把該專案部署到阿里雲函式計算上,只需要增加一個 default_app 的物件即可:

app=bottle.default_app()

整個專案:

# index.py
import bottle

@bottle.route('/hello/<name>')
def index(name):
    return "Hello world"

app = bottle.default_app()

if __name__ == '__main__':
    bottle.run(host='localhost', port=8080, debug=True)

此時,在阿里雲函式計算平臺,建立函式時,將函式入口設定為:index.app 即可。除了 Bottle 之外,其他的 Web 框架的操作方法是類似的,再以 Flask 為例:

# index.py
from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World!'
   
if __name__ == '__main__':
    app.run(
        host="0.0.0.0",
        port=int("8001")
)

在配置函式的時候寫上入口函式為:index.app 即可,就可以保證該 Flask 專案執行在函式計算平臺上。

當然,除了使用已有的語言化的 Runtime,還可以考慮使用 Custom Runtime 和 Custom Container 來實現,例如,一個 Web 專案完成之後,可以編寫一個 Bootstrap 檔案(在 Bootstrap 檔案中寫一些啟動命令即可),例如我要啟動一個 Express 的專案,我把我的 Express 專案準備完成之後,可以直接通過 Bootstrap 為:

#!/usr/bin/env bash
export PORT=9000
npm run star
  • 通過開發者工具快速遷移/部署

微信頭圖白底.jpg

如果通過開發者工具進行傳統框架的支援,可以直接通過 Serverless Devs 的命令,進行案例的專案的建立。目前 Serverless Devs 已經支援以下框架:

image.png

詳情可以參考:https://github.com/devsapp/start-web-framework

以 Express 專案為例,可以在命令列工具執行:

s init start-express

即可進行專案的初始化:

    _____                             
    |  ___|                            
    | |____  ___ __  _ __ ___  ___ ___ 
    |  __\ \/ / '_ \| '__/ _ \/ __/ __|
    | |___>  <| |_) | | |  __/\__ \__ \
    \____/_/\_\ .__/|_|  \___||___/___/
              | |                      
              |_|                      
                                        
? please select credential alias default

    Welcome to the start-express application
     This application requires to open these services: 
         FC : https://fc.console.aliyun.com/
     Express development docs: https://www.expressjs.com.cn/4x/api.html

     * 額外說明:s.yaml中宣告瞭actions:
        部署前執行:npm install --production
       如果遇到npm命令找不到等問題,可以適當進行手動專案構建,並根據需要取消actions內容 
     * 專案初始化完成,您可以直接進入專案目錄下,並使用 s deploy 進行專案部署


?‍ Thanks for using Serverless-Devs
? You could [cd /Users/jiangyu/Desktop/fc-custom-lua-event/image-prediction-app/start-express] and enjoy your serverless journey!
?️ If you need help for this example, you can use [s -h] after you enter folder.
? Document ❤ Star:https://github.com/Serverless-Devs/Serverless-Devs

完成之後,可以進入專案並部署:

$ s deploy


framework: 
  region:   cn-beijing
  service: 
    name: web-framework
  function: 
    name:       express
    runtime:    custom
    handler:    index.handler
    memorySize: 128
    timeout:    60
  url: 
    system_url:    https://1583208943291465.cn-beijing.fc.aliyuncs.com/2016-08-15/proxy/web-framework/express/
    custom_domain: 
      - 
        domain: http://express.web-framework.1583208943291465.cn-beijing.fc.devsapp.net
  triggers: 
    - 
      type: http
      name: httpTrigger

此時可以通過瀏覽器開啟頁面:

image.png

此時,可以根據案例提供的 Bootstrap 以及 s.yaml 進行參考,並將自身的專案部署/遷移到阿里雲 Serverless 架構。其中 Bootstrap 為:

#!/bin/bash

node index.js

其中 s.yaml 為:

# ------------------------------------
#   歡迎您使用阿里雲函式計算 FC 元件進行專案開發
#   元件倉庫地址/幫助文件:https://github.com/devsapp/fc
#   Yaml參考文件:https://github.com/devsapp/fc/blob/jiangyu-docs/docs/zh/yaml.md
#   關於:
#      - Serverless Devs和FC元件的關係、如何宣告/部署多個函式、超過50M的程式碼包如何部署
#      - 關於.fcignore使用方法、工具中.s目錄是做什麼、函式進行build操作之後如何處理build的產物
#   等問題,可以參考文件:https://github.com/devsapp/fc/blob/jiangyu-docs/docs/zh/tips.md
#   關於如何做CICD等問題,可以參考:https://github.com/Serverless-Devs/Serverless-Devs/blob/master/docs/zh/cicd.md
#   有問題快來釘釘群問一下吧:33947367
# ------------------------------------
edition: 1.0.0          #  命令列YAML規範版本,遵循語義化版本(Semantic Versioning)規範
name: framework         #  專案名稱
access: "default"       #  祕鑰別名

services:
  framework: # 業務名稱/模組名稱
    component: fc  # 元件名稱
    actions:
      pre-deploy: # 在deploy之前執行
        - run: npm install --production  # 要執行的命令列
          path: ./code # 命令列執行的路徑
    props: # 元件的屬性值
      region: cn-beijing
      service:
        name: web-framework
        description: 'Serverless Devs Web Framework Service'
      function:
        name: express
        description: 'Serverless Devs Web Framework Express Function'
        codeUri: './code'
        runtime: custom
        timeout: 60
        caPort: 9000
      triggers:
        - name: httpTrigger
          type: http
          config:
            authType: anonymous
            methods:
              - GET
      customDomains:
        - domainName: auto
          protocol: HTTP
          routeConfigs:
            - path: '/*'

6、可觀測性

Serverless 應用的可觀測性是被很多使用者所關注的。可觀測性是通過外部表現判斷系統內部狀態的衡量方式,在應用開發中,可觀測性幫助判斷系統內部的健康狀況。在系統出現問題時,幫助定位問題、排查問題、分析問題;在系統平穩執行時,幫助評估風險,預測可能出現的問題。

在 Serverless 應用開發中,如果觀察到函式的併發度持續升高,很可能是業務推廣團隊的努力工作導致業務規模迅速擴張,為了避免達到併發度限制觸發流控,開發者就需要提前提升併發度,以阿里雲函式計算為例,阿里雲函式計算就在可觀測性層面提供了多種緯度,包括 Logging、Metrics 以及 Tracing 等內容。

image.png

如圖,在控制檯監控中心,可以檢視到整體的 Metrics,服務級 Metrics 以及每個函式的 Metrics。除此之外,還可以看到當前函式的請求記錄:

image.png

根據不同的請求記錄,我們可以檢視到函式的詳細資訊:

image.png

除了在控制檯的監控中心處可以檢視到函式的日誌等資訊,在函式詳情頁面,也可以看到函式的詳細日誌資訊:

image.png

以及 Tracing 相關資訊:

image.png

當然,通過 Serverless Devs 開發者工具,以及函式計算元件也可以進行觀測相關操作,下面我們來一起看一下是怎麼進行的。

  • 通過工具進行 Metrics 檢視
詳情參考:https://github.com/devsapp/fc/blob/main/docs/zh/command/metrics.md
  • 有資源描述檔案(Yaml)時,可以直接執行 s metrics 檢視函式的指標資訊;
  • 純命令列形式(在沒有資源描述 Yaml 檔案時),需要指定服務所在地區以及服務名稱,函式名等,例如 sclifcmetrics--regionch-hangzhou--service-namemyService--function-namemyFunction;

上述命令的執行結果示例如下:

[2021-06-07T12:20:06.661] [INFO ] [FC-METRICS] - 請用瀏覽器訪問Uri地址進行檢視: http://localhost:3000

此時,通過瀏覽器開啟地址,可以看到函式指標資訊:

image.png

P.S.需要開啟請求級別指標,才能檢視函式指標資訊,否則圖表不展示資料。

關於如何開通請求級別指標:

1.https://fcnext.console.aliyun.com/
2.服務及函式中-找到自己region-對應的服務名稱-在操作欄點選配置開啟請求級別指標

  • 通過工具進行 Logs 檢視
詳情參考:https://github.com/devsapp/fc/blob/main/docs/zh/command/logs.md
  • 有資源描述檔案(Yaml)時,可以直接執行 s logs 進行線上函式的日誌查詢;
  • 純命令列形式(在沒有資源描述 Yaml 檔案時),需要指定服務所在地區以及服務名稱,函式名等,例如 s cli fc logs --region cn-hangzhou --service-name fc-deploy-service --function-name http-trigger-py36

上述命令的執行結果示例:

FunctionCompute python3 runtime inited.

FC Invoke Start RequestId: 84d6ae81-02ff-4011-b3ca-45e65b210cc3
FC Invoke End RequestId: 84d6ae81-02ff-4011-b3ca-45e65b210cc3

FC Invoke Start RequestId: de4812be-9137-4a33-9869-370cb61ac427
FC Invoke End RequestId: de4812be-9137-4a33-9869-370cb61ac427

如果需要以 tail 模式進行日誌的查詢,可以增加 --tail 引數,例如 s logs --tail;

查詢指定時間段的日誌,可以通過增加 --start-time 和 --end-time 引數實現,例如 s logs -s 2021-11-04T15:40:00 -e 2021-11-04T15:45:00;

7、如何對應用進行除錯

在應用開發過程中,或者應用開發完成,但是所執行結果不符合預期時,通常要進行一定的除錯工作。但是在 Serverless 架構下,除錯往往會受到極大的環境因素限制,有可能出現的情況是,所開發的應用在本地是可以比較健康的、符合預期的執行,但是在 FaaS 平臺上,則會出現一些不可預測的問題;或者是在一些特殊的環境下,本地沒有辦法模擬線上環境,難以進行專案的開發和除錯。

Serverless 應用除錯被視為 Serverless 落地最大的痛點與挑戰,但是各個雲廠商並沒有因此放棄在除錯方向的不斷深入探索。以阿里雲函式計算為例目前就提供線上除錯、本地除錯等多種除錯方案。一些具體的操作可參考這篇文章:<硬核除錯實操 | 手把手帶你實現 Serverless 斷點除錯>,這裡就不再贅述啦。

結語

以上就是我在 Serverless 應用開發中的一些經驗分享,Forrester 曾提出:Serverless 架構的興起,讓 FaaS (Function As A Service) 成為繼 IaaS、PaaS、SaaS 之後一種新的雲端計算能力提供方式。未來也將會有大量主流企業的核心應用,從原來的主機架構遷移到 Serverless 架構。

Serverless 架構正當時,其已然開啟從概念到實踐的大規模落地之路,正如 Gartner 報告中的預測:到 2025 年,全球一半的企業將採用 FaaS 部署;

Serverless 不僅可以做到讓開發者無需再管理伺服器,無需再對資源做預估並考慮擴充套件;發揮降本提效,按量付費的優勢,它能讓你進入只專心在業務邏輯的狀態,從而全面提升工作中的研發效能。

好啦,今天是世界讀書日,感謝閱讀,希望我的分享能夠對你有所幫助。


banner900x383.png

本文節選自《Serverless 開發速查手冊》第五章 - Serverless 應用開發常見思路 內容,更多閱讀可關注 Serverless 公眾號,後臺回覆 手冊 免費下載整本工具書。

作者簡介:

劉宇(花名:江昱)
阿里雲 Serverless 產品經理,阿里雲麒麟佈道師,雲原生十佳佈道師,國防科技大學在讀博士。阿里雲 戰略級開源專案 Serverless Devs 發起人和負責人。
著有暢銷書《Serverless 架構:從原理、設計到專案實戰》、《Serverless 工程實踐:從入⻔到進階》、《Serverless 開發速查手冊》、《Serverless 架構與人工智慧最佳實踐(出版中)》等。


世界讀書日,獎勵看到最後的你:

  • Serverless 公眾號後臺回覆 讀書 免費獲得作者掘金演說之《雲時代效能革命:從 Serverless 看應用上線新路徑》學習資源 PPT!
  • 公眾號原文評論區留言寫下你對 Serverless 的學習見解和體悟,或者直接 #Serverless YYDS# 加油打 call;每一位開發者都是我們的朋友,大家可以暢所欲言字數不限,點贊最高的開發者,可以收到阿 Ser 會送出的精美禮品~

更多內容關注 Serverless 微信公眾號(ID:serverlessdevs),彙集 Serverless 技術最全內容,定期舉辦 Serverless 活動、直播,使用者最佳實踐。

相關文章