Django之使用celery和NGINX生成静态页面实现性能优化

性能优化原理:

当我们要给client浏览器返回一个页面时,我们需要去数据库查询数据并将数据和基本页面模板渲染形成页面返回给客户端,但如果每一个用户访问时都去查询一次首页的的数据时,当日访问量很大时那么无疑会给数据库查询带来很大的性能问题。为了解决这个问题,我们可以给未登录用户返回一个早就渲染好的静态首页(给已登录的用户返回一个调用缓存数据和个人数据渲染的页面),这样就可以提高网站的性能了。

使用celery生成静态首页

生成静态页面原理:

在一个为静态首页准备的基础模板之上,获取数据,使用django的loader加载基础模板,使用render渲染页面即可生成几台页面。

安装celery

pip install celery

为redis配置settings文件

# diango的缓存配置
CACHES = {
 "default": {
  "BACKEND": "django_redis.cache.RedisCache",
  "LOCATION": "redis://127.0.0.1:6379/9",
  "OPTIONS": {
   "CLIENT_CLASS": "django_redis.client.DefaultClient",
  }
 }
}

准备一个首页静态模板文件static_base.html

{# 首页 注册 登录 #}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
{% load staticfiles %}
<head>
 <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
 {# 网页标题内容块 #}
 <title>{% block title %}{% endblock title %}</title>
 <link rel="stylesheet" type="text/css" href="{% static 'css/reset.css' %}">
 <link rel="stylesheet" type="text/css" href="{% static 'css/main.css' %}">
 {# 网页顶部引入文件块 #}
 {% block topfiles %}{% endblock topfiles %}
</head>
<body>
{# 网页顶部欢迎信息块 #}
{% block header_con %}
 <div class="header_con">
  <div class="header">
   <div class="welcome fl">欢迎来到商城!</div>
   <div class="fr">
    <div class="login_btn fl">
     <a href="{% url 'user:login' %}">登录</a>
     <span>|</span>
     <a href="{% url 'user:register' %}">注册</a>
    </div>
    <div class="user_link fl">
     <span>|</span>
     <a href="{% url 'user:user' %}">用户中心</a>
     <span>|</span>
     <a href="cart.html">我的购物车</a>
     <span>|</span>
     <a href="{% url 'user:order' %}">我的订单</a>
    </div>
   </div>
  </div>
 </div>
{% endblock header_con %}

{# 网页顶部搜索框块 #}
{% block search_bar %}
 <div class="search_bar clearfix">
  <a href="index.html" class="logo fl"><img src="{% static 'images/logo.png' %}"></a>
  <div class="search_con fl">
   <input type="text" class="input_text fl" name="" placeholder="搜索商品">
   <input type="button" class="input_btn fr" name="" value="搜索">
  </div>
  <div class="guest_cart fr">
   <a href="#" class="cart_name fl">我的购物车</a>
   <div class="goods_count fl" id="show_count">{{ cart_count }}</div>
  </div>
 </div>
{% endblock search_bar %}

{# 网站主体内容块 #}
{% block body %}{% endblock body %}

 <div class="footer">
  <div class="foot_link">
   <a href="#">关于我们</a>
   <span>|</span>
   <a href="#">联系我们</a>
   <span>|</span>
   <a href="#">招聘人才</a>
   <span>|</span>
   <a href="#">友情链接</a>
  </div>
  <p>CopyRight © 2016 北京商城信息技术有限公司 All Rights Reserved</p>
  <p>电话:010-****888 京ICP备*******8号</p>
 </div>
 {# 网页底部html元素块 #}
 {% block bottom %}{% endblock bottom %}
 {# 网页底部引入文件块 #}
 {% block bottomfiles %}{% endblock bottomfiles %}
</body>
</html>

在首页静态模板文件的基础上继承生成一个首页静态文件 static_index.html 方便celery获取数据库文件并进行渲染

{% extends 'static_base.html' %}
{% load staticfiles %}
{% block title %}首页{% endblock title %}
{% block topfiles %}
 <script type="text/javascript" src="{% static 'js/jquery-1.12.4.min.js' %}"></script>
 <script type="text/javascript" src="{% static 'js/jquery-ui.min.js' %}"></script>
 <script type="text/javascript" src="{% static 'js/slide.js' %}"></script>
{% endblock topfiles %}
{% block body %}
 <div class="navbar_con">
  <div class="navbar">
   <h1 class="fl">全部商品分类</h1>
   <ul class="navlist fl">
    <li><a href="">首页</a></li>
    <li class="interval">|</li>
    <li><a href="">手机生鲜</a></li>
    <li class="interval">|</li>
    <li><a href="">抽奖</a></li>
   </ul>
  </div>
 </div>

 <div class="center_con clearfix">
  <ul class="subnav fl">
   {% for type in types %}
    <li><a href="#model0{{ forloop.counter }}" class="{{ type.logo }}">{{ type.name }}</a></li>
   {% endfor %}
  </ul>
  <div class="slide fl">
   <ul class="slide_pics">
    {% for banner in goods_banners %}
     <li><a href="#"><img src="{{ banner.image.url }}" alt="幻灯片"></a></li>
    {% endfor %}
   </ul>
   <div class="prev"></div>
   <div class="next"></div>
   <ul class="points"></ul>
  </div>
  <div class="adv fl">
   {% for banner in promotion_banners %}
    <a href="{{ banner.url }}"><img src="{{ banner.image.url }}"></a>
   {% endfor %}
  </div>
 </div>

 {% for type in types %}
 <div class="list_model">
  <div class="list_title clearfix">
   <h3 class="fl" id="model0{{ forloop.counter }}">{{ type.name }}</h3>
   <div class="subtitle fl">
    <span>|</span>
    {% for banner in type.title_banners %}
     <a href="#">{{ banner.sku.name }}</a>
    {% endfor %}
   </div>
   <a href="#" class="goods_more fr" id="fruit_more">查看更多 ></a>
  </div>

  <div class="goods_con clearfix">
   <div class="goods_banner fl"><img src="{{ type.image.url }}"></div>
   <ul class="goods_list fl">
    {% for banner in type.image_banners %}
    <li>
     <h4><a href="#">{{ banner.sku.name }}</a></h4>
     <a href="#"><img src="{{ banner.sku.image.url }}"></a>
     <div class="prize">¥ {{ banner.sku.price }}</div>
    </li>
    {% endfor %}
   </ul>
  </div>
 </div>
 {% endfor %}
{% endblock body %}

在项目下新建celery_tasks文件夹,在文件夹中新建tasks.py文件, 编写tasks文件

from django.conf import settings
from celery import Celery
from django.template import loader

# 在任务处理者一端加这几句
import os
# import django
# os.environ.setdefault("DJANGO_SETTINGS_MODULE", "shoppingmall.settings")
# django.setup()

# 这几个类要放在django环境初始化那四句的下面
from goods.models import GoodsType, IndexGoodsBanner, IndexPromotionBanner, IndexTypeGoodsBanner

# 创建一个Celery类的实例对象
app = Celery('celery_tasks.tasks', broker='redis://127.0.0.1:6379/8')

@app.task
def generate_static_index_html():
 '''产生首页静态页面'''
 # 获取商品的种类信息
 types = GoodsType.objects.all()
 # 获取首页轮播商品信息
 goods_banners = IndexGoodsBanner.objects.all().order_by('index')
 # 获取首页促销活动信息
 promotion_banners = IndexPromotionBanner.objects.all().order_by('index')
 # 获取首页分类商品展示信息
 for type in types: # GoodsType
  # 获取type种类首页分类商品的图片展示信息
  image_banners = IndexTypeGoodsBanner.objects.filter(type=type, display_type=1).order_by('index')
  # 获取type种类首页分类商品的文字展示信息
  title_banners = IndexTypeGoodsBanner.objects.filter(type=type, display_type=0).order_by('index')
  # 动态给type增加属性,分别保存首页分类商品的图片展示信息和文字展示信息
  type.image_banners = image_banners
  type.title_banners = title_banners

 # 组织模板上下文
 context = {
    'types': types,
    'goods_banners': goods_banners,
    'promotion_banners': promotion_banners
   }

 # 使用模板
 # 1.加载模板文件,返回模板对象
 temp = loader.get_template('static_index.html')
 # 2.模板渲染
 static_index_html = temp.render(context)

 # 生成首页对应静态文件
 save_path = os.path.join(settings.BASE_DIR, 'static/index.html')
 with open(save_path, 'w', encoding='utf-8') as f:
  f.write(static_index_html)

开启redis服务

E:\>cd E:\YifChanSoft\Database\Redis\RedisSoft\Redis-x64-3.2.100

E:\YifChanSoft\Database\Redis\RedisSoft\Redis-x64-3.2.100>redis-server --service-install redis.windows-service.conf --loglevel verbose

E:\YifChanSoft\Database\Redis\RedisSoft\Redis-x64-3.2.100>redis-cli
127.0.0.1:6379> select 8
OK
127.0.0.1:6379[8]> keys *
1) "_kombu.binding.celery"
2) "_kombu.binding.celery.pidbox"
127.0.0.1:6379[8]>

开启redis服务截图

将项目代码拷贝一份放在某处,进入该处, 启动tasks的worker模式

注意,用作worker的代码的tasks文件中应该有提前启动django的初始化的代码,不然worker没法调用conf信息;

即应该有以下内容

# 在任务处理者一端加这几句
import os
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "shoppingmall.settings")
django.setup()

为了解决celery4.x在win10上运行的错误,安装eventlet

pip install eventlet

进入复制用来做celery工作者的项目代码所在处

开启worker模式

celery -A celery_tasks.tasks worker -l info -P eventlet

开启worker模式截图

如果有就删除celery代码文件中static中的index.html文件;

主动调用 generate_static_index_html.delay() 即可验证生成index.html;

from celery_tasks.tasks import generate_static_index_html
generate_static_index_html.delay()

验证截图

可以看到在项目下的static文件夹下生成了index.html;

开启项目在浏览器中输入 http://127.0.0.1:8888/static/index.html/ 即可看到生成的静态首页;因为数据库中还没有数据,所以页面比较空。

NGINX的安装

参考教程: https://www.jb51.net/article/171374.htm

1.下载nginx: http://nginx.org/en/download.html

2.解压缩nginx包

下载好后在放入合适的目录,解压缩后如下

3.使用cmd命令,进入nginx所在解压缩目录,使用如下命令进行 安装nginx

start nginx.exe

安装截图

安装完成后,我们可以在 任务管理器中看到nginx任务,如图

至此,nginx就算安装完成了。

nginx命令

start nginx.exe # 开启nginx
nginx -s reload # 重新启动
nginx -s stop # 停止nginx
nginx -s quit # 退出nginx

使用NGINX提供静态首页

修改nginx配置

找到nginx的配置文件,如下图所示,为了方便以后其他的项目使用,我们拷贝一份源文件重命名为nginx_origin.conf

用编辑器打开 nginx.conf 文件,修改配置文件中内容如下:

location /static {
 alias E:/Pycharm/Pycharm_save/cp15/18Django_fresh2/step206/shoppingmall206/static/;
}

location / {
 # root html;
 root E:/Pycharm/Pycharm_save/cp15/18Django_fresh2/step206/shoppingmall206/static/;
 index index.html index.htm;
}

配置截图

注意,其中的地址应该是你使用celery的项目所在的绝对路径地址,并且地址之间应该使用斜杠/而不是反斜杠\,否则会报错。

修改好配置保存后,我们使用一下命令进行nginx的重启

nginx -s reload

然后,我们打开浏览器输入一下两个链接之一就可以看到项目主页面了。

http://127.0.0.1/ # 注意,后面必须有一个/,否则会进入nginx默认界面
http://127.0.0.1/static/index.html

项目主页面截图

nginx的cmd命令截图,其中的报错都是因为使用的是win10目录自带的反斜杠

在Django网站和celery可以理解是并列的关系,在他们之前,其实还有一个nginx服务器负责调度;

一般是当用户直接访问127.0.0.1时,我们通过nginx调度去celery的nginx中返回静态页面;

而当用户访问127.0.0.1/index时,我们返回调用Django网站的IndexView;

在网站上线时我们会使用nginx对它们进行配置。

后台数据修改时重新生成静态页面

原理

在数据库的数据改变时,会调用admin.ModelAdmin下的sava_model和delete_model方法用来更新数据,而我们需要当数据改变后重新生成静态页面;

因此,我们可以自定义一个类继承admin.ModelAdmin,重写更新和删除数据的方法,调用父类的更新删除方法后,调用celery中的方法重新生成静态首页;

实现

我们要配置当某个表的数据改变时重新生成静态页面,就要给该表定义一个 xxxModelAdmin 类,继承自admin.ModelAdmin并重写其中的方法,并且在admin中注册时该表应该同时继承xxxModelAdmin 类;

因为有很多表都需要如此配置,且类中的代码都相同,所以我们可以抽出一个 BaseModelAdmin 类,编写更新后重新调用生成静态页面的代码,然后让各个需要修改的表继承该类即可。

在首页对应的应用中的admin.py文件中编写如下代码

from django.contrib import admin
# from django.core.cache import cache
from goods.models import GoodsType, GoodsSKU, Goods, GoodsImage, IndexGoodsBanner, IndexTypeGoodsBanner, IndexPromotionBanner
from celery_tasks.tasks import generate_static_index_html

class BaseModelAdmin(admin.ModelAdmin):
 """当后台数据库数据改动时使celery重新生成静态首页页面"""
 def save_model(self, request, obj, form, change):
  """当更新或者新增数据时调用"""
  super().save_model(request, obj, form, change)
  # 发出任务,让celery worker重新生成静态首页
  generate_static_index_html.delay()

  # 清除首页的缓存数据
  # cache.delete("index_page_data")

 def delete_model(self, request, obj):
  """当删除数据时调用"""
  super().delete_model(request, obj)
  generate_static_index_html.delay()

  # 清除首页的缓存数据
  # cache.delete("index_page_data")

class GoodsTypeAdmin(BaseModelAdmin):
 pass

class IndexGoodsBannerAdmin(BaseModelAdmin):
 pass

class IndexTypeGoodsBannerAdmin(BaseModelAdmin):
 pass

class IndexPromotionBannerAdmin(BaseModelAdmin):
 pass

admin.site.register(GoodsType, GoodsTypeAdmin)
admin.site.register(GoodsSKU)
admin.site.register(Goods)
admin.site.register(GoodsImage)
admin.site.register(IndexGoodsBanner, IndexGoodsBannerAdmin)
admin.site.register(IndexTypeGoodsBanner, IndexTypeGoodsBannerAdmin)
admin.site.register(IndexPromotionBanner, IndexPromotionBannerAdmin)

至此,当我们在admin后台更新数据时就会重新生成静态首页了,大家可以自行尝试一下~

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Nginx服务器高性能优化的配置方法小结

    通常来说,一个优化良好的 Nginx Linux 服务器可以达到 500,000 – 600,000 次/秒 的请求处理性能,然而我的 Nginx 服务器可以稳定地达到 904,000 次/秒 的处理性能,并且我以此高负载测试超过 12 小时,服务器工作稳定. 这里需要特别说明的是,本文中所有列出来的配置都是在我的测试环境验证的,而你需要根据你服务器的情况进行配置: 从 EPEL 源安装 Nginx: yum -y install nginx 备份配置文件,然后根据你的需要进行配置: cp /e

  • Nginx服务器配置性能优化方案

    高层的配置 nginx.conf文件中,Nginx中有少数的几个高级配置在模块部分之上. user www-data; pid /var/run/nginx.pid; worker_processes auto; worker_rlimit_nofile 100000; user和pid应该按默认设置 - 我们不会更改这些内容,因为更改与否没有什么不同. worker_processes 定义了nginx对外提供web服务时的worker进程数.最优值取决于许多因素,包括(但不限于)CPU核的数

  • Django之使用celery和NGINX生成静态页面实现性能优化

    性能优化原理: 当我们要给client浏览器返回一个页面时,我们需要去数据库查询数据并将数据和基本页面模板渲染形成页面返回给客户端,但如果每一个用户访问时都去查询一次首页的的数据时,当日访问量很大时那么无疑会给数据库查询带来很大的性能问题.为了解决这个问题,我们可以给未登录用户返回一个早就渲染好的静态首页(给已登录的用户返回一个调用缓存数据和个人数据渲染的页面),这样就可以提高网站的性能了. 使用celery生成静态首页 生成静态页面原理: 在一个为静态首页准备的基础模板之上,获取数据,使用dj

  • ASP.NET编程简单实现生成静态页面的方法【附demo源码下载】

    本文实例讲述了ASP.NET编程简单实现生成静态页面的方法.分享给大家供大家参考,具体如下: 1. 使用场景 当页面的数据不需要经常更改时可采用静态页面方式. 2. 使用静态页面的好处 (1)提高网站的访问速度 (2)减轻服务器负担 (3)利于搜索引擎抓取 3. ASP.NET生成静态页面 生成静态页面方法有很多种,先说下我使用的其中的一种.参考资料 基本思路: (1)创建模板template.html文件,在里面定义一些特殊的字符串格式用于替换内容,如$htmlformat (2)读取模板,赋

  • ASP.NET动态生成静态页面的实例代码

    最近突然想把项目中新闻管理模块做成静态页,在网上找到很多很好的文章,在这里记录一下,现在只是实现静态页面的生成并没有实现分页功能.其主要原理就是读取数据库的数据然后替换掉静态模板页的内容.首先制作一个模板页,暂时命名为template.htm,示例代码如下:<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-trans

  • php 生成静态页面的办法与实现代码详细版

    php中主要用到的就是要用到fread()和fwirte().而静态页面生成了之后,就会牵扯到修改的问题.这里可以用到正则匹配的方法来替换模版中改变的部位.不过此种方法太麻烦,值得推荐的方法是直接把原来生成的模版砍掉,重新生成,呵呵,真正的一了百了. 还需要说明的一点就是,这种生成静态页面的方法一般都用于那些变化不是很频繁的页面,比如信息的最终页面.而针对列表页,如果信息更新不是很频繁的话,也是可取的.现在网上流行好多可以生成静态页面的blog或者论坛程序,都是通过手动点击后台"生成html页&

  • 比较详细PHP生成静态页面教程

    一,PHP脚本与动态页面. PHP脚本是一种服务器端脚本程序,可通过嵌入等方法与HTML文件混合,也可以类,函数封装等形式,以模板的方式对用户请求进行处理.无论以何种方式,它的基本原理是这样的.由客户端提出请求,请求某一页面 -----> WEB服务器引入指定相应脚本进行处理 -----> 脚本被载入服务器 -----> 由服务器指定的PHP解析器对脚本进行解析形成HTML语言形式 ----> 将解析后的HTML语句以包的方式传回给浏览器.由此不难看出,在页面发送到浏览器后,PHP

  • Java 项目生成静态页面的代码

    不外乎有以下因素: 1.从页面加载时间来看:静态页面不需要与数据库建立连接,尤其是访问数据量较大的页面,这种页面大多要查很多结果集,因此建立连接次数就增多了,时间不可观,而静态页面则省去了这些时间. 2.从便于搜索引擎抓取的角度来讲:搜索引擎更喜欢静态的网页,静态网页与动态网页相比,搜索引擎更喜欢静的,更便于抓取,搜索引擎SEO排名更容易提高,一些大门户站页面大多都采用静态或伪静态网页来显示,更便于搜索引擎抓取与排名. 3.从安全性来看:静态网页不宜遭到黑客攻击,因为黑客不知道你的网站的后台.网

  • PHP生成静态页面详解

    一,PHP脚本与动态页面.  PHP脚本是一种服务器端脚本程序,可通过嵌入等方  法与HTML文件混合,也可以类,函数封装等形式,以模板的方式对用户请求进行处理.无论以何种方式,它的基本原理是这样的.由客户端提出请求,请求某一页面 -----> WEB服务器引入指定相应脚本进行处理 -----> 脚本被载入服务器 -----> 由服务器指定的PHP解析器对脚本进行解析形成HTML语言形式 ----> 将解析后的HTML语句以包的方式传回给浏览器.由此不难看出,在页面发送到浏览器后,

  • php使用标签替换的方式生成静态页面

    这段代码演示了php如何通过自定义的模板页面和自定义标签生成静态页面.原理非常简单,就是将模板页面中的标签替换成动态数据即可.希望能给你一定的启发. template.html 模板文件 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmln

  • 谈PHP生成静态页面分析 模板+缓存+写文件

    一.引 言 在速度上,静态页面要比动态页面的比方php快很多,这是毫无疑问的,但是由于静态页面的灵活性较差,如果不借助数据库或其他的设备保存相关信息的话,整体的管理上比较繁琐,比方修改编辑.比方阅读权限限制等,但是,对应一些我们经常频频使用的文件,比方说,开发的新闻发布系统,我们不希望很多用户都读取数据库才显示结果,这样一方面消耗了服务器的资源,另一方面占去了浏览者大量可贵的响应时间,所有,有了"静态页面话"的做法,当前很多网站都采用这种技术,一般都是由管理后台控制,或者生成html直

  • 网站生成静态页面,及网站数据采集的攻、防原理和策略

    发布时间:2005年11月27日 晚 文章作者:翟振凯 (小琦) 交流方式: 个人站:http://www.xiaoqi.net     技术站:http://www.iisvs.net 商业站:http://www.iisvs.com QQ:53353866 22336848 关于本文:         本着互联网共享主义精神,特写此文献给建站新手,授人以鱼,不如授人以渔,本文所讲的只是方法和原理,希 望大家看完此文,能够从中得到些帮助和启发. 本文从一个ASP程序员的角度用大量实例祥细介绍了

随机推荐