《redis實戰》讀書筆記-第二章:使用redis構建web應用

來源:互聯網
上載者:User
歡迎訪問本人部落格查看原文:http://wangnan.tech

登入和cookie緩衝

cookie:當我們登入互連網服務的時候,這些服務都會使用cookie來記錄我們的身份,cookie由少量資料群組成,網站會要求我們的瀏覽器儲存這些資料,並在每次服務發生請求時將這些資料傳回給服務

對於用來登入的cookie,有兩種方法可以將登入資訊儲存在cookie裡面,一種是簽名(signed)cookie一種是令牌(token)cookie

簽名cookie通常會儲存使用者名稱,還可能有使用者ID,使用者最後一次成功登入的時間,以及網站覺得有用的其他資訊,除此之外,cookie還會包含一個簽名,伺服器可以用它來驗證瀏覽器發生的資訊是否被改動(比如cookie中的登入使用者名稱改成另一個使用者)

令牌cookie會在cookie裡面儲存一串隨機位元組作為令牌,伺服器可以根據令牌在資料庫中尋找令牌的擁有者,隨著時間的推移,舊令牌會被新令牌取代


redis實現令牌登入cookie:首先,我們將使用一個hash來儲存登入cookie令牌和已登入使用者之間的映射,要檢查一個使用者是否已經登入,需要根據給定的令牌來尋找與之對應的使用者,並在使用者已經登入的情況下,返回該使用者的id

嘗試擷取並返回令牌對應的使用者

def check_token(conn,token):
return conn.hget('login:',token)

更新令牌:使用者每次瀏覽頁面的時候,程式都會對使用者儲存在登入hash裡面的資訊進行更新,並將使用者的令牌和目前時間戳添加到記錄最近登入使用者的有序集合裡面,如果使用者正在瀏覽一個商品頁面,那麼程式還會將這個商品添加到記錄這個使用者最近瀏覽過的商品的有序集合裡面,並在被記錄的商品的數量超過25個時,對這個有序集合進行修剪

def update_token(conn,token,user,item=None):
timestamp = time.time() //擷取目前時間戳
conn.hset('login:',token,user) //維持令牌與使用者之間的映射
conn.zadd('recent',token,timestamp)//記錄令牌最後一次出現的時間
if item:
conn.zadd('viewed:'+token,item,timestamp) //記錄使用者瀏覽過的商品
conn.zremrangebyrank('viewed:'+token,0,-26)//移除舊的記錄,只儲存使用者瀏覽過的25個商品

儲存會話的資料所需的記憶體會隨著時間的推移不斷增加,需要清理舊資料,只儲存1000萬個,清理程式是一個迴圈,檢查集合的大小,超過了限制就移除最多100箇舊令牌,並移除記錄使用者資訊的hash資訊,並清除瀏覽資訊。如果沒有要清理的,休眠1秒,在檢查(附:使用redis到期時間,就可以在一段時間之後讓redis自動刪除他們)

QUIT = False
LIMIT = 10000000

def clean_sessions(conn):
while not QUIT:
//找出目前已有令牌的數量
size = conn.zcard('recent:')
//令牌數量未超過限制,休眠並在之後重新檢查
if size <= LIMIT:
time.sleep(1)
continue
//擷取需要移除的令牌id
end_index = min(size-LIMIT,100)
tokens = conn.zrange('recent:',0,end_index-1)
//為那些要被刪除的令牌構建鍵名
session_keys = []
for token in tokens:
session_keys.append(‘viewed:’+token)
//移除舊的那些令牌
conn,delete(*session_keys)
conn.hdel('login:',*tokens)
conn.zrem('recent',*tokens)
購物車

每個使用者的購物車是一個散列,這個散列儲存了商品ID與商品訂購數量之間的映射,對商品數量驗證的工作由web應用程式複雜,我們要做的是在商品的訂購數量發生變化的時候,對購物車進行更新

