使用微服務(wù)架構(gòu)部署應(yīng)用程序有幾個(gè)優(yōu)點(diǎn):更容易進(jìn)行主系統(tǒng)集成、更簡單的測試和可重用的代碼組件。 FastAPI 最近已成為 Python 中用于開發(fā)微服務(wù)的最流行的 web 框架之一。 FastAPI 比 Flask ( Python 中常用的 web 框架),因?yàn)樗腔?異步服務(wù)器網(wǎng)關(guān)接口( ASGI ) 而不是 Web 服務(wù)器網(wǎng)關(guān)接口( WSGI ) 。
什么是微服務(wù)
微服務(wù)定義了構(gòu)建軟件應(yīng)用程序的架構(gòu)和組織方法。微服務(wù)的一個(gè)關(guān)鍵方面是它們是分布式的,并且具有松散耦合。實(shí)現(xiàn)更改不太可能破壞整個(gè)應(yīng)用程序。
您還可以將使用微服務(wù)架構(gòu)構(gòu)建的應(yīng)用程序視為由幾個(gè)通過應(yīng)用程序編程接口( API )通信的小型獨(dú)立服務(wù)組成。通常,每個(gè)服務(wù)都由一個(gè)較小的、自包含的團(tuán)隊(duì)擁有,負(fù)責(zé)在必要時(shí)實(shí)現(xiàn)更改和更新。
使用微服務(wù)的一個(gè)主要好處是,它們使團(tuán)隊(duì)能夠快速為其應(yīng)用程序構(gòu)建新組件。這對于與不斷變化的業(yè)務(wù)需求保持一致至關(guān)重要。
另一個(gè)好處是它們使按需擴(kuò)展應(yīng)用程序變得多么簡單。企業(yè)可以加快上市時(shí)間,以確保不斷滿足客戶需求。
微服務(wù)和整體服務(wù)的區(qū)別
單片是另一種軟件體系結(jié)構(gòu),它為設(shè)計(jì)軟件應(yīng)用程序提供了一種更傳統(tǒng)、統(tǒng)一的結(jié)構(gòu)。這里有一些不同之處。
微服務(wù)是解耦的
想想微服務(wù)如何將應(yīng)用程序分解為其核心功能。每個(gè)功能都稱為服務(wù),并執(zhí)行單個(gè)任務(wù)。
換句話說,服務(wù)可以獨(dú)立構(gòu)建和部署。這樣做的好處是,單個(gè)服務(wù)在不影響其他服務(wù)的情況下工作。例如,如果一項(xiàng)服務(wù)比其他服務(wù)的需求更大,則可以獨(dú)立擴(kuò)展。
巨石是緊密耦合的
另一方面,整體架構(gòu)是緊密耦合的,并作為單個(gè)服務(wù)運(yùn)行。缺點(diǎn)是,當(dāng)一個(gè)進(jìn)程遇到需求高峰時(shí),必須擴(kuò)展整個(gè)應(yīng)用程序,以防止該進(jìn)程成為瓶頸。由于單個(gè)進(jìn)程故障會影響整個(gè)應(yīng)用程序,因此應(yīng)用程序停機(jī)的風(fēng)險(xiǎn)也會增加。
對于單片架構(gòu),隨著代碼庫的增長,更新或向應(yīng)用程序添加新功能要復(fù)雜得多。這限制了實(shí)驗(yàn)的空間。
何時(shí)使用微服務(wù)或巨石?
這些差異并不一定意味著微服務(wù)比單一服務(wù)更好。在某些情況下,使用單體仍然更有意義,例如構(gòu)建一個(gè)不需要太多業(yè)務(wù)邏輯、優(yōu)異的可伸縮性或靈活性的小型應(yīng)用程序。
然而,機(jī)器學(xué)習(xí)( ML )應(yīng)用程序通常是具有許多運(yùn)動部件的復(fù)雜系統(tǒng),必須能夠擴(kuò)展以滿足業(yè)務(wù)需求。通常需要為 ML 應(yīng)用程序使用微服務(wù)架構(gòu)。
包裝機(jī)器學(xué)習(xí)模型
在我深入了解用于此微服務(wù)的體系結(jié)構(gòu)的細(xì)節(jié)之前,有一個(gè)重要的步驟需要完成:模型打包。只有當(dāng) ML 模型的預(yù)測可以提供給最終用戶時(shí),您才能真正實(shí)現(xiàn) ML 模型的價(jià)值。在大多數(shù)情況下,這意味著從筆記本電腦到腳本,以便將模型投入生產(chǎn)。
在本例中,將用于訓(xùn)練和預(yù)測新實(shí)例的腳本轉(zhuǎn)換為 Python 包。軟件包是編程的重要組成部分。沒有它們,大部分開發(fā)時(shí)間都浪費(fèi)在重寫現(xiàn)有代碼上。
為了更好地理解包是什么,從腳本開始,然后介紹模塊要容易得多。
腳本:預(yù)期將直接運(yùn)行的文件。每個(gè)腳本執(zhí)行都執(zhí)行開發(fā)人員定義的特定行為。創(chuàng)建腳本就像保存擴(kuò)展名為.py 的文件以表示 Python 文件一樣簡單。
模塊:為導(dǎo)入其他腳本或模塊而創(chuàng)建的程序。一個(gè)模塊通常由幾個(gè)類和函數(shù)組成,這些類和函數(shù)用于其他文件。將模塊視為代碼的另一種方式是反復(fù)重用。
包可以被定義為相關(guān)模塊的集合。這些模塊以特定的方式相互作用,從而使您能夠完成任務(wù)。在 Python 中,包通常通過 PyPi 并且可以使用 pip ,一個(gè) Python 包安裝程序。
圖 1 顯示了該模型的目錄結(jié)構(gòu)。
圖 1.模型的目錄結(jié)構(gòu)
包模塊包括以下內(nèi)容:
config.yml: YAML 文件以定義常量變量。
pipeline.py:執(zhí)行所有特征轉(zhuǎn)換和建模的管道。
predict.py:使用訓(xùn)練模型對新實(shí)例進(jìn)行預(yù)測。
train_pipeline.py:進(jìn)行模型培訓(xùn)。
版本:當(dāng)前版本。
config/core.py:用于解析 YAML 文件的模塊,以便可以在 Python 中訪問常量變量。
資料/:用于項(xiàng)目的所有數(shù)據(jù)。
模型/:經(jīng)過訓(xùn)練的序列化模型。
processing/data_manager.py:用于數(shù)據(jù)管理的實(shí)用功能。
processing/features.py:要在管道中使用的特征轉(zhuǎn)換。
processing/validation.py:數(shù)據(jù)驗(yàn)證架構(gòu)。
該模型沒有針對這個(gè)問題進(jìn)行優(yōu)化,因?yàn)楸疚牡闹饕攸c(diǎn)是展示如何使用微服務(wù)架構(gòu)構(gòu)建 ML 應(yīng)用程序。
現(xiàn)在該模型已經(jīng)準(zhǔn)備好分發(fā),但存在一個(gè)問題。通過 PyPi 索引分發(fā)包意味著它可以在全球范圍內(nèi)訪問。對于模型中沒有業(yè)務(wù)價(jià)值的場景,這可能是可以的。然而,在真實(shí)的業(yè)務(wù)場景中,這將是一場徹底的災(zāi)難。
您可以使用第三方工具,如 Gemfury 完成此操作的步驟超出了本文的范圍。有關(guān)詳細(xì)信息,請參閱 安裝專用 Python 軟件包 。
圖 2 顯示了我的 Gemfury 存儲庫中的私有打包模型。我做了這個(gè) 用于演示目的的包公開 。
圖 2.Gemfury 存儲庫中的打包模型
微服務(wù)系統(tǒng)設(shè)計(jì)
在訓(xùn)練并保存模型后,您需要一種向最終用戶提供預(yù)測的方法。 RESTAPI 是實(shí)現(xiàn)這一目標(biāo)的好方法。有幾種應(yīng)用程序架構(gòu)可用于集成 RESTAPI 。圖 3 顯示了我在本文中使用的嵌入式體系結(jié)構(gòu)。
圖 3.嵌入式方法的可視化表示
嵌入式體系結(jié)構(gòu)指的是一個(gè)系統(tǒng),其中訓(xùn)練的模型嵌入到 API 中并作為依賴項(xiàng)安裝。
在簡單性和靈活性之間有一個(gè)自然的權(quán)衡。嵌入式方法比其他方法簡單得多,但靈活性較差。例如,每當(dāng)進(jìn)行模型更新時(shí),必須重新部署整個(gè)應(yīng)用程序。如果你的服務(wù)是在手機(jī)上提供的,那么你必須發(fā)布新版本的軟件。
使用 FastAPI 構(gòu)建 API
構(gòu)建 API 時(shí)需要考慮的是依賴關(guān)系。您將不會創(chuàng)建虛擬環(huán)境,因?yàn)槟谑褂眠\(yùn)行應(yīng)用程序 tox ,這是一個(gè)命令行驅(qū)動的自動化測試工具,也用于通用 虛擬人 經(jīng)營因此,調(diào)用tox創(chuàng)建虛擬環(huán)境并運(yùn)行應(yīng)用程序。
盡管如此,以下是依賴項(xiàng)。
--extra-index-url="https://repo.fury.io/kurtispykes/" car-evaluation-model==1.0.0 uvicorn>=0.18.2, <0.19.0 fastapi>=0.79.0, <1.0.0 python-multipart>=0.0.5, <0.1.0 pydantic>=1.9.1, <1.10.0 typing_extensions>=3.10.0, <3.11.0 loguru>=0.6.0, <0.7.0
如果在 PyPI 中找不到包,pip
還有一個(gè)額外的索引,用于搜索包。這是到托管打包模型的 Gemfury 帳戶的公共鏈接,因此,您可以從 Gemfurry 安裝經(jīng)過訓(xùn)練的模型。這將是專業(yè)設(shè)置中的私有包,這意味著鏈接將被提取并隱藏在環(huán)境變量中。
另一件需要注意的事情是uvicorn.Uvicorn 是實(shí)現(xiàn) ASGI 接口的服務(wù)器網(wǎng)關(guān)接口。換句話說,它是一個(gè)專門的 web 服務(wù)器,負(fù)責(zé)處理入站和出站請求。它在Procfile
中定義。
web: uvicorn app.main:app --host 0.0.0.0 --port $PORT
既然指定了依賴項(xiàng),您就可以繼續(xù)查看實(shí)際的應(yīng)用程序了。 API 應(yīng)用程序的主要部分是main.py
腳本:
from typing import Any from fastapi import APIRouter, FastAPI, Request from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import HTMLResponse from loguru import logger from app.api import api_router from app.config import settings, setup_app_logging # setup logging as early as possible setup_app_logging(config=settings) app = FastAPI( title=settings.PROJECT_NAME, openapi_url=f"{settings.API_V1_STR}/openapi.json" ) root_router = APIRouter() @root_router.get("/") def index(request: Request) -> Any: """Basic HTML response.""" body = ( "" "" "Welcome to the API
" "" "Check the docs: here" "" "" "" ) return HTMLResponse(content=body) app.include_router(api_router, prefix=settings.API_V1_STR) app.include_router(root_router) # Set all CORS enabled origins if settings.BACKEND_CORS_ORIGINS: app.add_middleware( CORSMiddleware, allow_origins=[str(origin) for origin in settings.BACKEND_CORS_ORIGINS], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) if __name__ == "__main__": # Use this for debugging purposes only logger.warning("Running in development mode. Do not run like this in production.") import uvicorn # type: ignore uvicorn.run(app, host="localhost", port=8001, log_level="debug")
如果你不能跟上,不要擔(dān)心。需要注意的關(guān)鍵是,主應(yīng)用程序中有兩個(gè)路由器:
-
root_router
:此端點(diǎn)定義返回 HTML 響應(yīng)的主體。您幾乎可以將其視為稱為索引的主端點(diǎn)。 -
api_router
:此端點(diǎn)用于指定允許其他應(yīng)用程序與 ML 模型交互的更復(fù)雜的端點(diǎn)。
深入了解api.py
模塊以更好地理解api_router
。首先,本模塊中定義了兩個(gè)端點(diǎn):health
和predict
。
看看代碼示例:
@api_router.get("/health", response_model=schemas.Health, status_code=200) def health() -> dict: """ Root Get """ health = schemas.Health( name=settings.PROJECT_NAME, api_version=__version__, model_version=model_version ) return health.dict() @api_router.post("/predict", response_model=schemas.PredictionResults, status_code=200) async def predict(input_data: schemas.MultipleCarTransactionInputData) -> Any: """ Make predictions with the Fraud detection model """ input_df = pd.DataFrame(jsonable_encoder(input_data.inputs)) # Advanced: You can improve performance of your API by rewriting the # `make prediction` function to be async and using await here. logger.info(f"Making prediction on inputs: {input_data.inputs}") results = make_prediction(inputs=input_df.replace({np.nan: None})) if results["errors"] is not None: logger.warning(f"Prediction validation error: {results.get('errors')}") raise HTTPException(status_code=400, detail=json.loads(results["errors"])) logger.info(f"Prediction results: {results.get('predictions')}") return results
health
端點(diǎn)非常簡單。當(dāng)您訪問 web 服務(wù)器時(shí),它返回模型的健康響應(yīng)模式(圖 4 )。您在schemas
目錄中的health.py
模塊中定義了此架構(gòu)。
圖 4.來自健康端點(diǎn)的服務(wù)器響應(yīng)
predict端點(diǎn)稍微復(fù)雜一些。以下是所涉及的步驟:
獲取輸入并將其轉(zhuǎn)換為 pandas 數(shù)據(jù)幀 : jsonable_encoder 返回的 JSON 兼容版本 pydantic model.
記錄輸入數(shù)據(jù)以進(jìn)行審計(jì)。
使用 ML 模型的make_prediction函數(shù)進(jìn)行預(yù)測。
捕獲模型產(chǎn)生的任何錯(cuò)誤。
如果模型沒有錯(cuò)誤,則返回結(jié)果。
通過從終端窗口使用以下命令啟動服務(wù)器,檢查所有功能是否正常:
py -m tox -e run
如果服務(wù)器正在運(yùn)行,這將顯示多個(gè)日志,如圖 5 所示。
圖 5.顯示服務(wù)器正在運(yùn)行的日志
現(xiàn)在,您可以導(dǎo)航到 http://localhost:8001 查看 API 的交互端點(diǎn)。
測試微服務(wù) API
導(dǎo)航到本地服務(wù)器將從main.py腳本轉(zhuǎn)到root_rooter中定義的索引端點(diǎn)。您可以通過在本地主機(jī)服務(wù)器 URL 的末尾添加/docs來獲得有關(guān) API 的更多信息。
例如,圖 6 顯示您已經(jīng)將predict端點(diǎn)創(chuàng)建為 POST 請求,health端點(diǎn)是 GET 請求。
圖 6.API 端點(diǎn)
首先,展開predict標(biāo)題以接收有關(guān)端點(diǎn)的信息。在本標(biāo)題中,您將看到請求主體中的一個(gè)示例。我在其中一個(gè)模式中定義了這個(gè)示例,以便您可以測試 API 。這超出了本文的范圍,但您可以瀏覽 模式代碼 。
要在請求體示例中嘗試該模型,請選擇試試看。
圖 7.使用微服務(wù)的示例預(yù)測
圖 7 顯示了模型返回的預(yù)測輸出類為 1 。在內(nèi)部,您知道 1 表示acc類值,但您可能希望在用戶界面中顯示時(shí)向用戶顯示該值。
下一步是什么?
恭喜您,您現(xiàn)在已經(jīng)為微服務(wù)構(gòu)建了自己的 ML 模型。接下來的步驟涉及部署它,以便它可以在生產(chǎn)中運(yùn)行。
總而言之,微服務(wù)是一種架構(gòu)和組織設(shè)計(jì)方法,用于安排松散耦合的服務(wù)。在 ML 應(yīng)用程序中使用微服務(wù)方法的主要好處之一是獨(dú)立于主要軟件產(chǎn)品。擁有與主軟件產(chǎn)品分離的功能服務(wù)( ML 應(yīng)用程序)有兩個(gè)關(guān)鍵好處:
它使跨職能團(tuán)隊(duì)能夠參與分布式開發(fā),從而加快部署速度。
軟件的可擴(kuò)展性得到了顯著提高。
關(guān)于作者
Kurtis Pykes 是一位自學(xué)成才的機(jī)器學(xué)習(xí)實(shí)踐者,目前是一名自由職業(yè)者。
審核編輯:郭婷
-
python
+關(guān)注
關(guān)注
56文章
4792瀏覽量
84627
發(fā)布評論請先 登錄
相關(guān)推薦
評論