Tornado +jinja2+pymysql 与nginx部署+supervisor监控

Tornado异步框架深度解析:从事件循环到高并发实战 异步编程是现代高性能Web服务的核心技术,其核心思想是通过非阻塞I/O和事件驱动模型,让单线程在等待I/O操作时能够处理其他任务,从而极大提升服务器的并发处理能力。这种模型特别适合I/O密集型应用,如实时通信、API网关和高并发请求场景。Tornado作为Python生态中一个成熟且纯粹的异步网络框架,其核心价值在于原生、高效地解决了C10K乃至C100K问题。它通过事件循环(Event Loop)和IOLoop实现高效调度,并提供了基于协程的异步编程范式,让开发者能够以接近同步代码的清晰度编写高性能异步应 阅读详情
前言

Django本身是同步框架,采用wsgi协议与web服务器进行交互,而web服务器都是基于多线程去处理多个请求,这种情况下如果要处理高并发就很难应对。

Tornado为了解决高并发的性能问题,使用异步非阻塞的处理方式。其原理是tornado的核心io循环模块,底层封装了Linux的I/O复用模型epoll。

概述

tornado三大组件

  • tornado.web

RequestHandler-封装了处理请求的所有方法,get,post等方法监听同名方法的请求,write方法为响应请求内容。

Application-作为服务器的入口组件,初始化参数中配置请求路由地址。

  • tornado.ioloop

current方法返回当前IOLoop实例,start方法打开服务器监听。

  • tornado.httpserver

HTTPServer方法可以传入Application实例,该方法为tornadohttp服务器的实现。

Demo项目

tornado 4.2+jinja2+pymysql/peewee/sqlachemy

部署环境 centos 6.2+nginx

简述:

该项目采用jinja2作为模板引擎(django模板使用方式非常接近),数据库交互方式采用pymysql非orm框架,当然也可以选用peewee,sqlachemy轻量级的orm框架,如果考虑到性能,pymysql作为首选。

一、项目目录结构

handlers目录为处理请求的主目录


1.db

config.py连接数据库配置

# -*- coding:utf-8 -*-
from utils.aesimp import decrypt_aes

# Mysql config
mysql_db_config = {
    'db':'tornado',
    'host':'localhost',
    'port':3306,
    'user':'root',
    # 数据库密码采用非明文的方式
    'password': decrypt_aes('SPivfEfVD9cr9/g9nxY3rw=='),
    'charset': 'utf8'
}

connections.py管理数据库连接,这里采用单连接的方式,如果需要可以拓展成连接池的方式

# -*- coding:utf-8 -*-
import pymysql
from contextlib import contextmanager
from config import mysql_db_config


# 该上下文装饰器用于自动管理数据连接的创建和关闭,不需每次手动去执行
@contextmanager
def connect(cursor_type=pymysql.cursors.DictCursor):
    conn = pymysql.connect(**mysql_db_config)
    cursor = conn.cursor(cursor=cursor_type)
    try:
        yield cursor
    finally:
        conn.commit()
        conn.close()
        cursor.close()

2.handlers

indexhandler.py 处理首页请求,没有业务逻辑,渲染一个页面给前端

# -*- coding:utf-8 -*-
from tornado.web import RequestHandler
import uuid


class IndexHandler(RequestHandler):

    def get(self, *args, **kwargs):
        page_dict = dict()
        page_dict['order_forms'] = [
            {'name':'order_id','value':str(uuid.uuid4()).replace("-", "")[:24],'lable':u'订单号'},
            {'name':'order_amt','value':'','lable':u'订单金额'},
            {'name':'order_curr','value':'156','lable':u'订单币种'},
        ]
        self.render("index.html",**page_dict)

其他业务处理通用,可以自己根据业务需求进行设计

3.static用于存放css,js,image等静态文件

4.template用于存放html模板

ps:jinja2模板与django类似,支持模板的继承和子模块的重写,为了提高复用,这里拆分出来几个模板。

