Celery高级用法——接口加缓存、双写一致性

轮播图接口加缓存

为什么要加缓存

  • 网站首页被访问的频率很高,同一时间1w个人在访问,首页的轮播图接口会执行1w次,如果每一次都向后台拿数据,则效率较低
  • 想一种方式,让这1w个访问,效率更高一些,不查数据库了,直接走缓存--》redis--》效率高
  • 现在的逻辑变成了
    • 轮播图接口请求来了,先去缓存中看,如果有,直接返回
    • 如果没有,查数据库,然后把轮播图数据,放到redis中,缓存起来

轮播图接口修改

from rest_framework.viewsets import GenericViewSet
from .models import Banner
from .serializer import BannerSerializer

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


class BannerView(GenericViewSet,ListModelMixin):
    queryset = Banner.objects.filter(is_delete=False,is_show=True).order_by('orders')
    serializer_class = BannerSerializer
    
    # 原来的接口
    # def list(self, request, *args, **kwargs):
    #     res = super().list(request,*args,**kwargs)
    #     return APIResponse(data=res.data)

    # 加入缓存的轮播图接口
    def list(self, request, *args, **kwargs):
        # 获取缓存中的数据
        banner_list=cache.get('banner_list')
        if banner_list:
            print('走了缓存')
            # 缓存中有数据,直接返回缓存中的数据
            return APIResponse(data=banner_list)
        else:
            print('走了数据库')
            # 缓存中没有,走数据库
            res = super().list(request,*args,**kwargs)
            # 把序列化后的数据存入缓存中
            cache.set('banner_list',res.data)
            return APIResponse(data=res.data)

封装接口加缓存

utils下新建一个py文件

# utils/common_view.py

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


class CacheListModelMixin(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(CacheListModelMixin, self).list(request, *args, **kwargs)
            # 把序列化后的数据存入缓存中
            cache.set(self.cache_key, res.data)
            return APIResponse(data=res.data)

双写一致性

  • 加入缓存后,缓存中有数据,先去缓存拿,但是如果mysql中数据变了,缓存不会自动变化,出现数据不一致的问题

如何解决数据不一致问题

  • 1 修改数据,删除缓存
  • 2 修改数据,更新缓存
  • 3 定时更新缓存 ---》实时性差

示例:定时更新(使用celery的定时任务)

celery_task/home_task.py

from .celery import app
from home.models import Banner
from home.serializer import BannerSerializer
from django.core.cache import cache

@app.task
def update_banner():
    # 只要这个任务一更新,就更新轮播图的缓存
    banners = Banner.objects.all().filter(is_delete=False,is_show=True).order_by('orders')
    ser=BannerSerializer(instance=banners,many=True)
    cache.set('banner_list',ser.data)
    return True

celery.py

from celery import Celery

import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'luffy_api.settings.dev')

broker = 'redis://127.0.0.1:6379/1'
backend = 'redis://127.0.0.1:6379/2'

app = Celery('test',broker=broker,backend=backend,include=['celery_task.home_task'])


# 设置时区
app.conf.timezone = 'Asia/Shanghai'
# 是否使用UTC
app.conf.enable_utc = False

from datetime import timedelta
from celery.schedules import crontab

# 任务的定时配置
app.conf.beat_schedule = {
            'update_banner': {
                'task': 'celery_task.home_task.update_banner',  # 定时任务路径
                'schedule': timedelta(days=7),  # 每隔7天更新一次,具体时间看项目需求
        }
}

补充:使用视图函数存在的问题

  • home页面图片无法正常显示(轮播图地址显示不全)
  • 如果是在视图类中,会自动处理

解决方法:

1. 在配置文件设置后台路径

# dev.py
BACKEND_URL='http://127.0.0.1:8000'

2. celery_task/home_task.py修改

from .celery import app
from home.models import Banner
from home.serializer import BannerSerializer
from django.core.cache import cache
from settings.dev import BACKEND_URL

@app.task
def update_banner():
    # 只要这个任务一更新,就更新轮播图的缓存
    banners = Banner.objects.all().filter(is_delete=False,is_show=True).order_by('orders')
    ser=BannerSerializer(instance=banners,many=True)
    for item in ser.data:
        item['image'] = BACKEND_URL + item['image']
    cache.set('banner_list',ser.data)
    return True

 

posted @ 2023-03-09 23:06  莫~慌  阅读(97)  评论(0编辑  收藏  举报