一、輪播圖加快取
有些知名網站首頁被訪問的頻率很高,假設瞬間 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中的資料 也要同步去更新。使用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
確保過程中不出錯,把前後端都重啟一遍