一直使用nginx做爲反向代理服務器,一來nginx基於事件驅動,速度快。而來nginx的反向代理模塊能很好的支持頁面緩存和負載均衡。nginx
nginx有proxy_cache這個內置的緩存功能,是基於文件的。若是把緩存路徑設置到RAMDISK上面,能夠達到和內存緩存差很少的緩存讀寫速度。這樣作雖然解決了文件讀寫慢的問題,可是若是分佈式部署的時候,這個緩存不能跨機器共享。git
章大神寫的這個模塊支持和另外一個模塊配合將頁面緩存寫入redis集羣。就很好的解決了github
緩存不能跨機器共享的問題redis
也使得緩存大小不受單機資源限制。後端
同時,redis自己還能提供快速的讀寫速度。緩存
看上面列的幾點,彷佛已經很完美了。
可是在實際使用的時候仍是發現有須要改善的地方:服務器
緩存不存在的時候:
第一個請求查詢redis失敗,到後端,最後還要存儲redis。比沒有緩存的狀況還多出兩次redis訪問,一次讀一次寫。並且當併發訪問的時候還可能請求都會進入後端服務器,後端不夠健壯的時候會致使「雪崩效應」。(若是使用默認的proxy_cache模塊還能經過proxy_cache_use_stale命令避免,可是srcache模塊沒有實現相似功能)併發
緩存失效的時候
一般咱們爲頁面設置緩存時間,緩存失效的時候,須要從新更新緩存。這個時候也會出現第一種狀況相似的問題。負載均衡
以上兩種狀況,第一種出現較少,第二種狀況出現較多。都是因爲redis自動刪除過時緩存,致使的緩存缺失。異步
因爲nginx不知道redis裏面數據的緩存時間,因此會頻繁的致使緩存缺失的狀況出現。
既然知道緣由了,那麼我們就來針對性的解決一下這個問題。讓nginx可以知道甚至參與到緩存時間的管理裏面,就能有效的避免被動的緩存缺失問題,能有意識的主動更新緩存。
這裏須要提到一個nginx的第三方模塊就是把lua集成到nginx裏面擴展了nginx配置文件語法,支持在配置文件裏面直接使用lua語言編寫邏輯。
我將本身在項目中使用的一個倉庫開源到github上面了。
能讓nginx主動的檢測緩存的過時時間
在快過時的時候,直接返回舊的緩存數據
使用異步任務更新緩存
以上的第二第三兩點,就能在緩存快過時的時候,主動的異步更新緩存,讓終端用戶感知不到更新緩存的過程。
項目中實測,使用這個緩存機制以後,用戶感知到的平均響應速度提高了10倍(nginx access log分析結果),而這都是在原有系統性能不變的狀況下實現的!是否是有點難以想象。
下面就來講一說提高速度的原理:
若是緩存缺失,直接跳過srcache_fetch步驟,將請求發到後端server。同時申請一個共享內存鎖,併發而來的相同的請求不用發送到後端,而是等待這個請求返回。
更新緩存的時候,在過時時間expire基礎上加上一個stale time。那麼在到了過時時間的時候,redis還不會當即刪掉這個數據。
若是檢測到數據過時,可是redis還能拿到這個「過時」數據,則當即返回過時數據給終端用戶。
在結束請求的同時,使用一個異步任務去更新緩存,考慮到併發狀況,這裏也須要使用一個共享內存鎖。
這樣,即便在緩存過時的時候,用戶也不多會遇到只能從後端server拿數據的狀況。因此能節省至關的時間,在速度上有這麼大的提高。
這個庫運行了有好幾個月了,很是的穩定。固然這得益於nginx的穩定。可是也不得不說,使用這個庫以後,後端server可以收到的請求,已經絕大部分都是由那個異步的任務發出的。用戶基本都能在緩存裏面直接拿到數據。因此,後端server的性能,沒有提高,可是給用戶的感受倒是快了不少!!!