雲計算

無服務計算應用場景探討及 FaaS 應用實戰

頭圖.jpg

作者 | 宋文龍(聞可)  阿里雲全球技術服務部高級交付專家

什麼是無服務計算

無服務器計算(Serverless Computing)在構建和運行應用時無需管理服務器等基礎設施。它描述了一個細粒度的部署模型,在該模型中,應用被拆解為一個或多個細顆粒度的函數,在雲端託管環境中被觸發運行,然後根據需要執行、擴展容量並且計費。各大雲廠商 Amazon、微軟、Google、IBM、阿里雲、騰訊雲、華為雲相繼推出 Serverless 產品。

無服務計算本身是一個概念或者理論模型,落地到具體技術上主要有函數即服務(FaaS)以及後端即服務(BaaS)兩種形式,阿里雲提供函數即服務 FaaS 產品。

阿里雲對於 FaaS 的定義如下:

函數計算是事件驅動的全託管計算服務。使用函數計算,您無需採購與管理服務器等基礎設施,只需編寫並上傳代碼。函數計算為您準備好計算資源,彈性地、可靠地運行任務,並提供日誌查詢、性能監控和報警等功能。

關於 FaaS 的詳細介紹官方文檔已經講的很清楚,本文不再贅述。本文重點討論無服務計算的應用場景以及應用實踐。

無服務計算應用場景

1. 無服務計算的優勢

無服務計算有很多優點,個人認為其中最主要的有三點:

  • 使用無服務計算,用戶無需考慮基礎設施,可以更加專注於業務邏輯;
  • 無服務計算支持彈性伸縮,按需使用,按量計費,非常適合流量不穩定、有明顯波峰波谷的業務;
  • 無服務計算是雲原生產品,可以無縫對接各種雲上產品,作為黏合劑串聯各種雲原生產品。

下圖說明了阿里雲 FaaS 產品的核心優勢:

1.png

2. 無服務計算應用場景

前面探討了無服務計算的優勢,那麼無服務計算都有哪些典型的應用場景呢?

在此分享筆者之前在項目中構建無服務應用的兩個案例:

  • 雲端視頻轉碼:

    • 技術方案:設備端捕獲短視頻,上傳到雲端存儲(例如阿里雲 OSS),雲端存儲監測到文件上傳後觸發無服務計算函數函數,函數中調用 FFmpeg 給視頻加水印、加特效,將視頻轉碼後再轉存到雲端存儲上,同時通知業務服務更改視頻狀態。
    • 方案優勢:設備端視頻上傳頻率很不穩定,可能有一段時間所有設備空閒,也有可能某一段時間幾千臺設備同時上傳,而視頻轉碼是比較消耗資源的,如果通過普通服務器提供轉碼能力並要確保所有視頻都能在預期時間內轉碼完成的話,必須按最高併發量配置服務器資源,這些服務器成本是相當可觀的。即使雲服務器採用 Auto Scalling 策略,也需常備部分服務器,無法做到不使用時零運行成本,而且雲服務 Auto Scalling 觸發及啟動時間也是分鐘級的,很難達到服務能力秒級快速伸縮。
  • 物聯網設備監控:

    • 技術方案:設備端通過雲原生 IoT 服務上報狀態,雲原生 IoT 服務收到消息後觸發無服務計算函數,函數中對 IoT 原始消息做簡單清洗後轉發到後端服務做進一步業務處理,例如:發推送消息給設備管理 App,當然也可以通過函數將 IoT 消息轉存到 NoSQL 數據庫。
    • 方案優勢:端側設備活躍時間不固定,如果想通過其他後端服務監控設備狀態, 該服務必須保持 7*24 小時在線,架構和應用都需要確保高可用。而且設備併發量也是不穩定的,要考慮服務伸縮架構。還有一點需要考慮的是,雲端資源通過事件或者規則直接喚起無服務計算函數比價方便,只需要簡單配置即可,而對接自定義服務則要複雜得多。

