成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

Python--Redis實(shí)戰(zhàn):第二章:使用Redis構(gòu)建Web應(yīng)用:第一節(jié):登錄和cookie緩存

makeFoxPlay / 3698人閱讀

摘要:需要在服務(wù)中存儲更多信息,如果使用的是關(guān)系數(shù)據(jù)庫,那么載入和存儲的的代價可能會很高。這次我們使用令牌來引用關(guān)系數(shù)據(jù)庫表中負(fù)責(zé)存儲用戶登錄信息的條目。而我們要做的就是適用重新實(shí)現(xiàn)登錄功能,取代由關(guān)系數(shù)據(jù)庫實(shí)現(xiàn)的登錄功能。

上一篇文章:Python--Redis實(shí)戰(zhàn):第一章:初識Redis:第三節(jié):你好Redis-文章投票試煉
下一篇文章:Python--Redis實(shí)戰(zhàn):第二章:使用Redis構(gòu)建Web應(yīng)用:第二節(jié):使用Redis實(shí)現(xiàn)購物車

從高層次的角度來看,Web應(yīng)用就是通過HTTP協(xié)議對網(wǎng)頁瀏覽器發(fā)送的請求進(jìn)行響應(yīng)的服務(wù)器或者服務(wù)【service】。一個Web服務(wù)器對請求進(jìn)行響應(yīng)的典型步驟如下:

服務(wù)器對客戶端發(fā)來的請求【request】進(jìn)行解析。

請求被轉(zhuǎn)發(fā)給一個預(yù)定義的處理器【handler】

處理器可能會從數(shù)據(jù)庫取出數(shù)據(jù)

處理器根據(jù)取出的數(shù)據(jù)對模板【template】進(jìn)行渲染(render)

處理器向客戶端返回渲染后的內(nèi)容作為對請求的響應(yīng)【response】

以上列舉的5個步驟從高層次的角度展示了典型Web服務(wù)器的運(yùn)作方式,這種情況下的Web請求被認(rèn)為是無狀態(tài)的【stateless】,也就是說,服務(wù)器本身不會記錄與過往有關(guān)的任何信息,這使得失效【fail】的服務(wù)器可以很容易地被替換掉。有不少書籍專門介紹了如何優(yōu)化響應(yīng)過程的各個步驟,本章要做的事情也類似,不同之處是,我們將介紹如何使用更快的Redis查詢來替代傳統(tǒng)的關(guān)系數(shù)據(jù)庫查詢,已經(jīng)如何使用Redis來完場一些使用關(guān)系數(shù)據(jù)庫沒有辦法高效完場的任務(wù)。

本章的所有內(nèi)容都是圍繞著發(fā)現(xiàn)并解決【Fake Web Retailer】這個虛構(gòu)的大型網(wǎng)上商店來展開的,這個商店每天都會有大約500萬名不同的用戶,這些用戶會給網(wǎng)站帶來一億次點(diǎn)擊,并從網(wǎng)站購買超過10萬件商品。我們之所以將這幾個數(shù)據(jù)量設(shè)置的特別大,是考慮【如果可以在大數(shù)據(jù)背景下順利解決問題,那么解決小數(shù)據(jù)量和中等數(shù)據(jù)量引發(fā)的問題就更不在話下】。

登錄和cookie緩存

每當(dāng)我們登錄互聯(lián)網(wǎng)服務(wù)的時候,這些服務(wù)都會使用cookie來記錄我們的身份。cookie由少量數(shù)據(jù)組成,網(wǎng)站會要求我們的瀏覽器存儲這些數(shù)據(jù),并在每次服務(wù)器請求發(fā)送時將這些數(shù)據(jù)傳回給服務(wù)器。對于用來登錄的cookie,有兩種常見的方式可以將登錄信息存儲在cookie里面:

簽名【signed】cookie

令牌【token】cookie

