Faas無服務器架構雜談

FAAS原理白話就是,用戶提交一段函數代碼(如js代碼),我們後臺把代碼拼接爲dockerfile(根據用戶的函數語言,自動組裝(如js代碼需要js環境,nginx),後臺打一個鏡像,然後k8s集羣根據用戶的配置需求,跑這個docker鏡像。用戶刪除函數,直接把鏡像銷燬。

以下爲開源FAAS:Openwhisk的基本使用

Openwhisk是屬於Apache基金會的開源Faas計算平臺,由IBM在2016年公佈並貢獻給開源社區。IBM Cloud本身也提供完全託管的OpenWhisk Faas服務IBM Cloud Function。從業務邏輯來看,OpenWhisk同AWS Lambda一樣,爲用戶提供基於事件驅動的無狀態的計算模型,並直接支持多種編程語言。
OpenWhisk特點:
• 高性能,高擴展性的分佈式FaaS計算平臺
• 函數的代碼及運行時全部在Docker容器中運行,利用Docker engine實現FaaS函數運行的管理、負載均衡、擴展.
• OpenWhisk所有其他組件(如:API網關,控制器,觸發器等)也全部運行在 Docker容器中。這使得OpenWhisk全棧可以很容易的部署在任意IaaS/PaaS平臺上。
• 相比其他FaaS實現(比如OpenFaaS),OpenWhisk更像是一套完整的Serverless 解決方案,除了容器的調用和函數的管理,OpenWhisk 還包括了用戶身份驗證/鑑權、函數異步觸發等功能。
目前支持的語言: Nodejs, Python, Java, php, Ruby, Go, Rust, dotnet, Ballerina, blackBoxes。
安裝

整個安裝需要提前安裝java跟nodejs。
• 安裝java

下載JDK

http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html

將JDK安裝包上傳到服務器上並解壓

$ tar -zxvf jdk-8u171-linux-x64.tar.gz
#切換到當前用戶目錄下面,編輯配置文件
$ cd ~
$ vim .bash_profile

在.bash_profile文件最後添加

JAVA_HOME=/home/tomcat/jdk1.8.0_171
CLASSPATH=$JAVA_HOME/lib:$JAVA_HOME/jre/lib
PATH=$PATH:$JAVA_HOME/bin:$JAVA_HOME/jre/bin

export JAVA_HOME CLASSPATH PATH

#驗證

$ java -version

• 安裝nodejs

下載Node.js安裝包

wget https://nodejs.org/dist/v10.15.3/node-v10.15.3-linux-x64.tar.xz

#解壓文件

tar xvf node-v10.15.3-linux-x64.tar.xz

創建軟鏈接

ln -s /home/node-v10.15.3-linux-x64.tar.xz/bin/node /usr/local/bin/node
ln -s /home/node-v10.15.3-linux-x64.tar.xz/bin/npm /usr/local/bin/npm

查看node, npm版本

node -v
npm -v

如果成功,則安裝完成

• 編譯openwhisk

如果沒有代碼,可以從本地上傳或從git clone下載

yum install git

git clone下來

git clone https://github.com/apache/incubator-openwhisk.git openwhisk

切換到openwhisk目錄,運行下面命令

$ ./gradlew :core:standalone:build

• 配置OpenWhisk Cli工具:下載https://github.com/apache/openwhisk-cli

上傳到服務器解壓, 解壓

設置API HOST

wsk property set --apihost http://172.17.0.1:3233

設置auth

wsk property set --auth 789c46b1-71f6-4ed5-8c54-816aa4f8c502

可以通過以下命令獲取當前的auth

wsk property get --auth

• 在.\bin目錄下面會有相應的可執行文件。

java -jar openwhisk-standalone.jar

會有如下輸出:

        ____      ___                   _    _ _     _     _
       /\   \    / _ \ _ __   ___ _ __ | |  | | |__ (_)___| | __
  /\  /__\   \  | | | | '_ \ / _ \ '_ \| |  | | '_ \| / __| |/ /
 /  \____ \  /  | |_| | |_) |  __/ | | | |/\| | | | | \__ \   <
 \   \  /  \/    \___/| .__/ \___|_| |_|__/\__|_| |_|_|___/_|\_\
  \___\/ tm           |_|
    

Running pre flight checks ...

Local Host Name: 172.17.0.1
Local Internal Name: 172.17.0.1

[  OK   ] 'docker' cli found. (Docker version 19.03.6, build 369ce74a3c)
[  OK   ] 'docker' version 19.3.6 is newer than minimum supported 18.3.0
[  OK   ] 'docker' is running.
[  OK   ] 'wsk' cli found. (2019-09-23T17:46:38.323+0000)
[ WARN  ] Configure wsk via below command to connect to this server as [guest]

wsk property set --apihost 'http://172.17.0.1:3233' --auth '23bc46b1-71f6-4ed5-8c54-816aa4f8c502:123zO3xZCLrMN6v2BKK1dXYFpXlPkccOFqm12CdAsMgRU4VrNZ9lyGVCGuMDGIwP'
[  OK   ] Server port [3233] is free

