用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 zip文件 压缩
Dec 24 Python
使用python获取CPU和内存信息的思路与实现(linux系统)
Jan 03 Python
利用Python获取操作系统信息实例
Sep 02 Python
简单谈谈Python中函数的可变参数
Sep 02 Python
asyncio 的 coroutine对象 与 Future对象使用指南
Sep 11 Python
python 搭建简单的http server,可直接post文件的实例
Jan 03 Python
Python提取特定时间段内数据的方法实例
Apr 01 Python
解决Atom安装Hydrogen无法运行python3的问题
Aug 28 Python
Python填充任意颜色,不同算法时间差异分析说明
May 16 Python
详解python3 GUI刷屏器(附源码)
Feb 18 Python
python 爬取京东指定商品评论并进行情感分析
May 27 Python
OpenCV-Python实现轮廓拟合
Jun 08 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
怎么样可以把 phpinfo()屏蔽掉?
2006/11/24 PHP
phpmyadmin 常用选项设置详解版
2010/03/07 PHP
TMDPHP 模板引擎使用教程
2012/03/13 PHP
WordPress中编写自定义存储字段的相关PHP函数解析
2015/12/25 PHP
PHP利用递归函数实现无限级分类的方法
2019/03/22 PHP
Laravel配置全局公共函数的方法步骤
2019/05/09 PHP
javaScript如何生成xmlhttp
2013/12/16 Javascript
ECMAScript 6即将带给我们新的数组操作方法前瞻
2015/01/06 Javascript
js简单判断flash是否加载完成的方法
2016/06/21 Javascript
angularjs中ng-bind-html的用法总结
2017/05/23 Javascript
Angular中使用MathJax遇到的一些问题
2017/12/15 Javascript
node.js用fs.rename强制重命名或移动文件夹的方法
2017/12/27 Javascript
JS脚本加载后执行相应回调函数的操作方法
2018/02/28 Javascript
vue-cli扩展多模块打包的示例代码
2018/04/09 Javascript
Vue-component全局注册实例
2018/09/06 Javascript
史上最为详细的javascript继承(推荐)
2019/05/18 Javascript
jQuery利用cookie 实现本地收藏功能(不重复无需多次命名)
2019/11/07 jQuery
Vue双向绑定实现原理与方法详解
2020/05/07 Javascript
JS 获取文件后缀,判断文件类型(比如是否为图片格式)
2020/05/09 Javascript
[02:43]DOTA2英雄基础教程 半人马战行者
2014/01/13 DOTA
Python简单进程锁代码实例
2015/04/27 Python
python初学者,用python实现基本的学生管理系统(python3)代码实例
2019/04/10 Python
Python 如何批量更新已安装的库
2020/05/26 Python
Python库安装速度过慢解决方案
2020/07/14 Python
Python配置pip国内镜像源的实现
2020/08/20 Python
Django Auth用户认证组件实现代码
2020/10/13 Python
鲜为人知的HTML5语音合成功能
2019/05/17 HTML / CSS
在印度上传处方,在线订购药品:Medlife
2019/03/28 全球购物
工商管理专业学生的自我评价
2013/10/01 职场文书
学年末自我鉴定
2014/01/21 职场文书
大学生英文求职信范文
2015/03/19 职场文书
保护动物的宣传语
2015/07/13 职场文书
Python中Selenium对Cookie的操作方法
2021/07/09 Python
SQL IDENTITY_INSERT作用案例详解
2021/08/23 MySQL
Kubernetes中Deployment的升级与回滚
2022/04/01 Servers
IDEA 2022 Translation 未知错误 翻译文档失败
2022/04/24 Java/Android