基於項目經歷以及個人理解,筆者認為無服務計算主要有以下幾種典型的應用場景: 

  • 可分解成獨立運行單元的 CPU 密集計算型任務;
  • 構建彈性伸縮 Web 後臺應用;
  • 無縫粘合調度雲上資源;
  • 快速低成本上線敏捷應用。

3. 無服務計算不適合做什麼

前面列舉了很多無服務計算的優點以及運用在一些場景中的好處,很多人肯定覺得無服務計算太好用了,太想用了,這個場景能否用無服務計算?那個業務能否用無服務計算代替?

這裡筆者可能要先潑一瓢冷水:無服務計算很好用,但不一定處處好用。當然這瓢冷水以及接下來的一些總結只是基於個人理解, 歡迎拍磚。

個人認為無服務計算其實只適合應用在一些邏輯相對簡單、外部依賴相對較少、不需要複雜編排治理、沒有極致性能要求的業務,主要原因如下:

  • 無服務計算在服務編排以及服務治理方面是比較弱的,雖然主流雲廠商都提供無服務計算的函數編排產品(例如阿里雲的 Serverless 工作流,AWS 的 Step Functions 等),但想要實現函數的限流降級、調用鏈追蹤、自動註冊發現等比較複雜的編排治理以及可探測性還是需要做很多額外的工作,彌補這些不足所要做的工作遠大於無服務計算本身節省的工作量。這點也是和無服務計算無需運維、配置簡單、開箱即用的思想是背道而馳的。
  • 無服務計算應用運行所依託的底層服務器以及運行環境對用戶是透明的,用戶無法選擇,也無法優化。例如在筆者之前的視頻轉碼方案中,有些特效處理如果運行在 GPU 服務器上是可以大幅加速的,但是在無服務計算中只能依靠 CPU 計算。
  • 無服務計算程序運行的環境是高度標準化的,有些依賴於特定運行環境、特定服務器版本、甚至特定硬件資源的依賴是很難確保兼容性的。如果有些應用尤其是原有技術資產受到運行環境制約的話,儘量還是迴歸到傳統的雲服務器部署方案。
  • 無服務計算的彈性伸縮並非沒有上限,和普通應用一樣,無服務應用在實際生產系統中也需要考慮並發達到上限的情況。雖然所有廠商的無服務計算產品都能根據併發量彈性伸縮,但這個彈性本身還是靠底層硬件資源支撐的,一般來講各廠商的無服務計算產品都會有默認的併發上限設置,雖然通過工單申請可以調整,但也不能調整為無限量。如果賬號下有多個無服務應用,需要對不同應用做的流量分配或者限制,並且考慮某一應用訪問流量達到併發上限的情況。

4. 無服務能否替代微服務

筆者認為這兩者應該不是一個維度的概念,微服務更多的是一種服務構建的架構思想,而無服務更偏重於一種服務部署和運行的技術方案,例如:微服務架構中某一個接口是可以通過無服務方式實現的。

當然,涉及到具體技術層面,通過 SpringCloud 或者 Dubbo 對外提供 RESTful 接口服務,還是將無服務函數掛載到 API 網關下對外提供 RESTful 服務,這兩種技術方案確實是可以放到一起比較的。至於選擇哪種技術實現,個人認為主要取決於運用場景和業務複雜度,前面總結了無服務計算的優勢和不一定那麼好用的場景。下面是個人的建議:

  • 如果應用中需要複雜的服務編排、服務治理、調用鏈追蹤、統一的配置管理、自動註冊發現等能力,建議還是採用“傳統的”微服務技術方案;
  • 相反,如果只需要構建一個“短平快”的應用,採用無服務計算方案會讓你好體驗到極大的便利。正如筆者接下來將要分享的案例,就是採用無服務技術構建一個簡單的 Web 後臺應用。

阿里雲 FaaS 實戰

前面談了比較多抽象的概念和看法, 下面結合筆者經歷的一個實際案例展示如何使用阿里雲 FaaS 產品構建一個無服務應用,尤其是實現 FaaS 應用的自動構建、自動部署。 

1. 項目背景介紹

