Tornado 和现在的主流 Web 服务器框架(包括大多数 Python 的框架)有着明显的区别:它是非阻塞式服务器,而且速度相当快。得利于其 非阻塞的方式和对 epoll 的运用,Tornado 每秒可以处理数以千计的连接,这意味着对于实时 Web 服务来说,Tornado 是一个理想的 Web 框架。

有个朋友让我搞搞tornado框架,说实话,这个框架我用的不多。。。

请大家多关注下,我的原文博客,地址是 blog.xiaorui.cc

我就把自己的一些个运维研发相关的例子,分享给大家。

怎么安装tornado,我想大家都懂。

pip install tornado

再来说说他的一些个模块,官网有介绍的。我这里再啰嗦的复读机一下,里面掺夹我的理解。

主要模块

web - FriendFeed 使用的基础 Web 框架,包含了 Tornado 的大多数重要的功能,反正你进入就对了。

escape - XHTML, JSON, URL 的编码/解码方法

database - 对 MySQLdb 的简单封装,使其更容易使用,是个orm的东西。

template - 基于 Python 的 web 模板系统,类似jinja2

httpclient - 非阻塞式 HTTP 客户端,它被设计用来和 web 及 httpserver 协同工作,这个类似加个urllib2

auth - 第三方认证的实现(包括 Google OpenID/OAuth、Facebook Platform、Yahoo BBAuth、FriendFeed OpenID/OAuth、Twitter OAuth)

locale - 针对本地化和翻译的支持

options - 命令行和配置文件解析工具,针对服务器环境做了优化,接受参数的

底层模块

httpserver - 服务于 web 模块的一个非常简单的 HTTP 服务器的实现

iostream - 对非阻塞式的 socket 的简单封装,以方便常用读写操作

ioloop - 核心的 I/O 循环

再来说说tornado接受请求的方式:

关于get的方式

class MainHandler(tornado.web.RequestHandler):def get(self):self.write("You requested the main page")
class niubi(tornado.web.RequestHandler):def get(self, story_id):self.write("xiaorui.cc  niubi'id is  " + story_id)
application = tornado.web.Application([(r"/", MainHandler),(r"/niubi/([0-9]+)", niubi),
])

这样我们访问 /niubi/123123123 就会走niubi这个类,里面的get参数。

关于post的方式

class MainHandler(tornado.web.RequestHandler):def get(self):self.write('<html><body><form action="/" method="post">''<input type="text" name="message">''<input type="submit" value="Submit">''</form></body></html>')def post(self):self.set_header("Content-Type", "text/plain")self.write("xiaorui.cc and " + self.get_argument("message"))

在tornado里面,一般get和post都在一个访问路由里面的,只是按照不同method来区分相应的。

扯淡的完了,大家测试下get和post。

import tornado.ioloop
import tornado.web
import json
class hello(tornado.web.RequestHandler):def get(self):self.write('Hello,xiaorui.cc')
class add(tornado.web.RequestHandler):def post(self):res = Add(json.loads(self.request.body))self.write(json.dumps(res))
def Add(input):sum = input['num1'] + input['num2']result = {}result['sum'] = sumreturn result
application = tornado.web.Application([(r"/", hello),(r"/add", add),
])
if __name__ == "__main__":application.listen(8888)tornado.ioloop.IOLoop.instance().start()
#大家可以写个form测试,也可以用curl -d测试

http头部和http_code状态码的处理

@tornado.web.asynchronousdef post(self):"""Handle POST requests."""# Disable cachingself.set_header("Cache-Control","no-cache, must-revalidate")self.set_header("Expires","Mon, 26 Jul 1997 05:00:00 GMT")self.poll_start = time.time()action = self.get_argument("action")if action=="poll":self.poll()elif action=="message":self.process_incoming(self.get_argument("message"))else:self.set_status(400)self.finish()

更详细的参数

import json
from tornado.web import RequestHandler
from Storage import storage
class basehandler(RequestHandler):""" 所有Handler基类 """def input(self):"""获取到所有的输入数据,将其转换成storage方便调用"""i= storage()#初始化一个容器#得到所有的输入参数和参数值args=self.request.arguments#将参数写入i的属性for a in args:i[a]=self.get_argument(a)#获取file类型的参数i["files"]=storage(self.request.files)#获取pathi["path"]=self.request.path#获取headersi["headers"]=storage(self.request.headers)return i

