粗糙學(xué)習(xí)Serverless

前言

Serverless是近些年來流行起來的架構(gòu)理念,進入市場化應(yīng)該是2014年亞馬遜發(fā)布FaaS Lambda。
一個熱詞的產(chǎn)生,必然會有一些商家搶注商標(biāo)的現(xiàn)象,所以,我們目前搜索Serverless,搜索結(jié)果第一頁會看到名為Serverless的產(chǎn)品。
我們?nèi)粘Uf的Serverless,一般是指架構(gòu)理念,或基于架構(gòu)理念產(chǎn)生的產(chǎn)品全類,而非指某個具體的產(chǎn)品。


Serverless是對運維體系的極端抽象,這里有一個名次“抽象”、兩個定語“運維體系的”、“極端”。

  • Serverless是一個抽象,就說明Serverless不是指具體的某個產(chǎn)品。
  • "運維體系的",說明了Serverless的職能邊界,是對運維體系流程的優(yōu)化,當(dāng)然,也對開發(fā)流程產(chǎn)生了一些副作用,但,主要的職能在運維方向。
  • "極端抽象",是表明基于Serverless理念輸出的產(chǎn)品,將運維體系的復(fù)雜度內(nèi)化,只預(yù)留簡單的接口供外部調(diào)用。

帶來的結(jié)果就是,可以讓零運維經(jīng)驗的人,幾分鐘就部署一個Web應(yīng)用上線,稍后我會在==示例==中演示一下。

運維發(fā)展史

發(fā)展史.png

先看一下整個發(fā)展流程,經(jīng)歷了手動運維、自動運維、DevOps開發(fā)運維、智能運維幾個階段。
按社會的精細(xì)化分工來說:

  • 手動運維階段,開發(fā)者交付代碼,運維團隊需要進行服務(wù)器協(xié)調(diào)、運行環(huán)境部署、上線、版本控制、日志監(jiān)控、擴縮容設(shè)計、容錯容災(zāi)高可用設(shè)計...等等工作。
    • 如果線上產(chǎn)品出現(xiàn)問題,需要開發(fā)者和運維團隊共同查找問題。
  • 自動運維階段,通過編排腳本命令將一些簡單的工作進行打包處理,一定程度上減少重復(fù)性的手工操作。
  • 隨著微服務(wù)、容器技術(shù)的發(fā)展,來到了DevOps階段,DevOps=Development + Operations,開發(fā)者開始承擔(dān)一部分的運維職責(zé),甚至有些公司出現(xiàn)了跨職能團隊:運維、開發(fā)團隊融合,打破手動運維階段開發(fā)、運維兩座孤島的現(xiàn)象。這個階段,就Docker工具而言,開發(fā)者交付鏡像,運維團隊不必在操心代碼的運行環(huán)境問題。
  • 智能運維階段,Serverless只是其中的一個發(fā)展節(jié)點。
    • 各大服務(wù)廠商將基礎(chǔ)設(shè)施云化,對外提供接口,實現(xiàn)基礎(chǔ)設(shè)施即代碼,讓開發(fā)者可以通過應(yīng)用程序代碼訪問、配置基礎(chǔ)設(shè)施(BaaS:抽象粒度大多在機器級別)。
    • 計算機算力的提升,如函數(shù)計算[阿里云]、云函數(shù)[騰訊云]將計算服務(wù)的抽象粒度提高到了函數(shù)級別,實現(xiàn)實時的彈性伸縮容機制,按毫秒級計量、按需計費(FaaS)。

產(chǎn)生背景

  • 從整個發(fā)展史可以看出,技術(shù)的發(fā)展起到了重要的推動作用。
  • 歷史運維體系的痛點:企業(yè)中長尾應(yīng)用的運營成本問題。
    • 什么是中長尾應(yīng)用?就是每天大部分時間沒有流量或者有很少流量的應(yīng)用
    • 為了保證這些應(yīng)用的正常運行,至少要安排一臺服務(wù)器跑這些應(yīng)用。
    • Serverless借助計算機算力,可以實現(xiàn)實時的彈性擴縮容機制。
  • 減少研發(fā)人員的關(guān)注點,研發(fā)人員無需管理、維護底層的基礎(chǔ)設(shè)施,無需規(guī)劃預(yù)估容器所需要的計算資源,降低整合和決策的代價,只需要專注應(yīng)用程序代碼的編寫,提高研發(fā)效能。

