用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教程之用py2exe将PY文件转成EXE文件
Jun 12 Python
Python多进程同步Lock、Semaphore、Event实例
Nov 21 Python
Python的装饰器模式与面向切面编程详解
Jun 21 Python
简单学习Python time模块
Apr 29 Python
利用Python画ROC曲线和AUC值计算
Sep 19 Python
Python编程实现线性回归和批量梯度下降法代码实例
Jan 04 Python
Python内置模块ConfigParser实现配置读写功能的方法
Feb 12 Python
python3安装pip3(install pip3 for python 3.x)
Apr 03 Python
通过python实现弹窗广告拦截过程详解
Jul 10 Python
在Python中画图(基于Jupyter notebook的魔法函数)
Oct 28 Python
python二元表达式用法
Dec 04 Python
python_tkinter弹出对话框创建
Mar 20 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
html中select语句读取mysql表中内容
2006/10/09 PHP
PHP中遍历stdclass object的实现代码
2011/06/09 PHP
分享一个PHP数据流应用的简单例子
2012/06/01 PHP
php向js函数传参的几种方法
2014/08/10 PHP
关于php中的json_encode()和json_decode()函数的一些说明
2016/11/20 PHP
phpcms的分类名称和类别名称的调用
2017/01/05 PHP
PHP自定义递归函数实现数组转JSON功能【支持GBK编码】
2018/07/17 PHP
实例讲解php实现多线程
2019/01/27 PHP
TP5框架页面跳转样式操作示例
2020/04/05 PHP
做网页的一些技巧(续)
2007/02/01 Javascript
基于jquery实现导航菜单高亮显示(两种方法)
2015/08/23 Javascript
jquery ezUI 双击行记录弹窗查看明细的实现方法
2016/06/01 Javascript
详解AngularJS中ng-src指令的使用
2016/09/07 Javascript
Bootstrap Search Suggest使用例子
2016/12/21 Javascript
js实现微信/QQ直接跳转到支付宝APP打开口令领红包功能
2018/01/09 Javascript
vue2.0 循环遍历加载不同图片的方法
2018/03/06 Javascript
vue中手机号,邮箱正则验证以及60s发送验证码的实例
2018/03/16 Javascript
javascript中的this作用域详解
2019/07/15 Javascript
通过实例了解JS 连续赋值
2019/09/24 Javascript
基于vue-cli3和element实现登陆页面
2019/11/13 Javascript
微信小程序如何获取地址
2019/12/24 Javascript
浅谈vue 二级路由嵌套和二级路由高亮问题
2020/08/06 Javascript
python执行使用shell命令方法分享
2017/11/08 Python
python数据结构之线性表的顺序存储结构
2018/09/28 Python
解决python os.mkdir创建目录失败的问题
2018/10/16 Python
使用Python画出小人发射爱心的代码
2019/11/23 Python
Python通过Pillow实现图片对比
2020/04/29 Python
Matplotlib 折线图plot()所有用法详解
2020/07/28 Python
详解BeautifulSoup获取特定标签下内容的方法
2020/12/07 Python
python软件测试Jmeter性能测试JDBC Request(结合数据库)的使用详解
2021/01/26 Python
新加坡最早生产电动滑板车的制造商之一:FunsToTheFore
2020/09/08 全球购物
竟聘演讲稿范文
2013/12/31 职场文书
大学生村官考核材料
2014/05/23 职场文书
2014年卫生保健工作总结
2014/12/08 职场文书
超强台风观后感
2015/06/09 职场文书
2019毕业论文致谢词
2019/06/24 职场文书