用Python的Tornado框架结合memcached页面改善博客性能


Posted in Python onApril 24, 2015

原因

Blog是一个更新并不很频繁的一套系统,但是每次刷新页面都要更新数据库反而很浪费资源,添加静态页面生成是一个解决办法,同时缓存是一个更好的主意,可以结合Memcached添加少量的代码进行缓存,而且免去去了每次更新文章都要重新生成静态页面,特别当页面特别多时.
实现

主要通过页面的uri进行缓存,结合tornado.web.RequestHandler的prepare和on_finish方法函数, prepare 主要是请求前执行,on_finish()是请求结束之前执行.在渲染模板时缓存页面内容,然后在请求前检测是否有缓存,如果有直接输出缓存,结束请求,在POST提交之后清空所有缓存,重新生成缓存,从而保证内容实时性.由于登录用户和普通用户的页面不相同,所以不缓存登录用户页面(代码中没有体现,请自行实现).主要python代码(省略了模板渲染的代码):

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#
#  Author :  cold
#  E-mail :  wh_linux@126.com
#  Date  :  13/01/14 09:57:31
#  Desc  :  
#
import config
import pylibmc
from tornado.web import RequestHandler
#### 省略Cache类定义 #####

class Memcached(object):
  _mc = pylibmc.client.Client(config.CACHE_HOST, binary = True)

  def __enter__(self):
    if config.CACHED:
      return Memcached
    else:
      return Cache()

  def __exit__(self, exc_type, exc_val, exc_tb):
    pass

  @classmethod
  def get_cache(cls):
    return cls._mc

  @classmethod
  def get(cls, key, default = None):
    r = cls._mc.get(key)
    if not r:
      r = default
    return r

  @classmethod
  def set(cls, key, value, timeout = 0):
    timeout = timeout if timeout else config.CACHE_TIMEOUT
    return cls._mc.set(key, value, timeout)

  @classmethod
  def delete(cls, key):
    return cls._mc.delete(key)

  @classmethod
  def flush(cls):
    return cls._mc.flush_all()

  def __getattr__(self, key):
    return Memcached.get(key)

  def __setattr__(self, key, value):
    return Memcached.set(key, value)


class BaseHandler(RequestHandler):
  """ 继承tornado请求基类,重写 prepare和on_finish方法 """
  cache = Memcached

  def render(self, template_path, *args, **kwargs):
    """ 渲染模板 """
    # 省略渲染模板代码
    content = ''   # 渲染模板后的内容
    if self.request.method == "GET" and CACHED and \
      not self.request.path.startswith("/admin"):
      self.cache.set(self.request.uri, content) # 将渲染后的内容缓存起来
    self.write(content)

  def prepare(self):
    super(BaseHandler, self).prepare()
    # 如果请求是GET方法,而且不是请求后台
    if self.request.method == "GET" and CACHED and \
      not self.request.path.startswith("/admin"):

      # 尝试获取当前页面的缓存
      cache = self.cache.get(self.request.uri)
      # 获取缓存则输出页面,结束请求
      if cache:
        return self.finish(cache)

  def on_finish(self):
    """ 重写结束请求前的方法函数 """
    if self.request.method == "POST":
      # 如果遇到POST提交则清空缓存
      self.cache.flush()

缓存系统在redis和Memcached选择了很久,因为只是单纯的缓存页面所以最后选择了memcached,使用pylibmc python库.
测试

使用webbench 网站压力测试对比了缓存前后的结果: 使用缓存前

$ webbench -c 500 -t 30 http://www.linuxzen.com/
Webbench - Simple Web Benchmark 1.5
Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.

Benchmarking: GET http://www.linuxzen.com/
500 clients, running 30 sec.

Speed=54 pages/min, 38160 bytes/sec.
Requests: 27 susceed, 0 failed.

使用缓存后:

$ webbench -c 500 -t 30 http://www.linuxzen.com/
Webbench - Simple Web Benchmark 1.5
Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.

Benchmarking: GET http://www.linuxzen.com/
500 clients, running 30 sec.

Speed=256 pages/min, 238544 bytes/sec.
Requests: 128 susceed, 0 failed.

明显快了很多...

