1. 程式人生 > >【快取】-快取中介軟體

【快取】-快取中介軟體

簡介:主要介紹快取中介軟體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恢復;

……完