首頁>技術>

說起 Serverless 這個詞,我想大家應該都不陌生,那麼 Serverless 這個詞到底是什麼意思?Serverless 到底能解決什麼問題?可能很多朋友還沒有深刻的體會和體感,這篇文章我就和大家一起聊聊 Serverless。

什麼是 Serverless

我們先將 Serverless 這個詞拆開來看。Server,大家都知道是伺服器的意思,說明 Serverless 解決的問題範圍在服務端。Less,大家肯定也知道它的意思是較少的。那麼 Serverless 連起來,再稍加修飾,那就是較少的關心伺服器的意思。

Serverfull 時代

我們都知道,在研發側都會有研發人員和運維人員兩個角色,要開發一個新系統的時候,研發人員根據產品經理的PRD開始寫程式碼開發功能,當功能開發、測試完之後,要釋出到伺服器。這個時候開始由運維人員規劃伺服器規格、伺服器數量、每個服務部署的節點數量、伺服器的擴縮容策略和機制、釋出服務過程、服務優雅上下線機制等等。這種模式是研發和運維隔離,服務端運維都由專門的運維人員處理,而且很多時候是靠純人力處理,也就是 Serverfull 時代。

DevOps 時代

網際網路公司裡最辛苦的是誰?我相信大多數都是運維同學。白天做各種網路規劃、環境規劃、資料庫規劃等等,晚上熬夜釋出新版本,做上線保障,而且很多事情是重複性的工作。然後慢慢就有了賦能研發這樣的聲音,運維同學幫助研發同學做一套運維控制檯,可以讓研發同學在運維控制檯上自行釋出服務、檢視日誌、查詢資料。這樣一來,運維同學主要維護這套運維控制檯系統,並且不斷完善功能,輕鬆了不少。這就是研發兼運維的 DevOps 時代。

Serverless 時代

漸漸的,研發同學和運維同學的關注點都在運維控制檯了,運維控制檯的功能越來越強大,比如根據運維側的需求增加了自動彈性擴縮、效能監控的功能,根據研發側的需求增加了自動化釋出的流水線功能。因為有了這套系統,程式碼質量檢測、單元測試、打包編譯、部署、整合測試、灰度釋出、彈性擴縮、效能監控、應用防護這一系列服務端的工作基本上不需要人工參與處理了。這就是 NoOps,Serverless 時代。

Serverless在程式設計教育中的應用

2020 年註定是不平凡的一年,疫情期間,多少家企業如割韭菜般倒下,又有多少家企業如雨後春筍般茁壯成長,比如線上教育行業。

沒錯,線上教育行業是這次疫情的最大受益者,在線上教育在這個行業裡,有一個細分市場是線上程式設計教育,尤其是少兒程式設計教育和麵向非專業人士的程式設計教育,比如程式設計貓、斑馬 AI、小象學院等。這些企業的線上程式設計系統都有一些共同的特點和訴求:

螢幕一側寫程式碼,執行程式碼,另一側顯示執行結果。根據題目編寫的程式碼都是程式碼塊,每道題的程式碼量不會很大。執行程式碼的速度要快。支援多種程式語言。能支撐不可預計的流量洪峰衝擊。

例如小象學院的程式設計課介面:

結合上述這些特點和訴求,不難看出,構建這樣一套線上程式設計系統的核心在於有一個支援多種程式語言的、健壯高可用的程式碼執行環境。

那麼我們先來看看傳統的實現架構:

從 High Level 的架構來看,前端只需要將程式碼片段和程式語言的標識傳給 Server 端即可,然後等待響應展示結果。所以整個 Server 端要負責對不同語言的程式碼進行分類、預處理然後傳給不同程式語言的 Runtime。這種架構有以下幾個比較核心的問題。

工作量大,靈活性差

首先是研發和運維工作量的問題,當市場有新的需求,或者洞察到新業務模式時需要增加程式語言,此時研發側需要增加程式設計程式碼分類和預處理的邏輯,另外需要構建對應程式語言的 Runtime。在運維側需要規劃支撐新語言的伺服器規格以及數量,還有整體的 CICD 流程等。所以支援新的程式語言這個需求要落地,需要研發、運維花費不少的時間來實現,再加上黑/白盒測試和 CICD 流程測試的時間,對市場需求的支撐不能快速的響應,靈活性相對較差。

高可用自己兜底

其次整個線上程式設計系統的穩定性是重中之重。所以所有 Server 端服務的高可用架構都需要自己搭建,用以保證流量高峰場景和穩態場景下的系統穩定。高可用一方面是程式碼邏輯編寫的是否優雅和完善,另一方面是部署服務的叢集,無論是 ECS 叢集還是 K8s 叢集,都需要研發和運維同學一起規劃,那麼對於對程式語言進行分類和預處理的服務來講,尚能給定一個節點數,但是對於不同語言的 Runtime 服務來講,市場需求隨時會變,所以不好具體衡量每個服務的節點數。另外很重要的一點是所以服務的擴容,縮容機制都需要運維同學來實時手動操作,即便是透過指令碼實現自動化,那麼 ECS 彈起的速度也是遠達不到業務預期的。

