Python--Redis實戰:第二章:使用Redis構建Web應用:第四節:數據行緩存

上一篇文章: Python--Redis實戰:第二章:使用Redis構建Web應用:第三節:網頁緩存
下一篇文章: Python--Redis實戰:第二章:使用Redis構建Web應用:第五節:網頁分析

到目前爲止,咱們已經:數據庫

  • 將本來由關係數據庫和網頁瀏覽器實現的登陸和訪客會話轉移到了Redis上面實現;
  • 將本來有關係數據庫實現的購物車也放到了Redis上面實現;
  • 將全部頁面緩存到了Redis裏面;

這一系列工做提高了網站的性能,下降了關係數據庫的負載並較少了網站的成本。json

如今通過分析,咱們的網站的商品頁面一般只會從數據庫裏面載入一兩行數據,包括已登陸用戶的用戶信息【這些信息能夠經過AJAX動態載入,因此不會對頁面緩存形成影響】和商品自己的信息。即便是那些沒法被整個緩存起來的頁面:好比用戶帳號頁面、記錄用戶以往購買商品的頁面等等,程序也能夠經過緩存頁面載入時所需的數據庫行來減小載入頁面所需的時間。segmentfault

爲了展現數據行緩存的做用,咱們假設咱們的網站爲了清空舊庫存和吸引客戶消費,決定開始新一輪的促銷活動:這個活動天天都會推出一些特價商品供用戶搶購,全部特價商品的數量都是限定的,賣完即止。在這種狀況下,網址是不能對整個促銷頁面進行緩存的,由於這可能會致使用戶看到錯誤的特價商品的剩餘數量,可是每次載入頁面都從數據庫裏面取出特價商品的剩餘數量的話,又會給數據庫帶來巨大的壓力,並致使咱們須要花費額外的成原本擴展數據庫。瀏覽器

爲了應對促銷互動帶來的大量負載,咱們須要對數據行進行緩存,具體的作法是:編寫一個持續運行的守護進程函數,讓這個函數將指定的數據行緩存到Redis裏面,並不按期地對這些緩存進行更新。緩存函數會將數據行編碼【encode】爲JSON字典並存儲在Redis的字符串裏面,其中,數據列【column】的名字會被映射爲JSON字典的鍵,而數據行的值則會被映射爲JSON字典的值。緩存

程序使用了兩個有序集合來記錄應該在什麼時候對緩存進行更新:函數

  • 第一個有序集合爲調度【schedule】有序集合,它的成員爲數據行的行ID,而分值則是一個時間戳,這個時間戳記錄了應該在什麼時候將制定的數據行緩存到Redus裏面
  • 第二個有序集合爲延時【delay】有序集合,它的成員也是數據行的ID,而分值則記錄了指定數據行的緩存須要每隔多少秒更新一次。

爲了讓緩存函數按期的緩存數據行,程序首先須要將行ID和給定的延遲值添加到延遲有序集合裏面,而後再將行ID和當前時間的時間戳添加到調度有序集合裏面。實際執行緩存操做的函數須要用到數據行的延遲值,若是某個數據行的延遲值不存在,那麼程序將取消對這個數據行的調度。若是咱們想要移除某個數據行已有的緩存,而且讓緩存函數再也不緩存那個數據行,那麼只須要把那個數據行的延遲值設置爲小於或等於0就能夠了。性能

#負責調度緩存和終止緩存的函數
import time

def schedule_row_cache(conn,row_id,delay):
    #先設置數據行的延遲值
    conn.zadd('delay:',row_id,delay)
    #當即對須要緩存的數據行進行調度
    conn.zadd('schedule:',row_id,time.time())

如今咱們已經完成了調度部分,那麼接下來該如何對數據進行緩存呢?負責緩存數據行的函數會嘗試讀取調度有序集合的第一個元素以及該元素的分值,若是調度有序集合沒有包含任何元素,或者分值存儲的時間戳所指定的時間還沒有來臨,那麼函數會先休眠50毫秒,而後再從新進行檢查。當緩存函數發現了一個須要理解進行更新的數據行時,緩存函數會檢查這個數據行的延遲值:若是數據行的延遲值小於或者等於0,那麼緩存函數會從延遲有序集合和調度有序集合裏面移除這個數據行ID,並從緩存裏面刪除這個數據行已有的緩存,而後再從新進行檢查;對於延遲值大於0的數據行來講,緩存函數會中數據庫裏面取出這些行,將他們編碼爲JSON格式並存儲到Redis裏面,而後更新這些行的調度時間。學習

def cahce_rows(conn):
    while not QUIT:
        #嘗試獲取下一個須要被緩存的數據行以及該行的調度時間戳,命令會返回一個包含0或1個元祖【tuple】的列表
        next=conn.zrange('schedule:',0,0,withscores=True)
        now=time.time()

        if not next or next[0][3]>now:
            #暫時沒有行須要被緩存,休眠50毫秒後重試
            time.sleep(.05)
            continue
        row_id=next[0][0]

        #獲取下一次調度的延遲水岸
        delay=conn.zscore('delay:',row_id)
        if delay<=0:
            #沒必要再緩存這個行,將他從緩存中移除
            conn.zrem('delay:',row_id)
            conn.delete('inv:'+row_id)
            continue

        #讀取行數據
        row=Inventory.get(row_id)
        #更新調度時間並設置緩存值
        conn.zadd('schedule:',row_id,now+delay)
        conn.set('inv:'+row_id,json.dumps(row.to_dict()))

經過組合使用調度函數和持續運行緩存函數,咱們實現了一種重複進行調度的自動緩存機制,而且能夠爲所欲爲地控制緩存行緩存的更新頻率:若是數據行記錄的是特價促銷商品的剩餘數量,而且參與促銷活動的用戶很是多的話,那麼咱們最好每隔幾秒更新一次數據行緩存;另外一方面,若是數據並不常常改變,或者商品缺貨是能夠接受的,那麼咱們能夠每分鐘更新一次緩存。網站

在這一節中,咱們學習瞭如何將數據行緩存到Redis裏面,在下面一節中,咱們經過只緩存一部分頁面來減小時間頁面緩存所需的內存數量。編碼

上一篇文章: Python--Redis實戰:第二章:使用Redis構建Web應用:第三節:網頁緩存
下一篇文章: Python--Redis實戰:第二章:使用Redis構建Web應用:第五節:網頁分析
相關文章
相關標籤/搜索