轮播图接口加缓存

接口加缓存

以轮播图为例,但是轮播图其实用不到缓存因为轮播图很少更新。这个并不是什么紧急的东西。不影响用户的体验,数据实时性。

为什么接口要加缓存

如果是一个互联网项目轮播图在同一个网址的首页,如果一瞬间有很多访问量,轮播图的接口就会被执行很多次,而轮播图是从mysql里查询出来的,瞬间访问量过大很可能导致接口崩溃。

优化查询,访问来了先去缓存中找,没有再去sql里找,在把轮播图数据放到缓存中。后面的查询都可以在redis中查询。

代码

重写drf list方法在内部写逻辑后给接口继承

from rest_framework.mixins import ListModelMixin
from utils.common_response import APIResponse
from django.core.cache import cache


class CommonListBannerModelMixin(ListModelMixin):
    cache_key = None

    def list(self, request, *args, **kwargs):
        # 拿到缓存中的数据
        data = cache.get(self.cache_key)
        # 判断是否存在
        if data:
            # 有直接返回
            return APIResponse(data=data)
        else:
            # 不存在则去数据库里查
            res = super().list(request, *args, **kwargs)
            # 查出来以后存入缓存,便于后面访问接口从缓存中拿
            cache.set(self.cache_key, res.data)
            return APIResponse(data=res.data)


查看轮播图接口

from django.shortcuts import render

# Create your views here.
from rest_framework.viewsets import GenericViewSet
from .models import Banner
from .serializer import BannerSerializer
from utils.common_ListBannerModelMixin import CommonListBannerModelMixin


class BannerView(GenericViewSet, CommonListBannerModelMixin):
    queryset = Banner.objects.filter(is_delete=False, is_show=True).order_by('orders')
    serializer_class = BannerSerializer
    cache_key = 'banner_list'

但是,有一个严重的问题,这个时候如果我们的数据库中轮播图数据有变化,但是我们redis缓存中已经有了之前的数据,修改数据库数据,缓存中并没有影响。导致数据不一致。

双写一致性

解决数据不一致问题

  1. mysql数据修改后,删除缓存。
  2. 修改数据,更新缓存。
  3. 定时任务,隔一段时间更新一次缓存。 (这个不太好,实时性差,但是可以用在不是很重要的接口上)

使用celery来做

代码

在celery包里创建一个新任务,home_task

from .celery import app


from home.models import Banner
from home.serializer import BannerSerializer
from django.core.cache import cache
from django.conf import settings
# 更新缓存轮播图任务
@app.task
def update_banner():
    # 拿出轮播图数据
    banners = Banner.objects.filter(is_delete=False,is_show=True).order_by('orders')
    # 序列化
    ser =BannerSerializer(instance=banners,many=True)
    # for循环拿出对象
    for item in ser.data:
        # 修改自己拼接后的地址
        item['image'] = settings.BACKEND_URL + item['image']
    cache.set('banner_list',ser.data)  
    return True

轮播图不显示的原因是没有request对象就不会带上前缀,自己加上

settings/dev.py

# 后端地址
BACKEND_URL= 'http://127.0.0.1:8001'

在celery里写一个定时任务

from celery import Celery
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'luffy_api.settings.dev')
# 中间件 用本地的redis 1库,提交的任务放在里面
broker  ='redis://127.0.0.1:6379/1'
# 执行结果 用本地的redis 2库,执行完的结果放在里面
backend ='redis://127.0.0.1:6379/2'
# 实例化得到对象,并起个名字可以__name__获得这个文件的名字   include 指定管理的任务
app = Celery('test',broker=broker,backend=backend,include=['celery_task.order_task','celery_task.user_task','celery_task.home_task'])

from datetime import timedelta
# 定时任务
# celery的配置文件#####
# 第一步:在celery的py文件中写入
app.conf.timezone = 'Asia/Shanghai'
# 是否使用UTC
app.conf.enable_utc = False
# 任务的定时配置
app.conf.beat_schedule = {
    'update_banner':{
        'task':'celery_task.home_task.update_banner',
        'schedule': timedelta(seconds=10)
    }
}

新写的任务一定要在celery里的include托管

app = Celery('test',broker=broker,backend=backend,include=['celery_task.order_task','celery_task.user_task','celery_task.home_task'])
posted @ 2023-03-09 19:54  李阿鸡  阅读(37)  评论(0编辑  收藏  举报
Title