【併發編程】java 如何解決redis緩存穿透、緩存雪崩(高性能示例代碼)

緩存穿透

  • 1、什麼是緩存穿透:
    從字面上理解,緩存穿透就是運行程序擊穿了你的Redis緩存服務器,去訪問MySQL數據庫;
    由於Redis存在一定的命中概率,進來的請求發現Redis中並沒有相關數據或者是沒有命中指定數據,會去數據庫查詢。
  • 2、緩存穿透有什麼危害:
    如果大量請求進來,直接去訪問數據庫服務查詢,數據庫服務器CPU短時間內會超負載運行,致使數據庫服務宕機。

解決思路:

  • 1、簡單:加synchronized關鍵字(同步鎖);
  • 2、推薦:使用Lock對象的tryLock()方法(定時鎖);
package com.cn.seesun2012.cache;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import com.cn.seesun2012.mapper.ProductInfoMapper;
import com.cn.seesun2012.util.JedisClient;

/**
 * 
 *           ┏┓    ┏┓+ +
 *        ┏┛┻━━━┛┻┓ + +
 *        ┃       ┃
 *        ┃   ━   ┃ ++ + + +
 *        ████━████ ┃+
 *        ┃       ┃ +
 *        ┃   ┻   ┃
 *        ┃       ┃ + +
 *        ┗━┓   ┏━┛
 *          ┃   ┃
 *          ┃   ┃ + + + +
 *          ┃   ┃			God beast body, code no BUG
 *          ┃   ┃ +			神獸護體,代碼無BUG
 *          ┃   ┃
 *          ┃   ┃  +
 *          ┃    ┗━━━┓ + +
 *          ┃        ┣┓
 *          ┃        ┏┛
 *          ┗┓┓┏━┳┓┏┛ + + + +
 *           ┃┫┫ ┃┫┫
 *           ┗┻┛ ┗┻┛+ + + +
 *
 * @title:	商品信息-模塊
 * @version	v1.0.0
 * @author	csdn:seesun2012
 * @date	2018年11月22日  下午17:21:33  週四
 *
 */
public class ProductInfoCache {
	
	// Jedis 緩存對象
	private JedisClient jedisClient;
	// 商品信息XML映射類
	private ProductInfoMapper productInfoMapper;
	// 緩存業務KEY前綴
	private static final String PRODUCT_KEY = "項目名.模塊名.業務名.";
	// 鎖-實例
	private Lock lock = new ReentrantLock();
	
	/**
	 * 獲取商品圖片路徑
	 * @param id
	 */
	public synchronized String getProductImgUrlById(String id){
		// 獲取緩存
		String product = jedisClient.get(PRODUCT_KEY + id);
		if (null == product) {
			// 如果沒有獲取鎖等待3秒,SECONDS代表:秒
			try {
				if (lock.tryLock(3, TimeUnit.SECONDS)) {
					try {
						// 獲取鎖後再查一次,查到了直接返回結果
						product = jedisClient.get(PRODUCT_KEY + id);
						if (null == product) {
							// 查詢數據庫
							product = productInfoMapper.getProductInfoById(id);
							if (null == product) {
								// 假設有10000人的併發量,第一次查也沒有數據,
								// 那麼設定爲"null",加入有效期6秒
								jedisClient.setex((PRODUCT_KEY+id), "null", 6);
								return product;
							}
							jedisClient.set((PRODUCT_KEY + id), product);
							return product;
						}
						return product;
					} catch (Exception e) {
						product = jedisClient.get(PRODUCT_KEY + id);
					} finally {
						// 釋放鎖(成功、失敗都必須釋放,如果是lock.tryLock()方法會一直阻塞在這)
						lock.unlock();
					}
				} else {
					product = jedisClient.get(PRODUCT_KEY + id);
				}
			} catch (InterruptedException e) {
				product = jedisClient.get(PRODUCT_KEY + id);
			}
		}
		return product;
	}
	
}

tryLock(long time, TimeUnit unit)方法和tryLock()方法是類似的,只不過區別在於這個方法在拿不到鎖時會等待一定的時間,在時間期限之內如果還拿不到鎖,就返回false;如果一開始拿到鎖或者在等待期間內拿到了鎖,則返回true。

Lock的使用法方法: https://blog.csdn.net/zengmingen/article/details/53259394?utm_source=blogxgwz7


緩存雪崩

  • 1、什麼是緩存雪崩: 緩存在同一時間內大量鍵過期(失效),接着來的一大波請求瞬間都落在了數據庫中導致連接異常。

解決思路:

  • 1、也是像解決緩存穿透一樣加鎖排隊,實現同上;
  • 2、建立備份緩存,緩存A和緩存B,A設置超時時間,B不設值超時時間,先從A讀緩存,A沒有讀B,並且更新A緩存和B緩存;



布隆過濾器

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。






























注:以上內容僅提供參考和交流,請勿用於商業用途,如有侵權聯繫本人刪除!


持續更新中…

如有對思路不清晰或有更好的解決思路,歡迎與本人交流,QQ羣:273557553
你遇到的問題是小編創作靈感的來源!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章