WSGI与Nova

本文介绍了WSGI(Python Web Server Gateway Interface)的基本概念,包括其在web请求处理中的作用和工作流程。接着详细阐述了WSGI服务器如何通过环境变量和回调函数与web应用程序交互。在Nova项目中,WSGI被用于启动和管理API服务,如nova-api-wsgi,通过配置文件如api-paste.ini定义中间件和应用。Nova利用WSGI服务器如eventlet.wsgi创建并运行WSGI应用程序,实现高效率和灵活性的云服务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

2021SC@SDUSC

WSGI与Nova

WSGI简介

全称Python Web Server Gateway Interface,指定了web服务器和Python web应用或web框架之间的标准接口,以提高web应用在一系列web服务器间的移植性。

web处理请求流程:

  1. 用户操作操作浏览器发送请求;
  2. 请求转发至对应的web服务器
  3. web服务器将请求转交给web应用程序,web应用程序处理请求
  4. web应用将请求结果返回给web服务器,由web服务器返回用户响应结果
  5. 浏览器收到响应,向用户展示

WSGI则是一种协议,web服务器在将请求转交给web应用程序之前,需要先将http报文转换为WSGI规定的格式。

WSGI规定,Web程序必须有一个可调用对象,且该可调用对象接收两个参数,返回一个可迭代对象:

  1. environ:字典,包含请求的所有信息
  2. start_response:在可调用对象中调用的函数,用来发起响应,参数包括状态码,headers等

WSGI将 web 组件分为三类: web服务器,web中间件,web应用程序, wsgi基本处理模式为 : WSGI Server -> (WSGI Middleware)* -> WSGI Application 。

WSGI Server/gateway

​ wsgi server可以理解为一个符合wsgi规范的web server,接收request请求,封装一系列环境变量,按照wsgi规范调用注册的wsgi app,最后将response返回给客户端。文字很难解释清楚wsgi server到底是什么东西,以及做些什么事情,最直观的方式还是看wsgi server的实现代码。以python自带的wsgiref为例,wsgiref是按照wsgi规范实现的一个简单wsgi server。wsgi server 基本工作流程

  1. 服务器创建socket,监听端口,等待客户端连接。
  2. 当有请求来时,服务器解析客户端信息放到环境变量environ中,并调用绑定的handler来处理请求。
  3. handler解析这个http请求,将请求信息例如method,path等放到environ中。
  4. wsgi handler再将一些服务器端信息也放到environ中,最后服务器信息,客户端信息,本次请求信息全部都保存到了环境变量environ中。
  5. wsgi handler 调用注册的wsgi app,并将environ和回调函数传给wsgi app
  6. wsgi app 将reponse header/status/body 回传给wsgi handler
  7. 最终handler还是通过socket将response信息塞回给客户端。
WSGI Application

​ wsgi application就是一个普通的callable对象,当有请求到来时,wsgi server会调用这个wsgi app。这个对象接收两个参数,通常为environ,start_response。environ就像前面介绍的,可以理解为环境变量,跟一次请求相关的所有信息都保存在了这个环境变量中,包括服务器信息,客户端信息,请求信息。start_response是一个callback函数,wsgi application通过调用start_response,将response headers/status 返回给wsgi server。此外这个wsgi app会return 一个iterator对象 ,这个iterator就是response body。

WSGI & Nova

尽管计算和元数据API可以使用提供基于事件的HTTP服务器的独立脚本来运行,但一般认为使用支持WSGI的通用HTTP服务器(如Apache或nginx)来运行它们更具有性能和灵活性。

nova项目提供了两个自动生成的入口点来支持此功能:nova-api-wsgi和nova-metadata-wsgi。它们读取nova.conf和api-paste.ini,并生成大多数WSGI服务器所需的模块级应用。如果nova是用pip安装的,这两个脚本将被安装到任何环境下的预期bin目录。

Nova-api(nova/cmd/api.py) 服务启动时,初始化 nova/wsgi.py 中的类 Server,建立了 socket 监听 IP 和端口,再由 eventlet.spawn 和 eventlet.wsgi.server 创建 WSGI server:

class Server(object):
    """Server class to manage a WSGI server, serving a WSGI application."""

    def __init__(self, name, app, host='0.0.0.0', port=0, pool_size=None,
                       protocol=eventlet.wsgi.HttpProtocol, backlog=128,
                       use_ssl=False, max_url_len=None):
        """Initialize, but do not start, a WSGI server."""
        self.name = name
        self.app = app
        self._server = None
        self._protocol = protocol
        self._pool = eventlet.GreenPool(pool_size or self.default_pool_size)
        self._logger = logging.getLogger("nova.%s.wsgi.server" % self.name)
        self._wsgi_logger = logging.WritableLogger(self._logger)

        if backlog < 1:
            raise exception.InvalidInput(
                    reason='The backlog must be more than 1')

        bind_addr = (host, port)

        # 建立 socket,监听 IP 和端口
        self._socket = eventlet.listen(bind_addr, family, backlog=backlog)

    def start(self):
        """Start serving a WSGI application.

        :returns: None
        """

        # 构建所需参数
        wsgi_kwargs = {
            'func': eventlet.wsgi.server,
            'sock': self._socket,
            'site': self.app,
            'protocol': self._protocol,
            'custom_pool': self._pool,
            'log': self._wsgi_logger,
            'log_format': CONF.wsgi_log_format
            }

        if self._max_url_len:
            wsgi_kwargs['url_length_limit'] = self._max_url_len

        # 由 eventlet.sawn 启动 server
        self._server = eventlet.spawn(**wsgi_kwargs)

Application 的加载由 nova/wsgi.py 的类 Loader 完成,Loader 的 load_app 方法调用了 paste.deploy.loadapp 加载了 WSGI 的配置文件 /etc/nova/api-paste.ini:

class Loader(object):
    """Used to load WSGI applications from paste configurations."""

    def __init__(self, config_path=None):

        # 获取 WSGI 配置文件的路径
        self.config_path = config_path or CONF.api_paste_config

    def load_app(self, name):

        # paste.deploy 读取配置文件并加载该配置
        return paste.deploy.loadapp("config:%s" % self.config_path, name=name)

配置文件 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。

[composite:osapi_compute]
use = call:nova.api.openstack.urlmap:urlmap_factory
/v2: openstack_compute_api_v2
/v3: openstack_compute_api_v3

[composite:openstack_compute_api_v2]
use = call:nova.api.auth:pipeline_factory
noauth = faultwrap sizelimit noauth ratelimit osapi_compute_app_v2
keystone = faultwrap sizelimit authtoken keystonecontext ratelimit osapi_compute_app_v2
keystone_nolimit = faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v2

[composite:openstack_compute_api_v3]
...

[filter:keystonecontext]
paste.filter_factory = nova.api.auth:NovaKeystoneContext.factory

[filter:authtoken]
paste.filter_factory = keystoneclient.middleware.auth_token:filter_factory

[app:osapi_compute_app_v2]
paste.app_factory = nova.api.openstack.compute:APIRouter.factory

[app:osapi_compute_app_v3]
paste.app_factory = nova.api.openstack.compute:APIRouterV3.factory
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值