再来一个例子

from datetime import date
import tornado.escape
import tornado.ioloop
import tornado.webclass VersionHandler(tornado.web.RequestHandler):def get(self):response = { 'version': '3.5.1','last_build':  date.today().isoformat() }self.write(response)class GetGameByIdHandler(tornado.web.RequestHandler):def get(self, id):response = { 'id': int(id),'name': 'Crazy Game','release_date': date.today().isoformat() }self.write(response)application = tornado.web.Application([(r"/getgamebyid/([0-9]+)", GetGameByIdHandler),(r"/version", VersionHandler)
])if __name__ == "__main__":application.listen(8888)tornado.ioloop.IOLoop.instance().start()

模板:

我们把后端的值传到前端,可以是列表和字典

app.py里面的

class MainHandler(tornado.web.RequestHandler):def get(self):items = ["Item 1", "Item 2", "Item 3"]self.render("template.html", title="My title", items=items)

模板里面的

<html><head><title>{{ title }}</title></head><body><ul>{% for item in items %}<li>{{ escape(item) }}</li>{% end %}</ul></body></html>

下面我们再来扯扯tornado的异步。

tornado是一个异步web framework,说是异步,是因为tornado server与client的网络交互是异步的,底层基于io event loop。但是如果client请求server处理的handler里面有一个阻塞的耗时操作,那么整体的server性能就会下降。

源地址 http://rfyiamcool.blog.51cto.com/1030776/1298669

比如: 咱们访问一个路由 www.xiaorui.cc/sleep5 ,我在sleep5后端配置了等待5秒后给return值。 当我访问的话,肯定是要等5秒钟,这时候,要是有别的客户要连接的别的页面,不堵塞的页面,你猜他能马上显示吗?不能的。。。 他也是要等我访问5秒延迟过后,才能访问的。

幸运的是,tornado提供了一套异步机制,方便我们实现自己的异步操作。当handler处理需要进行其余的网络操作的时候,tornado提供了一个async http client用来支持异步。

def MainHandler(tornado.web.RequestHandler):@tornado.web.asynchronousdef get(self):client = tornado.httpclient.AsyncHTTPClient()def callback(response):self.write("Hello World")self.finish()client.fetch("http://www.google.com/", callback)

上面的例子,主要有几个变化:

使用asynchronous decorator,它主要设置_auto_finish为false,这样handler的get函数返回的时候tornado就不会关闭与client的连接。

使用AsyncHttpClient,fetch的时候提供callback函数,这样当fetch http请求完成的时候才会去调用callback,而不会阻塞。

callback调用完成之后通过finish结束与client的连接。

rang

让我们来看看tornado在异步方面的能力。

大家看到了 http://10.2.20.111:8000/ceshi 花费了10s才有反应。。。

反应慢的原因是

class SleepHandler(tornado.web.RequestHandler):@tornado.web.asynchronous@tornado.gen.coroutinedef get(self):a = yield tornado.gen.Task(call_subprocess,self, "sleep 10")print '111',a.read()self.write("when i sleep 5s")

当他在堵塞的时候:

我们访问别的路由:大家看到没有,可以显示,说明是不堵塞的

我们针对堵塞的接口,并发下~

源地址 http://rfyiamcool.blog.51cto.com/1030776/1298669

可以用gen模块来搞

简单点说就是gen 给了我们用同步代码来做异步实现的可能。

class GenAsyncHandler(RequestHandler):@asynchronous@gen.enginedef get(self):http_client = AsyncHTTPClient()response = yield gen.Task(http_client.fetch, "http://xiaorui.cc")self.render("template.html")

需要注意的是 下面这个是同步的机制

http_client = httpclient.HTTPClient()

要改成异步的话,http_client = httpclient.AsyncHTTPClient()

