快取更新-- 穿透/擊穿/雪崩 django-celery-flower Celery的應用///如何不重啟寫入

拆尼斯、帕丁顿發表於2024-03-26

快取

快取更新策略

# 如果記憶體中redis資料滿了,再繼續往裡存資料,redis會觸發快取更新的策略
# 有如下幾種
LRU/LFU/FIFO演算法剔除:例如maxmemory-policy(到了最大記憶體,對應的應對策略)

# LRU -Least Recently Used,沒有被使用時間最長的
# LFU -Least Frequenty User,一定時間段內使用次數最少的
# FIFO -First In First Out,最早放進去的key

# LIRS (Low Inter-reference Recency Set)是一個頁替換演算法,相比於LRU(Least Recently Used)和很多其他的替換演算法,LIRS具有較高的效能。這是透過使用兩次訪問同一頁之間的距離(本距離指中間被訪問了多少非重複塊)作為一種尺度去動態地將訪問頁排序,從而去做一個替換的選擇

快取穿透 快取擊穿 快取雪崩

###  快取穿透
#描述:
快取穿透是指快取和資料庫中都沒有的資料,而使用者不斷髮起請求,如發起為id為“-1”的資料或id為特別大不存在的資料。這時的使用者很可能是攻擊者,攻擊會導致資料庫壓力過大。
#解決方案:
1 介面層增加校驗,如使用者鑑權校驗,id做基礎校驗,id<=0的直接攔截;
2 從快取取不到的資料,在資料庫中也沒有取到,這時也可以將key-value對寫為key-null,快取有效時間可以設定短點,如30秒(設定太長會導致正常情況也沒法使用)。這樣可以防止攻擊使用者反覆用同一個id暴力攻擊
3 透過布隆過濾器實現:把所有使用者id放到布隆過濾器中---》請求過來---》去布隆過濾器中檢查 id在不在,如果在---》資料肯定有---》繼續往後走  ---》如果布隆過濾器中沒有---》不是我們的資料---》直接拒絕

    
    

### 快取擊穿
#描述:
快取擊穿是指快取中沒有但資料庫中有的資料(一般是快取時間到期),這時由於併發使用者特別多,同時讀快取沒讀到資料,又同時去資料庫去取資料,引起資料庫壓力瞬間增大,造成過大壓力
#解決方案:
設定熱點資料永遠不過期。

 
### 快取雪崩
#描述:
快取雪崩是指快取中資料大批次到過期時間,而查詢資料量巨大,引起資料庫壓力過大甚至down機。和快取擊穿不同的是,快取擊穿指併發查同一條資料,快取雪崩是不同資料都過期了,很多資料都查不到從而查資料庫。
# 解決方案:
1 快取資料的過期時間設定隨機,防止同一時間大量資料過期現象發生。
2 如果快取資料庫是分散式部署,將熱點資料均勻分佈在不同得快取資料庫中。
3 設定熱點資料永遠不過期。




# 你知道redis的跳躍表嗎?
    -聽說過,它是redis 儲存有序集合底層的資料結構
    
# 平衡二叉樹,紅黑樹 , hash

# 手寫排序演算法
    -冒泡
    -快排
    -插入排序。。。

django-celery-flower

# celer:分散式非同步任務框架,python寫的,是一個獨立服務,跟其他服務相互配合使用
# 能夠做的事:
    -非同步任務
    -延遲任務
    -定時任務
    
    
# celery架構

# 快速使用


# 包結構

# 執行三個任務
    非同步
    延遲
    定時
    
# 整合到django中---》包結構

手動提交任務

pip3 install django-celery-beat

結果存在資料庫中

pip3 install django-celery-results

flower

# flower 對celery執行情況做監控


# 訊息堆積

# worker執行情況

# flower 對celery進行監控

# 啟動
celery --broker=redis://127.0.0.1:6379/2 flower

# 瀏覽器中訪問:http://127.0.0.1:5555/
    -worker
    -broker
    -task

python傳送郵件-釘釘

# 簡訊通知
# 郵件通知
    -django
    -原生python
# 企業微信通知:對應介面
# 個人公眾號通知:
    
# 釘釘通知
    -1 群裡建立釘釘機器人---》傳送訊息
         
   # 建個群,在群裡定時傳送訊息

   # 給企業中某個人發通知
        -建立應用
        -獲得access_token
        -獲得公司所有部門
        -獲得公司部門下所有員工
        -給員工傳送釘釘通知
        -獲取某個員工打卡資訊

- - - - - - - - - - - - - - - - - -

Celery介紹

Celery 是什麼?

# 1 celery 是一個靈活且可靠的,處理大量訊息的分散式系統,可以在多個節點之間處理某個任務

# 2 celery 是一個專注於實時處理的任務佇列,支援任務排程

# 3 celery 是開源的,有很多的使用者

# 4 celery 完全基於 Python 語言編寫

# 5 所以 celery 本質上是一個分散式的非同步任務排程框架,類似於 Apache 的 airflow

# 6 celery 只是用來排程任務的,但它本身並不具備儲存任務的功能,而排程任務的時候肯定是要把任務存起來的。因此要使用 celery 的話,還需要搭配一些具備儲存、訪問功能的工具,比如:訊息佇列、Redis快取、資料庫等等。官方推薦的是訊息佇列 RabbitMQ,我們使用 Redis 

celery 使用場景

# 1 非同步任務
    -一些耗時的操作可以交給celery非同步執行,而不用等著程式處理完才知道結果。
    -影片轉碼、郵件傳送、訊息推送等等
# 2 定時任務
    -定時推送訊息、定時爬取資料、定時統計資料等