某外企客戶需要將一個為用戶提供產品諮詢的服務從某友商無服務平臺遷移到阿里雲 FaaS。這個應用原部署於友商海外平臺,基於 Nodejs 開發,通過 API Gateway 暴露 RESTful 接口,數據存儲採用友商雲原生 NoSQL 數據庫。

遷移改造主要涉及以下三部分工作:

  • 阿里雲產品適配選型
  • 代碼邏輯改造
  • 應用部署工具選擇及腳本編寫

其中第三部分構建、部署腳本改造是此次遷移工作的重點,接下來逐一展開說明。

2. 阿里雲產品適配選型

友商的無服務計算及網關在阿里雲上均有對應產品,在此不展開比較。

友商雲原生 NoSQL 數據庫為該平臺獨有產品,經過和客戶討論認為,完全可以用其他 NoSQL 產品代替,加之現有開發人員更熟悉 MongoDB 技術棧,最後數據存儲選型為阿里云云原生 MongoDB。

以下為整體遷移方案示意圖:

2.png

3. 代碼邏輯改造

用戶編寫無服務應用代碼時,原則上只需要關注代碼邏輯即可,主體代碼邏輯部分大體上差異不大,比較明顯的差異主要體現在事件處理入口函數寫法上。參考FaaS 代碼示例改造針對 API 網關事件的處理函數:

module.exports.handler = function(event, context, callback) {    
    var response = {};
    callback(null, response);
};

4. 應用部署工具選擇及腳本編寫

  • 應用構建及部署工具選擇

