4

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

 1 year ago
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.
neoserver,ios ssh client

一、轮播图加缓存

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

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

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

通过代码实现加缓存

python
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)

2987444-20230312161829678-2025742822.png


Redis数据库也查到了缓存数据的信息

2987444-20230312170305725-620417182.png

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

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

2987444-20230312162255150-1381047675.png

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

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

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

通过截图解释代码的流程

2987444-20230312174744637-421532294.png


在celery.py文件里面写如下代码

python
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),  # 时间对象
    },
}

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

python
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

python
celery  -A celery_task  worker -l info -P eventlet

启动beat

python
celery -A celery_task beat -l info

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

__EOF__


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK