導讀 | Lightbot近來,在計算領域出現了很多關于 serverless 的讨論。serverless 是一個概念,它允許你提供代碼或可執行程式給某個服務,由服務來為你執行它們,而你無需自己管理伺服器。這就是所謂的執行即服務execution-as-a-service,它帶來了很多機會,同時也遇到了它獨有的挑戰。 |
簡短回憶下計算領域的發展
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZwpmL00SMvwFMx8CX2EDMy8CXzRWYvxGc19CX05WZ052bj1Cc39CXt92YuUmYvJHc4VnbpxmL3d3dvw1LcpDc0RHaiojIsJye.jpg)
早期,出現了……好吧,這有點複雜。很早的時候,出現了機械計算機,後來又有了埃尼阿克 ENIAC(Electronic Numerical Integrator And Computer,很早的電子計算機),但是都沒有規模生産。直到大型機出現後,計算領域才快速發展。
- 上世紀 50 年代 - 大型機
- 上世紀 60 年代 - 微型機
- 1994 - 機架伺服器
- 2001 - 刀片伺服器
- 本世紀初 - 虛拟伺服器
- 2006 - 伺服器雲化
- 2013 - 容器化
- 2014 - serverless(計算資源服務化)
這些日期是大概的釋出或者流行日期,無需和我争論時間的準确性。
計算領域的演進趨勢是執行的功能單元越來越小。每一次演進通常都意味着運維負擔的減小和運維靈活性的增加。
發展前景
喔,Serverless!但是,serverless 能給我們帶來什麼好處? 我們将面臨什麼挑戰呢?
未執行代碼時無需付費。我認為,這是個巨大的賣點。當無人通路你的站點或用你的 API 時,你無需付錢。沒有持續支出的基礎設施成本,僅僅支付你需要的部分。換句話說,這履行了雲計算的承諾:“僅僅支付你真正用的資源”。
無需維護伺服器,也無需考慮伺服器安全。伺服器的維護和安全将由你的服務提供商來處理(當然,你也可以架設自己的 serverless 主機,隻是這似乎是在向錯誤的方向前進)。由于你的執行時間也是受限的,安全更新檔也被簡化了,因為完全不需要重新開機。這些都應該由你的服務提供商無縫地處理。
無限的可擴充性。這是又一個大的好處。假設你又開發了一個 Pokemon Go, 與其頻繁地把站點下線維護更新,不如用 serverless 來不斷地擴充。當然,這也是個雙刃劍,大量的賬單也會随之而來。如果你的業務的利潤強依賴于站點上線率的話,serverless 确實能幫上忙。
強制的微服務架構。這也有兩面性,一方面,微服務似乎是一種好的建構靈活可擴充的、容錯的架構的方式。另一方面,如果你的業務沒有按照這種方式設計,你将很難在已有的架構中引入 serverless。
但是現在你被限制在他們的平台上
受限的環境。你隻能用服務提供商提供的環境,你想在 Rust 中用 serverless?你可能不會太幸運。
受限的預裝包。你隻有提供商預裝的包。但是你或許能夠提供你自己的包。
受限的執行時間。你的 Function 隻可以運作這麼長時間。如果你必須處理 1TB 的檔案,你可能需要有一個解決辦法或者用其他方案。
強制的微服務架構。參考上面的描述。
受限的監視和診斷能力。例如,你的代碼在幹什麼? 在 serverless 中,基本不可能在調試器中設定斷點和跟蹤流程。你仍然可以像往常一樣記錄日志并發出統計度量,但是這帶來的幫助很有限,無法定位在 serverless 環境中發生的難點問題。
競争領域
自從 2014 年出現 AWS Lambda 以後,serverless 的提供商已經增加了一些。下面是一些主流的服務提供商:
- AWS Lambda - 起步最早的
- OpenWhisk - 在 IBM 的 Bluemix 雲上可用
- Google Cloud Functions
- Azure Functions
這些平台都有它們的相對優勢和劣勢(例如,Azure 支援 C#,或者緊密內建在其他提供商的平台上)。這裡面最大的玩家是 AWS。
通過 AWS 的 Lambda 和 API Gateway 建構你的第一個 API
我們來試一試 serverless。我們将用 AWS Lambda 和 API Gateway 來建構一個能傳回 Jimmy 所說的“Guru Meditations”的 API。
所有代碼在 GitHub 上可以找到。
API文檔:
POST /
{
"status": "success",
"meditation": "did u mention banana cognac shower"
}
怎樣組織工程檔案
檔案結構樹:
.
├── LICENSE
├── README.md
├── server
│ ├── __init__.py
│ ├── meditate.py
│ └── swagger.json
├── setup.py
├── tests
│ └── test_server
│ └── test_meditate.py
└── tools
├── deploy.py
├── serve.py
├── serve.sh
├── setup.sh
└── zip.sh
AWS 中的資訊(想了解這裡究竟在做什麼的詳細資訊,可檢視源碼tools/deploy.py)。
- API。實際建構的對象。它在 AWS 中表示為一個單獨的對象。
- 執行角色。在 AWS 中,每個 Function 作為一個單獨的角色執行。在這裡就是 meditations。
- 角色政策。每個 Function 作為一個角色執行,每個角色需要權限來幹活。我們的 Lambda Function 不幹太多活,故我們隻添加一些日志記錄權限。
- Lambda Function。運作我們的代碼的地方。
- Swagger。 Swagger 是 API 的規範。API Gateway 支援解析 swagger 的定義來為 API 配置大部分資源。
- 部署。API Gateway 提供部署的概念。我們隻需要為我們的 API 用一個就行(例如,所有的都用生産或者 yolo等),但是得知道它們是存在的,并且對于真正的産品級服務,你可能想用開發和暫存環境。
- 監控。在我們的業務崩潰的情況下(或者因為使用産生大量賬單時),我們想以雲告警檢視方式為這些錯誤和費用添加一些監控。注意你應該修改 tools/deploy.py 來正确地設定你的 email。
代碼
Lambda Function 将從一個寫死清單中随機選擇一個并傳回 guru meditations,非常簡單:
import logging
import random
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def handler(event, context):
logger.info(u"received request with id '{}'".format(context.aws_request_id))
meditations = [
"off to a regex/",
"the count of machines abides",
"you wouldn't fax a bat",
"HAZARDOUS CHEMICALS + RKELLY",
"your solution requires a blood eagle",
"testing is broken because I'm lazy",
"did u mention banana cognac shower",
]
meditation = random.choice(meditations)
return {
"status": "success",
"meditation": meditation,
}
deploy.py 腳本
這個腳本相當長,我沒法貼在這裡。它基本隻是周遊上述“AWS 中的資訊”下的項目,確定每項都存在。
我們來部署這個腳本
隻需運作 ./tools/deploy.py。
基本完成了。不過似乎在權限申請上有些問題,由于 API Gateway 沒有權限去執行你的 Function,是以你的 Lambda Function 将不能執行,報錯應該是“Execution failed due to configuration error: Invalid permissions on Lambda function”。我不知道怎麼用 botocore 添權重限。你可以通過 AWS console 來解決這個問題,找到你的 API, 進到 "/POST" 端點,進到“integration request”,點選“Lambda Function”旁邊的編輯圖示,修改它,然後儲存。此時将彈出一個視窗提示“You are about to give API Gateway permission to invoke your Lambda function”, 點選“OK”。
當你完成後,記錄下/tools/deploy.py 列印出的 URL,像下面這樣調用它,然後檢視你的新 API 的行為:
$ curl -X POST https://a1b2c3d4.execute-api.us-east-1.amazonaws.com/prod/
{"status": "success", "meditation": "the count of machines abides"}
本地運作
不幸的是,AWS Lambda 沒有好的方法能在本地運作你的代碼。在這個例子裡,我們将用一個簡單的 flask 伺服器來在本地托管合适的端點,并調用 handler 函數。
from __future__ import absolute_import
from flask import Flask, jsonify
from server.meditate import handler
app = Flask(__name__)
@app.route("/", methods=["POST"])
def index():
class FakeContext(object):
aws_request_id = "XXX"
return jsonify(**handler(None, FakeContext()))
app.run(host="0.0.0.0")
你可以在倉庫中用 /tools/serve.sh 運作它,像這樣調用:
$ curl -X POST http://localhost:5000/
{
"meditation": "your solution requires a blood eagle",
"status": "success"
}
測試
你總是應該測試你的代碼。我們的測試方法是導入并運作我們的 handler 函數。這是最基本的 python 測試方法:
from __future__ import absolute_import
import unittest
from server.meditate import handler
class SubmitTestCase(unittest.TestCase):
def test_submit(self):
class FakeContext(object):
aws_request_id = "XXX"
response = handler(None, FakeContext())
self.assertEquals(response["status"], "success")
self.assertTrue("meditation" in response)
你可以在倉庫裡通過 nose2 運作這個測試代碼。
更多前景
- 和 AWS 服務的無縫內建。通過 boto,你可以完美地輕易連接配接到任何其他的 AWS 服務。你可以輕易地讓你的執行角色用 IAM 通路這些服務。你可以從 S3 取檔案或放檔案到 S3,連接配接到 Dynamo DB,調用其他 Lambda Function,等等。
- 通路資料庫。你也可以輕易地通路遠端資料庫。在你的 Lambda handler 子產品的最上面連接配接資料庫,并在handler 函數中執行查詢。你很可能必須從它的安裝位置上傳相關的包内容才能使它正常工作。可能你也需要靜态編譯某些庫。
- 調用其他 webservices。API Gateway 也是一種把 webservices 的輸出從一個格式轉換成另一個格式的方法。你可以充分利用這個特點通過不同的 webservices 來代理調用,或者當業務變更時提供後向相容能力。
本文原創位址:http://www.linuxprobe.com/lambda-api-gateway.html
免費提供最新Linux技術教程書籍,為開源技術愛好者努力做得更多更好:http://www.linuxprobe.com/thread