{% block name %}{% endblock %}name不能使用'-'符号骂人,这是一个坑

  • base.html-模板的基本骨架

<!DOCTYPE html>
<html>
<head>

    <meta charset="utf-8">
    <meta name="test" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">

    <title>{% block title %}{% endblock %}</title>
    <!-- 引入通用样式-->
    <!-- static_url动态转义成静态文件static目录地址-->
    <link href="{{ static_url('css/bootstrap.min.css') }}" rel="stylesheet">
    <link href="{{ static_url('font-awesome/css/font-awesome.css') }}" rel="stylesheet">
    <link href="{{ static_url('css/style.css') }}" rel="stylesheet">
    <!--子模板中可以引入额外的样式-->
    {% block extrastyle %}{% endblock %}

</head>

<body>
    <div id="wrapper">
        <!--左侧导航栏,这里直接引入了模板,可以继承或者重载-->
        {% block leftsidebar %}
            {% include 'left-nav.html' %}
        {% endblock %}
        <div id="page-wrapper" class="gray-bg dashbard-1">
            {% block breadcrumb %}
                {% include 'breadcrumb.html' %}
            {% endblock %}
            <!--显示内容的区域-->
            {% block content %}{% endblock %}
        </div>
    </div>
    <!-- Mainly scripts -->
    <!-- js放置页面底部引入可以加速页面渲染 -->
    <script src="/static/js/jquery-2.1.1.js"></script>
    <script src="/static/js/bootstrap.min.js"></script>
    {% block extrascript %}{% endblock %}