成本控制粒度粗

再次是整個 IaaS 資源的成本控制,我們都知道這種線上教育是有明顯的流量潮汐的,比如上午 10 點到 12 點,下午 3 點到 5 點,晚上 8 點到 10 點這幾個時段是流量比較大的時候,其他時間段流量比較小,而且夜晚更是沒什麼流量。所以在這種情況下,傳統的部署架構無法做到IaaS資源和流量的貼合。舉個例子,假如為了應對流量高峰時期,需要 20 臺 ECS 搭建叢集來承載流量衝擊,此時每臺 ECS 的資源使用率可能在 70% 以上,利用率較高,但是在流量小的時候和夜晚,每臺 ECS 的資源使用率可能就是百分之十幾甚至更低,這就是一種資源浪費。

Serverless 架構

那麼我們來看看如何使用 Serverless 架構來實現同樣的功能,並且解決上述幾個問題。在選擇 Serverless 產品時,在國內自然而然優先想到的就是阿里雲的產品。阿里雲有兩款 Serverless 架構的產品 Serverless 應用引擎和函式計算,這裡我們使用函式計算來實現程式設計教育的場景。

函式計算(Function Compute)是事件驅動的全託管計算服務,簡稱 FC。使用函式計算,我們無需採購與管理伺服器等基礎設施,只需編寫並上傳程式碼。函式計算為您準備好計算資源,彈性地、可靠地執行任務,並提供日誌查詢、效能監控和報警等功能。

這裡不對 FC 的含義做過多贅述,只舉一個例子。FC 中有兩個概念,一個是服務,一個是函式。一個服務包含多個函式:

這裡拿 Java 微服務架構來對應,可以理解為,FC 中的服務是 Java 中的一個類,FC 中的函式是 Java 類中的一個方法:

但是 Java 類中的方法固然只能是 Java 程式碼,而 FC 中的函式可以設定不同語言的 Runtime 來執行不同的程式語言:

這個結構理解清楚之後,我們來看看如何呼叫 FC 的函式,這裡會引出一個觸發器的概念。我們最常使用的 HTTP 請求協議其實就是一種型別的觸發器,在 FC 裡稱為 HTTP 觸發器,除了 HTTP 觸發器以外,還提供了 OSS(物件儲存)觸發器、SLS(日誌服務)觸發器、定時觸發器、MNS 觸發器、CDN 觸發器等。

從上圖可以大概理解,我們可以透過多種途徑呼叫 FC 中的函式。舉例兩個場景,比如每當我在指定的 OSS Bucket 的某個目錄下上傳一張圖片後,就可以觸發 FC 中的函式,函式的邏輯是將剛剛上傳的圖片下載下來,然後對圖片做處理,然後再上傳回 OSS。再比如向 MNS 的某個佇列傳送一條訊息,然後觸發 FC 中的函式來處理針對這條訊息的邏輯。

最後我們再來看看 FC 的高可用。每一個函式在執行程式碼時底層肯定還是IaaS資源,但我們只需要給每個函式設定執行程式碼時需要的記憶體數即可,最小 128M,最大 3G,對使用者而言,不需要考慮多少核數,也不需要知道程式碼執行在什麼樣的伺服器上,不需要關心啟動了多少個函式例項,也不需要關心彈性擴縮的問題等,這些都由 FC 來處理。

從上圖可以看到,高可用有兩種策略:

給函式設定併發例項數,假如設定為 3,那麼有三個請求進來時,該函式只啟一個例項,但是會啟三個執行緒來執行邏輯。

執行緒數達到上限後,會再拉起一個函式例項。

大家看到這裡,可能已經大概對基於 FC 實現線上程式設計教育系統的架構有了一個大概的輪廓。

上圖是基於 FC 實現的線上程式設計教育系統的架構圖,在這個架構下來看看上述那三個核心問題怎麼解:

工作量和靈活性:我們只需要關注在如何執行程式碼的業務邏輯上,如果要加新語言,只需要建立一個對應語言 Runtime 的 FC 函式即可。高可用:多執行緒執行業務邏輯和多例項執行業務邏輯兩層高可用保障,並且函式例項的擴縮完全都是 FC 自動處理,不需要研發和運維同學做任何配置。成本最佳化:當沒有請求的時候,函式例項是不會被拉起的,此時也不會計費,所以在流量低谷期或者夜間時,整個 FC 的成本消耗是非常低的。可以做到函式例項個數、計費粒度和流量完美的貼合。Python程式語言示例

