用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 30 Python
Nginx搭建HTTPS服务器和强制使用HTTPS访问的方法
Aug 16 Python
Linux系统上Nginx+Python的web.py与Django框架环境
Dec 25 Python
利用Hyperic调用Python实现进程守护
Jan 02 Python
python调用API实现智能回复机器人
Apr 10 Python
Python中反射和描述器总结
Sep 23 Python
python+pyqt5编写md5生成器
Mar 18 Python
python实现几种归一化方法(Normalization Method)
Jul 31 Python
Django 博客实现简单的全文搜索的示例代码
Feb 17 Python
python 等差数列末项计算方式
May 03 Python
浅析python函数式编程
Sep 26 Python
使用python操作lmdb对数据读取的实例
Dec 11 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
开发大型PHP项目的方法
2006/10/09 PHP
php面向对象全攻略 (十二) 抽象方法和抽象类
2009/09/30 PHP
帝国cms常用标签汇总
2015/07/06 PHP
PHP pear安装配置教程
2016/05/14 PHP
基于PHP实现短信验证码发送次数限制
2020/07/11 PHP
jquery操作select大全
2014/04/25 Javascript
JavaScript中的对象序列化介绍
2014/12/30 Javascript
Bootstrap每天必学之面板
2015/11/30 Javascript
使用bootstrap3开发响应式网站
2016/05/12 Javascript
javascript中href和replace的比较(详解)
2016/11/25 Javascript
如何用input标签和jquery实现多图片的上传和回显功能
2018/05/16 jQuery
JavaScript原型对象原理与应用分析
2018/12/27 Javascript
JS实现头条新闻的经典轮播图效果示例
2019/01/30 Javascript
[03:55]显微镜下的DOTA2特别篇——430灰烬之灵神级操作
2014/06/24 DOTA
[01:05:29]DOTA2-DPC中国联赛 正赛 PSG.LGD vs Aster BO3 第二场 1月24日
2021/03/11 DOTA
Python3.2模拟实现webqq登录
2016/02/15 Python
Python之虚拟环境virtualenv,pipreqs生成项目依赖第三方包的方法
2019/07/23 Python
利用Python的sympy包求解一元三次方程示例
2019/11/22 Python
python__new__内置静态方法使用解析
2020/01/07 Python
Windows系统下pycharm中的pip换源
2020/02/23 Python
Python3开发环境搭建详细教程
2020/06/18 Python
PIP和conda 更换国内安装源的方法步骤
2020/09/21 Python
Html5 audio标签样式的修改
2016/01/28 HTML / CSS
是什么让J2EE适合用来开发多层的分布式的应用
2015/01/16 面试题
过滤器的用法
2013/10/08 面试题
人事档案接收函
2014/01/12 职场文书
秋天的雨教学反思
2014/04/27 职场文书
护士长竞聘演讲稿
2014/04/30 职场文书
信息与计算机科学职业规划范文:成为一艘有方向的船
2014/09/11 职场文书
2014旅游局领导班子四风问题对照检查材料思想汇报
2014/09/19 职场文书
倡议书作文
2015/01/19 职场文书
董事长年会致辞
2015/07/29 职场文书
MySQL 常见存储引擎的优劣
2021/06/02 MySQL
html css3不拉伸图片显示效果
2021/06/07 HTML / CSS
Python3中PyQt5简单实现文件打开及保存
2021/06/10 Python
Redis性能监控的实现
2021/07/09 Redis