客戶原來採用第三方工具 Serverless (https://www.serverless.com/) 實現無服務計算應用的構建和部署。Serverless 框架雖然宣稱支持幾乎所有主流雲廠商的無服務產品,但經過調研後發現其對某友商支持是最全面的,有很多代碼示例或者工程腳手架,幾乎是開箱即用。但該工具對阿里雲的支持比較有限,示例也相對較少。經過評估,我們決定採用阿里雲自己的工具 Funcraft。 

Funcraft 如何安裝配置請參考產品文檔,此處不展開討論。接下來主要展示如何通過 Funcraft 腳本實現服務、函數、網關、日誌、鑑權等相關資源的部署及配置。

  • 編寫腳本

編寫腳本前,先看一下目標系統的部署架構以及 Funcraft 要實現的功能藍圖:

3.png

Funcraft 腳本及配置說明詳見以下代碼:

yaml
ROSTemplateFormatVersion: '2015-09-01'
Transform: 'Aliyun::Serverless-2018-04-03'
Resources:
  demoService: #資源名稱, 根據需要命名
    Type: 'Aliyun::Serverless::Service'
    Properties: #屬性設置
      Description: 'This is a faas demo ' #資源描述
      Policies:  #安全策略,系統自動根據策略為函數創建角色
        - AliyunOSSFullAccess
        - AliyunRAMFullAccess
        - AliyunLogFullAccess
        - AliyunApiGatewayFullAccess
        - AliyunFCFullAccess
        - AliyunMongoDBFullAccess
        - AliyunVPCFullAccess
        - AliyunECSNetworkInterfaceManagementAccess #特別說明,配置此策略才能創建彈性網卡進而打通函數以及VPC內連接
      VpcConfig: #允許函數訪問的VPC配置
        VpcId: 'vpc-xxxxxx'
        VSwitchIds: ['vsw-xxxxxx']
        SecurityGroupId: 'sg-xxxxxx'
      LogConfig: #日誌服務配置
        Project: sls-demo
        Logstore: logstore-demo
    demoFunction: #函數名稱
      Type: 'Aliyun::Serverless::Function' #資源類型為服務,服務內可以掛載多個函數
      Properties:
        Handler: index.handler #事件處理入口
        Runtime: nodejs10   #程序運行環境
        CodeUri: './src'  #程序代碼相對於當前腳本的路徑
        EnvironmentVariables:   #環境變量設置,
          MONGO_URL: mongodb://userx:[email protected]:3717/demoDb #Mongo內網連接地址
          RESULT_TABLE_NAME: demo_table
  demoGroup: # Api Group
    Type: 'Aliyun::Serverless::Api' #資源類型為API,每個API分組下可以掛載多個API接口
    Properties:
      StageName: RELEASE  #發佈環境
      DefinitionBody:
        '/v1/recommendervera/[resultId]': # request path
          get: # http method
            x-aliyun-apigateway-api-name: demo_api # api name
            x-aliyun-apigateway-fc: # 當請求該 api 時,要觸發的函數,
              arn: acs:fc:cn-shanghai:xxx:services/demoService.LATEST/functions/demoFunction
              timeout: 3000
            x-aliyun-apigateway-request-parameters: #設置參數類型
                - apiParameterName: 'resultId'
                  location: 'Path'  #傳參方式,此處為在URI請求路徑中傳餐
                  parameterType: 'String'
                  required: 'REQUIRED'  #設置為必選參數
        '/v1/recommendervera/': # request path
          post: # http method
            x-aliyun-apigateway-api-name: demo_api_post # api name
            x-aliyun-apigateway-fc: # 當請求該 api 時,要觸發的函數,
              arn: acs:fc:cn-shanghai:xxxx:services/demoService.LATEST/functions/demoFunction
              timeout: 3000
            x-aliyun-apigateway-auth-type: APP  #設置鑑權類型,此處設置為簡單的APP code類型鑑權
            x-aliyun-apigateway-app-code-auth-type: HEADER #鑑權加密方式,此處設置為通過Header傳遞授權後的app
  • 資源準備

服務、函數、API 網關都可以通過以上Funcraft 腳本一站式創建完成,日誌、MongoDB、鑑權所需應用等外部資源需要提前創建或者配置好。

這裡特別要說明的是:函數通過內網鏈接 MongoDB 時,需要通過配置允許函數訪問 MongoDB 所在 VPC 及交換機,併為函數訪問創建一個獨立的安全組用於配置彈性網卡,並且將此安全組加入到 MongoDB 的白名單中,進而打通函數計算與 VPC 之間的網絡聯通。

前面提到的 VPC、交換機以及安全組已經提前創建好並配置在 Funcraft 腳本中了,下面看看在實際的 MongoDB 資源中如何配置白名單安全組:

4.png

5. 構建和部署

以上腳本資源都準備好後,就可以執行 fun build 命令進行構建了。構建時,工具會讀取指定代碼目錄下的 package.json 文件加載相關插件依賴及配置。

構建執行命令示例:

bash
$ fun build
using template: template.yml
start building function dependencies without docker
building demoService/demoFunction
running task: flow NpmTaskFlow
running task: CopySource
running task: NpmInstall
Build Success
Built artifacts: .fun/build/artifacts
Built template: .fun/build/artifacts/template.yml
Tips for next step
======================
* Invoke Event Function: fun local invoke
* Invoke Http Function: fun local start
* Deploy Resources: fun deploy

構建完成後, 執行 fun deploy 命令部署到雲端。示例如下:

bash
$ fun deploy
using template: .fun/build/artifacts/template.yml
using region: cn-shanghai
using accountId: ***********3452
using accessKeyId: ***********1fap
using timeout: 60
Collecting your services information, in order to caculate devlopment changes...
Resources Changes(Beta version! Only FC resources changes will be displayed):
┌──────────────┬──────────────────────────────┬────────┬──────────────────────┐
│ Resource     │ ResourceType                 │ Action │ Property             │
├──────────────┼──────────────────────────────┼────────┼──────────────────────┤
│              │                              │        │ Description          │
│              │                              │        ├──────────────────────┤
│              │                              │        │ Policies             │
│ demoService  │ Aliyun::Serverless::Service  │ Add    ├──────────────────────┤
│              │                              │        │ VpcConfig            │
│              │                              │        ├──────────────────────┤
│              │                              │        │ LogConfig            │
├──────────────┼──────────────────────────────┼────────┼──────────────────────┤
│              │                              │        │ Handler              │
│              │                              │        ├──────────────────────┤
│              │                              │        │ Runtime              │
│ demoFunction │ Aliyun::Serverless::Function │ Add    ├──────────────────────┤
│              │                              │        │ CodeUri              │
│              │                              │        ├──────────────────────┤
│              │                              │        │ EnvironmentVariables │
└──────────────┴──────────────────────────────┴────────┴──────────────────────┘
? Please confirm to continue. Yes
Waiting for service demoService to be deployed...
make sure role 'aliyunfcgeneratedrole-cn-shanghai-demoService' is exist
role 'aliyunfcgeneratedrole-cn-shanghai-demoService' is already exist
attaching policies ["AliyunOSSFullAccess","AliyunRAMFullAccess","AliyunLogFullAccess","AliyunApiGatewayFullAccess","AliyunFCFullAccess","AliyunMongoDBFullAccess","AliyunVPCFullAccess","AliyunECSNetworkInterfaceManagementAccess"] to role: aliyunfcgeneratedrole-cn-shanghai-demoService
attached policies ["AliyunOSSFullAccess","AliyunRAMFullAccess","AliyunLogFullAccess","AliyunApiGatewayFullAccess","AliyunFCFullAccess","AliyunMongoDBFullAccess","AliyunVPCFullAccess","AliyunECSNetworkInterfaceManagementAccess"] to role: aliyunfcgeneratedrole-cn-shanghai-demoService
attaching police 'AliyunECSNetworkInterfaceManagementAccess' to role: aliyunfcgeneratedrole-cn-shanghai-demoService
attached police 'AliyunECSNetworkInterfaceManagementAccess' to role: aliyunfcgeneratedrole-cn-shanghai-demoService
Waiting for function demoFunction to be deployed...
Waiting for packaging function demoFunction code...
The function demoFunction has been packaged. A total of 1675 files were compressed and the final size was 2.1 MB
function demoFunction deploy success
service demoService deploy success
Waiting for api gateway demoGroup to be deployed...
    URL: GET http://xxx-cn-shanghai.alicloudapi.com/v1/recommender/[resultId]
      stage: RELEASE, deployed, version: 20200715144450426
      stage: PRE, undeployed
      stage: TEST, undeployed
    URL: POST http://xxx-cn-shanghai.alicloudapi.com/v1/recommender/
      stage: RELEASE, deployed, version: 20200715144453967
      stage: PRE, undeployed
      stage: TEST, undeployed
api gateway demoGroup deploy success

腳本正常執行後,可以在雲端看到相關函數及 API 已經部署完成並且可以正常運行了。

5.png

6.png

接下來可以將以上 Funcraft 命令及腳本可以加入到 Jenkins、Gitlab 等工具流水線中,結合代碼版本管理工具實現函數應用的持續集成、持續發佈。

總結

隨著無服務計算產品和技術的進一步成熟,會有越來越多的用戶選擇無服務計算技術;隨著阿里雲的進一步發展壯大,也會有越來越多用戶採用阿里雲 FaaS 構建無服務應用。

本文探討了無服務計算的應用場景,並且結合實際應用案例,講解了如何用 FaaS 構建無服務 Web 後臺應用,並實現自動構建、自動部署,希望以上探討和經驗能夠幫到大家。

作者簡介

宋文龍,花名聞可,阿里雲全球技術服務部高級交付專家,有多年雲原生應用開發架構經驗以及多年高性能服務器研發經驗。目前專注於運用阿里雲中間件技術、結合阿里巴巴中臺架構經驗為客戶構建符合行業需要的業務中臺解決方案並完成交付。

課程推薦

為了更多開發者能夠享受到 Serverless 帶來的紅利,這一次,我們集結了 10+ 位阿里巴巴 Serverless 領域技術專家,打造出最適合開發者入門的 Serverless 公開課,讓你即學即用,輕鬆擁抱雲計算的新範式——Serverless。

點擊即可免費觀看課程:https://developer.aliyun.com/learning/roadmap/serverless

Serverless 公眾號,發佈 Serverless 技術最新資訊,彙集 Serverless 技術最全內容,關注 Serverless 趨勢,更關注你落地實踐中的遇到的困惑和問題。

Leave a Reply

Your email address will not be published. Required fields are marked *