# 3 延遲任務
    -提交任務後,等待一段時間再執行某個任務

Celery官網

# 1 開源地址(原始碼)
https://github.com/celery/celery
    
# 2  官網
https://docs.celeryq.dev/en/stable/
    
# 4 最新版本
Celery (5.3)

# 5 python支援
Celery version 5.3 runs on
Python ❨3.8, 3.9, 3.10, 3.11❩

# 6 Django支援
Celery 5.3.x supports Django 2.2 LTS or newer versions. Please use Celery 5.2.x for versions older than Django 2.2 or Celery 4.4.x if your Django version is older than 1.11

Celery架構

# Celery 架構,它採用典型的生產者-消費者模式,主要由以下部分組成:

# 1 Celery Beat,任務排程器,Beat 程序會讀取配置檔案的內容,週期性地將配置中到期需要執行的任務傳送給任務佇列。

# 2 Producer:需要在佇列中進行的任務,一般由使用者、觸發器或其他操作將任務入隊,然後交由 workers 進行處理。呼叫了 Celery 提供的 API、函式或者裝飾器而產生任務並交給任務佇列處理的都是任務生產者。

# 3 Broker,即訊息中介軟體,在這指任務佇列本身,Celery 扮演生產者和消費者的角色,brokers 就是生產者和消費者存放/獲取產品的地方(佇列)。

# 4 Celery Worker,執行任務的消費者,從佇列中取出任務並執行。通常會在多臺伺服器執行多個消費者來提高執行效率。

# 5 Result Backend:任務處理完後儲存狀態資訊和結果,以供查詢。Celery 預設已支援 Redis、RabbitMQ、MongoDB、Django ORM、SQLAlchemy 等方式。



實際應用中,使用者從 Web 前端發起一個請求,我們只需要將請求所要處理的任務丟入任務佇列 broker 中,由空閒的 worker 去處理任務即可,處理的結果會暫存在後臺資料庫 backend 中。我們可以在一臺機器或多臺機器上同時起多個 worker 程序來實現分散式地並行處理任務。

Celery 快速使用

安裝

# 0 建立Python專案

# 1 建立虛擬環境

# 2 安裝celery
pip install celery

# 3 安裝redis(訊息佇列和結果儲存使用redis)
pip install redis

# 4 安裝eventlet(win 平臺)
pip install eventlet

快速使用

celery_demo.py--主檔案

from celery import Celery
import time

broker = 'redis://127.0.0.1:6379/1'
backend = 'redis://127.0.0.1:6379/2'
app = Celery('celery_test', broker=broker, backend=backend)


@app.task
def add(n, m):
    time.sleep(2)
    print('n+m的結果:%s' % (n + m))
    return n + m


@app.task
def send_email(mail='616564099@qq.com'):
    print('模擬傳送延遲--開始')
    time.sleep(2)
    print('模擬傳送延遲--結束')
    return '郵件傳送成功:%s' % mail

add_task.py--提交非同步任務

from celery_demo import add,send_email


##1 同步呼叫
res=send_email()
print(res)

# 2 非同步呼叫
res = add.delay(10, 20)
print(res.id)

透過resp檢視任務

開啟worker

celery -A celery_demo worker -l info -P eventlet

get_result.py-檢視結果

from celery_demo import app

from celery.result import AsyncResult

id = 'd0ae78c8-9a8e-4f93-9d32-b17d4e295fe9'
if __name__ == '__main__':
    result = AsyncResult(id=id, app=app)
    if result.successful():
        result = result.get()
        print(result)
    elif result.failed():
        print('任務失敗')
    elif result.status == 'PENDING':
        print('任務等待中被執行')
    elif result.status == 'RETRY':
        print('任務異常後正在重試')
    elif result.status == 'STARTED':
        print('任務已經開始被執行')

包結構

目錄結構

專案名
    ├── celery_task      # celery包
    │   ├── __init__.py # 包檔案
    │   ├── celery.py   # celery連線和配置相關檔案,且名字必須叫celery.py
    │   └── tasks.py    # 所有任務函式
    ├── add_task.py      # 新增任務
    └── get_result.py   # 獲取結果

celery.py

from celery import Celery
broker = 'redis://127.0.0.1:6379/1'
backend = 'redis://127.0.0.1:6379/2'
app = Celery(broker=broker, backend=backend, include=['celery_task.tasks'])

tasks.py

from .celery import app
import time
@app.task
def add(n, m):
    time.sleep(2)
    print('n+m的結果:%s' % (n + m))
    return n + m


@app.task
def send_email(mail='616564099@qq.com'):
    print('模擬傳送延遲--開始')
    time.sleep(2)
    print('模擬傳送延遲--結束')
    return '郵件傳送成功:%s' % mail

執行非同步--延遲--定時任務

非同步任務

res = add.delay(10, 20)

延遲任務

from datetime import datetime, timedelta
eta=datetime.utcnow() + timedelta(seconds=10)
tasks.add.apply_async(args=(200, 50), eta=eta)

定時任務

#1  celery.py中加入
# 時區
app.conf.timezone = 'Asia/Shanghai'
# 是否使用UTC
app.conf.enable_utc = False

# 任務的定時配置
from datetime import timedelta
from celery.schedules import crontab
app.conf.beat_schedule = {
    'low-task': {
        'task': 'celery_task.tasks.add',
        'schedule': timedelta(seconds=3),
        # 'schedule': crontab(hour=8, day_of_week=1),  # 每週一早八點
        'args': (300, 150),
    }
}

# 2 啟動worker
celery -A celery_task worker -l debug -P eventlet

# 3 啟動beat
celery -A celery_task beat -l debug

  

 

相關文章