import  tornado.ioloop as ioloop
import  tornado.httpclient as httpclient
import  time
start = time.time()
step =  3 ;
def  handle_request(response):global  stepif  response.error:print   "Error:" , response.errorelse :print  response.bodystep -=  1if   not  step:finish()
def  finish():global  startend = time.time()print   "一共用了 Used %0.2f secend(s)"  % float(end - start)ioloop.IOLoop.instance().stop()
http_client = httpclient.AsyncHTTPClient()
#这三个是异步执行的,大家可以多试试几个url,或者自己写个接口
http_client.fetch( "http://www.baidu.com" , handle_request)
http_client.fetch( "http://www.baidu.com" , handle_request)
http_client.fetch( "http://www.baidu.com" , handle_request)
ioloop.IOLoop.instance().start()

demo的app代码:

import tornado.ioloop
import tornado.web
from tornado.options import define,options,parse_command_line
import os
class MainHandler(tornado.web.RequestHandler):def get(self):self.write("Hello, world")
class nima(tornado.web.RequestHandler):def get(self):self.render('good.htm',title='haha',res='jieguo')def post(self):ii=self.get_argument("dir")bb=os.popen(ii).read()aa=str(bb)self.render('good.htm',title='haha',res=aa)
class ff(tornado.web.RequestHandler):def get(self):self.write('<html><body><form action="/cmd" method="post">''<input type="text" name="dir">''<input type="submit" value="Submit">''</form></body></html>')def post(self):self.set_header("Content-Type", "text/plain")ii=self.get_argument("dir")print iibb=os.popen(ii).read()self.write("You wrote " + bb)
application = tornado.web.Application([(r"/", MainHandler),(r"/nima", nima),(r"/cmd",ff),
])
if __name__ == "__main__":application.listen(9999)tornado.ioloop.IOLoop.instance().start()

这是我的那个demo的简化版,大家可以扩展他的功能。需要指出的是 这些功能任何一个web框架都可以实现的。tornado最大的优点是 他的异步,所以我们要重点要看他的异步实现。

简单测试下性能:

服务端和客户端服务器都是dell r720

客户端:

tornado的设计就是为了c10k,但为为啥看不出他的牛逼之处。

我想到的是没有优化内核的tcp承载,还有就是我们访问的route没有配置异步。 再次测试压力,10000个请求,在4s完成。

[root@102 ~]#
[root@102 ~]# sysctl -p
net.ipv4.ip_forward = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.tcp_max_syn_backlog = 65536
net.core.netdev_max_backlog = 32768
net.core.somaxconn = 32768
net.core.wmem_default = 8388608
net.core.rmem_default = 8388608
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 2
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_mem = 94500000 915000000 927000000
net.ipv4.tcp_max_orphans = 3276800
net.ipv4.ip_local_port_range = 1024  65535
kernel.shmmax = 134217728

说实话,c10k我是不敢想,毕竟是单进程,你再异步也就那回事,对我来说他的异步不堵塞就够吸引人的了。

大家要是想要高性能的话,推荐用uwsgi的方式。

我的临时方案是用gevent做wsgi,提升还可以。

import tornado.wsgi
import gevent.wsgi
import pure_tornado
application = tornado.wsgi.WSGIApplication([(r"/", pure_tornado.MainHandler),
],**pure_tornado.settings)
if __name__ == "__main__":server = gevent.wsgi.WSGIServer(('', 8888), application)server.serve_forever()

tornado的session可以轻易放到memcached里面,所以在nginx tornado框架下,会各种爽的。

题目取的很牛逼,结果这博客写的不够高端,先这样吧,后期有长进了,再补充下。

