1. 程式人生 > 實用技巧 >django介面快取與Redis快取存在問題

django介面快取與Redis快取存在問題

django介面快取與Redis快取存在問題

django介面快取的示範

# 首頁輪播圖的快取
def list(self, request, *args, **kwargs):
    """
    先從快取中去取,沒有查詢資料庫,同時返還一份給快取儲存;若快取中有,直接將快取中的值返回
    """
    banner_list = cache.get(settings.BANNER_LIST_CACHE)
    if not banner_list:
        queryset = self.filter_queryset(self.get_queryset())
        serializer = self.get_serializer(queryset, many=True)
        cache.set(settings.BANNER_LIST_CACHE, serializer.data,60*60)
        return Response(data=serializer.data)
    return Response(data=banner_list)

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

快取穿透

# 查詢一個數據庫一定不存在的資料。正常快取的使用流程是:先到快取中查,如果快取中沒有,再去資料庫中查,如果查詢不到,則不放進快取。

這就會造成一個嚴重的問題:如果黑客利用這個漏洞,往伺服器傳送大量的請求,使用不存在的key查詢,會瞬間壓倒資料庫。

正常的訪問流程

但是如果Redis資料不存在,資料庫資料也不存在,返回空,但是一般來說,空值是不會被寫入Redis,如果反覆請求同一條資料,則會發生快取穿透的現象

解決方案一

# 如果查詢資料的值為空值,設定個預設值,用Redis儲存起來,不過設定的過期時間很短,如30秒

def list(self,request,*args,**kwargs):
    query_res = cache.get(cachekey)
    if not query_res:
        query_res = self.get_object()
        if not query_res:
            cache.set(cachekey,'null',30)
            return Response(data='null')
        else:
            cache.set(cachekey,query_res,24*60*60)
            return Response(data=query_res)
    retrun Response(data=query_res)

但是,如果黑客,每次都使用不同步存在的key進行進行反問,還是會有造成快取穿透的風險

解決思路:

可以中介軟體裡面進行限制,對於存在大量異常請求的IP進行限制,直接返回

解決方案二:

採用布隆過濾器,將所有可能存在的資料雜湊到一個足夠大的bitmap中,一個一定查詢不到的資料會被這個bitmap給攔截掉,從而避免了對底層儲存系統的查詢壓力。

快取擊穿

# 快取擊穿是指,一個key非常地熱點,扛著超高的併發,當這個key失效的瞬間,持續的高併發就穿透了快取,直接訪問資料庫,導致資料庫癱瘓

解決方案:

業界比較常用的做法,是使用mutex。簡單地來說,就是在快取失效的時候(判斷拿出來的值為空),不是立即去load db,而是先使用快取工具的某些帶成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一個mutex key,當操作返回成功時,再進行load db的操作並回設快取;否則,就重試整個get快取的方法。
SETNX,是「SET if Not eXists」的縮寫,也就是隻有不存在的時候才設定,可以利用它來實現鎖的效果。

快取雪崩

快取雪崩是指,由於快取層承載著大量請求,有效的保護了儲存層,但是如果快取層由於某些原因整體不能提供服務,於是所有的請求都會達到儲存層,儲存層的呼叫量會暴增,造成儲存層也會掛掉的情況。
解決方案

保證快取層服務高可用性

即使個別節點、個別機器、甚至是機房宕掉,依然可以提供服務,比如 Redis Sentinel 和 Redis Cluster 都實現了高可用。

依賴隔離元件為後端限流並降級

在快取失效後,通過加鎖或者佇列來控制讀資料庫寫快取的執行緒數量。比如對某個key只允許一個執行緒查詢資料和寫快取,其他執行緒等待。

資料預熱

可以通過快取reload機制,預先去更新快取,再即將發生大併發訪問前手動觸發載入快取不同的key,設定不同的過期時間,讓快取失效的時間點儘量均勻。

快取併發

快取併發是指,高併發場景下同時大量查詢過期的key值、最後查詢資料庫將快取結果回寫到快取、造成資料庫壓力過大

分散式鎖

在快取更新或者過期的情況下,先獲取鎖,在進行更新或者從資料庫中獲取資料後,再釋放鎖,需要一定的時間等待,就可以從快取中繼續獲取資料。