面試衝刺——Redis 專題
Redis 專題
Redis 的持久化機制
RDB ----------> 記憶體中的資料集快照 ; 預設開啟的 ; -------> dump.rdb
配置 : save 60 10 --------> 60s內,有10個key發生變化,觸發RDB操作.
優點 :
1). 恢復速度快 ; ----->
2). 佔用磁碟空間小
缺點 :
1). 容易丟失資料 ; ------> 丟失資料風險高
2). 如果記憶體中的資料量過大,會造成持久化時,造成大量的磁碟IO,及CPU,有可能會影響其他的執行緒;
3). 檔案不可讀
AOF -----------> redis操作的指令,操作日誌 ; 預設未開啟的 ; -----> append only file
開啟 :
appendonly yes
#appendfsync always
appendfsync everysec
#appendfsync no
優點 :
1). 檔案是可讀的 ;
2). 丟失資料的風險小 ;
缺點 :
1). 恢復速度慢 ;
2). aof的日誌檔案可能會比較大 ;
日誌重寫 :
bgrewriteaof
redis 中的資料庫一共有16個,預設為第一個0 號資料庫 ;
切換資料庫 : select 0 ;
Redis 記憶體淘汰策略
概述 :
每臺redis的伺服器的記憶體都是有限的,而且也不是所有的記憶體都用來儲存資訊。 而且redis的實現並沒有在記憶體這塊做太多的優化,所以實現者為了防止記憶體過於飽和,採取了一些措施來管控記憶體。
Redis的記憶體設定 :
maxmemory <bytes>
記憶體淘汰(置換)策略 :
1). volatile-lru -> remove the key with an expire set using an LRU algorithm 只從設定失效(expire set)的key中選擇最近最不經常使用的key進行刪除,用以儲存新資料 2). allkeys-lru -> remove any key according to the LRU algorithm 優先刪除掉最近最不經常使用的key,用以儲存新資料 3). volatile-random -> remove a random key with an expire set 只從設定失效(expire set)的key中,(隨機)選擇一些key進行刪除,用以儲存新資料 4). allkeys-random -> remove a random key,any key 隨機從all-keys中(隨機)選擇一些key進行刪除,用以儲存新資料 5). volatile-ttl -> remove the key with the nearest expire time (minor TTL) 只從設定失效(expire set)的key中,選出存活時間(TTL)最短的key進行刪除,用以儲存新資料 6). noeviction -> don't expire at all,just return an error on write operations 不進行淘汰,表示即使記憶體達到上限也不進行置換,所有能引起記憶體增加的命令都會返回error 配置 : maxmemory-policy noeviction
樣本數量 :
maxmemory-samples 3
Redis 中的 LRU 不是嚴格意義上的LRU演算法實現,是一種近似的 LRU 實現,主要是為了節約記憶體佔用以及提升效能。Redis 有這樣一個配置 —— maxmemory-samples,Redis 的 LRU 是取出配置的數目的key,然後從中選擇一個最近最不經常使用的 key 進行置換,預設的 5,可以通過調整樣本數量來取得 LRU 置換演算法的速度或是精確性方面的優勢。
快取穿透
快取穿透,是指查詢一個數據庫一定不存在的資料。正常的使用快取流程大致是,資料查詢先進行快取查詢,如果key不存在或者key已經過期,再對資料庫進行查詢,並把查詢到的物件,放進快取。如果資料庫查詢物件為空,則不放進快取。
@Override
public List findByCategoryId(Long categoryId) { // -1 / -10
// 加入快取的程式碼:
List list = (List) redisTemplate.boundHashOps(“content”).get(categoryId);
if(list==null){
System.out.println("查詢資料庫===================");
TbContentExample example = new TbContentExample();
Criteria criteria = example.createCriteria();
// 有效廣告:
criteria.andStatusEqualTo("1");
criteria.andCategoryIdEqualTo(categoryId);
// 排序
example.setOrderByClause("sort_order");
list = contentMapper.selectByExample(example);
if(list !=null){
redisTemplate.boundHashOps("content").put(categoryId,list);
}
}else{
System.out.println("從快取中獲取====================");
}
return list;
}
解決方案 :
1). 設定過期時間
@Override
public List findByCategoryId(Long categoryId) {
// 加入快取的程式碼:
List list = (List) redisTemplate.boundValueOps(“content_”+categoryId).get();
if(list == null){
System.out.println("查詢資料庫===================");
TbContentExample example = new TbContentExample();
Criteria criteria = example.createCriteria();
// 有效廣告:
criteria.andStatusEqualTo("1");
criteria.andCategoryIdEqualTo(categoryId);
// 排序
example.setOrderByClause("sort_order");
list = contentMapper.selectByExample(example);
if(list != null){
redisTemplate.boundValueOps("content_"+categoryId).set(list); //-1
}else{ //-1,-2,-10
redisTemplate.boundValueOps("content_"+categoryId).set(null); //null
redisTemplate.expire("content_"+categoryId,7200,TimeUnit.SECONDS);
}
}else{
System.out.println("從快取中獲取====================");
}
return list;
}
2). 只查詢快取,不查詢資料庫 ;
快取擊穿
快取擊穿,是指一個key非常熱點,在不停的扛著大併發,大併發集中對這一個點進行訪問,當這個key在失效的瞬間,持續的大併發就穿破快取,直接請求資料庫,就像在一個屏障上鑿開了一個洞 。
解決方案 :
1). 對熱點資料,不設定過期時間 ;
2). 互斥鎖
3). 只查詢redis快取,不查詢資料庫 ;
public class RedisDemo {
private static Lock lock = new ReentrantLock();
public static String getData(String key) throws InterruptedException {
String result = getDataFromRedis(key); //從redis獲取資料
if(result == null){ // 如果資料為null,需要從資料庫中獲取 lock.lock(); lock.unlock(); lock.tryLock()
if(lock.tryLock()){ //嘗試獲取鎖
result = getDataFromMysql(key); //從資料庫中查詢
if(result != null){ //如果查詢到資料,就快取在redis中
saveDataToRedis(key,result);
}
lock.unlock();//釋放鎖
}else{
TimeUnit.MILLISECONDS.sleep(100);
result = getData(key);
}
}
return result;
}
private static void saveDataToRedis(String key,String result) {
System.out.println("儲存資料到redis中,key - value ");
}
private static String getDataFromMysql(String key) {
System.out.println("從資料庫中獲取資料 ");
return null;
}
public static String getDataFromRedis(String key){
System.out.println("從redis中獲取資料 ");
return null;
}
}
快取雪崩
快取雪崩,是指在某一個時間點,快取集中過期失效。
產生雪崩的原因之一,比如在寫本文的時候,馬上就要到雙十二零點,很快就會迎來一波搶購,這波商品時間比較集中的放入了快取,假設快取一個小時。那麼到了凌晨一點鐘的時候,這批商品的快取就都過期了。而對這批商品的訪問查詢,都落到了資料庫上,對於資料庫而言,就會產生週期性的壓力波峰。
解決方案
1). 如果設定快取的過期時間,需要根據業務劃分,不同型別的資料,可以設定不同的過期時間,不要設定為相同的過期時間,從而造成快取在同一個時間點過期 ;
2). 只查詢redis,不查詢資料庫 ;
Linux 版本的 redis 安裝
1). 上傳 redis-3.0.0.tar.gz
alt + p ------> put D:/redis-3.0.0.tar.gz
2). 安裝C語言編譯環境
yum install gcc-c++ (需要聯網)
3). 解壓壓縮包
tar -zxvf redis-3.0.0.tar.gz
4). 編譯原始碼
cd redis-3.0.0
make
5). 安裝
make install PREFIX=/usr/local/redis
6). 拷貝解壓目錄下的redis配置檔案redis.conf到redis安裝目錄
cp redis.conf /usr/local/redis
7). 啟動
cd /usr/local/redis
bin/redis-server redis.conf
啟動之後,介面如下(不要關閉該視窗,預設為前臺執行) :