用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正则表达式教程之三:贪婪/非贪婪特性
Mar 02 Python
pygame实现简易飞机大战
Sep 11 Python
python之消除前缀重命名的方法
Oct 21 Python
解决python Markdown模块乱码的问题
Feb 14 Python
Python 循环终止语句的三种方法小结
Jun 24 Python
Django 外键的使用方法详解
Jul 19 Python
使用OpCode绕过Python沙箱的方法详解
Sep 03 Python
python实现批量文件重命名
Oct 31 Python
Python判断字符串是否为空和null方法实例
Apr 26 Python
从python读取sql的实例方法
Jul 21 Python
Python实现Excel自动分组合并单元格
Feb 22 Python
一篇文章弄懂Python中的内建函数
Aug 07 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
评分9.0以上的动画电影,剧情除了经典还很燃
2020/03/04 日漫
phpphp图片采集后按原路径保存图片示例
2014/02/18 PHP
Linux下php5.4启动脚本
2014/08/03 PHP
PHP使用strtotime计算两个给定日期之间天数的方法
2015/03/18 PHP
正确的PHP匹配UTF-8中文的正则表达式
2015/05/13 PHP
用php定义一个数组最简单的方法
2019/10/04 PHP
PHP利用缓存处理用户注册时的邮箱验证,成功后用户数据存入数据库操作示例
2019/12/31 PHP
爱恋千雪-US-AscII加密解密工具(网页加密)下载
2007/06/06 Javascript
基于MooTools的很有创意的滚动条时钟动画
2010/11/14 Javascript
JS获得QQ号码的昵称,头像,生日的简单实例
2013/12/04 Javascript
JavaScript将数据转换成整数的方法
2014/01/04 Javascript
Jquery实现自定义tooltip示例代码
2014/02/12 Javascript
jquery中JSON的解析方式
2015/03/16 Javascript
jquery在ie7下选择器的问题导致append失效的解决方法
2016/01/10 Javascript
让你一句话理解闭包(简单易懂)
2016/06/03 Javascript
ES6新特性之模块Module用法详解
2017/04/01 Javascript
bootstrap轮播图示例代码分享
2017/05/17 Javascript
Vue工程模板文件 webpack打包配置方法
2017/12/26 Javascript
微信小程序的tab选项卡的实现效果
2019/05/15 Javascript
Electron-vue开发的客户端支付收款工具的实现
2019/05/24 Javascript
vue仿ios列表左划删除
2019/09/26 Javascript
webpack常用构建优化策略小结
2019/11/21 Javascript
javascript实现计算器功能
2020/03/30 Javascript
在react中使用vue的状态管理的方法示例
2020/05/02 Javascript
django rest framework 数据的查找、过滤、排序的示例
2018/06/25 Python
python爬虫的一个常见简单js反爬详解
2019/07/09 Python
详解python 降级到3.6终极解决方案
2020/02/06 Python
浅谈python print(xx, flush = True) 全网最清晰的解释
2020/02/21 Python
什么是python的id函数
2020/06/11 Python
详解python安装matplotlib库三种失败情况
2020/07/28 Python
爱尔兰电子产品购物网站:Komplett.ie
2018/04/04 全球购物
Opodo英国旅游网站:预订廉价航班、酒店和汽车租赁
2018/07/14 全球购物
迷你分体式空调:SoGoodToBuy
2018/08/07 全球购物
军用级手机壳,专为冒险而建:Zizo Wireless
2019/08/07 全球购物
小学语文课后反思精选
2014/04/25 职场文书
保卫钓鱼岛口号
2014/06/20 职场文书