zoukankan      html  css  js  c++  java
  • Python Web 服务

    Web 服务器

    用于完成和客户端建立链接,接受并解析请求,转发请求,调用 Web 框架处理业务并生成返回内容,组织并返回内容给客户端,关闭链接等工作,比如 Nginx,Gunicorn,uWSGI 等就是 Web 服务器

    Web 框架

    对 Web 服务的常用功能提取、组织、简化使用,令开发人员可以专注于业务逻辑,比如 Flask、Django 就是 Web 框架

    WSGI

    为了使得任意 Web 服务器都可以和任意 Web 框架搭配,设计出了 WSGI(Web Server Gateway Interface)接口协议,凡是符合 WSGI 协议的 Web 服务器和 Web 框架都可以搭配使用(注意:uWSGI 和 WSGI 是两个概念,uWSGI 是一个实现了 WSGI 协议的 Web 服务器)

    prefork

    prefork 是一种服务端编程模型,Gunicorn, uWSGI 都是这种模型的实现
    prefork 就是有一个 master 进程 fork 出多个 worker 子进程,由子进程处理请求,master 进程只负责监控worker 子进程状态,如果子进程出现问题,可以重启一个,子进程监听同一端口,可以配置 reuse_port 参数在worker 进程间负载均衡,为了避免多线程编程带来的问题,通常设置一个 worker 就一个线程用于处理请求,同时使用协程模块比如 gevent 使得一个线程可以高效地处理高并发 IO 请求

    Gunicorn

    Green Unicorn(绿色独角兽)是一个满足 WSGI 协议的、轻量的、简易的、由 Python 实现的、pre-fork 模型的 Web 服务器,支持 sync、eventlet、gevent、tornado、gthread、gaiohttp 等多种 worker 类型

    uWSGI

    uWSGI 是由 C 语言实现的、满足 WSGI 的、pre-fork 模型的 Web 服务器,支持 uGreen,Greenlet,Stackless,Gevent,Coro::AnyEvent,Tornado,Goroutines,Fibers 等技术,实际上 uWSGI 不仅是一个 Web 服务器,也可以作为 Web 框架,只不过一般都只是当 Web 服务器使用

    Nginx

    实际上 Gunicorn 或 uWSGI 搭配 Flask 或 Django 就可以提供 Web 服务了,但实际生产环境上经常会在前面再加一个 Nginx 服务器,哪怕 Nginx 和 Gunicorn/uWSGI 是一对一的关系,主要因为 Nginx 有一些其他服务器不具备的强大功能:

    • 负载均衡,Nginx 后面可以有多个节点处理同一个业务,可以在不同节点的服务器之间实现负载均衡
    • 地址映射和端口映射,对于处理不同业务的多个节点,Nginx 可以作为统一入口,通过地址映射隐藏后面的多个服务器
    • 静态文件支持,经过配置之后,Nginx 可以直接处理静态文件请求,不需要经过 Gunicorn/uWSGI 服务器,Gunicorn/uWSGI 服务器负责处理动态请求
    • 伪静态,通过 rewrite 配置实现伪静态,比如把 index.html 指向到一个 test.php?v=1 的动态请求,伪静态会增加性能损耗
    • 缓存静态和伪静态页面,对于静态页面,或是一定时间内不会变化的伪静态页面,可以缓存起来,设置一个超时时间,这样 Nginx 就可以不用每次都去读文件,或是每次都要动态生成页面
    • 缓冲请求和响应,如果由于网络问题,导致请求和响应比较慢,可能会占用 Web 服务器的资源,影响业务逻辑的处理,而 Nginx 可以做缓冲,等收到完整的连接、请求消息后,再发给后端处理,收到后端返回后,立刻响应后端,再将消息响应到前端,这样在后端的 Web 服务器看起来,网络的请求响应都非常快,自己主要时间都是在处理业务逻辑,而相应的缓冲请求响应的工作又是 Nginx 比较擅长的,这样就提高了性能
    • Nginx 的高可用性,高并发抗压能力,都比较强
    • 访问控制、限速等功能
    • 避免直接暴露 WSGI 服务器,可以同时作为防火墙防御网络攻击

    Supervisor

    为了防止 Gunicorn/uWSGI 等意外挂了,通常可以加一个 Supervisor 做监控 master 进程

    Flask

    一个 Python 的 Web 框架,主要基于 Werkzeug 和 jinja2

    Werkzeug 是一个 WSGI 工具包,它实现了请求,响应对象和实用函数,Flask 通过 Werkzeug 实现 WSGI 协议,同时 Werkzeug 还提供了一个 WSGI 服务器,Flask 默认就是使用 Werkzeug 服务器,但一般只是用于开发调式,生产环境还是用 Gunicorn 等服务器,因为 Werkzeug 服务器性能差一些

    jinja2 是 Python 的一个模板引擎,用于渲染生成 HTML 页面

    Flask + Gunicorn + Nginx 简例

    安装 flask

    pip install flask
    pip install flask_restplus     ## 方便实现 REST API 的扩展,不是必须的
    

    flask 代码 flask_test.py

    import time
    
    from flask import Flask
    from flask import request
    from flask import Response
    
    from flask_restplus import Api
    from flask_restplus import Resource
    
    from functools import wraps
    
    app = Flask(__name__)
    
    api = Api(app, version='1.0', doc='/doc', title='Test API', description='Test API')
    '''
    api = Api(None, version='1.0', doc='/doc', title='Test API', description='Test API')
    api.init_app(app)
    '''
    
    
    def time_it(func):
        @wraps(func)
        def time_it_decorated(*args, **kwargs):
            start_time = time.time()
            result = func(*args, **kwargs)
            end_time = time.time()
            print(f"time consumption : {end_time - start_time}
    ")
            return result
    
        return time_it_decorated
    
    
    count = {}
    
    
    def count_it(url_type):
        def count_it_decorated(func):
            @wraps(func)
            def new_func(*args, **kwargs):
                if url_type not in count:
                    count[url_type] = 0
    
                count[url_type] += 1
    
                print(f"receive {url_type} request : {count[url_type]}
    ")
                return func(*args, **kwargs)
    
            return new_func
    
        return count_it_decorated
    
    
    ns = api.namespace('api_v1', path='/api/v1/', description='Test Interface', decorators=[time_it])
    
    USE_NAMESPACE = False
    
    if USE_NAMESPACE:
        @ns.route('/test')
        class Test(Resource):
            @count_it("test_1")
            def get(self):
                return Response(f"Hello {request.remote_addr}
    current time is {time.time()}
    ")
    
            @count_it("test_2")
            def post(self):
                time.sleep(5)
                return Response(f"Hello {request.remote_addr}
    ")
    else:
        @app.route('/test/1', methods=['GET'])
        @time_it
        @count_it("test_1")
        def test():
            return f"Hello {request.remote_addr}
    current time is {time.time()}
    "
    
        @app.route('/test/2', methods=['POST'])
        @time_it
        @count_it("test_2")
        def test_2():
            time.sleep(5)
            return f"Hello {request.remote_addr}
    "
    
    
    if __name__ == '__main__':
        app.run()
    
    

    可以直接运行这个 flask 程序,这时用的是 Werkzeug 自带的服务器

    python3.6 flask_test.py
    

    安装 Gunicorn

    pip3.6 install gunicorn
    pip3.6 install gevent     # 使用 gevent 模式才需要,不是必须的
    

    创建 Gunicorn 配置文件 gunicorn_config.py (也可以通过 gunicorn 参数指定,但通过配置文件更方便)

    import gevent.monkey
    gevent.monkey.patch_all()       # 使用 gevent 模式才需要这步
    
    import multiprocessing
    
    debug = True
    loglevel = "debug"
    accesslog = "./access.log"
    errorlog = "./error.log"
    #daemon = True
    #capture_output = True
    
    bind = '127.0.0.1:8000'
    
    workers = multiprocessing.cpu_count() * 2 + 1
    worker_class = 'gevent'
    
    preload_app = True
    reload = True
    
    x_forwarded_for_header = 'X-FORWARDED-FOR'
    proxy_allow_ips = '*'
    
    

    启动 gunicorn 服务器

    sudo gunicorn -c gunicorn_config.py flask_test:app
    

    安装 Nginx

    sudo apt-get install nginx
    

    Nginx 配置

    /etc/nginx/nginx.conf
    

    这个配置文件会引入下面两个目录的配置文件

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
    

    创建 /etc/nginx/conf.d/flask_test.conf (配置文件可以有多个)

    server {
        listen       80;
        server_name  localhost;
    
        # location 的 URL 匹配语法
        # ~* 表示正则表达式,不区分大小写
        # ~  表示正则表达式,要区分大小写
        # =  表示精确匹配
        # 没有修饰符的,以指定模式开始,比如 location / 匹配所有以 / 开始的 URL
    
        # 静态页面,直接读取 html 文件
        location ~* .*.html$ {
            gzip on;
            root /usr/share/nginx/html;
        }
            
        # 动态页面,转发给 gunicorn
        location / {
            proxy_pass http://127.0.0.1:8000;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
    

    检测配置

    sudo nginx -t
    

    启动

    sudo nginx
    

    sudo nginx -s reload
    

    如果需要负载均衡,配置如下

    upstream flask_test {
        server 192.168.1.2:8001;
        server 192.168.1.3:8002;
    }
    
    server {
        listen       80;
        server_name  localhost;
    
        # 动态页面,转发给 gunicorn
        location / {
            proxy_pass http://flask_test;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
    


  • 相关阅读:
    ASP.NET Core 中文文档 第四章 MVC(3.2)Razor 语法参考
    ASP.NET Core 中文文档 第四章 MVC(3.1)视图概述
    ASP.NET Core 中文文档 第四章 MVC(2.3)格式化响应数据
    ASP.NET Core 中文文档 第四章 MVC(2.2)模型验证
    ASP.NET Core 中文文档 第四章 MVC(2.1)模型绑定
    ASP.NET Core 中文文档 第四章 MVC(01)ASP.NET Core MVC 概览
    mysql 解除正在死锁的状态
    基于原生JS的jsonp方法的实现
    HTML 如何显示英文单、双引号
    win2008 r2 服务器php+mysql+sqlserver2008运行环境配置(从安装、优化、安全等)
  • 原文地址:https://www.cnblogs.com/moonlight-lin/p/12828452.html
Copyright © 2011-2022 走看看