簽名cookie通常會存儲用戶名,可能還有用戶ID,用戶最后一次登錄成功的時間,以及網(wǎng)站覺得有用的其他任何信息。除了用戶的相關(guān)信息之外,簽名cookie還包含了一個簽名,服務(wù)器可以使用這個簽名來驗(yàn)證瀏覽器發(fā)送的消息是否未經(jīng)改動(比如將cookie中的登錄用戶名改成另一個用戶)。

令牌cookie會在cookie里面存儲一串隨機(jī)字節(jié)作為令牌,服務(wù)器可以根據(jù)令牌在數(shù)據(jù)庫中查詢令牌的擁有者。隨著時間的推移,舊令牌會被新令牌去掉。

cookie類型 優(yōu)點(diǎn) 缺點(diǎn)
簽名cookie 驗(yàn)證cookie所需的一切信息都存儲在cookie里面,cookie可以包含額外的信息,并且對這些信息進(jìn)行簽名也很容易。 正確的處理簽名很難,很容易忘記對數(shù)據(jù)進(jìn)行簽名,或者忘記驗(yàn)證數(shù)據(jù)的簽名,從而造成安全漏洞。
令牌cookie 添加信息非常容易,cookie的體積非常小,因此移動終端和速度較慢的客戶端可以更快地發(fā)送請求。 需要在服務(wù)中存儲更多信息,如果使用的是關(guān)系數(shù)據(jù)庫,那么載入和存儲的cookie的代價可能會很高。

這次我們使用令牌cookie來引用關(guān)系數(shù)據(jù)庫表中負(fù)責(zé)存儲用戶登錄信息的條目【entry】。除了用戶登錄信息之外,我們還可以將用戶的訪問時長和已瀏覽商品的數(shù)量等信息存儲到數(shù)據(jù)庫里面,這樣便于將來通過分析這些信息來學(xué)習(xí)如果更好得向用戶推銷商品。

一般來說,用戶在決定購買某個或某些商品之前,通常都會先瀏覽多個不同商品,而記錄用戶瀏覽過的所有商品以及用戶最后一次訪問頁面的時間等信息,通常會導(dǎo)致大量的數(shù)據(jù)庫寫入。從長遠(yuǎn)來看,用戶的這些瀏覽數(shù)據(jù)的確非常有用,但問題是,即便經(jīng)過優(yōu)化,大多數(shù)關(guān)系數(shù)據(jù)庫在每臺數(shù)據(jù)庫服務(wù)器上每秒也只能插入、更細(xì)或者刪除200~2000個數(shù)據(jù)行。盡量批量插入、批量更新和批量刪除等操作可以更快地速度執(zhí)行,但因?yàn)榭蛻舳嗣看螢g覽網(wǎng)頁都只更新少數(shù)幾行,所以高速的批量插入在這里并不適用。

我們假設(shè)我們的網(wǎng)站每天的負(fù)載量都比較大:平均每秒大約1200次寫入,高峰時期每秒接近6000次寫入,所以它必須部署10臺關(guān)系數(shù)據(jù)服務(wù)器才能應(yīng)對高峰時期的負(fù)載量。而我們要做的就是適用Redis重新實(shí)現(xiàn)登錄cookie功能,取代由關(guān)系數(shù)據(jù)庫實(shí)現(xiàn)的登錄cookie功能。

首先,我們將使用一個散列來存儲登錄cookie令牌和已登錄用戶之間的映射。要檢查一個用戶是否已經(jīng)登錄,需要根據(jù)給定的令牌來查找與之對應(yīng)的用戶,并在用戶已經(jīng)登錄的情況下,返回該用戶的ID。

def check_token(conn,token):
    #嘗試獲取并返回令牌對應(yīng)的用戶
    return conn.hget("login:",token)

