zoukankan      html  css  js  c++  java
  • 第一个python flask web服务实践

    本文参考flask+Gunicorn 的实例和配置,在本地启动flask服务。
    Gunicorn 配置可以参考python gunicorn详解
    首先看下测试代码结构:

    - web
      - __init__.py
      - access.log
      - app_run.log
      - flask_simple.py
      - gunicorn_config.py 
      - meinheld_gunicorn_config.py
    

    单flask

    • 编写 flask_simple.py 文件:
    from flask import Flask, request
    import time
    
    my_app = Flask(__name__) #flask实例名字为 my_app
    my_app.config['JSON_AS_ASCII'] = False
    
    # http://127.0.0.1:5001/app,这里装饰方法的名字与实例名字一致:my_app
    @my_app.route('/app', methods=['GET'])
    def func():
        # time.sleep(5)
        return 'simple flask demo'
    
    
    if __name__ == "__main__":
        my_app.run() #默认http://127.0.0.1:5000/,启动使用实例名字 my_app
    
    • PyCharm 启动,启动日志:
     * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
     * Serving Flask app "flask_simple" (lazy loading)
     * Environment: production
       WARNING: Do not use the development server in a production environment.
       Use a production WSGI server instead.
     * Debug mode: off
    
    • terminal执行:python flask_simple.py ,启动日志:
     * Serving Flask app "flask_simple" (lazy loading)
     * Environment: production
       WARNING: Do not use the development server in a production environment.
       Use a production WSGI server instead.
     * Debug mode: off
     * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
    
    • 浏览器请求 http://127.0.0.1:5000/app,返回 simple flask demo

    gunicorn+gevent

    • 编写文件 gunicorn_config.py,如下:
    # 多进程
    import multiprocessing
    
    """gunicorn+gevent 的配置文件"""
    '''执行:gunicorn -c gunicorn_config.py flask_simple:my_app
    '''
    
    # 预加载资源
    preload_app = True
    # 绑定 ip + 端口
    bind = "127.0.0.1:5000"
    # 进程数 = cup数量 * 2 + 1
    workers = multiprocessing.cpu_count() * 2 + 1
    
    # 线程数 = cup数量 * 2
    threads = multiprocessing.cpu_count() * 2
    
    # 等待队列最大长度,超过这个长度的链接将被拒绝连接
    backlog = 2048
    
    # 工作模式--协程
    worker_class = "gevent"
    
    # 最大客户客户端并发数量,对使用线程和协程的worker的工作有影响
    # 服务器配置设置的值  1200:中小型项目  上万并发: 中大型
    # 服务器硬件:宽带+数据库+内存
    # 服务器的架构:集群 主从
    worker_connections = 1200
    
    # 进程名称
    proc_name = 'gunicorn.pid'
    # 进程pid记录文件
    pidfile = 'app_run.log'
    # 日志等级
    loglevel = 'debug'
    # 日志文件名
    logfile = 'debug.log'
    # 访问记录
    accesslog = 'access.log'
    # 访问记录格式
    access_log_format = '%(h)s %(t)s %(U)s %(q)s'
    
    • terminal 执行 gunicorn -c gunicorn_config.py flask_simple:my_app
    • gunicorn_config.py 为配置文件的名字
    • flask_simple 是模块名,要启动的文件名字,即flask_simple.py 的文件名
    • my_app 为Flask实例名字,见flask_simple.py内。
    查看 运行成功日志
    [2021-09-06 23:20:28 -0700] [23069] [DEBUG] Current configuration:
     config: gunicorn_config.py
     wsgi_app: None
     bind: ['127.0.0.1:5000']
     backlog: 2048
     workers: 25
     worker_class: gevent
     threads: 24
     worker_connections: 1200
     max_requests: 0
     max_requests_jitter: 0
     timeout: 30
     graceful_timeout: 30
     keepalive: 2
     limit_request_line: 4094
     limit_request_fields: 100
     limit_request_field_size: 8190
     reload: False
     reload_engine: auto
     reload_extra_files: []
     spew: False
     check_config: False
     print_config: False
     preload_app: True
     sendfile: None
     reuse_port: False
     chdir: /Users/danxiao/python/study_demo/web
     daemon: False
     raw_env: []
     pidfile: app_run.log
     worker_tmp_dir: None
     user: 501
     group: 20
     umask: 0
     initgroups: False
     tmp_upload_dir: None
     secure_scheme_headers: {'X-FORWARDED-PROTOCOL': 'ssl', 'X-FORWARDED-PROTO': 'https', 'X-FORWARDED-SSL': 'on'}
     forwarded_allow_ips: ['127.0.0.1']
     accesslog: access.log
     disable_redirect_access_to_syslog: False
     access_log_format: %(h)s %(t)s %(U)s %(q)s
     errorlog: -
     loglevel: debug
     capture_output: False
     logger_class: gunicorn.glogging.Logger
     logconfig: None
     logconfig_dict: {}
     syslog_addr: unix:///var/run/syslog
     syslog: False
     syslog_prefix: None
     syslog_facility: user
     enable_stdio_inheritance: False
     statsd_host: None
     dogstatsd_tags: 
     statsd_prefix: 
     proc_name: gunicorn.pid
     default_proc_name: flask_simple:my_app
     pythonpath: None
     paste: None
     on_starting: <function OnStarting.on_starting at 0x1020d2830>
     on_reload: <function OnReload.on_reload at 0x1020d2950>
     when_ready: <function WhenReady.when_ready at 0x1020d2a70>
     pre_fork: <function Prefork.pre_fork at 0x1020d2b90>
     post_fork: <function Postfork.post_fork at 0x1020d2cb0>
     post_worker_init: <function PostWorkerInit.post_worker_init at 0x1020d2dd0>
     worker_int: <function WorkerInt.worker_int at 0x1020d2ef0>
     worker_abort: <function WorkerAbort.worker_abort at 0x1020e9050>
     pre_exec: <function PreExec.pre_exec at 0x1020e9170>
     pre_request: <function PreRequest.pre_request at 0x1020e9290>
     post_request: <function PostRequest.post_request at 0x1020e9320>
     child_exit: <function ChildExit.child_exit at 0x1020e9440>
     worker_exit: <function WorkerExit.worker_exit at 0x1020e9560>
     nworkers_changed: <function NumWorkersChanged.nworkers_changed at 0x1020e9680>
     on_exit: <function OnExit.on_exit at 0x1020e97a0>
     proxy_protocol: False
     proxy_allow_ips: ['127.0.0.1']
     keyfile: None
     certfile: None
     ssl_version: 2
     cert_reqs: 0
     ca_certs: None
     suppress_ragged_eofs: True
     do_handshake_on_connect: False
     ciphers: None
     raw_paste_global_conf: []
     strip_header_spaces: False
    [2021-09-06 23:20:28 -0700] [23069] [INFO] Starting gunicorn 20.1.0
    [2021-09-06 23:20:28 -0700] [23069] [DEBUG] Arbiter booted
    [2021-09-06 23:20:28 -0700] [23069] [INFO] Listening at: http://127.0.0.1:5000 (23069)
    [2021-09-06 23:20:28 -0700] [23069] [INFO] Using worker: gevent
    [2021-09-06 23:20:28 -0700] [23075] [INFO] Booting worker with pid: 23075
    [2021-09-06 23:20:28 -0700] [23076] [INFO] Booting worker with pid: 23076
    [2021-09-06 23:20:28 -0700] [23077] [INFO] Booting worker with pid: 23077
    [2021-09-06 23:20:28 -0700] [23078] [INFO] Booting worker with pid: 23078
    [2021-09-06 23:20:28 -0700] [23080] [INFO] Booting worker with pid: 23080
    [2021-09-06 23:20:28 -0700] [23081] [INFO] Booting worker with pid: 23081
    [2021-09-06 23:20:28 -0700] [23083] [INFO] Booting worker with pid: 23083
    [2021-09-06 23:20:28 -0700] [23084] [INFO] Booting worker with pid: 23084
    [2021-09-06 23:20:28 -0700] [23085] [INFO] Booting worker with pid: 23085
    [2021-09-06 23:20:28 -0700] [23086] [INFO] Booting worker with pid: 23086
    [2021-09-06 23:20:29 -0700] [23087] [INFO] Booting worker with pid: 23087
    [2021-09-06 23:20:29 -0700] [23088] [INFO] Booting worker with pid: 23088
    [2021-09-06 23:20:29 -0700] [23089] [INFO] Booting worker with pid: 23089
    [2021-09-06 23:20:29 -0700] [23090] [INFO] Booting worker with pid: 23090
    [2021-09-06 23:20:29 -0700] [23091] [INFO] Booting worker with pid: 23091
    [2021-09-06 23:20:29 -0700] [23092] [INFO] Booting worker with pid: 23092
    [2021-09-06 23:20:29 -0700] [23093] [INFO] Booting worker with pid: 23093
    [2021-09-06 23:20:29 -0700] [23094] [INFO] Booting worker with pid: 23094
    [2021-09-06 23:20:29 -0700] [23095] [INFO] Booting worker with pid: 23095
    [2021-09-06 23:20:29 -0700] [23096] [INFO] Booting worker with pid: 23096
    [2021-09-06 23:20:29 -0700] [23100] [INFO] Booting worker with pid: 23100
    [2021-09-06 23:20:29 -0700] [23101] [INFO] Booting worker with pid: 23101
    [2021-09-06 23:20:29 -0700] [23102] [INFO] Booting worker with pid: 23102
    [2021-09-06 23:20:29 -0700] [23103] [INFO] Booting worker with pid: 23103
    [2021-09-06 23:20:29 -0700] [23104] [INFO] Booting worker with pid: 23104
    [2021-09-06 23:20:29 -0700] [23069] [DEBUG] 25 workers
    
    • 运行成功之后,可以看到新生成的两个文件access.logapp_run.log

      • 浏览器中执行 http://127.0.0.1:5000/app 都会记录在 access.log中。
      • 本服务的pid保存在 app_run.log 中,打开可以看到pid。如果要关闭服务,terminal执行 kill -9 {pid}
    • 如果执行报错:

    Error: class uri 'gevent' invalid or not found: 
    
    [Traceback (most recent call last):
      File "/usr/local/lib/python3.7/site-packages/gunicorn/workers/ggevent.py", line 13, in <module>
        import gevent
    ModuleNotFoundError: No module named 'gevent'
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "/usr/local/lib/python3.7/site-packages/gunicorn/util.py", line 99, in load_class
        mod = importlib.import_module('.'.join(components))
      File "/usr/local/Cellar/python@3.7/3.7.10_3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/importlib/__init__.py", line 127, in import_module
        return _bootstrap._gcd_import(name[level:], package, level)
      File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
      File "<frozen importlib._bootstrap>", line 983, in _find_and_load
      File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
      File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
      File "<frozen importlib._bootstrap_external>", line 728, in exec_module
      File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
      File "/usr/local/lib/python3.7/site-packages/gunicorn/workers/ggevent.py", line 15, in <module>
        raise RuntimeError("gevent worker requires gevent 1.4 or higher")
    RuntimeError: gevent worker requires gevent 1.4 or higher
    ]
    

    重新安装 gunicorngevent,即:

    pip3 uninstall gunicorn
    pip3 install gunicorn
    pip3 uninstall gevent
    pip3 install gevent
    

    meinheld + gunicorn + flask

    • 编写 meinheld_gunicorn_config.py 文件,与上一个配置不同仅在于worker_class设置不一样,如下:
     import multiprocessing
    
    # gunicorn+meinheld 的配置文件
    # 运行方式 命令行 gunicorn -c meinheld_gunicorn_config.py flask_simple:my_app
    
    # 预加载资源
    preload_app = True
    # 绑定
    bind = "0.0.0.0:5000"
    # 进程数: cup数量 * 2 + 1
    workers = multiprocessing.cpu_count() * 2 + 1
    # 线程数 cup数量 * 2
    threads = multiprocessing.cpu_count() * 2
    # 等待队列最大长度,超过这个长度的链接将被拒绝连接
    backlog = 2048
    # 工作模式
    worker_class = "egg:meinheld#gunicorn_worker"
    
    # 最大客户客户端并发数量,对使用线程和协程的worker的工作有影响
    worker_connections = 1200
    
    # 进程名称
    proc_name = 'gunicorn.pid'
    # 进程pid记录文件
    pidfile = 'app_run.log'
    # 日志等级
    loglevel = 'debug'
    # 日志文件名
    logfile = 'debug.log'
    # 访问记录
    accesslog = 'access.log'
    # 访问记录格式
    access_log_format = '%(h)s %(t)s %(U)s %(q)s'
    
    • 安装 pip3 install meinheld, 报错:
    Collecting meinheld
      Using cached meinheld-1.0.2-cp37-cp37m-macosx_11_0_x86_64.whl
    Collecting greenlet<0.5,>=0.4.5
      Using cached greenlet-0.4.17-cp37-cp37m-macosx_11_0_x86_64.whl
    Installing collected packages: greenlet, meinheld
      Attempting uninstall: greenlet
        Found existing installation: greenlet 1.1.1
        Uninstalling greenlet-1.1.1:
          Successfully uninstalled greenlet-1.1.1
    ERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.
    sqlalchemy 1.4.11 requires greenlet!=0.4.17; python_version >= "3", but you have greenlet 0.4.17 which is incompatible.
    gevent 21.8.0 requires greenlet<2.0,>=1.1.0; platform_python_implementation == "CPython", but you have greenlet 0.4.17 which is incompatible.
    Successfully installed greenlet-0.4.17 meinheld-1.0.2
    

    其实是 meinheld 包依赖 greenlet 版本号范围为 [0.4.5, 0.5),而 gevent 依赖 greenlet 版本号范围为 [1.1.0, 2.0) 两者有冲突。可以使用虚拟环境解决。

    • 卸载本环境的 meinheld: pip3 uninstall meinheld
    • 使用conda 创建并激活一个新的虚拟环境: conda activate xiaoju
    • 安装meinheld: pip3 install meinheld
    • 执行:gunicorn -c meinheld_gunicorn_config.py flask_simple:my_app
      成功日志与上一个方案的一致。
  • 相关阅读:
    牛客网 二叉树的镜像 JAVA
    牛客网 反转链表 JAVA
    牛客网 调整数组顺序使奇数位于偶数前面 JAVA
    Integer to Roman LeetCode Java
    Valid Number leetcode java
    Longest Common Prefix
    Wildcard Matching leetcode java
    Regular Expression Matching
    Longest Palindromic Substring
    Add Binary LeetCode Java
  • 原文地址:https://www.cnblogs.com/shoren/p/15238178.html
Copyright © 2011-2022 走看看