下個定義

狹義Serverless = FaaS架構(gòu)
狹義的Severless是指基于函數(shù)計算將Serverless體系產(chǎn)品整合在一起,構(gòu)建成一個Serverless應(yīng)用。
狹義Serverless = FaaS架構(gòu) = Trigger + FaaS + BaaS = FaaS + Baas


廣義Serverless是指具備Serverless特性的云服務(wù)。


Serverless可以分為Serverless,其中less不是指無服務(wù)器端,或者少服務(wù)器端,而是指無感知,也對應(yīng)了“Serverless是對運維體系的極端抽象”這句話。

發(fā)展現(xiàn)狀

目前大多數(shù)互聯(lián)網(wǎng)公司都還在DevOps時代。
部分一線大廠有自己的Serverless解決方案并對外開放。如阿里云的函數(shù)計算、騰訊云的云函數(shù)。
目前Serverless架構(gòu)實現(xiàn)并沒有統(tǒng)一的規(guī)范,實現(xiàn)和提供服務(wù)的廠商強關(guān)聯(lián),如果在不同廠商之間遷移,會有很大的工作量和困難。

函數(shù)計算

以阿里云平臺的函數(shù)計算來介紹一下FaaS函數(shù)即服務(wù)。

我們先熟悉一下平臺設(shè)計。

  • 可以通過支付寶掃碼授權(quán)登陸。
  • 直接用“產(chǎn)品”菜單下的搜索功能搜索“函數(shù)計算”。
  • 點擊“控制臺”直接進入。
  • 頂部
    • 可以切換代碼部署的地域
    • 如果在“服務(wù)/函數(shù)”下找不到自己已有的代碼,檢查一下地域是否選擇正確。
  • “概覽”頁面
    • 可以直觀的看到使用量、監(jiān)控的概覽,還有一些快捷入口。
    • 免費執(zhí)行次數(shù)和免費資源使用量,在測試階段可以有效的防止用超過,也很難用超過。
    • 監(jiān)控的可視化圖形
    • 新建函數(shù)的快捷入口
  • “服務(wù)及函數(shù)”
    • 可以創(chuàng)建新服務(wù)、新函數(shù),查看已有服務(wù)和函數(shù)。
    • 點擊服務(wù)列表中的某項,可以在右側(cè)查看、編輯包含的函數(shù)列表、服務(wù)相關(guān)的配置信息。
    • 點擊函數(shù)列表中的某項,可以進入函數(shù)詳情,查看、配置函數(shù)的信息。
  • 自定義域名
    • 通過自定義域名訪問FC函數(shù),需要配合HTTP觸發(fā)器使用
    • ==HTTP觸發(fā)器==后續(xù)講函數(shù)類型的時候會提到。

FaaS

下面我們具體看一下函數(shù)計算。
首先,我們創(chuàng)建一個服務(wù)、一個函數(shù)。
創(chuàng)建好一個服務(wù)以后,默認(rèn)打開“服務(wù)配置”Tab,從該Tab頁,我們可以查看服務(wù)當(dāng)前的配置并進行修改。


切換到“函數(shù)列表”Tab頁,點擊新增函數(shù)按鈕,這時會發(fā)現(xiàn),函數(shù)有兩類:

  • 事件函數(shù)
  • HTTP函數(shù)
    這里HTTP函數(shù),就是上邊所說,有HTTP觸發(fā)器的函數(shù),可以通過網(wǎng)絡(luò)請求觸發(fā)FC函數(shù)的執(zhí)行;

因為上邊我們提到了HTTP觸發(fā)器,那就先創(chuàng)建一個HTTP函數(shù)。
創(chuàng)建成功后,默認(rèn)進入函數(shù)的“觸發(fā)器”Tab頁,可以看到“事件類型”是http,請求方法是GETPOST,不需要授權(quán)訪問。
為了更清晰的看到觸發(fā)器的配置項,我們重新創(chuàng)建一個觸發(fā)器。
然后,切換到“代碼執(zhí)行”Tab頁,我們可以看到示例代碼。

