一. 簡述:?
? ? ?緩存是一個大型系統中非常重要的一個組成部分。在硬件層面,大部分的計算機硬件都會用緩存來提高速度,比如CPU會有多級緩存、RAID卡也有讀寫緩存。在軟件層面,我們用的數據庫就是一個緩存設計非常好的例子,在SQL語句的優化、索引設計、磁盤讀寫的各個地方,都有緩存。一個生產環境的緩存系統,需要根據自己的業務場景和系統瓶頸,來找出最好的方案,這是一門平衡的藝術。
? 通常情況下,緩存有兩個原則:
1. 盡量靠近用戶:如能用本地緩存的就不要發送HTTP請求,能用CDN緩存的就不要打到web服務器,能用nginx緩存的就不要用數據庫的緩存。
2. ?盡量使用本進程和本機:因為跨了進程和機器甚至機房,緩存的網絡開銷就會變大,在高并發的時候會非常明顯。
二. 關于nginx?lua緩存:
在nginx的lua模塊中,通常情況下,可采用兩種緩存方式;
?1. ?跨worker共享:lua_shared_dict
? ?在使用前,需要在配置文件中進行聲明:
#/etc/nginx/nginx.conf
lua_shared_dict my_cache 20m;
?調用代碼片段:
function get_from_cache(key)local cache_ngx = ngx.shared.my_cachelocal value = cache_ngx:get(key)return value
endfunction set_to_cache(key, value, exptime)if not exptime thenexptime = 0endlocal cache_ngx = ngx.shared.my_cachelocal succ, err, forcible = cache_ngx:set(key, value, exptime)return succ
end--這里面用的就是ngx shared dict cache。如同它的名字一樣,這個cache是nginx所有worker之間共享的,內部使用的LRU算法來判斷緩存是否在內存占滿時被清除。
2)worker獨享:lua LRU cache
? ?代碼片段:
local _M = {}-- alternatively: local lrucache = require "resty.lrucache.pureffi"
local lrucache = require "resty.lrucache"-- we need to initialize the cache on the lua module level so that
-- it can be shared by all the requests served by each nginx worker process:
local c = lrucache.new(200) -- allow up to 200 items in the cache
if not c thenreturn error("failed to create the cache: " .. (err or "unknown"))
endfunction _M.go()c:set("dog", 32)c:set("cat", 56)ngx.say("dog: ", c:get("dog"))ngx.say("cat: ", c:get("cat"))c:set("dog", { age = 10 }, 0.1) -- expire in 0.1 secc:delete("dog")
endreturn _M-- 這個cache是worker級別的,不會在nginx wokers之間共享。并且,它是預先分配好key的數量,而shared dcit需要自己用key和value的大小和數量,來估算需要把內存設置為多少。
兩者差異:
? ? 1.?shared.dict 使用的是共享內存(相對占用較少),每次操作都是全局鎖,如果高并發環境,不同worker之間容易引起競爭。所以單個shared.dict的體積不能過大。lrucache是worker內使用的,由于nginx是單進程方式存在,所以永遠不會觸發鎖,效率上有優勢,并且沒有shared.dict的體積限制,內存上也更彈性,但不同worker之間數據不同享,同一緩存數據可能被冗余存儲。
? ? 2. lua lru cache提供的API比較少,現在只有get、set和delete,而ngx shared dict還可以add、replace、incr、get_stale(在key過期時也可以返回之前的值)、get_keys(獲取所有key,雖然不推薦)。