</body>
</html>
  • index.html
{# 支持继承通用模板 #}
{% extends 'base.html' %}
{% block content %}
    {# macro为自定义函数,支持传递参数 #}
    {% macro input(name,value,label) %}
        <div class="col-sm-4">
            <div class="form-group">
                <label class="control-label" for="{{ label | replace(' ','_') | lower }}">{{ label }}</label>
                <input type="text" id="{{ name }}" name="{{ name }}" value="{{ value }}" class="form-control"  >
            </div>
        </div>
    {% endmacro %}
    <div class="wrapper wrapper-content animated fadeInRight ecommerce">
        <div class="ibox-content m-b-sm border-bottom">
            <div class="row">
                {# 该标签支持server端响应内容 #}
                {% for feild in order_forms %}
                    {{ input(feild.name,feild.value,feild.lable) }}
                {% endfor %}
            </div>
            <div class="row">
                <div class="ibox-content">
                    <button id="submit" class="btn btn-primary pull-right">
                        <i class="fa fa-shopping-cart"></i>
                        提交订单
                    </button>
                </div>
            </div>
        </div>
    </div>
{% endblock %}

5.application.py

控制handlers的一个集合容器,初始化时还可以以dict形式配置httpserver的参数

# -*- coding:utf-8 -*-
import tornado.web
import os
from urls import *
from utils.jinjaloader import JinjaLoader

settings = {
    "cookie_secret": "bZJc2sWbQLKos6GkHn/VB9oXwQt8S0R0kRvJ5/xJ89E=",
    "xsrf_cookies": True,
    # 这里为引入jinja2模板引擎的关键配置
    "template_loader": JinjaLoader(os.path.join(os.path.dirname(__file__), 'templates/')),
    "template_path": os.path.join(os.path.dirname(__file__), "templates"),
    "static_path": os.path.join(os.path.dirname(__file__), "static"),
    "debug": True,
    "autoreload": True  # debug为True模式下,允许自动重载
}

application = tornado.web.Application(handlers=urls, **settings)

6.urls.py


映射路由地址与handler

# -*- coding:utf-8 -*-
from handlers import *
from tornado.web import url, RedirectHandler

urls = [
    # 支持使用url进行配置别名name,Application.reverse_url可以转义出实际路由地址
    url(r"/test/order/", OrderHandler, name='order'),
    url(r"^/$", IndexHandler, name='index'),
    # 支持路由地址参数化,这里使用了tornado自带重定向handler,需要传递url这个参数
    (r"/redirect/P?<url>.*", RedirectHandler, dict(url='/test/order/')),
]

7.server.py


项目启动程序,ioloop启动服务监听

# -*- coding:utf-8 -*-
import tornado.ioloop
import tornado.options
import tornado.httpserver
from application import application
from tornado.options import define,options

define("port",default=8123,help="run on th given port",type=int)


def main():

    tornado.options.parse_command_line()
    http_server = tornado.httpserver.HTTPServer(application)
    # http_server.listen(options.port)
    http_server.bind(options.port)
    # start()传入参数可以启动子进程数目,如果<=0,启动数量和cpu核数
    http_server.start(0)
    print('Development server is running at http://127.0.0.1:%s/' % options.port)
    print('Quit the server with Control-C')
    tornado.ioloop.IOLoop.current().start()

if __name__ == "__main__":
    main()

二、tornado引入Jinja2模板

方法一、重写basehandler的render方法,目前大多数都是采用这种方式,但该方法侵入性太强。

# -*- coding:utf-8 -*-
import tornado.web
from jinja2 import Environment, FileSystemLoader, TemplateNotFound

class TemplateRender(object):
    """
    A simple class to hold methods for rendering templates.
    """
    def render_template(self, template_name, **kwargs):
        template_dirs = []
        if self.settings.get('template_path', ''):
            template_dirs.append(self.settings['template_path'])
        env = Environment(loader=FileSystemLoader(template_dirs))
        try:
            template = env.get_template(template_name)
        except TemplateNotFound:
            raise TemplateNotFound(template_name)
        content = template.render(kwargs)
        return content


class BaseHandler(tornado.web.RequestHandler, TemplateRender):
    """
    Tornado RequestHandler subclass.
    """
    def initialize(self):
        pass

    def get_current_user(self):
        user = self.get_secure_cookie('user')
        return user if user else None

    def render_html(self, template_name, **kwargs):
        kwargs.update({
          'settings': self.settings,
          'static_path': self.settings.get('static_url_prefix', '/static/'),
          'request': self.request,
          'current_user': self.current_user,
          'xsrf_token': self.xsrf_token,
          'xsrf_form_html': self.xsrf_form_html,
        })
        content = self.render_template(template_name, **kwargs)
        self.write(content)

方法二、在tornado的application中配置模板引擎,前面已经引入,下面为jinjia2的模板加载器

# -*- coding:utf-8 -*-
import threading
from tornado import template, web
import jinja2


class TTemplate(object):
    def __init__(self, template_instance):
        self.template_instance = template_instance

    def generate(self, **kwargs):
        return self.template_instance.render(**kwargs)


class JinjaLoader(template.BaseLoader):

    def __init__(self, root_directory, **kwargs):
        super(JinjaLoader,self).__init__(root_directory, **kwargs)
        self.jinja_env = jinja2.Environment(
            loader=jinja2.FileSystemLoader(root_directory), extensions=['jinja2.ext.i18n'], **kwargs
        )
        self.templates = {}
        self.lock = threading.RLock()

    def resolve_path(self, name, parent_path=None):
        return name

    def _create_template(self, name):
        template_instance = TTemplate(self.jinja_env.get_template(name))
        return template_instance

三、tornado.ioloop原理图


四、nginx部署+supervisor监控

简述:nginx作为高效的负载均衡服务器,作为反向代理可以转发到不同的tornado服务器中处理。

Supervisor是基于Python实现的监控进程的工具。

nginx配置

upstream tornados{
    server 127.0.0.1:8001; # 分发到不同端口的tornado服务器中
    server 127.0.0.1:8002;
    server 127.0.0.1:8003;
}
proxy_next_upstream error;
server {
    listen 80; #还可以支持ssl方式
    server_name www.tornado.com;

    # 静态文件直接由Nginx处理
    location /static/{
        alias /project_path/static/;
        expires 24h;
    }
    location /{
        proxy_pass_header Server;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_set_header X-Real-IP $remote_addr;
        # 把请求方向代理传给tornado服务器,负载均衡
        proxy_pass http://tornados;
    }
}

Supervisor配置

# 为了方便管理,增加一个tornado组
[group:tornados]
programs=tornado-0,tornado-1,tornado-2

# 分别定义三个tornado的进程配置
[program:tornado-0]
# 进程要执行的命令
command=python /project_path/server.py --port=8020
directory=/project_path/
user=tornado
# 自动重启
autorestart=true
redirect_stderr=true
# 日志路径
stdout_logfile=/home/user/tornado0.log
loglevel=info

[program:tornado-1]
command=python /project_path/server.py --port=8021
directory=/project_path/
user=tornado
autorestart=true
redirect_stderr=true
stdout_logfile=/home/user/tornado1.log
loglevel=info

[program:tornado-2]
command=python /project_path/server.py --port=8022
directory=/project_path/
user=tornado
autorestart=true
redirect_stderr=true
stdout_logfile=/home/user/tornado2.log
loglevel=info

基于Tornado框架的企业级Web应用实战demo Tornado框架中,是所有HTTP请求处理的核心基类。它不仅封装了对客户端请求的解析逻辑,还提供了完整的生命周期控制机制和灵活的数据输出方式。开发者通过继承并重写其方法,可以实现高度定制化的业务逻辑响应流程。与此同时,Tornado的路由系统基于正则表达式匹配,支持动态参数提取、命名分组传递以及嵌套路由组织,为构建结构清晰、可维护性强的RESTful API服务提供了坚实基础。本章将深入剖析的核心执行流程,揭示其内部方法调用顺序与异步协作机制; 阅读详情

相关推荐

Tornado Web应用开发项目模板详解

简介:Tornado是一个高性能、轻量级的Python Web框架和异步网络库,非常适合处理大量并发连接。本文深入解析了一个基于Tornado的项目模板,涵盖基本项目结构、路由和处理程序、数据库操作、模板引擎以及如何进行设置和配置。通过这个模板,开发者能够快速搭建和运行自己的Tornado应用,并了解如何部署和优化应用,以满足生产环境的需求。

weixin_42298254的博客 905

pymysql 与tornado数据库的交互。和使用。

import pymysql import tornado.httpserver import tornado.ioloop import tornado.options import tornado.web from tornado.options import define,options define('port', default=8000, help='run port', type...

KEELON的博客 788

Tornado-MySQL:用于Tornado的PyMySQL分支

Tornado-MySQL:用于Tornado的PyMySQL分支

python中操作mysql的pymysql模块详解

       pymsql是Python中操作MySQL的模块,其使用方法和MySQLdb几乎相同。但目前pymysql支持python3.x而后者不支持3.x版本。 本文测试python版本:3.5.2。mysql版本:5.7.18 一、安装 pip install pymysql 二、使用操作 1. 执行SQL #!/usr/bin/env python ...

ronon77的专栏 805

tornado_react:测试 PyReact + Tornado + Jinja2 + reactjs

概念证明 测试 PyReact + Tornado + Motor + Jinja2 + reactjs $ mkdir tornado_react && cd tornado_react $ virtualenv --no-site-packages -p python3.4 . $ source bin/activate $ git clone https://github.com/slothyrulez/tornado_react.git $ svn checkout http://v8.googlecode.com/svn/trunk/ v8 $ svn checkout http://pyv8.googlecode.com/svn/trunk/ pyv8 $ cd v8 $ export V8_HOME=`pwd` $ cd ../pyv8 $ python

Python的Tornado框架实现异步非阻塞访问数据库的示例

Tornado框架的异步非阻塞特性是其最大的亮点,这里我们将立足于基础来介绍一种简单的Python的Tornado框架实现异步非阻塞访问数据库的示例:

tornado 入门之(MySQL+Pymysql)【5】

标题 tornado 入门之(MySQL+Pymysql)酱酱仙的博客【5】 连接数据库的准备 安装pymysql pip install pymysql 安装 SQLAlchemy pip install sqlalchemy 安装Mysql 安装Navicat for MySQL 提取码:ytue 安装Postman 客户端连接mysql,问题:1251 client do...

洋洋的博客 617

B站充电视频下载器(需配合会员Cookie使用,仅供学习交流,Python)

这个程序是一个用于下载B站充电视频的工具,依赖于用户提供的会员Cookies。

qq_40753021的博客 2万+

为tornado框架支持jinja2

Jinja2是人气Web框架Flask中的内置模板引擎,而且与Django的模板引擎比较类似,这里我们就来看一下为Python的Tornado框架配置使用Jinja2模板引擎的方法 tornado 默认有一个模板引擎但是功能简单(其实我能用到的都差不多)使用起来颇为麻烦, 而jinja2语法与django模板相似所以决定使用他. 下载jinja2 还是用pip 下载 p

hqzxsc2006的专栏 1368

S7-1200模拟量

将两种不同的金属或合金金属焊接起来,构成一个闭合回路,利用温差电动势来测量温度,当两端存在温度梯度时,回路中就会有电流通过,此时两端之间就存在电动势--热电动势,这就是所谓的塞贝克效应(seebeck effect)。温差越大,热电动势越高。热电偶是有正负极性的,所以需要确保导线连接到正确的极性,否则会造成明显的测量误差。为了使温度补偿达到最佳效果,必须将热电偶模块安装在温度稳定的环境中简述:两种金属,每一种金属随温度变化是不同的,出现温差--由俩金属构成的回路就会有电流经过,因此两端形成热电动势。

王阿妹小天才的博客 2593

Window系统下搭建GIT本地服务器

这是一篇在window下搭建git本地服务器的教程,带你一步步搭建出本地的git服务器。

qwer971211的博客 2万+

Tornado使用同步Mysql

Tornado是一个异步网络服务框架

大隐隐于市 3616

RK3588开发板实战:从零开始移植Ubuntu 24.04(讯为SDK版)

本文详细介绍了如何在RK3588开发板上从零开始移植Ubuntu 24.04系统(讯为SDK版),涵盖开发环境准备、SDK解析、根文件系统定制、驱动适配、系统集成与烧录等全流程。通过实战案例,帮助开发者快速掌握RK3588开发板的系统移植技巧,适用于嵌入式开发与定制化Linux系统构建。

sand8的博客 438

Tornado Web 开发 框架搭建 (2)

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34342992的博客 150

OpenClaw人人养虾:接入Synology Chat

Synology Chat 是群晖 NAS(Network Attached Storage,网络附属存储)内置的即时通讯应用。

王国平的博客 781

OpenClaw 子代理配对失败问题分析与解决方案

OpenClaw子代理配对失败问题分析与解决方案 问题核心在于agent设备权限不足,仅有operator.approvals权限而缺少operator.admin权限,导致子代理启动时形成权限死锁。本文提供三种解决方案: 直接编辑设备配对文件(推荐):修改本地JSON文件,为agent设备添加完整operator.admin权限,操作简单快捷。 标准重新配对流程:删除现有agent设备后重新配对,通过正常审批流程获取完整权限,符合系统安全设计。 修改源码降低权限要求(仅限开发环境):调整子代理代码避免强制

多媒体编程、网络编程、系统编程、网络安全编程、驱动编程 151

推荐使用:Tornado-MySQL——异步处理MySQL的高效工具

推荐使用:Tornado-MySQL——异步处理MySQL的高效工具 项目介绍 Tornado-MySQL 是一个基于 PyMySQL 的扩展库,专为支持 Tornado 框架的异步操作而设计。虽然此项目被认为是实验性和未维护的,但对那些寻求在非阻塞环境中进行MySQL交互的开发者来说,它仍然可以提供有用的解决方案。 项目技术分析 Tornado-MySQL 实现了与 MySQL 数据库的连接和查...

gitblog_00053的博客 602

《Zephyr OS 入门与实战》第15章:LoRaWAN 集成

【代码】《Zephyr OS 入门与实战》第15章:LoRaWAN 集成。

2301_79143213的博客 612

搭建Tornado Https服务器之Tornado连接MySql数据库(4-1基本操作)

tornado通过pymysql连接mysql数据库

江湖人称王某人的程序员 754

CloudCompare 二次开发(17)——点云添加均匀分布的随机噪声

使用CloudCompare编程实现点云添加随机噪声。

点云侠的博客 840

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Python Web: Tornado连接mysql数据库

Tornado有一个自己的操作数据库模块torndb,而torndb是依赖于MySQLdb实现的对MySQL数据库操作,但是python3中不支持MySQLdb,而是使用pymysql。 pymysql连接数据库 连接配置 配置文件application.py加入: mysql = dict( host = "127.0.0.1", user = "root", password = "root" ) 建立连接 ...

sinat_37623490的博客 1363

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

tornado连接mysql数据库与pymysql的简单操作

       本人的python是3.5,由于3.0后用的是pymysql,就不能用tornado自带的torndb来进行简单的连接操作。Application这个类是初始化一些全局变量,按照道理说里边的self.db 也应该能够被其他类或者派生类调用的,但是db这个属性就是不行,无奈只好创建了一个全局的db句柄,然后在HouseHandler类中根据这个db初始化一个实例。当然要在Aplicat...

runner668的博客 1万+

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

【运维知识进阶篇】Ansible Jinja2模板详解

哈喽大家好,我是koten,本篇文章给大家介绍jinja2模板,这是python的全功能模板引擎。在Ansible中,通常会使用jinja2模板来修改被管理主机的配置文件(saltstack中也会用到)Ansible中使用的jinja2模板其实就是使用template模块,该模块与copy模块一样,都有复制管理机的配置文件到客户机的作用,区别在于template模块可以获取到文件中的变量,而copy则是原封不动把文件内容复制过去。如:我们想把脚本中的变量名改成主机名,如果使用copy推送的就是{

吾日三省吾身,想出类拔萃,要把知识学牢,学全,学深,学广。 2073

Tornado框架配置使用Jinja2模板引擎

安装jinja2包 pip install jinja2 定义继承tornado.web.RequestHandler的子类BaseHandler。如果请求处理类继承这个类将会使用jinja模板引擎;如果请求处理类继承tornado.web.RequestHandler,则会使用Tornado框架的模板引擎。 1 import os 2 3 from j...

diaoli4010的专栏 338

[Jinja2]基本使用

1.介绍Jinja2是python的一种模板语言,以Django的模板语言为原本,和Django的模板语言有很多相似之处,同时Jinja本身也是一种系统的、完整的Python模板语言。2.为什么需要模板语言在html中写for if或者其他流程控制语句? 在html中使用include、extend等方法复用html? …考虑到我们用Python做web开发的情况,首先我们既想后台业务逻辑的代码

u011056389的专栏 1万+

tornado连接mysql

Tornado参考链接:http://demo.pythoner.com/itt2zh/index.html 环境:centos 6.7, tornado 4.4.2,python 3.5.1 1、 MySQLdb Python 2.x 上连接MySQL的库比较多,其中比较著名就是MySQLdb, 大名鼎鼎的Django项目都使用它。地址见: http://sourceforge.ne

厚积薄发的博客 8207
上一篇: Django models,forms,session,cache,crsf,模板标签
下一篇: Twisted 使用心得
core_coder
博客等级 码龄11年 4粉丝 6原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值