HTTP函數(shù)示例代碼:

  1. 結(jié)構(gòu):exports.handler = (req, resp, context) => {}
  • 函數(shù)調(diào)用時,執(zhí)行定義的handler邏輯,參數(shù)是req、resp、context;
  • 這些參數(shù)后續(xù)==調(diào)試階段==我們可以看一下
  1. 打印標(biāo)準(zhǔn)版的輸出hello world
  2. 組裝請求數(shù)據(jù)字段
  3. body數(shù)據(jù)提取并輸出組裝的數(shù)據(jù)

我們執(zhí)行一下看看會發(fā)生什么?

  1. 打印返回的結(jié)果
  2. 打印函數(shù)執(zhí)行日志
  3. 打印RequestID
    • 這是唯一存在的ID,每次執(zhí)行都會改變。
    • 可以通過該ID查詢?nèi)罩尽?/li>

在“執(zhí)行”按鈕處,可以配置一些參數(shù),改變一下配置看看輸出的結(jié)果。

  • POST請求
  • 路徑
  • Params改變URL上的過濾參數(shù)
  • Body改變POST的請求輸出,GET請求下不會出現(xiàn)該Tab頁

而且,在修改的過程中,會發(fā)現(xiàn)上方的URL會發(fā)生變化。
我們可以通過Postman去請求該地址,調(diào)用FC函數(shù),可以通過“日志查詢”查看調(diào)用結(jié)果。

最后,我們看一下exports導(dǎo)出的函數(shù),默認(rèn)函數(shù)名為handler,這個名字能修改么?
答案是肯定的。

  • 切換到“概覽”Tab頁,“修改配置”,修改“函數(shù)入口”
  • 切換回“代碼執(zhí)行”,執(zhí)行看一下結(jié)果,報錯
  • exports.[fnName]修改成配置項,“保存”,再執(zhí)行,成功。

看完了HTTP函數(shù),我們返回去看一下事件函數(shù)。
返回到服務(wù)列表頁面。
“新增函數(shù)” ——> “事件函數(shù)” ——> “配置部署”
配置頁面:

  • 運行環(huán)境
  • 彈性實例
    • 彈性實例有免費額度
    • 性能實例沒有免費額度
    • 性能實例擴容速度慢,彈性伸縮能力不及彈性實例:對比文檔
  • 函數(shù)入口
    • 和“HTTP函數(shù)”一樣,可以修改約定的導(dǎo)出函數(shù)名

點擊“完成”創(chuàng)建函數(shù)。

“HTTP函數(shù)”跳轉(zhuǎn)到“觸發(fā)器”Tab,而“事件函數(shù)”直接跳轉(zhuǎn)到“代碼執(zhí)行”Tab。
切換到“觸發(fā)器”,我們可以看到,沒有任何數(shù)據(jù)。


我們看一下“事件函數(shù)”的實例代碼:

  1. 結(jié)構(gòu):exports.handler = (event, context, callback) => {}
  • 函數(shù)調(diào)用時,執(zhí)行定義的handler邏輯,參數(shù)是event, context, callback;
  • 這些參數(shù)我們依舊在后續(xù)==調(diào)試階段==看一下
  1. 依舊打印標(biāo)準(zhǔn)版的輸出hello world
  2. 通過callback返回數(shù)據(jù)
  • callback(err, data)
    • 第一個參數(shù)是錯誤信息
    • 第二個參數(shù)是數(shù)據(jù),只有在第一個參數(shù)為null時,才返回數(shù)據(jù)

代碼的“執(zhí)行”按鈕在上邊,嘗試修改代碼,也能看到是自動保存。

執(zhí)行一下程序看看會發(fā)生什么?

  1. 打印返回的結(jié)果
  2. 打印函數(shù)執(zhí)行日志
  3. 打印RequestID
    • 這是唯一存在的ID,每次執(zhí)行都會改變。
    • 可以通過該ID查詢?nèi)罩尽?/li>

我們從兩個示例函數(shù)中,都可以看到注釋的exports.initializer函數(shù)。
這個函數(shù)是做什么的呢?
通過函數(shù)名,可以知道,這是實例的初始化函數(shù),保證同一實例成功且僅成功執(zhí)行一次。
值得注意的是:這個函數(shù)沒有返回值。
將“事件函數(shù)”中的注釋去掉,“保存并執(zhí)行”,看看有什么不同。
發(fā)現(xiàn)執(zhí)行結(jié)果和原來沒什么不同,初始化函數(shù)中的console.log('initializing')并沒有打印出來。

