花了两个星期,我终于把 WSGI 整明白了 (2)

从其名字上就看出,它是用纯Python编写的WSGI服务器的参考实现。所谓“参考实现”是指该实现完全符合WSGI标准,但是不考虑任何运行效率,仅供开发和测试使用。

有了 wsgiref 这个模块,你就可以很快速的启动一个wsgi server。

from wsgiref.simple_server import make_server # 这里的 appclass 暂且不说,后面会讲到 app = appclass() server = make_server('', 64570, app) server.serve_forever()

当你运行这段代码后,就会开启一个 wsgi server,监听 0.0.0.0:64570 ,并接收请求。

使用 lsof 命令可以查到确实开启了这个端口

以上使用 wsgiref 写了一个demo,让你对wsgi有个初步的了解。其由于只适合在学习测试使用,在生产环境中应该另寻他道。

04. 实现“高并发”的 WSGI Server

上面我们说不能在生产中使用 wsgiref ,那在生产中应该使用什么呢?选择有挺多的,比如优秀的 uWSGI,Gunicore等。但是今天我并不准备讲这些,一是因为我不怎么熟悉,二是因为我本人从事 OpenStack 的二次开发,对它比较熟悉。

所以下面,是我花了几天时间阅读 OpenStack 中的 Nova 组件代码的实现,刚好可以拿过来学习记录一下,若有理解偏差,还望你批评指出。

在 nova 组件里有不少服务,比如 nova-api,nova-compute,nova-conductor,nova-scheduler 等等。

其中,只有 nova-api 有对外开启 http 接口。

要了解这个http 接口是如何实现的,从服务启动入口开始看代码,肯定能找到一些线索。

从 Service 文件可以得知 nova-api 的入口是 nova.cmd.api:main()

打开nova.cmd.api:main() ,一起看看是 OpenStack Nova 的代码。

在如下的黄框里,可以看到在这里使用了service.WSGIService 启动了一个 server,就是我们所说的的 wsgi server

那这里的 WSGI Server 是依靠什么实现的呢?让我们继续深入源代码。

wsgi.py 可以看到这里使用了 eventlet 这个网络并发框架,它先开启了一个绿色线程池,从配置里可以看到这个服务器可以接收的请求并发量是 1000 。

可是我们还没有看到 WSGI Server 的身影,上面使用eventlet 开启了线程池,那线程池里的每个线程应该都是一个服务器吧?它是如何接收请求的?

再继续往下,可以发现,每个线程都是使用 eventlet.wsgi.server 开启的 WSGI Server,还是使用的 eventlet。

由于源代码比较多,我提取了主要的代码,精简如下

# 创建绿色线程池 self._pool = eventlet.GreenPool(self.pool_size) # 创建 socket:监听的ip,端口 bind_addr = (host, port) self._socket = eventlet.listen(bind_addr, family, backlog=backlog) dup_socket = self._socket.dup() # 整理孵化协程所需的各项参数 wsgi_kwargs = { 'func': eventlet.wsgi.server, 'sock': dup_socket, 'site': self.app, # 这个就是 wsgi 的 application 函数 'protocol': self._protocol, 'custom_pool': self._pool, 'log': self._logger, 'log_format': CONF.wsgi.wsgi_log_format, 'debug': False, 'keepalive': CONF.wsgi.keep_alive, 'socket_timeout': self.client_socket_timeout } # 孵化协程 self._server = utils.spawn(**wsgi_kwargs)

就这样,nova 开启了一个可以接受1000个绿色协程并发的 WSGI Server。

05. 第一次路由:PasteDeploy

上面我们提到 WSGI Server 的创建要传入一个 Application,用来处理接收到的请求,对于一个有多个 app 的项目。

比如,你有一个个人网站提供了如下几个模块

/blog # 博客 app /wiki # wiki app

如何根据 请求的url 地址,将请求转发到对应的application上呢?

答案是,使用 PasteDeploy 这个库(在 OpenStack 中各组件被广泛使用)。

PasteDeploy 到底是做什么的呢?

根据 的说明,翻译如下

PasteDeploy 是用来寻找和配置WSGI应用和服务的系统。PasteDeploy给开发者提供了一个简单的函数loadapp。通过这个函数,可以从一个配置文件或者Python egg中加载一个WSGI应用。

使用PasteDeploy的其中一个重要意义在于,系统管理员可以安装和管理WSGI应用,而无需掌握与Python和WSGI相关知识。

由于 PasteDeploy 原来是属于 Paste 的,现在独立出来了,但是安装的时候还是会安装到paste目录(site-packages\paste\deploy)下。

我会先讲下在 Nova 中,是如何借助 PasteDeploy 实现对url的路由转发。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwppjj.html