轮播图接口加缓存和定时更新(双写一致性问题以及其解决方案)

一、轮播图加缓存

有些知名网站首页被访问的频率很高,假设瞬间 1w个人在访问,首页的轮播图接口会执行1w次,1w次查询轮播图标的sql在执行,轮播图基本不变,首先我们给自己写的轮播图接口加缓存,我们可以用缓存数据库Redis来实现加缓存的需求

首先罗列一下文字版的逻辑,之后在代码上实现

  1. 当轮播图接口来了请求
  2. 先去缓存看看,如果有缓存,直接返回
  3. 如果没有缓存,则去数据库查询
  4. 然后拿到数据放到Redis中,缓存起来

通过代码实现加缓存

from rest_framework.viewsets import GenericViewSet from rest_framework.mixins import ListModelMixin from luffy_api.utils.common_response import APIResponse from .models import Banner from .serializer import BannerSerializer 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, headers={'Access-control-Allow-Origin': '*'})     """加缓存之后的逻辑"""     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)  

轮播图接口加缓存和定时更新(双写一致性问题以及其解决方案)
Redis数据库也查到了缓存数据的信息
轮播图接口加缓存和定时更新(双写一致性问题以及其解决方案)

二、那么到底什么是双写一致性?

双写一致性指的是当我们更新了数据库的数据之后redis中的数据 也要同步去更新。使用redis读取数据的流程,当用户访问数据的时候,会先从缓存中读取数据,如果命中缓存的话,那么直接把缓存中的数据返回给用户,如果缓存中没有数据的话,先查询数据库把查询到的数据保存到缓存中,然后返回给用户。总结下来就是写入mysql,redis没动,数据不一致存在问题
轮播图接口加缓存和定时更新(双写一致性问题以及其解决方案)

三、如何解决双写一致性问题

  1. 修改数据,删除缓存
  2. 修改数据,更新缓存
  3. 定时更新,用celery

四、使用celery来解决双写一致性问题

通过截图解释代码的流程
轮播图接口加缓存和定时更新(双写一致性问题以及其解决方案)
在celery.py文件里面写如下代码

from datetime import timedelta 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' # 不要忘了include app = Celery('test', broker=broker, backend=backend,              include=['celery_task.banner_update_task'])  # 任务的定时配置(celery的配置文件) app.conf.timezone = 'Asia/Shanghai'  # 时区 app.conf.enable_utc = False  # 是否使用UTC # 定时任务 app.conf.beat_schedule = {     'update_banner': {         'task': 'celery_task.banner_update_task.update_banner',         'schedule': timedelta(seconds=3),  # 时间对象     }, }  

在任务文件里面写如下代码

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.all().filter(is_delete=False, is_show=True).order_by('orders')     ser = BannerSerializer(instance=banners, many=True)     for item in ser.data:         item['image'] = settings.BACKEND_URL + item['image']      cache.set('banner_list', ser.data)  # 会出问题,轮播图地址显示不全     return True  

启动worker

celery  -A celery_task  worker -l info -P eventlet 

启动beat

celery -A celery_task beat -l info 

确保过程中不出错,把前后端都重启一遍

发表评论

相关文章