要怎么做呢?
要初始化函數(shù)執(zhí)行,需要特殊的配置。
切換到“概覽”Tab,“修改配置” ——> “是否配置函數(shù)初始化入口”,定義為剛剛解注的函數(shù)名,“確認(rèn)”后跳轉(zhuǎn)至“代碼執(zhí)行”。
“執(zhí)行”代碼,查看執(zhí)行結(jié)果:報錯——> 無效的函數(shù)名。
重新“修改配置”,初始化入口定義為index.initialzer即可。

FC Initialize Start RequestId: e8acfe4c-9670-4255-86f1-2659291031c1
load code for handler:index.initializer
2020-12-24T09:13:36.846Z e8acfe4c-9670-4255-86f1-2659291031c1 [verbose] initializing
FC Initialize End RequestId: e8acfe4c-9670-4255-86f1-2659291031c1

會看到函數(shù)執(zhí)行日志中,多出來幾條日志。
連續(xù)多次點擊“執(zhí)行”,也僅僅在第一次執(zhí)行的時候,會多這幾條日志,表明“初始化函數(shù)”僅僅執(zhí)行一次。
修改“初始化函數(shù)”中的callback(null, 123)發(fā)現(xiàn)執(zhí)行日志中并沒有輸出,表明“初始化函數(shù)”沒有輸出。


有沒有疑惑:

var ret = '';
function handlerRet() {
    console.log('-------');
    ret = 'return success';
}
handlerRet();
exports.handler = (event, context, callback) => {
  console.log(ret);
  callback(null, 'hello world');
}

上邊這個代碼的執(zhí)行結(jié)果是怎樣的?
和“初始化函數(shù)”有什么不同?

  • 執(zhí)行時機不同
    • “初始化函數(shù)”在函數(shù)實例初始化之前執(zhí)行;
    • 上述看似“全局”的代碼是在實例化之后執(zhí)行的;
  • 執(zhí)行次數(shù)
    • 上述代碼和“初始化函數(shù)”一樣,都僅執(zhí)行一次;

我們可以看到,上述三種類型的函數(shù)(HTTP函數(shù)、事件函數(shù)、初始化函數(shù))與普通定義的函數(shù)最大的區(qū)別在于,F(xiàn)C的函數(shù)預(yù)置了Context參數(shù),這是和Runtime運行平臺/上下文相關(guān)的參數(shù)。


我們可以通過URL請求去調(diào)用“HTTP函數(shù)”,那如何去調(diào)用“事件函數(shù)”呢?

  • 創(chuàng)建觸發(fā)器
    • 我們切換到“觸發(fā)器”面板,“創(chuàng)建觸發(fā)器”,以一個最簡單的“定時觸發(fā)器”為例。
      • 最小1分鐘時間間隔
      • 默認(rèn)“啟動觸發(fā)器”
      • 通過“日志查詢”面板,“每分鐘自動刷新”,可以查看執(zhí)行日志(會有延遲)。
    • 修改觸發(fā)器的“觸發(fā)消息”:JSON數(shù)據(jù),修改“代碼執(zhí)行”,在入口函數(shù)中打印eventconsole.log(JSON.parse(event))查看輸出結(jié)果。
      • 可以看到,我們可以通過“觸發(fā)消息”傳遞參數(shù)。
    • 關(guān)閉“觸發(fā)器”的狀態(tài)
  • SDK調(diào)用
    • 本地編寫代碼程序
      'use strict';
      var FCClient = require('@alicloud/fc2');
      var client = new FCClient(
        '<account id>',
        {
          accessKeyID: '<access key>',
          accessKeySecret: '<access key secret>',
          region: 'cn-beijing',
          timeout: 10000 // milliseconds, default is 10s
        }
      );
      async function test () {
        try {
            var ret = await client.invokeFunction('case-1.LATEST', 'case-event', 'event')
            console.log('invoke function: %j', ret);
        } catch (err) {
            console.error(err);
          }
      }
      test().then();
      
    • node invoke/index.js
      • 可以看到本地終端有日志打印出來,正是代碼中的console.log('invoke function: %j', ret);執(zhí)行的結(jié)果
    • 控制臺切換到“日志查詢”,查看執(zhí)行日志,確定FC的函數(shù)被觸發(fā)。

