什么是緩存
緩存通俗點說就是臨時存儲數(shù)據(jù)的可高速訪問的地方。
當(dāng)從原始位置獲取數(shù)據(jù)的代價太大或者時間太長的時候鹊漠,就可以把獲取到的數(shù)據(jù)存放在緩存中巴刻,這樣下次訪問的時候就提高了訪問速度降低了訪問成本。
緩存的基本知識點
- 緩存的對象
緩存的對象應(yīng)該是花費了時間計算或者獲取到的數(shù)據(jù)突勇,并且這些數(shù)據(jù)在不久會被訪問到涮因。
在 Java 應(yīng)用中废睦,常見的緩存例子有如下幾種
- Web Service 客戶端調(diào)用結(jié)果的緩存
- 獲取到的 DB 數(shù)據(jù)
- Servlet response 的緩存
- 復(fù)雜計算的結(jié)果
代碼實例如 String 的 hashCode 計算結(jié)果
/** Cache the hash code for the string */
private int hash; // Default to 0
public int hashCode() {
//get from cache first
int h = hash;
//cannot found
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
//set to cache
hash = h;
}
return h;
}
- 緩存命中率
緩存命中指的是當(dāng)前請求發(fā)生在緩存中,就是說數(shù)據(jù)可以從緩存中獲得养泡。
緩存命中率=緩存命中次數(shù)/總請求數(shù)[從緩存中讀取+慢速設(shè)備讀取]
緩存命中率是衡量緩存性能的一個重要指標(biāo)嗜湃。
- 緩存清除策略
當(dāng)緩存失效或者緩存空間不足的時候,需要提供緩存算法來清除一些不再使用的緩存數(shù)據(jù)澜掩,這個時候就涉及到了緩存清除策略购披,一般稱做緩存算法。
常見的緩存算法有:
- Least Recently Used (LRU)
- Most Recently Used (MRU)
- Least-Frequently Used(LFU)
- Low Inter-reference Recency Set (LIRS)
等肩榕,具體介紹請參考維基百科或者查閱對應(yīng)算法資料刚陡。
- 緩存存活期 TTL(Time To Live)
存活期即從緩存中創(chuàng)建時間點開始直到它到期的一個時間段(不管在這個時間段內(nèi)有沒有訪問都將過期) - 緩存空閑期 TTI(Time To Idle)
空閑期即一個數(shù)據(jù)多久沒被訪問將從緩存中移除的時間。
一般緩存使用方式
Spring cache abstraction
Spring cache 抽象層是 Spring 提供的一種能夠極小沖擊現(xiàn)有代碼的緩存機制株汉。它提供的是不依賴具體緩存框架的筐乳,使用 AOP 方式實現(xiàn)的緩存機制。
Spring 的緩存技術(shù)還具備相當(dāng)?shù)撵`活性乔妈,不僅能夠使用 SpEL(Spring Expression Language)來定義緩存的 key 和各種 condition蝙云,還提供開箱即用的緩存臨時存儲方案如 JDK 實現(xiàn)的緩存和 Guava cache,也支持和主流的專業(yè)緩存例如 EHCache 和 Redis 集成褒翰。
Spring 緩存技術(shù)基于 AOP 實現(xiàn)贮懈, 因此有兩種實現(xiàn)模式 proxy 和 aspectj 可以選擇以適應(yīng)不同情況匀泊。
Spring cache 的使用方式
Spring cache 提供了一些注解來聲明需要使用 Cache 的方法优训。
-
@Cacheable
聲明使用 Cache,方式是 put if not found -
@CacheEvict
觸發(fā)緩存清除操作 -
@CachePut
在方法執(zhí)行的時候更新特定緩存各聘,不影響方法執(zhí)行結(jié)果 -
@Caching
如果一個方法有多個緩存操作可以使用 -
@CacheConfig
配置當(dāng)前類中使用的緩存配置
每一個注解的使用說明請看 Spring 的文檔揣非。
使用 Spring Data Redis 實現(xiàn) Cache
Spring data redis 是 Spring 提供的對 Redis 操作進行封裝的框架,同時躲因,他還提供了 Spring cache 的 Redis 實現(xiàn)早敬,因此我們可以使用他來完成 Redis 緩存的集成。
Redis
Redis是一個開源大脉、支持網(wǎng)絡(luò)搞监、基于內(nèi)存、鍵值對存儲數(shù)據(jù)庫镰矿,可以用作數(shù)據(jù)庫琐驴、緩存和消息中間件。將 Redis 作為緩存的時候應(yīng)該注意:
- 設(shè)置最大可用的內(nèi)存,使用
maxmemory
設(shè)置 - 設(shè)置 Key 的清除策略(也就是緩存策略)绝淡,使用
maxmemory-policy
設(shè)置
如果不設(shè)置最大可用內(nèi)存的話:32位操作系統(tǒng)宙刘,最大默認值為 3G,而64位則不限定牢酵。這樣就會導(dǎo)致內(nèi)存占用過多悬包,并且可能會對緩存特定 Key 的檢索速度有影響。
Redis 真正支持的緩存策略只有 LRU馍乙,但是我們可以在 redis.conf
中配置以下不同的參數(shù)布近,來實現(xiàn)不同效果的 Key 清除策略:
- noeviction:在客戶端操作會導(dǎo)致更多內(nèi)存占用的時候拋出錯誤。
- allkeys-lru: 優(yōu)先清除最近最少使用的 key 來為新加數(shù)據(jù)讓出空間丝格。
- volatile-lru: 優(yōu)先在設(shè)置了過期時間的 key 中清除最近最少使用的來為新加數(shù)據(jù)讓出空間吊输。
- allkeys-random: 隨機清除 key 來為新加數(shù)據(jù)讓出空間。
- volatile-random: 隨機在設(shè)置了過期時間的 key 中清除一些
- volatile-ttl: 在設(shè)置了過期時間的 Key 中根據(jù)存活期長短來清除铁追,優(yōu)先清除存活期短的季蚂。
如果沒有 Key 滿足條件,volatile-lru琅束、volatile-random 和 volatile-ttl 會和 noeviction 一樣的表現(xiàn)扭屁。
配置 Redis 作為 Spring cache 實現(xiàn)
簡單基于注解的配置如下:
@Configuration
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport {
@Autowired
private RedisPropertiesVO properties;
@Bean
public JedisConnectionFactory jedisConnectionFactory() {
JedisConnectionFactory factory = new JedisConnectionFactory();
factory.afterPropertiesSet();
factory.setHostName(properties.getHost());
factory.setPort(properties.getPort());
factory.setUsePool(true);
factory.setDatabase(properties.getDatabase());
return factory;
}
@Bean
public RedisTemplate<Object, Object> redisTemplate() {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(jedisConnectionFactory());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean
public CacheManager cacheManager() {
return new RedisCacheManager(redisTemplate());
}
}