用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利用beautifulSoup实现爬虫
Sep 29 Python
python中文分词教程之前向最大正向匹配算法详解
Nov 02 Python
python如何读写json数据
Mar 21 Python
Python 在字符串中加入变量的实例讲解
May 02 Python
利用python脚本如何简化jar操作命令
Feb 24 Python
Python3中列表list合并的四种方法
Apr 19 Python
pandas计数 value_counts()的使用
Jun 24 Python
anaconda如何查看并管理python环境
Jul 05 Python
python使用ctypes库调用DLL动态链接库
Oct 22 Python
如何在windows下安装配置python工具Ulipad
Oct 27 Python
利用python 下载bilibili视频
Nov 13 Python
使用pipenv管理python虚拟环境的全过程
Sep 25 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的单引号和双引号 字符串效率
2009/05/27 PHP
php xml留言板 xml存储数据的简单例子
2009/08/24 PHP
发款php蜘蛛统计插件只要有mysql就可用
2010/10/12 PHP
PHP写日志的实现方法
2014/11/05 PHP
thinkphp连贯操作实例分析
2014/11/22 PHP
PHP编程之设置apache虚拟目录
2016/07/08 PHP
详解PHP中array_rand函数的使用方法
2016/09/11 PHP
PHP处理bmp格式图片的方法分析
2017/07/04 PHP
PHP使用ActiveMQ实例
2018/02/05 PHP
PHP自动生成缩略图函数的源码示例
2019/03/18 PHP
用显卡加速,轻松把笔记本打造成取暖器的办法!
2013/04/17 Javascript
js防止页面被iframe调用的方法
2014/10/30 Javascript
javascript实现无限级select联动菜单
2015/01/02 Javascript
jsonp跨域请求数据实现手机号码查询实例分析
2015/12/12 Javascript
Angular.js如何从PHP读取后台数据
2016/03/24 Javascript
JavaScript中的跨浏览器事件操作的基本方法整理
2016/05/20 Javascript
JavaScript面试题大全(推荐)
2016/09/22 Javascript
深入理解JavaScript定时机制
2016/10/27 Javascript
详解js产生对象的3种基本方式(工厂模式,构造函数模式,原型模式)
2017/01/09 Javascript
JavaScript实现瀑布流以及加载效果
2017/02/11 Javascript
Bootstrap输入框组件使用详解
2017/06/09 Javascript
详解webpack引入第三方库的方式以及注意事项
2019/01/15 Javascript
Vue中props的详解
2019/05/16 Javascript
Vue3.x源码调试的实现方法
2019/10/13 Javascript
原生js+canvas实现验证码
2020/11/29 Javascript
Python用Bottle轻量级框架进行Web开发
2016/06/08 Python
对python多线程SSH登录并发脚本详解
2019/02/14 Python
wxpython多线程防假死与线程间传递消息实例详解
2019/12/13 Python
python实现将range()函数生成的数字存储在一个列表中
2020/04/02 Python
一篇文章搞懂python的转义字符及用法
2020/09/03 Python
戴森美国官网:Dyson美国
2016/09/11 全球购物
美国Lolё官网:购买大胆而美丽的女性运动服装
2017/05/22 全球购物
工作能力自我评价2015
2015/03/05 职场文书
逃课检讨书范文
2015/05/06 职场文书
Mysql基础知识点汇总
2021/05/26 MySQL
Win11怎么解除儿童账号限制?Win11解除微软儿童账号限制方法
2022/07/07 数码科技