Python 相关文章推荐
Python中使用bidict模块双向字典结构的奇技淫巧
Jul 12 Python
利用python模拟实现POST请求提交图片的方法
Jul 25 Python
Python网络编程基于多线程实现多用户全双工聊天功能示例
Apr 10 Python
利用python对Excel中的特定数据提取并写入新表的方法
Jun 14 Python
解决python2 绘图title,xlabel,ylabel出现中文乱码的问题
Jan 29 Python
Django框架使用内置方法实现登录功能详解
Jun 12 Python
Python 窗体(tkinter)按钮 位置实例
Jun 13 Python
浅谈PySpark SQL 相关知识介绍
Jun 14 Python
Python 用三行代码提取PDF表格数据
Oct 13 Python
pandas中的数据去重处理的实现方法
Feb 10 Python
Python多线程Threading、子线程与守护线程实例详解
Mar 24 Python
python之np.argmax()及对axis=0或者1的理解
Jun 02 Python
使用Python编写一个在Linux下实现截图分享的脚本的教程
Apr 24 #Python
修改Python的pyxmpp2中的主循环使其提高性能
Apr 24 #Python
Python的Tornado框架异步编程入门实例
Apr 24 #Python
使用Python的Tornado框架实现一个简单的WebQQ机器人
Apr 24 #Python
Python程序中使用SQLAlchemy时出现乱码的解决方案
Apr 24 #Python
简单说明Python中的装饰器的用法
Apr 24 #Python
使用基于Python的Tornado框架的HTTP客户端的教程
Apr 24 #Python
You might like
ajax实现无刷新分页(php)
2010/07/18 PHP
php页面缓存ob系列函数介绍
2012/10/18 PHP
PHP的error_reporting错误级别变量对照表
2014/07/08 PHP
php上传图片之时间戳命名(保存路径)
2014/08/15 PHP
PHP实现简单搜歌的方法
2015/07/28 PHP
php实现基于pdo的事务处理方法示例
2017/07/21 PHP
不使用浏览器运行javascript代码的方法
2013/07/24 Javascript
JS 屏蔽键盘不可用与鼠标右键不可用的方法
2013/11/18 Javascript
JS中怎样判断undefined(比较不错的方法)
2014/03/27 Javascript
再探JavaScript作用域
2014/09/24 Javascript
jQuery+AJAX实现网页无刷新上传
2015/02/22 Javascript
基于jQuery实现放大镜特效
2020/10/19 Javascript
用js实现简单算法的实例代码
2016/09/24 Javascript
Radio 单选JS动态添加的选项onchange事件无效的解决方法
2016/12/12 Javascript
Vue.js用法详解
2017/11/13 Javascript
vue以组件或者插件的形式实现throttle或者debounce
2019/05/22 Javascript
轻松学习JavaScript函数中的 Rest 参数
2019/05/30 Javascript
微信小程序通过js实现瀑布流布局详解
2019/08/28 Javascript
vue项目前端微信JSAPI与外部H5支付相关实现过程及常见问题
2020/04/14 Javascript
python与C互相调用的方法详解
2017/07/14 Python
Python中GeoJson和bokeh-1的使用讲解
2019/01/03 Python
django数据库自动重连的方法实例
2019/07/21 Python
50行Python代码获取高考志愿信息的实现方法
2019/07/23 Python
python web框架Flask实现图形验证码及验证码的动态刷新实例
2019/10/14 Python
使用Python刷淘宝喵币(低阶入门版)
2019/10/30 Python
python字典key不能是可以是啥类型
2020/08/04 Python
Python对excel的基本操作方法
2021/02/18 Python
CSS3 media queries + jQuery实现响应式导航
2016/09/30 HTML / CSS
Emma Bridgewater官网:英国餐具制造商
2019/11/24 全球购物
Web Service面试题:如何搭建Axis2的开发环境
2012/06/20 面试题
会计毕业生自我鉴定
2013/11/04 职场文书
教育课题研究自我鉴定范文
2013/12/28 职场文书
交通违章检讨书
2014/09/21 职场文书
个人授权委托书范本格式
2014/10/12 职场文书
2014年幼儿园工作总结
2014/11/10 职场文书
Mysql超详细讲解死锁问题的理解
2022/04/01 MySQL