• WSGI & uWSGI 以及 uwsgi


    主要内容:

    • 1.WSGI
    • 2.uWSGI
    • 3.uwsgi

    1. WSGI

    1.1 WSGI相关概述

    引子: wsgi server (比如uWSGI) 要和 wsgi application(比如django )交互,uwsgi需要将过来的请求转给django 处理,那么uWSGI 和 django的交互和调用就需要一个统一的规范,这个规范就是WSGI WSGI(Web Server Gateway Interface)

    • WSGI,全称 Web Server Gateway Interface,或者 Python Web Server Gateway Interface ,是为 Python 语言定义的 Web 服务器和 Web 应用程序或框架之间的一种简单而通用的接口。自从 WSGI 被开发出来以后,许多其它语言中也出现了类似接口。
    • WSGI 的官方定义是,the Python Web Server Gateway Interface。从名字就可以看出来,这东西是一个Gateway,也就是网关。网关的作用就是在协议之间进行转换。
    • WSGI 是作为 Web 服务器与 Web 应用程序或应用框架之间的一种低级别的接口,以提升可移植 Web 应用开发的共同点。WSGI 是基于现存的 CGI 标准而设计的

    1.2 定义一个简版的WSGI 接口

    • 一个 application函数
      from wsgiref.simple_server import make_server
      
      def application(environ, start_response):
          start_response('200 OK', [('Content-Type', 'text/html')])
          return [b'<h1>Hello, web!</h1>']
      
      httpd = make_server('', 8080, application)
      
      print('Serving HTTP on port 8080...')
      # 开始监听HTTP请求:
      httpd.serve_forever()
    • 相关分析
      注意:
      
          整个application()函数本身没有涉及到任何解析HTTP的部分,也就是说,底层代码不需要我们自己编写,
      
          我们只负责在更高层次上考虑如何响应请求就可以了。
          application()函数必须由WSGI服务器来调用。有很多符合WSGI规范的服务器,我们可以挑选一个来用。
      
          Python内置了一个WSGI服务器,这个模块叫wsgiref   
          application()函数就是符合WSGI标准的一个HTTP处理函数,它接收两个参数:
      
              //environ:一个包含所有HTTP请求信息的dict对象;  
              //start_response:一个发送HTTP响应的函数。
      
      在application()函数中,调用:start_response('200 OK', [('Content-Type', 'text/html')])
      
      就发送了HTTP响应的Header,注意Header只能发送一次,也就是只能调用一次start_response()函数。
          start_response()函数接收两个参数,一个是HTTP响应码,一个是一组list表示的HTTP Header,每个Header用一个包含两个str的tuple表示。
      
          通常情况下,都应该把Content-Type头发送给浏览器。其他很多常用的HTTP Header也应该发送。
      然后,函数的返回值b'<h1>Hello, web!</h1>'将作为HTTP响应的Body发送给浏览器。
      有了WSGI,我们关心的就是如何从environ这个dict对象拿到HTTP请求信息,然后构造HTML,通过start_response()发送Header,最后返回Body。

    1.3 WSGI 的作用

    WSGI有两方:“服务器”或“网关”一方,以及“应用程序”或“应用框架”一方。服务方调用应用方,提供环境信息,以及一个回调函数(提供给应用程序用来将消息头传递给服务器方),并接收Web内容作为返回值。
    
    所谓的 WSGI中间件同时实现了API的两方,因此可以在WSGI服务和WSGI应用之间起调解作用:从WSGI服务器的角度来说,中间件扮演应用程序,而从应用程序的角度来说,中间件扮演服务器。“中间件”组件可以执行以下功能:
    
    重写环境变量后,根据目标URL,将请求消息路由到不同的应用对象。
    允许在一个进程中同时运行多个应用程序或应用框架。
    负载均衡和远程处理,通过在网络上转发请求和响应消息。
    进行内容后处理,例如应用XSLT样式表
    View Code

    2. uWSGI

    1.1 uWSGI的相关概述

    uWSGI是一个Web服务器,它实现了WSGI协议、uwsgi、http等协议。Nginx中HttpUwsgiModule的作用是与uWSGI服务器进行交换。

    • WSGI是一种通信协议。
    • uwsgi同WSGI一样是一种通信协议。
    • 而uWSGI是实现了uwsgi和WSGI两种协议的Web服务器。

    1.2 uWSGI配置的的理解

    (1) 通信接口:    http/http-socket/socket

    socket 方式:     socket  = 0.0.0.0:8000

    • 现在大部分web服务器(如nginx)支持uwsgi,这是这三种方式最高效的一种形式,socket通信速度会比http快 , 
    •  注: 指定socket协议,运行django,只能与nginx结合时

        

    http 方式:  http = 0.0.0.0:8000

       

       

         

    上面两个图都是http方式,使用http启动uwsgi,系统会额外启动一个http进程,从级别上来说,它和nginx是同一级别的,所以客户端和uwsgi通信,完全可以绕过nginx,不需要额外进行一个转发(如第二张图一样),但很显然,这是并不是一个很明智但选择,这样会失去了nginx很多优秀的功能。

    因此:  如果你没用nginx,只想自己启动一个http界面,用这个

    --- 另外 还有一方式,但是在uWSGI的配置文件中并未展示出: 具体使用待定---

     http -socket 方式        http-socket=127.0.0.1:8000

           

    http-socket方式,这个适用于web服务器不支持uwsgi时。

    (2)    processes/workers.

       表示开启多进程,根据你的应有开启合适的进程数,在一些参考资料上,可能会看到processes = 2 * cpucores或者workers = 2 * cpucores,如果应有比较简单,这样设置一般可以。如果想更合理,官方提供了uwsgitop去获得一个较为合理的值。

    (3)threads & enable-threads
    python中存在GIL,实际上不存在真正意义上的多线程,但是否需要,这个就根据各自但需求设定了。结合processes:

    • processes=2
    • threads=4

    表示2个进程,每个进程中有4个线程。

    • 由于GIL的存在,uwsgi索性默认不支持多线程,不对GIL进行初始化。但如果希望程序中的线程发挥作用,需要加入enable-threads=True;
    • 但如果已经在多线程模式(使用 threads 选项)下,那么uWSGI将会自动启用线程支持。

    (4)uid & gid & chmod-socket
           uwsgi不建议使用root权限去启动uwsgi实例。可以通过root用户去运行uwsgi文件,当通过uid和gid去修改用户(移除root权限)。并且,如果你使用的是socket的通信方式,最好加上chmod-socket字段,在linux下,socket的启动方式,套接字类似文件,你必须保证有权限去读取它。

    • chmod-socket=664
    • uid=1000
    • gid=1000

    (5)master
           意味着启动一个master主进程来管理其他进程,建议启动这个进程,在管理的时候比较方便;如果kill这个master进程,相当于关闭所有的uwsgi进程

    ----------- 内容摘自: https://blog.csdn.net/l_vip/article/details/81487608  -------------------------------------------

    3. uwsgi

     概述: uwsgi是服务器和服务端应用程序的通信协议,规定了怎么把请求转发给应用程序和返回 

    关于 uwsgi的理解 

      本文根据代码阅读以及参照多种文档,描述了uwsgi的启动多进程+多线程工作原因,以及thunder_lock参数的作用:

    • uwsgi是用c语言写的一个webserver,可以启动多个进程,进程里面可以启动多个线程来服务。进程分为主进程和worker进程,worker里面可以有多个线程。
    • 一开始进入main函数,启动这个就是主进程了,uwsgi_setup函数(主进程)里面针对选项参数做一些处理,执行环境设置,执行一些hook,语言环境初始化(python),如果没有设置延迟加载app,则app在主进程加载;如果设置了延迟加载,则在每一个worker进程中都会加载一次。uwsgi_setup函数还执行了插件的初始化(当前我只关心http、python:http是gateway类型的插件,这种插件是向外暴露http服务的,python的requests类型的插件,用来服务请求的)、tcp socket的绑定与监听(这个是指http与work之间的通信,且它的端口是自动产生的)。最后uwsgi主进程fork了指定worker进程用来接收(accept)请求。虽然在setup中就fork了子进程,但是现在还没有开始accept。
    • wsgi_run函数就是真正的开始执行了,这个函数分为俩个部分,主进程执行部分和worker进程执行部分。主进程执行部分是一个无限循环,他可以执行特定的hook以及接收信号等,总之是用来管理worker进程以及一些定时或者事件触发任务。worker部分:注册型号处理函数,执行一些hook,循环接收(accept)请求。在启动woker时可以根据--threads参数指定要产生的线程个数,否则只在当前进程启动一个线程。这些线程循环接收请求并处理。
    • 在worker中接收请求的函数wsgi_req_accept有一个锁:thunder_lock,这个锁用来串行化accept,防止“惊群”现象:参考这里
      •   惊群现象出现在这样的情况:主进程绑定并监听socket,然后调用fork,在各个子进程进行accept。无论任何时候,只要有一个连接尝试连接,所有的子进程都将被唤醒,但只有一个会连接成功,其他的会得到一个EAGAIN的错误,浙江导致巨大的CPU资源浪费,如果在进程中使用线程,这个问题被再度放大。一个解决方法是串行化accept,在accept前防止一个锁。

    -------- 以上内容摘自:   https://blog.csdn.net/pzqingchong/article/details/79522215 -------

  • 相关阅读:
    正则表达式中匹配中文
    计算机中的颜色——颜色概述
    人物系列Claude Shannon
    reading listfrom other blog
    how to write Makefile
    《麻省理工大学开放课程:线性代数》[中英双语字幕]视频下载
    正则表达式30分钟入门教程
    usage of fscanf and other read functions in C/C++
    《麻省理工大学开放课程:线性代数》学习
    Open review of papers
  • 原文地址:https://www.cnblogs.com/wcx666/p/10444400.html
Copyright © 2020-2023  润新知