對令牌進(jìn)行檢查并不困難,因?yàn)榇蟛糠謴?fù)雜的工作都是在更新令牌時完成的:用戶每次瀏覽頁面時,程序都會對用戶存儲在登錄散列里面的信息進(jìn)行更新,并將用戶的令牌和當(dāng)前時間戳添加到記錄最近登錄用戶的有序集合里面;如果用戶正在瀏覽的是一個商品頁面,那么程序還會將這個商品添加到記錄這個用戶最近瀏覽過的商品的有序集合里面,并在被記錄商品的數(shù)據(jù)超過25個時,對這個有序集合進(jìn)行修建。

#更新令牌
import time
def update_token(conn,token,user,item=None):
    timestamp=time.time() #h獲取當(dāng)前時間戳
    conn.hset("login:",token,user) #維持令牌與已登陸用戶之間的映射
    conn.zadd("recent:",token,timestamp) #記錄領(lǐng)哦哎最后一次出現(xiàn)的時間
    if item:
        conn.zadd("viewed:"+token,item,timestamp) #記錄用戶瀏覽郭的商品
        conn.zremrangebyrank("viewed:"+token,0,-26) #移除舊的記錄,值保留用戶最近瀏覽過的25個商品

通過update_token()函數(shù),我們可以記錄用戶最后一次瀏覽商品的時間以及用戶最近瀏覽了哪些商品。在一臺最近幾年生產(chǎn)的服務(wù)器上面,使用update_token()函數(shù)每秒至少記錄20000件商品,這比我們預(yù)估的網(wǎng)站高峰期所需的6000次寫入要高3倍有余。不僅如此,通過后面介紹的一些方法,我們還可以進(jìn)一步優(yōu)化update_token()函數(shù)的運(yùn)行速度。但在優(yōu)化前,性能也比原有的關(guān)系數(shù)據(jù)庫性能提升了10~100倍。

因?yàn)榇鎯挃?shù)據(jù)所需的內(nèi)存會隨著時間的推移而不斷增加,所以我們需要定期清理舊的會話數(shù)據(jù),為了限制會話數(shù)據(jù)的數(shù)量,我們決定只保留最新的1000萬個會話。清理舊會話的程序由一個循環(huán)構(gòu)成,這個循環(huán)每次執(zhí)行的時候,都會檢查存儲最新登錄令牌的有序集合大小,如果有序集合的大小超過了限制,那么程序就會從有序集合里面移除最多100個最舊的令牌,并從記錄用戶登錄頁面的散列表里面,移除被刪除令牌對應(yīng)的用戶的信息,并對存儲了這些用戶最近瀏覽商品記錄的有序集合進(jìn)行清理。如果令牌的數(shù)量未超過限制,那么程序會休眠1秒,之后再重新進(jìn)行檢查。

#清理舊會話
import time

QUIT=False
LIMIT=10,000,000

def clean_sessions(conn):
    while not QUIT:
        #目前已有令牌的數(shù)量
        size=conn.zcard("recent:")
        if size<=LIMIT:
            #令牌數(shù)量未超過限制,休眠1秒后再重新檢查
            time.sleep(1)
            continue
        end_index=min(size-LIMIT,100)
        tokens=conn.zrange("recent:",0,end_index-1)

        session_keys=[]
        #為那些將要刪除的令牌構(gòu)建鍵名
        for token in tokens:
            session_keys.append("viewed:"+token)
        #移除最舊的那些令牌
        conn.delete(*session_keys)
        conn.hdel("login:",*tokens)
        conn.zrem("recent:",*tokens)

讓我們通過計(jì)算來了解一下,這段簡短的代碼為什么能夠妥善地處理每天500萬人次的訪問:假設(shè)網(wǎng)站每天有500萬用戶訪問,并且每天的用戶都和之前的不一樣,那么只需要兩天,令牌的數(shù)量就會達(dá)到1000萬上限,并將網(wǎng)站的內(nèi)存空間銷毀殆盡,因?yàn)橐惶煊校?4*3600=86400秒,而網(wǎng)站平均每秒產(chǎn)生5 000 000/86400<58個新會話,如果清理函數(shù)以每秒的頻率運(yùn)行,那么它每秒需要清理將近60個令牌,才能防止令牌的數(shù)量過多的問題發(fā)生。但是實(shí)際上,我們定義的令牌清理函數(shù)在通過網(wǎng)絡(luò)來運(yùn)行時,每秒能夠清理10 000多個令牌,在本地運(yùn)行時,每秒能夠清理60 000多個令牌,這比所需的清理速度快樂150~1000倍,所以因?yàn)榕f令牌過多而導(dǎo)致網(wǎng)站空間耗盡的問題不會出現(xiàn)。