下面以執行 Python 程式碼為例來看看如何用 FC 實現 Python 線上程式設計 Demo。

建立服務和函式

開啟函式計算(FC)控制檯,選擇對應的 Region,選擇左側服務/函式,然後新建服務。

輸出服務名稱,建立服務。

進入新建立的服務,然後建立函式,選擇 HTTP 函式,即可配置 HTTP 觸發器的函式:

設定函式的各個引數:

幾個需要的注意的引數這裡做以說明:

執行環境:這個很好理解,這裡選擇P ython3函式例項型別:這裡有彈性例項和效能例項兩種,前者最大支援2C3G規格的例項,後者支援更大的規格,最大到8C16G。函式入口:詳細參見文件 - HTTP 觸發器認證方式:anonymous 為不需要鑑權,function 是需要鑑權的。

程式碼解析

函式建立好,進入函式,可以看到概述、程式碼執行、觸發器、日誌查詢等頁籤,我們先看觸發器,會看到這個函式自動建立了一個 HTTP 觸發器,有呼叫該函式對應的 HTTP 路徑:

然後我們選擇程式碼執行,直接線上寫入我們的程式碼:

具體程式碼如下:

-- coding: utf-8 --import loggingimport urllib.parseimport timeimport subprocessdef handler(environ, start_response):context = environ['fc.context']request_uri = environ['fc.request_uri']for k, v in environ.items():if k.startswith('HTTP_'):passtry:request_body_size = int(environ.get('CONTENT_LENGTH', 0))except (ValueError):request_body_size = 0# 獲取使用者傳入的coderequest_body = environ['wsgi.input'].read(request_body_size)codeStr = urllib.parse.unquote(request_body.decode("GBK"))# 因為body裡的物件裡有code和input兩個屬性,這裡分別獲取使用者code和使用者輸入codeArr = codeStr.split('&')code = codeArr[0][5:]inputStr = codeArr[1][6:]# 將使用者code儲存為py檔案,放/tmp目錄下,以時間戳為檔名fileName = '/tmp/' + str(int(time.time())) + '.py'f = open(fileName, "w")# 這裡預置引入了time庫f.write('import time \r\n')f = open(fileName, "a")f.write(code)f.close()# 建立子程序,執行剛才儲存的使用者code py檔案p = subprocess.Popen("python " + fileName, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, encoding='utf-8')# 透過標準輸入傳入使用者的input輸入if inputStr != '' :p.stdin.write(inputStr + "\n")p.stdin.flush()# 透過標準輸出獲取程式碼執行結果r = p.stdout.read()status = '200 OK'response_headers = [('Content-type', 'text/plain')]start_response(status, response_headers)return [r.encode('UTF-8')]

整個程式碼思路如下:

從前端傳入程式碼片段,格式是字串。在 FC 函式中獲取到傳入的程式碼字串,擷取 code 內容和 input 的內容。因為這裡簡單實現了 Python 中 input 互動的能力。將程式碼儲存為一個 Python 檔案,以時間戳為檔名,儲存在 FC 函式的 /tmp 目錄下。(每個 FC 函式都有獨立的 /tmp 目錄,可以存放臨時檔案)然後在檔案中追加了引入 time 庫的程式碼,應對 sleep 這種互動場景。透過 subprocess 建立子程序,以 Shell 的方式透過 Python 命令執行儲存在 /tmp 目錄下的 Python 檔案。如果有使用者輸入的資訊,則透過標準輸入輸出寫入子程序。最後讀取執行結果返回給前端。

前端程式碼

前端我使用 VUE 寫了簡單的頁面,這裡解析兩個簡單的方法:

頁面載入時初始化 HTTP 請求物件,呼叫的 HTTP 路徑就是方才函式的 HTTP 觸發器的路徑。

這個方法就是呼叫 FC 中的 PythonRuntime 函式,將前端頁面的程式碼片段傳給該函式。這裡處理 input 互動的思路是,掃描整個程式碼片段,以包含 input 程式碼為標識將整個程式碼段分成多段。沒有包含 input 程式碼的直接送給 FC 函式執行,包含 input 程式碼的,請求使用者的輸入,然後程式碼片段帶著使用者輸入的資訊一起送給 FC 函式執行。

演示如下:

結束語

這篇文章給大家介紹了 Serverless,阿里雲的 Serverless 產品函式計算(FC)以及基於函式計算(FC)實現的線上程式設計系統的 Demo。大家應該有所體感,基於函式計算(FC)實現線上程式設計系統時,研發同學只需要專注在如何執行由前端傳入的程式碼即可,整個 Server 端的各個環節都不需要研發同學和運維同學去關心,基本體現了 Serverless 的精髓。

14
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • GitLab 13.7釋出,審閱者,問題克隆,部署失敗回滾等