用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错误处理详解
Sep 28 Python
Python中的index()方法使用教程
May 18 Python
python 安装virtualenv和virtualenvwrapper的方法
Jan 13 Python
python实现给微信公众号发送消息的方法
Jun 30 Python
JSON文件及Python对JSON文件的读写操作
Oct 07 Python
python取数作为临时极大值(极小值)的方法
Oct 15 Python
python七夕浪漫表白源码
Apr 05 Python
python文件选择对话框的操作方法
Jun 27 Python
python3中利用filter函数输出小于某个数的所有回文数实例
Nov 24 Python
Python的in,is和id函数代码实例
Apr 18 Python
python3中布局背景颜色代码分析
Dec 01 Python
在Python 中将类对象序列化为JSON
Apr 06 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
ini_set的用法介绍
2014/01/07 PHP
php中使用GD库做验证码
2016/03/31 PHP
php-fpm开启状态统计的方法详解
2017/06/23 PHP
js判断鼠标同时离开两个div的思路及代码
2013/05/31 Javascript
JS实现侧悬浮浮动实例代码
2013/11/29 Javascript
浏览器窗口大小变化时使用resize事件对框架不起作用的解决方法
2014/05/11 Javascript
javascript搜索框效果实现方法
2015/05/14 Javascript
js图片轮播效果实现代码
2020/04/18 Javascript
jQuery实现横向带缓冲的水平运动效果(附demo源码下载)
2016/01/29 Javascript
javascript self对象使用详解
2016/10/18 Javascript
用iframe实现不刷新整个页面上传图片的实例
2016/11/18 Javascript
解析JavaScript数组方法reduce
2016/12/12 Javascript
js正则表达式验证表单【完整版】
2017/03/06 Javascript
最常用的jQuery表单验证(简单)
2017/05/23 jQuery
vue和react等项目中更简单的实现展开收起更多等效果示例
2018/02/22 Javascript
angularJS的radio实现单项二选一的使用方法
2018/02/28 Javascript
async/await地狱该如何避免详解
2018/05/10 Javascript
如何通过JS实现转码与解码
2020/02/21 Javascript
Python实现CET查分的方法
2015/03/10 Python
Python探索之SocketServer详解
2017/10/28 Python
浅析Python 3 字符串中的 STR 和 Bytes 有什么区别
2018/10/14 Python
python批量识别图片指定区域文字内容
2019/04/30 Python
Django-rest-framework中过滤器的定制实例
2020/04/01 Python
Python使用Matlab命令过程解析
2020/06/04 Python
html5实现输入框fixed定位在屏幕最底部兼容性
2020/07/03 HTML / CSS
埃弗顿足球俱乐部官方网上商店:Everton Direct
2018/01/13 全球购物
Jowissa官方网站:瑞士制造的手表,优雅简约的设计
2020/07/29 全球购物
Java语言程序设计测试题选择题部分
2014/04/03 面试题
本科毕业生自我鉴定
2013/11/02 职场文书
干部培训自我鉴定
2014/01/22 职场文书
总经理司机岗位职责
2014/02/06 职场文书
质量承诺书范文
2014/03/27 职场文书
在校大学生自我评价范文
2014/09/12 职场文书
商场圣诞节活动总结
2015/05/06 职场文书
优秀新员工事迹材料
2019/05/13 职场文书
一次项目中Thinkphp绕过禁用函数的实战记录
2021/11/17 PHP