上述編寫的函數(shù)除了“HTTP函數(shù)”并沒有引入外部依賴,如何引入第三方依賴呢?
其實,“HTTP函數(shù)”引入的依賴是阿里云平臺的Node.js環(huán)境內(nèi)置好的第三方包,如果我們需要使用沒有內(nèi)置的依賴包,需要在本地開發(fā)環(huán)境去安裝、編寫代碼邏輯。

所以,我們接下來說一下本地開發(fā)環(huán)境的配置

  • 安裝Docker; //編譯代碼、安裝依賴以及在本地運行調(diào)試等操作都是在Docker鏡像中進行;
  • Visual Studio Code中查找aliyun serverless插件并安裝;
    • 安裝過程中需要輸入account id、access key、access key secret。
    • 可以通過阿里云官網(wǎng)賬號一欄找到這些信息。
    • 我們會看到Visual Studio Code右側(cè)面板多出了兩個FC的Logo選項。
    • 可以通過界面查看到遠程控制臺創(chuàng)建的服務(wù)及函數(shù)。
    • 將遠程服務(wù)及函數(shù)下載到本地

    • A區(qū)域,我們可以看到下載到本地對應(yīng)的服務(wù)、函數(shù)及觸發(fā)器列表,點擊列表中的某項,會跳轉(zhuǎn)到template.yml文件對應(yīng)的配置
    • B區(qū)域,是對列表項的操作
      • 服務(wù):添加函數(shù)操作
      • 函數(shù):查看源碼、調(diào)試、執(zhí)行操作
      • 觸發(fā)器:無

接下來,我們通過代碼調(diào)試先看一下編寫代碼時,遺留的函數(shù)參數(shù)結(jié)構(gòu)的問題,然后再說依賴問題:
查看case-event函數(shù)的源碼,在行號上添加斷點,點擊“調(diào)試”操作


即可查看對應(yīng)的參數(shù)結(jié)構(gòu)。

引入第三方NPM包

  • 通過Visual Studio Code“資源管理器”查看一下case-event函數(shù)所在的路徑
  • “終端”切換到函數(shù)對應(yīng)目錄cd case-1/case-event
  • npm init -y初始化環(huán)境
  • npm i -S xss做示例
  • 修改代碼
'use strict';
var xss = require('xss');
/*
To enable the initializer feature (https://help.aliyun.com/document_detail/156876.html)
please implement the initializer function as below:
*/
exports.initializer = (context, callback) => {
  console.log('initializing');
  callback(null, '123');
};
exports.handler = (event, context, callback) => {
  console.log('hello world');
  var html = xss('<script>alert</script>')
  callback(null, html);
}
  • 執(zhí)行函數(shù),查看輸出結(jié)果:依賴正常執(zhí)行。
FC Initialize Start RequestId: e2c60d38-bed8-4a92-a48f-56b7c7949d9a
load code for handler:index.initializer
2020-12-25T03:21:47.571Z e2c60d38-bed8-4a92-a48f-56b7c7949d9a [verbose] initializing
FC Initialize End RequestId: e2c60d38-bed8-4a92-a48f-56b7c7949d9a
123FC Invoke Start RequestId: e2c60d38-bed8-4a92-a48f-56b7c7949d9a
load code for handler:index.handler
2020-12-25T03:21:47.651Z e2c60d38-bed8-4a92-a48f-56b7c7949d9a [verbose] hello world
FC Invoke End RequestId: e2c60d38-bed8-4a92-a48f-56b7c7949d9a
&lt;script&gt;alert&lt;/script&gt;
  • 然后,我們將服務(wù)整體上傳或在函數(shù)上右鍵單獨上傳,替換控制臺的代碼
    • 會將依賴node_modules一起上傳
    • FC函數(shù)所需要的依賴必須一同打包上傳,否則,會報資源查找不到。



介紹完阿里云平臺的函數(shù)計算,結(jié)合Serverless的定義思考一下,Serverless=FaaS架構(gòu),Serverless具有實時彈性擴縮容的優(yōu)勢,函數(shù)計算怎么實現(xiàn)這個優(yōu)勢的呢?