熟悉多線程編程或者并發(fā)編程的讀者可能會發(fā)現(xiàn)上面的清理函數(shù)包含了一個競爭條件【race condition】:如果清理函數(shù)正在刪除某個用戶的信息,而這個用戶又在同一時間訪問網(wǎng)站的話,那么競爭條件就會導(dǎo)致用戶的信息被錯誤的刪除。目前來看,這個競爭條件除了會使得用戶需要重新登錄一次之外,并不會對程序記錄的數(shù)據(jù)產(chǎn)生明顯的影響,所以我們暫時擱置這個問題,之后會講解防止類似的競爭條件發(fā)生的方法。

通過使用Redis來記錄用戶信息,我們成功地將每天要對數(shù)據(jù)庫執(zhí)行的行寫入操作減少了數(shù)百萬次。雖然這非常的了不起,但這只是我們使用Redis構(gòu)建Web應(yīng)用程序的第一步,接下來我們將展示如何使用Redis來處理另一種類型的cookie。

上一篇文章:Python--Redis實(shí)戰(zhàn):第一章:初識Redis:第三節(jié):你好Redis-文章投票試煉
下一篇文章:Python--Redis實(shí)戰(zhàn):第二章:使用Redis構(gòu)建Web應(yīng)用:第二節(jié):使用Redis實(shí)現(xiàn)購物車

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/42568.html

相關(guān)文章

  • Python--Redis實(shí)戰(zhàn)二章使用Redis構(gòu)建Web應(yīng)用第二節(jié):使用Redis實(shí)現(xiàn)購物

    摘要:上一篇文章實(shí)戰(zhàn)第二章使用構(gòu)建應(yīng)用第一節(jié)登錄和緩存下一篇文章實(shí)戰(zhàn)第二章使用構(gòu)建應(yīng)用第三節(jié)網(wǎng)頁緩存網(wǎng)景公司在世紀(jì)年代中期最先在網(wǎng)絡(luò)中使用了,這些最終變成了我們現(xiàn)在使用的。從購物車?yán)锩嬉瞥付ㄉ唐穼⒅付ǖ纳唐诽砑拥劫徫镘? 上一篇文章: Python--Redis實(shí)戰(zhàn):第二章:使用Redis構(gòu)建Web應(yīng)用:第一節(jié):登錄和cookie緩存下一篇文章:Python--Redis實(shí)戰(zhàn):第二章:使用R...

    animabear 評論0 收藏0
  • Python--Redis實(shí)戰(zhàn)第一章:初識Redis:第三節(jié):你好Redis-文章投票試煉

    摘要:為了防止用戶對同一篇文章進(jìn)行多次投票,網(wǎng)站需要為每一篇文章記錄一個已投票用戶名單。上一篇文章實(shí)戰(zhàn)第一章初識第二節(jié)數(shù)據(jù)結(jié)構(gòu)簡介下一篇文章實(shí)戰(zhàn)第二章使用構(gòu)建應(yīng)用第一節(jié)登錄和緩存 上一篇文章: Python--Redis實(shí)戰(zhàn):第一章:初識Redis:第二節(jié):Redis數(shù)據(jù)結(jié)構(gòu)簡介下一篇文章:Python--Redis實(shí)戰(zhàn):第二章:使用Redis構(gòu)建Web應(yīng)用:第一節(jié):登錄和cookie緩存 ...

    Meils 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<