【快取】-快取中介軟體
簡介:主要介紹快取中介軟體MemCached和Redis
MemCached
1、MemCached介紹
MemCached是一種基於記憶體的key-value儲存,用來儲存小塊的任意資料(字串、物件)。它便於快速開發,減輕開發難度,解決了大資料量快取的很多問題,本質上,它是一個簡潔的key-value儲存系統
2、MemCached工作原理
主要通過快取資料庫查詢結果,減少資料庫訪問次數,以提高動態Web應用的速度。見下圖:
Redis
1、Redis簡介
Redis 是完全開源免費的,是一個高效能的key-value資料庫。
Redis 與其他 key - value 快取產品有以下三個特點:
(1)Redis支援資料的持久化,可以將記憶體中的資料儲存在磁碟中,重啟的時候可以再次載入進行使用。
(2)Redis支援String、list、set、zset、hash等資料結構的儲存。
(3)Redis支援資料的備份,即master-slave模式的資料備份。
2、Linux下安裝Redis
下載地址:http://redis.io/download
(1)下載並安裝:
$ wget http://download.redis.io/releases/redis-4.0.10.tar.gz
$ tar xzf redis-4.0.10.tar.gz
$ cd redis-4.0.10
$ make
(2)啟動redis服務
$ cd src
$ ./redis-server
(3)使用redis客戶端
$ cd src
$ ./redis-cli
redis> set companyName G7
OK
redis> get companyName
"G7"
3、Java使用Redis
import redis.clients.jedis.Jedis;
import java.util.*;
/**
* Created by pc on 2018/7/23.
* Redis資料型別
*/
public class RedisDemo
{
//String
public static void redisString(){
//連線 Redis 服務
Jedis jedis = new Jedis("172.16.*.**",6379);
System.out.println("連線成功" );
//檢視服務是否執行
System.out.println("Server is running: " + jedis.ping());
//設定 redis 字串資料
jedis.set("runoobkey", "www.runoob.com");
// 獲取儲存的資料並輸出
System.out.println("redis 儲存的字串為: "+ jedis.get("runoobkey"));
}
//list
public static void redisList(){
//連線 Redis 服務
Jedis jedis = new Jedis("172.16.*.**",6379);
System.out.println("連線成功");
//儲存資料到列表中
jedis.lpush("site-list", "Baidu");
jedis.lpush("site-list", "Google");
jedis.lpush("site-list", "Taobao");
// 獲取儲存的資料並輸出
List<String> list = jedis.lrange("site-list", 0 ,2);
for(int i=0; i<list.size(); i++) {
System.out.println("列表項為: "+list.get(i));
}
}
//set
public static void redisSet(){
//連線 Redis 服務
Jedis jedis = new Jedis("172.16.*.**",6379);
System.out.println("連線成功");
//存入set的值
Long mySet = jedis.sadd("websites", "Baidu", "Taobao", "Google");
//獲取set的值
Set<String> website = jedis.smembers("websites");
Iterator<String> it = website.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
//hash
public static void redisHash(){
//連線 Redis 服務
Jedis jedis = new Jedis("172.16.*.**",6379);
System.out.println("連線成功");
Map<String, String> hashMap = new HashMap<>();
hashMap.put("Baidu","www.baidu.com");
hashMap.put("Taobao","www.taobao.com");
hashMap.put("Google","www.google.com");
jedis.hmset("website", hashMap);
System.out.println(jedis.hgetAll("website"));
}
public static void main(String[] args) {
redisString();
// redisList();
// redisSet();
// redisHash();
}
}
執行後,如下圖:
4、Redis快取策略
(1)快取【失效】:客戶端請求資料先從快取中查詢,如果沒有再查詢資料庫,最後將資料放入快取
(2)快取【命中】:客戶端從快取中直接取到資料,返回結果
(3)快取【更新】:客戶端寫入資料到資料庫,成功之後,讓快取失效(下次請求時從快取中拿不到,則查詢資料庫,再放入快取)
5、有問題的幾種更新快取策略
(1)先更新快取,然後更新DB。見下圖:
從圖中可以看出,兩個併發寫操作,由於某些原因(io阻塞,cpu時間片分配,協程排程,網路原因等等),導致Thread2的更新DB晚於Thread1的更新DB,但是Redis中此時的資料Thread1的,而DB中的資料時Thread2的,這就出現了不一致的問題,DB中是髒資料
(2)先更新DB,然後更新快取。見下圖:
從圖中可以看出,兩個併發寫操作,由於某些原因導致Thread2的更新Redis晚於Thread1的更新Redis ,但是DB中此時的資料Thread1的,而Redis中的資料時Thread2的,這就出現了不一致的問題
(3)先刪除快取,然後再更新資料庫。見下圖:
兩個併發操作,一個是更新操作,另一個是查詢操作,更新操作刪除快取後,查詢操作沒有命中快取,會把老資料讀出來後放到快取中,然後更新操作更新了DB。於是,在快取中的資料還是老的資料,導致快取中的資料是髒的
(4)先資料庫,成功之後,讓快取失效,下次請求時從快取中拿不到,則查詢資料庫,再放入快取。見下圖:
這種更新策略是我們實際最常用的,但也可能出現問題。實際上出現問題的概率可能非常低,因為這個條件需要發生在讀快取時快取失效,而且併發著有一個寫操作。而實際上資料庫的寫操作會比讀操作慢得多,而且還要鎖表,而讀操作必需在寫操作前進入資料庫操作,而又要晚於寫操作更新快取,所有的這些條件都具備的概率基本並不大。
6、Redis與MemCached的區別
(1)Redis和Memcache都是將資料存放在記憶體中,都是記憶體資料庫。不過memcache還可用於快取其他東西,例如圖片、視訊等等;
(2)Redis不僅僅支援簡單的k/v型別的資料,同時還提供list,set,hash等資料結構的儲存;
(3)虛擬記憶體–Redis當實體記憶體用完時,可以將一些很久沒用到的value 交換到磁碟;
(4)分散式叢集部署:
a、memcache叢集節點間的資料是獨立的,不能相互通訊,但可以利用magent開源軟體解決 ;
b、Redis高可用的,可以做一主多從,主從之間進行資料同步。 當Master宕機後,通過選舉演算法(Paxos、Raft)從slave中選舉出新Master繼續對外提供服務,主機恢復後以slave的身份重新加入
(5)儲存資料安全–memcache掛掉後,資料沒了;redis可以定期儲存到磁碟(持久化);
(6)災難恢復–memcache掛掉後,資料不可恢復; redis資料丟失後可以通過aof恢復;
……完