這和FC函數(shù)的進程模型有關(guān):

  • 服務(wù)托管細(xì)?;搅苏Z言單位,即函數(shù)調(diào)用
  • 事件驅(qū)動的計算模型
  • 用完即毀型設(shè)計:函數(shù)實例準(zhǔn)備好后,執(zhí)行完函數(shù)就直接結(jié)束。
    • 無狀態(tài),不存儲任何狀態(tài)
    • 正因為沒有任何狀態(tài),因此在并發(fā)量高的時候,我們可以對無狀態(tài)節(jié)點橫向擴容,而沒有流量時我們可以縮容到 0

剛剛說到FaaS或FC的函數(shù)是無狀態(tài)的,那我們需要狀態(tài)共享的時候,應(yīng)該怎么做?

借助于BaaS: 后端即服務(wù)。


“自定義域名”中,我們可以將編寫的函數(shù)與備案好的域名綁定在一起,這樣,可以通過自定義的域名訪問我們的“HTTP函數(shù)”。

應(yīng)用示例

Nuxt.js應(yīng)用的遷移

  1. 遷移應(yīng)用需要使用Funcraft命令行工具npm i -g @alicloud/fun全局安裝;
  2. fun --version查看版本信息驗證是否安裝成功;
  3. 這里我下載了一個已有的項目,進入項目目錄下,確保node版本在12.*以上,npm i安裝開發(fā)依賴;
  4. npm run dev保證我們的項目本地正常運行;
  5. npm run build編譯項目;
  6. npm run start保證編譯后的項目能夠正常啟動;
  7. fun deploy -y部署項目至函數(shù)計算;
    current folder is not a fun project.
    Generating /Users/****/Desktop/case/migc-open-act-master/bootstrap...
    Generating template.yml...
    Generate Fun project successfully!
    
    • 自動生成template.yml文件
      ROSTemplateFormatVersion: '2015-09-01'
      Transform: 'Aliyun::Serverless-2018-04-03'
      Resources:
        migc-open-act-master: # service name
          Type: 'Aliyun::Serverless::Service'
          Properties:
            Description: This is FC service
          migc-open-act-master: # function name
            Type: 'Aliyun::Serverless::Function'
            Properties:
              Handler: index.handler
              Runtime: custom
              CodeUri: oss://fun-gen-cn-beijing-***/9c517abf18826f644880440a12eebef7
              MemorySize: 1024
              InstanceConcurrency: 5
              Timeout: 120
      
            Events:
              httpTrigger:
                Type: HTTP
                Properties:
                  AuthType: ANONYMOUS
                  Methods: ['GET', 'POST', 'PUT']
        Domain:
          Type: Aliyun::Serverless::CustomDomain
          Properties:
            DomainName: Auto
            Protocol: HTTP
            RouteConfig:
              Routes:
                "/*":
                  ServiceName: migc-open-act-master
                  FunctionName: migc-open-act-master
      
      
    • 自動生成bootstrap文件
      #!/usr/bin/env bash
      export PORT=9000
      npx nuxt start --hostname 0.0.0.0 --port $PORT
      
    • 自動生成一個可訪問的臨時域名
    Detect 'DomainName:Auto' of custom domain 'Domain'
    Request a new temporary domain ...
    The assigned temporary domain is http://38880398-******.test.functioncompute.com,expired at 2021-01-04 15:13:18, limited by 1000 per day.
    Waiting for custom domain Domain to be deployed...
    

這兩個文件是做什么的呢?
帶著疑問,我們看Custom Runtime

Custom Runtime

剛剛我們遷移了Nuxt.js應(yīng)用,如果想遷移其它應(yīng)用呢?
遷移應(yīng)用之前,必須要了解一個前提:要在平臺支持的開發(fā)環(huán)境基礎(chǔ)上遷移項目。

  • Custom Runtime就是在平臺的基礎(chǔ)上,自定義運行環(huán)境。
  • Custom Runtime的本質(zhì)是HTTP Server

