1. 程式人生 > >Redis高併發可能產生的問題即個人見解解決方案

Redis高併發可能產生的問題即個人見解解決方案

1、  如果redis宕機了,或者連結不上,怎麼辦?

解決方法:

    ①配置主從複製,配置哨兵模式(相當於古代門派的長老級別可以選擇掌門人的權利),一旦發現主機宕機,讓下一個從機當做主機。

    ②如果最壞的情況,只能關閉Redis連線,去往資料庫連線。但由於資料量大,這樣SQL資料庫也會宕掉的。

2、  如果redis快取在高峰期到期失效,在這個時刻請求會向雪崩一樣,直接訪問資料庫如何處理?

     設定條件查詢判斷,判斷redis快取裡是否有資料,如果沒有,則去往資料庫連線。當然要加分散式鎖,利用redis的單執行緒+多路IO複用技術,原子性原理,讓其它的執行緒請求等待,假若第一個執行緒進去獲取到分散式鎖在查詢資料的途中宕掉了,不能讓其它執行緒一直等待,設定等待一定時間判斷是否取回資料,如果沒有,遞迴呼叫自己的方法讓第二個執行緒繼續拿分散式鎖查詢資料庫。當第二個鎖從資料庫拿到資料時,把資料值設定到redis資料庫快取中,設定失效時間,避免佔記憶體,方便使用提高效率。

3.   如果使用者不停地查詢一條不存在的資料,快取沒有,資料庫也沒有,那麼會出現什麼

    如果資料不存在,快取中沒有,資料庫也沒有,當然如果不設定判斷,會一直呼叫資料庫,使資料庫效率降低,訪問量大時甚至會宕機。

    解決方案:從資料庫查詢,如果資料庫沒有,則返回值為Null,判斷資料庫返回的值,如果為Null,則自定義把標識的欄位存到Redis中,用key,value的方法,jedis.setex(key,"empty"),設定失效時間跟具體情況而定,然後呼叫String json=jedis.get(key),判斷是否獲取的值"empty".equal(json),如果相等,則丟擲自定義異常,給使用者提示,或者直接return null。這樣使用者再次查詢的時候由於先從reids快取中查詢,redis會有對應的Key獲取之前設定的value值,這樣就不會再次呼叫資料庫,影響效率等問題。

具體程式碼如下:

@Override
public SkuInfo getSkuInfo(String skuId) {
try {
Thread.sleep(3*1000);
//自定義從redis工具類中獲取jedis物件
Jedis jedis = redisUtil.getJedis();
//拼接字串建立Redis裡面的Key值
String skuInfoKey= JedisConst.SKU_PREFIX+skuId+JedisConst.SKU_SUFFIX;
//根據key值獲取value值
String skuInfoJson = jedis.get(skuInfoKey);
//如果返回為空,則呼叫本地資料庫連線
if
(skuInfoJson==null || skuInfoJson.length()==0){
System.out.println(Thread.currentThread().getName()+"當前快取中未找到資料");
//判斷是否有人去取鎖
String skuLockKey=JedisConst.SKU_PREFIX+skuId+JedisConst.SKULOCK_SUFFIX;
String result = jedis.set(skuLockKey, "OK", "NX", "PX", JedisConst.SKULOCK_EXPIRE_PX);
if ("OK".equals(result)){
System.out.println(Thread.currentThread().getName()+"獲得分散式鎖");
SkuInfo skuInfo= getSkuInfoDB(skuId);
//如果資料庫裡面沒有值,別人惡意攻擊的話,直接設定到redis快取中
if (skuInfo==null){
jedis.setex(skuInfoKey,JedisConst.TIME_OUT,"empty");
return null;
}
skuInfoJson = JSON.toJSONString(skuInfo);
jedis.setex(skuInfoKey, JedisConst.TIME_OUT, skuInfoJson);
jedis.close();
return skuInfo;
} else {
//假設之後有人取鎖後dang掉了,遞迴呼叫自己去尋找鑰匙。
System.out.println(Thread.currentThread().getName()+"未獲得分散式鎖,開啟自旋模式俗稱遞迴.");
//等待1秒鐘
Thread.sleep(1*1000);
jedis.close();
return getSkuInfo(skuId);
}
}else if (skuInfoJson.equals("empty")){
return null;
}
else {
System.out.println(Thread.currentThread().getName()+"快取中已有資料正在查詢");
SkuInfo skuInfo = JSON.parseObject(skuInfoJson, SkuInfo.class);
jedis.close();
return skuInfo;
}
}catch (JedisConnectionException e){
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return getSkuInfoDB(skuId);