摘要:緩存是一個常談常新的話題,作為一名服務端的技術,如果你入行一年都還沒用過類產品,那只能說你的公司實在太小了,或者你干的活實在太邊緣了。這是緩存最原始的意義,同時也引申出了緩存最普遍的用法。但是現(xiàn)實中還有一種緩存,是主動更新的。
緩存是一個常談常新的話題,作為一名服務端的技術,如果你入行一年都還沒用過memcached類產品,那只能說你的公司實在太小了,或者你干的活實在太邊緣了。
說起緩存,可能大家最直接想到的就是:“在數(shù)據(jù)庫前面擋一層”。這是緩存最原始的意義,同時也引申出了緩存最普遍的用法。
原始模式 代碼示例1(原始模式)://從緩存中獲取數(shù)據(jù)[較快的方式] data = getfromcache(id) if data == null then //從數(shù)據(jù)庫中獲取數(shù)據(jù)[較慢的方式] data = getfromdb(id) //緩存1天 setintocache(id, data, 86400) return data end return data緩存加鎖
上面這種情況下,當同時有N個請求到達,都同時執(zhí)行getfromcache,那么都會發(fā)現(xiàn)data在緩存中不存在,然后都會去調用getfromdb,以及setintocache。這是不必要的,那么我們有沒有辦法減少這些并發(fā)呢。
最直接的想法是加鎖,當進入if條件中時,加一把鎖,讓其他進程不再執(zhí)行下面的邏輯,而是等第一個進程的setintocache執(zhí)行完成后,再重新執(zhí)行一次getfromcache。
那這個鎖如何加呢?這里推薦一種省時省力的方法。通過直接在緩存value中設置過期時間來實現(xiàn)。
比如緩存的value值為data,那我們修改一下,把它放到一個json中,改成
{data:data,atime:1429618765}
我們增加了一個atime來記錄緩存生成的時間。而邏輯就變成下面這樣。
代碼示例2(緩存加鎖)://從緩存中獲取數(shù)據(jù)[較快的方式] data = getfromcache(id) data = json.decode(data) //如果通過檢查緩存生成時間,發(fā)現(xiàn)緩存已經(jīng)過于陳舊,那么就將緩存過期時間設置為現(xiàn)在開始的5分鐘以后(這樣其他并發(fā)進程就會以為此緩存還未過期,還會繼續(xù)使用5分鐘,只讓當前這一個請求去重建緩存) if data != null && data.atime+86400 < now then data.atime = now+300-86400 data = json.encode(data) //對真正的cache來說,緩存10天或者更長時間 setintocache(id, data, 864000) //這里把data設置成null是為了走到下面的if中去重建緩存 data = null end if data == null then //從數(shù)據(jù)庫中獲取數(shù)據(jù)[較慢的方式] data = getfromdb(id) data = {data:data, atime:now} data = json.encode(data) //對真正的cache來說,緩存10天或者更長時間 setintocache(id, data, 864000) return data end return data
你可以會發(fā)現(xiàn),這里也會存在并發(fā)啊,和上面例1一樣,第一個getfromcache到setintocache之間,如果同時有N個請求到來,不還是都會執(zhí)行這段操作,都會去查庫嗎。
沒錯,是這樣的。但是我們仔細看一下,例1中,從getfromcache到setintocache之間,經(jīng)歷了一次漫長的getfromdb操作,這個時間耗費可能是上百毫秒的。而我們例2中,并沒有進行什么操作,這個時間耗費只在毫秒甚至微秒級的。
所以例1中getfromcache到setintocache之間的并發(fā)是遠大于例2中的。例2中通過減小時間窗口,有效的模擬了鎖機制。同時還沒有增強額外的存儲復雜度。所以是推薦的一種方式。
可以說,我們所有的緩存都應該是例2的方式,他在各方面都優(yōu)于例1(多保存的一個atime字段耗費的內存基本可以忽略不計。且atime很多時候對于調試程序還很有用)。
主動更新緩存那這樣就夠了嗎?對于被動過期型的緩存,這樣基本就可以了。但是現(xiàn)實中還有一種緩存,是主動更新的。試想有一種緩存,我們要求必須和數(shù)據(jù)庫中的數(shù)據(jù)一致,不能出現(xiàn)陳舊數(shù)據(jù)。那么上面的緩存方式就不合適了。
我們必然會添加一個流程:即當數(shù)據(jù)庫有更新時,同時更新緩存,因為緩存會自己重建,也可以修改為當數(shù)據(jù)庫有更新時,同時刪除緩存。
這里提到刪除或者更新緩存,就有點意思了。我們上面講到的都是非常簡單的緩存,即一個id對應一個key。那么試想,如果我們有一個分頁緩存,緩存了某一個文章最新的前10頁數(shù)據(jù)。分別的key是page_1,page_2...page10。
那么當我們有一條新數(shù)據(jù)產生,這10頁就都失效了,需要更新或者刪除10次。這顯然是不太科學的做法。
那么我們應該怎么做呢。我們可以借用上面例2中的方法,例2中,我們在緩存中增加了一個atime字段,標識為緩存的生成時間。我們既然知道緩存什么時候生成的,那問題就好解決了。我們在每次有新數(shù)據(jù)產生時,都去更新一個updatetime字段。然后獲取分頁緩存的時候,看一下這個updatetime字段是不是在atime之后,如果是,那么說明這份緩存太舊了,需要走更新流程。
代碼示例3(避免批量更新)://從緩存中獲取數(shù)據(jù)[較快的方式][這里的兩次get普通的緩存系統(tǒng)都支持一個請求完成] data = getfromcache(id) updatetime = getupdatetime(id) data = json.decode(data) //如果通過檢查緩存生成時間,發(fā)現(xiàn)緩存已經(jīng)過于陳舊,那么就將緩存過期時間設置為現(xiàn)在開始的5分鐘以后(這樣其他并發(fā)進程就會以為此緩存還未過期,還會繼續(xù)使用5分鐘,只讓當前這一個請求去重建緩存) if data != null && (data.atime+86400 < now || date.atime < updatetime) then data.atime = now+300-86400 data = json.encode(data) //對真正的cache來說,緩存10天或者更長時間 setintocache(id, data, 864000) //這里把data設置成null是為了走到下面的if中去重建緩存 data = null end if data == null then //從數(shù)據(jù)庫中獲取數(shù)據(jù)[較慢的方式] data = getfromdb(id) data = {data:data, atime:now} data = json.encode(data) //對真正的cache來說,緩存10天或者更長時間 setintocache(id, data, 864000) return data end return data
這僅僅是在代碼示例2的基礎上增加了下面這一個條件判斷而已
date.atime < updatetime
這樣,無論是緩存保存時間過期了,還是緩存本身有更新,都會觸發(fā)帶鎖機制的緩存更新。
好了,先說到這里,回頭有想起來的再做更新。原文地址
順便插播一則招聘廣告。(碼字不易,求別刪招聘廣告,謝!)
易手機坐標深圳,做一款易用安全的老年智能手機,做老年手機第一品牌。現(xiàn)在灰常需要服務端同學入伙。有興趣的同學請私信或簡歷發(fā)郵箱:ligang#pingyijinren.com
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/61769.html
摘要:緩存是一個常談常新的話題,作為一名服務端的技術,如果你入行一年都還沒用過類產品,那只能說你的公司實在太小了,或者你干的活實在太邊緣了。這是緩存最原始的意義,同時也引申出了緩存最普遍的用法。但是現(xiàn)實中還有一種緩存,是主動更新的。 緩存是一個常談常新的話題,作為一名服務端的技術,如果你入行一年都還沒用過memcached類產品,那只能說你的公司實在太小了,或者你干的活實在太邊緣了。 說起...
摘要:以下為大家整理了阿里巴巴史上最全的面試題,涉及大量面試知識點和相關試題。的內存結構,和比例。多線程多線程的幾種實現(xiàn)方式,什么是線程安全。點擊這里有一套答案版的多線程試題。線上系統(tǒng)突然變得異常緩慢,你如何查找問題。 以下為大家整理了阿里巴巴史上最全的 Java 面試題,涉及大量 Java 面試知識點和相關試題。 JAVA基礎 JAVA中的幾種基本數(shù)據(jù)類型是什么,各自占用多少字節(jié)。 S...
摘要:并總結經(jīng)典面試題集各種算法和插件前端視頻源碼資源于一身的文檔,優(yōu)化項目,在瀏覽器端的層面上提升速度,幫助初中級前端工程師快速搭建項目。 本文是關注微信小程序的開發(fā)和面試問題,由基礎到困難循序漸進,適合面試和開發(fā)小程序。并總結vue React html css js 經(jīng)典面試題 集各種算法和插件、前端視頻源碼資源于一身的文檔,優(yōu)化項目,在瀏覽器端的層面上提升速度,幫助初中級前端工程師快...
閱讀 882·2021-11-15 11:38
閱讀 2512·2021-09-08 09:45
閱讀 2812·2021-09-04 16:48
閱讀 2563·2019-08-30 15:54
閱讀 929·2019-08-30 13:57
閱讀 1617·2019-08-29 15:39
閱讀 495·2019-08-29 12:46
閱讀 3519·2019-08-26 13:39