那如何創(chuàng)建Custom Runtime?

  1. 搭建一個監(jiān)聽9000固定端口的HTTP Server
    // 部署靜態(tài)頁面為例
    var Koa = require('koa');
    var path = require('path');
    var htmlRender = require('koa-html-render');
    
    var app = new Koa();
    var port = 9000;
    app.use(htmlRender());
    
    app.use(async (ctx) => {
      await ctx.html(path.resolve(__dirname, ctx.path));
    })
    app.listen(process.env.PORT || port, () => {
      console.log(`----koa is running on ${process.env.PORT || port}=====`)
    })
    
  2. 將啟動Server的命令保存在一個名為bootstrap的文件
    // 創(chuàng)建bootstrap文件
    #!/usr/bin/env bash
    export PORT=9000
    node app.js
    
  3. fun deploy -y將項目部署到函數(shù)計算上
  4. 可以通過臨時鏈接訪問該靜態(tài)項目

由此,我們可以看到bootstrap文件是HTTP Server的啟動文件。
template.yml對應(yīng)我們服務(wù)列表、函數(shù)列表的配置項。

Koa應(yīng)用的遷移

上述例子,是靜態(tài)頁面的遷移,也可以看作是Koa應(yīng)用的遷移。

連接MongoDB示例

這里,開通了阿里云MongoDB的服務(wù),代碼示例鏈接數(shù)據(jù)庫,將testColl文檔數(shù)據(jù)導(dǎo)出。
這個示例需要注意依賴版本require('mongodb'),mongodb的版本需要是2.2.*。

var uuid = require('node-uuid');
var sprintf = require("sprintf-js").sprintf;
var mongoClient = require('mongodb').MongoClient;
var host = "dds-****-pub.mongodb.rds.aliyuncs.com";
var port = 3717;
var username = "user***";
var password = "***";
var demoDb = "sls";
var demoColl = "testColl";
// 官方建議使用的方案
var url = sprintf("mongodb://%s:%d/%s", host, port, demoDb);
console.info("url:", url);
var conn;
exports.initializer = async function (context, callback) {
    // 獲取mongoClient
    await mongoClient.connect(url, function(err, db) {
        if(err) {
            console.error("connect err:", err);
            return 1;
        }
        // 授權(quán). 這里的username基于admin數(shù)據(jù)庫授權(quán)
        var adminDb = db.admin();
        adminDb.authenticate(username, password, function(err, result) {
            if(err) {
                console.error("authenticate err:", err);
                return 1;
            }
            conn = db;
            // 取得Collecton句柄
            conn.db(demoDb)
            callback(null, '')
        });
    });
}
exports.handler = function (event, context, callback) {
    var collection = conn.collection(demoColl);
    collection.find({}).toArray(function(err, docs) {
        console.log("Found the following records");
        console.log(docs)
        callback(null, docs);
    });
}

總結(jié)

應(yīng)用場景

  • 長尾應(yīng)用
  • 大規(guī)模批處理任務(wù)
    • 彈性伸縮
  • 基于事件驅(qū)動架構(gòu)的應(yīng)用
    • 事件驅(qū)動
  • 運維自動化
    • 觸發(fā)器

局限

  • 用戶對底層計算資源沒有可控性
  • 由于目前技術(shù)的成熟度,Serverless領(lǐng)域尚沒有形成行業(yè)標(biāo)準(zhǔn),意味著用戶將一個平臺上的Serverless應(yīng)用移植到另一個平臺時付出的成本較高

前端學(xué)習(xí)Serverless的出發(fā)點

  • 打破潛意識技術(shù)邊界
    • 調(diào)優(yōu)行業(yè)內(nèi)的開發(fā)崗位分層結(jié)構(gòu)
    • Serverless補足了前端工程師的現(xiàn)有能力,前端與Serverless結(jié)合,是對前端的訴求從頁面開發(fā)向開發(fā)交付整個應(yīng)用轉(zhuǎn)變
  • 享受云服務(wù)紅利
    • 零運維
    • Node.js + Serverless,向全棧進發(fā)
  • 云開發(fā)者的切入點
    • 熟悉云開發(fā)模式與思想
  • 文件:boostraptemplate.yml分別是什么
  • 調(diào)試:查看請求參數(shù)的結(jié)構(gòu)
  • 示例:幾分鐘部署上線
  • 概念:HTTP觸發(fā)器
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容