用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中合并两个文本文件并按照姓名首字母排序的例子
Apr 25 Python
Python自动重试HTTP连接装饰器
Apr 28 Python
Python实现栈的方法
May 26 Python
基于python 字符编码的理解
Sep 02 Python
python读取和保存图片5种方法对比
Sep 12 Python
python使用requests模块实现爬取电影天堂最新电影信息
Apr 03 Python
解决Python3 抓取微信账单信息问题
Jul 19 Python
Python生成词云的实现代码
Jan 14 Python
TensorBoard 计算图的可视化实现
Feb 15 Python
Python实现清理微信僵尸粉功能示例【基于itchat模块】
May 29 Python
keras实现基于孪生网络的图片相似度计算方式
Jun 11 Python
浅谈keras中loss与val_loss的关系
Jun 22 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牛逼的面试题分享
2013/01/18 PHP
php 截取中英文混合字符串的方法
2018/05/31 PHP
让 JavaScript 轻松支持函数重载 (Part 2 - 实现)
2009/08/04 Javascript
js 延迟加载 改变JS的位置加快网页加载速度
2012/12/11 Javascript
jQuery关于导航条背景切换效果实现示例
2013/09/04 Javascript
判断JS对象是否拥有某种属性的两种方式
2013/12/02 Javascript
jQuery实现动画效果的简单实例
2014/01/27 Javascript
bootstrap data与jquery .data
2014/07/07 Javascript
javascript文本框内输入文字倒计数的方法
2015/02/24 Javascript
jQuery实现圣诞节礼物动画案例解析
2016/12/25 Javascript
AngularJS框架的ng-app指令与自动加载实现方法分析
2017/01/04 Javascript
解决Jstree 选中父节点时被禁用的子节点也会选中的问题
2017/12/27 Javascript
webpack4的迁移的使用方法
2018/05/25 Javascript
详解create-react-app 2.0版本如何启用装饰器语法
2018/10/23 Javascript
layui 实现表格某一列显示图标
2019/09/19 Javascript
使用vue cli4.x搭建vue项目的过程详解
2020/05/08 Javascript
python3+mysql查询数据并通过邮件群发excel附件
2018/02/24 Python
python爬虫之线程池和进程池功能与用法详解
2018/08/02 Python
Python操作MySQL数据库的两种方式实例分析【pymysql和pandas】
2019/03/18 Python
Python实现二叉树前序、中序、后序及层次遍历示例代码
2019/05/18 Python
opencv实现简单人脸识别
2021/02/19 Python
使用批处理脚本自动生成并上传NuGet包(操作方法)
2019/11/19 Python
Pandas将列表(List)转换为数据框(Dataframe)
2020/04/24 Python
MyFrenchPharma中文网:最大的法国药妆平台
2016/10/07 全球购物
华丽的手绘陶瓷:MacKenzie-Childs
2017/02/04 全球购物
国际性能运动服装品牌:Dare 2b
2018/07/27 全球购物
在职人员函授期间自我评价分享
2013/11/08 职场文书
学校安全教育制度
2014/01/31 职场文书
超市商业计划书
2014/05/04 职场文书
机电一体化专业求职信
2014/07/22 职场文书
效能风暴心得体会
2014/09/04 职场文书
用人单位终止解除劳动合同证明书
2014/10/06 职场文书
售后服务承诺函格式
2015/01/21 职场文书
写给媳妇的检讨书
2015/05/06 职场文书
赢在执行观后感
2015/06/16 职场文书
ORM模型框架操作mysql数据库的方法
2021/07/25 MySQL