• WSGI,uwsgi,uWSGI梳理


    WSGI,uwsgi,uWSGI梳理

    由于项目用的是uWSGI部署,想要了解uWSGI的工作流程,理清其在整个项目中的角色定位。在看了很多所谓技术文章之后脑子越发混沌,但最终在uWSGI的文档中找到了我所需的所有答案。

    uWSGI的中文文档的翻译虽然很欢乐,但还是免不了浓重的翻译腔,英文文档的表达更为清晰。

    本文涵括

    • WSGI,uwsgi,uWSGI的关系梳理
    • uWSGI不同情况下的角色定位
    • uWSGI所支持的http,WSGI,uwsgi协议用在何处。

    定性

    WSGI

    WSGI规定了web服务器与应用程序如何相互作用,是一种设计规范,也可称为编程接口。

    符合这种规范设计的web服务器可称为WSGI server,而符合这种规范设计的应用程序则可以被所有的WSGI server调用运行,例如Django,Flask。

    uWSGI

    uWSGI就是一种符合WSGI的设计规范的web服务器,支持实现了HTTP, uwsgi等协议,至于用在哪里,后面会涉及到。

    uwsgi

    uwsgi是uWSGI自己实现的一种传输协议,它用于与nginx,apache等上游服务器通讯,它很大一部分作用是代替http协议与nginx等服务器传输数据。

    注意

    请注意切勿将uwsgi, uWSGI, WSGI张冠李戴。

    概览图

    它们之间的关系可以用下图表示
    在这里插入图片描述
    目前看不懂没关系,现在只是看个大概,下面我们从自己实现一个web服务器的角度来理清这些东西究竟是什么,有什么用。

    简陋的web服务器

    用一下代码可实现最简陋的web服务器

    import socket
    
    ip_port = ('127.0.0.1', 80)
    back_log = 10
    buffer_size = 1024
    
    alldata = "<h1>Hello World</h1>"
    
    def main():
        webserver = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        webserver.bind(ip_port)
        webserver.listen(back_log)
    
        while True:
            conn, addr = webserver.accept()
            recvdata = conn.recv(buffer_size)
            conn.sendall(bytes("HTTP/1.1 201 OK\r\n\r\n", "utf-8"))  # 响应头
            conn.sendall(bytes(alldata, "utf-8"))
            conn.close()
            
    if __name__ == '__main__':
        main()
    

    这就是一个最简陋的web服务器,但它并没有实际应用意义,它监听本地80端口,接受一个连接后返回一段写好的data。在它身上我们看不到概览图中任何模块的影子。

    现在我们开始根据实际需求拓展功能,一点点靠近现实的web服务器。

    解析请求数据,处理业务,返回响应,实现http协议支持。

    作为web服务器,你应该根据相应请求,做出业务处理,返回响应。

    而第一步就是解析请求数据,最后一步则是返回响应,用什么格式解析请求,返回响应呢。目前我们监听的是80端口,毫无疑问,我们与client交流使用的协议是http协议。

    那么用伪代码表示如下

    ......
    conn, addr = webserver.accept()
    recvdata = conn.recv(buffer_size)
    # 根据http协议解析请求数据,获取相应参数
    data = parse_request(recvdata)
    #根据获取的数据做出相应的处理逻辑
    ......
    ......
    #返回数据
    response_data = ......
    #根据http协议处理响应的数据,并通过连接返回。
    response = parse_response(response_data)
    conn.sendall(bytes("HTTP/1.1 201 OK\r\n\r\n", "utf-8"))  # 响应头
    conn.sendall(bytes(alldata, "utf-8"))
    conn.close()
    

    如此我们实现了web服务器http协议支持。完成的模块如下图所示。
    在这里插入图片描述
    目前这个服务器至少有了一点实际意义,能通过支持http协议来完成一些业务处理。

    业务处理与服务器解耦,使用WSGI规范编写代码。

    业务处理逻辑与服务器其他功能分离

    现在有更多服务器的项目来临,它们的业务需求不尽相同,但对于服务器来说,监听端口,支持相应协议等功能是必不可少的,本着复用(偷懒)的原则,我们分离web服务器与业务处理逻辑,将业务处理逻辑抽象为一个应用,即app。

    服务器解析完请求,将请求数据传入并调用app完成业务处理,app返回响应的数据,服务器再根据协议包装数据返回响应。

    那么对于每一个项目,你只需要着力编写app即可。

    使用WSGI规范

    你的同事也本着复用(偷懒)的原则,想要用你的web服务器调用他的app。但你们事先并没有沟通过,你的服务器与他的app由于参数,调用形式等原因并不兼容。

    但如果你们都根据WSGI的规范来编写服务器与app,那么你的web服务器就可以严丝合缝地调用他的app。

    WSGI简介

    简单看看WSGI如何规范server和app的。

    • WSGI协议主要包括server和application两部分,server负责接受客户端请求并进行解析,然后将其传入application,客户端处理请求并将响应头和正文返回服务器。
    • 从application的角度来说,它应当是一个可调用的对象(实现了__call__ 函数的方法或者类),它接受两个参数:environ和start_response,其主要作用就是根据server传入的environ字典来生成一个“可迭代的”http报文并返回给server
    • 从server的角度来说,其主要工作是解析http请求,生成一个environ字典并将其传递给可调用的application对象;另外,server还要实现一个start_response函数,其作用是生成响应头,start_response作为参数传入application中并被其调用

    其数据流如下
    在这里插入图片描述

    该简介节选自

    python从小白到入门:10分钟搞懂WSGI协议

    截至目前,我们已完成如下模块
    在这里插入图片描述
    我们这个服务器的功能与uWSGI在uwsgi --http :80 --wsgi-file app.py的模式下运行的功能相似。即对外接受http请求,业务处理,返回http响应。

    请注意uWSGI的--http--http-socket选项是完全不同的工作模式。

    --http选项的工作模式下,前者会创建一个额外的进程,转发请求到一系列的worker进程 ,与apache或者nginx的定位相似,而后者是令worker为原生使用http协议处理请求。

    --http-socket会在使用nginx/apache等服务器作为上游服务器的架构中,随后会涉及到。

    选择nginx作为上游服务器

    uWSGI虽然也能处理静态资源处理,但能力远不如高效的nginx,且生产环境下一般需要其为集群实现负载均衡的功能。所以我们可以选择选择nginx作为上游服务器用作处理静态资源以及实现负载均衡。

    那么自然而然地,就能想到直接使用nginx的proxy_pass功能来向uWSGI转发http包。而proxy_pass模式下与uWSGI的沟通是使用http协议的。uWSGI这边,需要用--http-socket模式启动,nginx这边需要设置好代理配置,如此nginx就能向uWSGI转发相应的请求了。

    至此,我们已完成如下模块。
    在这里插入图片描述

    开发uwsgi协议代替http协议用以nginx与uWSGI沟通

    以nginx的proxy_pass代理http请求给uWSGI的架构,有一个小缺点,就是http解析了两次(nginx与uWSGI各一次),然后uWSGI就开发出一个uwsgi协议,该协议解析比http解析快,只要上游服务器兼容uwsgi协议,那么上游服务器(如nginx)就可以与uWSGI通过uwsgi协议传输数据。该情况下,http只在上游服务器解析一次,效率更高一点。

    当然,这也得上游服务器兼容uwsgi协议才可以,常用的nginx,Apache都兼容uwsgi协议,而Lighttpd则认为uwsgi协议是重复造轮子,建议使用FastCGI,当然,uWSGI也是支持FastCGI的。

    如果要使用uwsgi协议,则需用-socket参数代替--http-socket,上游服务器也应做相应的配置(如nginx要用uwsgi_pass代替proxy_pass)。

    最终我们常用的架构为什么如下图一般,就一清二楚了。
    在这里插入图片描述
    如有纰漏,欢迎斧正

    参考文献

    uWSGI项目文档

  • 相关阅读:
    3D引擎为什么使用三角形绘制曲面
    用SublimeText当Unity Shader的编辑器
    Lua模块的加载与内存释放
    wriesharek同时监听多个端口
    Unity的Input输入
    Unity项目中文字的统一管理
    Unity中的定时器与延时器
    Unity插件扩展中组件常用的几个方法
    u3d不显示阴影的处理方法
    使用ScriptableObject创建.asset文件
  • 原文地址:https://www.cnblogs.com/lymmurrain/p/15911760.html
Copyright © 2020-2023  润新知