def add_to_cart(conn,session,count)
if count <=0;
conn.hrem('cart:'+session,item)
else
conn.hset('cart:'+session,item,count)
網頁緩衝
def cache_request(conn,request,callback):
//對於不用背緩衝的請求,直接調用回呼函數
if not can_cache(conn,request);
return callback(request)
//將請求裝換成一個簡單的字串建。方便之後進 行尋找
page_key = 'cache:'+hash_request(request)
//尋找被緩衝的頁面
content = conn.get(request)
//如果頁面還沒有被緩衝,那麼產生頁面
if not content:
content=callback(request)
//將新產生的頁面放到緩衝裡
conn.setex(page_key,content,300)
return content
資料行緩衝

為了應對促銷活動帶來的大量負載,我們需要對資料進行緩衝,具體的做法是:編寫一個持續啟動並執行守護進程函數,讓這個函數將指定資料行緩衝到redis裡面,並不定期地對緩衝進行更新,資料將被轉為json儲存在redis的字串裡

程式使用了兩個zset,來記錄應該在何時何地對緩衝進行更新:第一個有序集合為調度有序集合,它的成員為資料行的行id,而分值是一個時間戳記,記錄了應該在何時將指定的資料行緩衝到redis裡面,第二個有序集合為延時zset,它的成員也是資料行的行id,而分值則記錄了指定資料行的緩衝需要每隔多少秒更新一次

調度緩衝和終止緩衝的函數

def schedule_row_cache(conn,row_id,delay):
//先設定資料行的延遲值
conn.zadd('delay',row_id,delay)
//立即對需要緩衝的資料進行調度
conn.zadd('schedule‘,row_id,time.time())

複雜快取資料的函數

def cache_rows(conn):
while not QUIT:
//嘗試擷取下一個需要被緩衝的資料行以及該行的調度時間戳記,命令會返回一個包含零個或一個元組的列表
next = conn.zrange('schedule:',0,0,withscores=Ture)
now = time.time()
//暫時沒有行需要被緩衝,休眠60ms後重試
if not next or next[0][1]>row
time.sleep(.05)
continue
row_id = next[0][0]
//提前擷取下一次調度的延遲時間
delay=conn.zscore('delay',row_id)
if delay <=0:
//不必緩衝這個行,從他從緩衝中移除
conn.zrem('delay:',row_id)
conn.zrem('schedule:',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.dump(row.to_dict()))
網頁分析

在原來的update_token中

def update_token(conn,token,user,item=None):
timestamp = time.time() //擷取目前時間戳
conn.hset('login:',token,user) //維持令牌與使用者之間的映射
conn.zadd('recent',token,timestamp)//記錄令牌最後一次出現的時間
if item:
conn.zadd('viewed:'+token,item,timestamp) //記錄使用者瀏覽過的商品
conn.zremrangebyrank('viewed:'+token,0,-26)//移除舊的記錄,只儲存使用者瀏覽過的25個商品
conn.zincrby('viewed:'item,-1)

新添加的代碼記錄了商品的瀏覽次數,並根據瀏覽次數對商品進行了排序,被瀏覽的最多的商品將被放在有序集合的索引0的位置上,並且具有最少的分值 
為了讓商品瀏覽次數保持最新,我們需要定期修剪有序集合的長度並調整已有元素的分值,從而使得新流行的商品也可以在熱門排行榜裡面佔據一席之地

def rescale_viewed(conn);
while not QUIT:
//刪除所有牌面在2萬名之後的商品
conn.zremrangebyrank('viewed',0,-20001)
//將瀏覽次數降低為原來的一般
conn,zinterstore('viewed:' .5)
time.sleep(300)

修改之前的的can_cache()函數

def can_cache(conn request);
//嘗試從頁面裡面擷取商品id
item_id = extract_itrm_id(request)
//檢查這個頁面能否被緩衝已經這個頁面是否為商品頁面
if not item_id or is_dynamic(request);
return False
//擷取商品的瀏覽次數牌面
rank = conn,zrank('viewed',item_id)
根據排名判斷是否需要被緩衝
return rank is not None and rank<10000
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.