深入理解 nova-api 的 WSGI

發表於2017-03-17

本文是 理解 WSGI 框架 的下篇,重點介紹 WSGI 框架下一些常用的 python module,並使用這些 module 編寫一個類似 nova-api 裡 WSGI 的簡單樣例,最後分析 nova 是如何使用這些 module 構建其 WSGI 框架。

  • eventlet: python 的高併發網路庫
  • paste.deploy: 用於發現和配置 WSGI application 和 server 的庫
  • routes: 處理 http url mapping 的庫

Eventlet

Eventlet 是一個基於協程的 Python 高併發網路庫,和上篇文章所用的 wsgiref 相比,它具有更強大的功能和更好的效能,OpenStack 大量的使用 eventlet 以提供併發能力。它具有以下特點:

  • 使用 epoll、kqueue 或 libevent 等 I/O 複用機制,對於非阻塞 I/O 具有良好的效能
  • 基於協程(Coroutines),和程式、執行緒相比,其切換開銷更小,具有更高的效能
  • 簡單易用,特別是支援採用同步的方式編寫非同步的程式碼

Eventlet.wsgi

Eventlet WSGI 簡單易用,數行程式碼即可實現一個基於事件驅動的 WSGI server。本例主要使用了 eventlet.wsgi.server 函式:

該函式的引數眾多,重點介紹以下 2 個引數:

  • sock: 即 TCP Socket,通常由 eventlet.listen(‘IP’, PORT) 實現
  • site: WSGI 的 application

回顧上篇文章內容,本例採用 callable 的 instance 實現一個 WSGI application,利用 eventlet.server 構建 WSGI server,如下:

Eventlet.spawn

Eventlet.spawn 基於 greenthread,它通過建立一個協程來執行函式,從而提供併發處理能力。

加入該函式後,樣例如下:


Paste.deploy

Paste.deploy 是一個使用者發現和配置 WSGI server 和 application 的 python 庫,它定義簡潔的 loadapp 函式,用於從配置檔案或者 python egg 中載入 WSGI 應用,它僅關注 application 的入口,不關心 application 的內部細節。

Paste.deploy 通常要求 application 實現一個 factory 的類方法,如下:

配置檔案的規則請參考官網介紹,相應的配置檔案如下,其中 app:animal 給出了 application 的入口,pipeline:animal_pipeline 用於配置 WSGI middleware。

現在我們新增一個 IPBlackMiddleware,用於限制某些 IP:

相關配置檔案:


Route

Routes 是基於 ruby on railsroutes system 開發的 python 庫,它根據 http url 把請求對映到具體的方法,routes 簡單易用,可方便的構建 Restful 風格的 url。

本例增加 CatController 和 DogController,對於 url_path 為 cats 的 HTTP 請求,對映到 CatController 處理,對於 url_path 為 dogs 的 HTTP 請求,對映到 DogController 處理,最終樣例如下:

測試如下:


WSGI In Nova-api

WSGI Server

Nova-api(nova/cmd/api.py) 服務啟動時,初始化 nova/wsgi.py 中的類 Server,建立了 socket 監聽 IP 和埠,再由 eventlet.spawn 和 eventlet.wsgi.server 建立 WSGI server:

Application Side & Middleware

Application 的載入由 nova/wsgi.py 的類 Loader 完成,Loader 的 load_app 方法呼叫了 paste.deploy.loadapp 載入了 WSGI 的配置檔案 /etc/nova/api-paste.ini:

配置檔案 api-paste.ini 如下所示,我們通常使用 v2 API,即 composite:openstack_compute_api_v2,也通常使用 keystone 做認證,即 keystone = faultwrap sizelimit authtoken keystonecontext ratelimit osapi_compute_app_v2,從 fautlwrap 到 ratelimit 均是 middleware,我們也可根據需求增加某些 middleware。

Routes

在 nova/api/openstack/compute/__init__.py 定義了類 APIRouter,它定義了各種 url 和 controller 之間的對映關係,最終由 nova/wsgi.py 的類 Router 載入這些 mapper。

nova/wsgi.py 中的 Router class 如下: