轮播图接口加缓存和定时更新(双写一致性问题以及其解决方案) - 阿丽米热
source link: https://www.cnblogs.com/almira998/p/17208674.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
一、轮播图加缓存
有些知名网站首页被访问的频率很高,假设瞬间 1w个人在访问,首页的轮播图接口会执行1w次,1w次查询轮播图标的sql在执行,轮播图基本不变,首先我们给自己写的轮播图接口加缓存,我们可以用缓存数据库Redis来实现加缓存的需求
首先罗列一下文字版的逻辑,之后在代码上实现
- 当轮播图接口来了请求
- 先去缓存看看,如果有缓存,直接返回
- 如果没有缓存,则去数据库查询
- 然后拿到数据放到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读取数据的流程,当用户访问数据的时候,会先从缓存中读取数据,如果命中缓存的话,那么直接把缓存中的数据返回给用户,如果缓存中没有数据的话,先查询数据库把查询到的数据保存到缓存中,然后返回给用户。总结下来就是写入mysql,redis没动,数据不一致存在问题
三、如何解决双写一致性问题
- 修改数据,删除缓存
- 修改数据,更新缓存
- 定时更新,用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
确保过程中不出错,把前后端都重启一遍
__EOF__
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK