liusheng / liusheng.github.io

Liusheng's blog
http://liusheng.github.io
5 stars 1 forks source link

uWSGI和OpenStack API服务启动方式变迁 #8

Open liusheng opened 5 years ago

liusheng commented 5 years ago

变迁历史: eventlet -- > mod_wsgi -- > uWSGI 注:Nova在最早的时候直接使用Python web server来作为API服务,但是很快淘汰

eventlet方式启动API服务

eventlet是基于greenlet的基础上实现,由于协程的“非阻塞”特性,基于eventlet的HTTP server 具有很好的网络性能。每一个任务都是在一个独立的线程中执行,并且在“用户态”进行调度。唯一需要注意一点的是,在代码实现上,或者调用上,需要保证引用的第三方库也是非阻塞的,我们可以对第三方I/O库进行“绿化”来使其非阻塞。eventlet提供的wsgi是单线程异步I/O,由于API服务是一个网络交互的过程,异步I/O对于提升性能有很大帮助。

mod_wsgi方式启动API服务

使用mod_wsgi主要基于安全考虑,apache提供了完整的生态,来支持一些安全标准。eventlet只提供了基本的认证功能。eventlet目前也不支持IPV6,目前是在上游做了一些实现来支持(D版的时候,现在已经支持了)。作为一个标准的开源web服务器,提供了更完备的审查机制。支持GSSAPI/Kerberos authentication,服务端和客户端都是基于证书的,也很好地支持IPv6。并且,apache在生产环境中应用广泛,也不会存在性能瓶颈。

mod_wsgi是一个Python包,实现了借助于Apache直接讲一个python的支持WSGI协议的application托管到Apache的web服务器上。有两种方式,一种是配置Apache来加载相应的模块。另一种是通过pip安装mod_wsig的Python包。

WSGI协议实现了web server 和 application的解耦,对于HTTP请求的处理,分为服务层和应用层,服务层,接收来自于socket的数据包,并将其解析,然后调用application,给application提供环境信息包括请求的详细信息,并且给application传入一个start_reponse的回调函数;在application层,会处理来自于服务器层的请求,然后调用start_reponse函数,返回请求的响应。 关于WSGI协议,详见[[1]][1]

mod_wsgi vs uWSGI

相比较于mod_wsgi,uWSGI的方式启动服务,主要有以下不同点

  1. 服务的日志可以放在不同的位置,以不同的形式来定义
  2. start/stop/status的方式和现在的不同
  3. apache重启时候重启所有服务
  4. 每一个API服务需要指定特定的端口

在部署方式上,mod_wsgi是直接将应用托管到apache上,而uWSGI的方式虽然也依赖于Apache,但是Apache只起到了一个代理的作用,而将具体的请求转发到uwsgi服务来处理。

注:它是一个二进制协议,可以携带任何类型的数据。一个uwsgi分组的头4个字节描述了这个分组包含的数据类型。 WSGI是一种Web服务器网关接口。它是一个Web服务器(如nginx)与应用服务器(如uWSGI服务器)通信的一种规范。

如何给一个项目增加uWSGI支持

这里需要注意,通常uWSGI指的是一个Web服务器,它实现了WSGI协议、HTTP、uwsgi等协议。 实现API服务的uWSGI方式启动,需要做如下工作:

    wsgi_scripts =
        mogan-api-wsgi = mogan.api.app:build_wsgi_app

其中上面的build_wsgi_app即定义了一个入口,用于返回一个WSGI引用,通过pbr安装项目,会生成一个/usr/local/binmogan-api-wsgi的二进制文件用于处理正真的API请求。各种常见的API server框架都提供了WSGI的支持,例如使用Pecan实现的API server,可以通过如下的方式来定义一个WSGI application的入口:

def setup_app(pecan_config=None, extra_hooks=None):
    pecan.configuration.set_config(dict(pecan_config), overwrite=True)
    app = pecan.make_app(
        pecan_config.app.root,
        static_root=pecan_config.app.static_root,
        debug=False,
        force_canonical=getattr(pecan_config.app, 'force_canonical', True),
        hooks=app_hooks,
        wrap_app=middleware.ParsableErrorMiddleware,
    )
    app = auth_token.AuthTokenMiddleware(
        app, dict(cfg.CONF),
        public_api_routes=pecan_config.app.acl_public_routes)

    return app
[uwsgi]
wsgi-file = /usr/local/bin/mogan-api-wsgi

chmod-socket = 666

socket = /var/run/uwsgi/mogan-api-wsgi.socket

# Override the default size for headers from the 4k default.
buffer-size = 65535

# This is running standalone
master = true

enable-threads = true

# Tune this to your environment.
processes = 4

# uwsgi recommends this to prevent thundering herd on accept.
thunder-lock = true

plugins = python

# This ensures that file descriptors aren't shared between Searchlight processes.
lazy-apps = true

在上面的配置文件样例中:wsgi-file定义了真正处理API请求的入口;socket定义了监听请求的端口信息。

sudo a2enmod proxy
sudo a2enmod proxy_uwsgi

http://localhost/baremetal_compute/v1

为什么要使用apache做的代理,直接使用uWSGI交互可以吗?答案是可以的,但是Apache2提供了完善的安全机制以及负载均衡。

涉及到uWSGI启动API服务的相关文件

● uwsgi文件 -- 用于生成一个wsgi对象 ● uwsgi 配置文件--定义一些uwsgi启动参数 ● Apache mod_proxy文件 -- 定义Apache代理入口 ● systemd启动脚本 执行uwsgi --ini /etc/{project}/xxx.ini

参考:

[1] http://geocld.github.io/2017/08/14/wsgi/ [2] http://adam.younglogic.com/2012/03/keystone-should-move-to-apache-httpd/ [3] http://adam.younglogic.com/2012/04/keystone-httpd/ [4] https://governance.openstack.org/tc/goals/pike/deploy-api-in-wsgi.html