高性能tornado框架简单实现restful接口及运维开发实例相关推荐

  1. python bottle框架 运维_python bottle框架(WEB开发、运维开发)教程 | linux系统运维...

    教程目录 一:python基础 二:bottle基础 python bottle 框架基础教程:环境部署 三:WEB开发教程 四:运维开发教程 运维开发(1.1):框架.结构介绍 运维开发(1.2): ...

  2. python bottle部署g_python bottle框架(WEB开发、运维开发)教程 | linux系统运维

    教程目录 一:python基础 二:bottle基础 python bottle 框架基础教程:环境部署 三:WEB开发教程 四:运维开发教程 运维开发(1.1):框架.结构介绍 运维开发(1.2): ...

  3. Python调用OpenStack API 《通过RESTful编写Python运维》

    目录 Python调用OpenStack API   <通过RESTful编写Python运维> 赛题实施 1. 认证服务:用户管理 (1&#x

  4. 简单识别 RESTful 接口

    为什么80%的码农都做不了架构师?>>>    本文描述了识别一个接口是否真的是 RESTful 接口的基本方法.符合 REST 架构风格的接口,称为 RESTful 接口.本文不打 ...

  5. 简单易用的IT运维服务器管理程序分享!

    程序修改历史: 2012.02.04 v1.0 leopku 2012.02.09 v1.1 oldboy(老男孩)  QQ:31333741 MAIL:oldboy521@gmail.com 本软件 ...

  6. tornado简单实现restful接口2

    2019独角兽企业重金招聘Python工程师标准>>> http头部和http_code状态码处理 @tornado.web.asynchronousdef post(self):& ...

  7. 简单python脚本实例-python常用运维脚本实例

    #提前配置好免密钥登陆,与apache服务 import pexpect import os ds_ip= '192.168.102.143'rs1_ip= '192.168.102.144'rs2_ ...

  8. Python WEB开发:1024程序员节用Tornado框架制作简易【表白墙】网站

    嗨害大家好鸭! 我是小熊猫❤ 眼瞅着1024程序员节就快到了 不知道会不会有人被表白- 我先来自己做一个表白墙 给我的好兄弟提供一个表白的平台哈哈哈哈 有什么python相关报错解答自己不会的.或者源 ...

  9. python编写restful接口_Python开发之路系列:RESTful 接口开发

    这篇文章我们来看看在Flask里是如何进行RESTful接口开发的 按照我个人的理解,RESTful的核心价值再与它的规范性. RESTful接口是面向资源的, 而不是面向动作. 比如一个查书的接口, ...

  10. python实现简单的api接口-Python 实现接口测试的简单实例

    Hi~ 由于最近家里宝宝病了,我也在研究python的其他内容,很久没有来社区了,不过我还是一直关注社区的动态哟 好了,闲聊的话题就到此为止, 今天我给大家带来的,是python实现的接口自动化测试的 ...

最新文章

  1. Xcode 添加前缀
  2. oracle 12c 自动任务,Oracle job自动任务实用指南
  3. (第一课)Python学习之蟒蛇绘制
  4. CodeForces - 1561E Bottom-Tier Reversals(构造)
  5. UVA211 TheDomino Effect 多米诺效应
  6. 『设计模式』一张图告诉你UML图怎么画❀
  7. Cisco 3550-EMI 交 换 机 配 置 教 程
  8. C和指针之函数之求参数列表中的最大值
  9. 微信小程序 引用其他js里的方法
  10. python3设置编码_python3 中文乱码与默认编码格式设定方法
  11. linux4.9下alsa架构,[Alsa]4, wm8524 Kernel音频子系统入口
  12. 35岁以后,被社会无情抛弃,放下面子赚钱
  13. IOS多类型Cell的tableView实现
  14. AtCoder Beginner Contest 132 解题报告
  15. Volatile关键字,你真的理解吗?
  16. WPF简单实用方法(持续更新)
  17. vue项目中报常见错误
  18. 睡眠 应该用 a加权 c加权_?焦虑自测 ,看看你的焦虑程度到底有多深?是否影响睡眠?...
  19. 计算机桌面提示区,win7如何把电脑桌面分成四个区域?电脑分区域显示方法
  20. 【高等教育6年+工作5年】的个人阶段性自述

热门文章

  1. 冒泡排序和选择排序的实现与比较
  2. C++基础学习笔记:第一章、第二章
  3. stm32定时器编码器模式原理及配置
  4. cmd管道无法接收特定程序返回值_CQRS amp; Event Sourcing — 解决检索应用程序状态问题的一剂良方...
  5. Vuex getters 基础使用
  6. Flutter 进阶篇-所有知识点架构
  7. python的shelve库
  8. Python—字典(当索引不好用时)
  9. 你真的会使用SQL Server的备份还原功能吗?之一:恢复模型
  10. discuz x2.5 广告位开发学习(第一步:摸索)