服務起來後設置提示的命令:設置apihost和auth

wsk property set --apihost 'http://172.17.0.1:3233' --auth '23bc46b1-71f6-4ed5-8c54-816aa4f8c502:123zO3xZCLrMN6v2BKK1dXYFpXlPkccOFqm12CdAsMgRU4VrNZ9lyGVCGuMDGIwP'

• 運行Hello world

創建hello.js文件

/**
 * Hello world as an OpenWhisk action.
 */
function main(params) {
    var name = params.name || 'World';
    return {payload:  'Hello, ' + name + '!'};
}

創建action

$ wsk action create hellotest hello.js
ok: created action hellotest
$ wsk action invoke hellotest --result
{
    "playload": "hello world"
}

系統流程

先介紹一下 OpenWhisk 中從事件觸發到函數執行完畢的流程。 OpenWhisk 中,代碼是基於事件(Event)觸發的。事件產生於事件源(feed),可以用於觸發函數的事件多種多樣:可以是IoT設備傳感器發出的信號,可以是一個 Github repo的push,也可以是最簡單的一個前端HTTP 請求。事件與對應的函數代碼,通過規則(Rule)綁定。通過匹配事件對應的規則,OpenWhisk會觸發對應的行爲(Action)。值得注意的是,多個Action 可以串聯,完成複雜的操作。
整體架構

參考鏈接:https://github.com/apache/openwhisk/blob/master/docs/about.md

  1. 面向用戶的REST API(Nginx): OpenWhisk 的核心繫統通過Rest API 接收函數觸發和函數的CRUD請求。如一個函數觸發的POST請求格式如下···POST /api/v1/namespaces/$userNamespace/actions/myAction ···此處的nginx 服務器主要用於接收 HTTPS 請求(SSL termination),並將處理後的 HTTP 請求直接轉發給控制器(Controller).
  2. 控制器(Controller, 真正進入系統): 真正開始處理請求的地方。控制器是用 Scala 語言實現的,並提供了對應的 REST API,接收 Nginx 轉發的請求。Controller 分析請求內容,進行下一步處理。
  3. CouchDB(身份驗證和鑑權):控制器首先需要驗證用戶的身份和權限。用戶的身份信息(credentials)保存在CouchDB的用戶身份數據庫(subjects database)中。驗證無誤後,控制器進行下一步處理。
  4. CouchDB(得到對應的Action的代碼及配置): 確認用戶的身份後,控制器需要從 CouchDB中讀取將要被觸發的函數(OpenWhisk將要執行的代碼片段抽象成爲 Action,爲了簡便,此處直接稱之爲函數)。函數對應的數據存儲在CouchDB的whisk 數據庫,主要包含要被執行的代碼、默認參數、被執行代碼的權限、及CPU/內存使用限制。
  5. Consul和負載均衡:到了這一步,控制器已經有了觸發函數所需要的全部信息,在將數據發送給觸發器(Invoker)之前,控制器需要和Consul確認,從Consul 獲取處於空閒狀態的觸發器的地址。Consul 是一個開源的服務註冊/發現系統,在 OpenWhisk中Consul負責記錄跟蹤所有觸發器的狀態信息。當控制器向Consul發出請求,Consul從後臺隨機選取一個空閒的觸發器信息,並返回。
  6. 觸發請求送進Kafka: Kafka 充當了Controller和Invoker之間的緩存,當後端 Invoker 負載過大,沒有及時處理Kafka數據流中的請求時,Controller 依然可以將請求送入Kafka,無需阻塞當前線程。同時所有送進Kafka 的請求消息都會被以log的形式的形式保存在文件系統中,即使系統癱瘓,已經由 Controller發出的請求也不會丟失。
  7. 觸發器運行用戶代碼: 觸發器從對應的 Kafka topic 中接收控制器傳來的請求,並執行響應代碼。OpenWhisk 的觸發器是構建在 Docker 之上的,每一個函數觸發都運行在一個獨立的 Docker 容器之內.
  8. CouchDB 保存運行結果: 觸發器執行結果最終會被保存在 CouchDB 中的 whisk 數據庫裏, 保存的格式如下:
{
   "activationId": "31809ddca6f64cfc9de2937ebd44fbb9",
   "response": {
       "statusCode": 0,
       "result": {
           "hello": "world"
       }
   },
   "end": 1474459415621,
   "logs": [
       "2016-09-21T12:03:35.619234386Z stdout: Hello World"
   ],
   "start": 1474459415595,
}

保存結果包括用戶函數的返回值,及日誌記錄。對異步觸發用戶,可以通過步驟6中返回的activationID取回函數運行結果。同步觸發的的結果和異步觸發一樣保存在 CouchDB裏,控制器在得到觸發結束的確認後,從CouchDB 中取得運行結果,直接返回給用戶。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章