更新時間:2022-10-24 09:49:05 來源:動力節點 瀏覽2316次
redis真的是一個很棒的技術,在一定程度上可以解決網站的并發問題,比如搶購商品等活動……
redis高的原因并發可以解決的是它可以直接訪問內存,我們以前使用數據庫(硬盤),提高了訪問效率,解決了數據庫服務器壓力。
為什么?redis 越來越高了,我們為什么不選擇 memcache,那是因為 memcache 只能存儲字符串,而 redis 的存儲類型非常多(比如有字符串,LIST,SET等),memcache 各有千秋value 最大只能存儲1M,存儲資源非常有限,會消耗大量內存資源,而redis可以存儲1G,最重要的是memcache還不如redis安全,萬一服務器故障或意外關機等,redsi內存中的數據會備份到硬盤,而memcache存儲的東西全部丟失;這也說明了 memcache 不適合做數據庫,可以用來做緩存。
下面就使用 redis 解決即時秒殺活動進行說明:
下面的程序模擬20w人秒沖進這個頁面,只有能秒成功的500人,我們把高級用戶放到redis中排隊,當隊列中的用戶達到500的時候,后來用戶轉向第二殺頁結束。這里我們使用隨機數來代表不同的用戶。
這里我們可以看到第一個秒殺成功的用戶id是208522,最后一個秒殺成功的用戶是176260,秒殺的總參與人數是20w。(大家關注的原因是為了驗證下面的準確性)。
接下來我們依次從隊列中殺掉第二個500個用戶取出來,觀察第一個用戶和最后一個用戶是否和之前的記錄值一樣
我們可以看到秒殺隊列的第一個用戶成功id是208522,最后一個用戶是176260,可以看出結果非常準確。
redis 解決高并發問題的能力確實不錯。
(1)如果redis掛了,或者沒有鏈接,怎么辦??
解決方法:
1)配置主從復制,配置哨兵模式(相當于古派的長輩級別,可以選擇leader的權利),一旦發現主機宕機,讓下一個slave做master。
2)最壞的情況,只能關閉 Redis 連接,去數據庫連接。但是由于數據量很大,這樣的 SQL 數據庫會崩潰。
(2)如果redis的緩存在高峰期會過期,此時請求就會像雪崩一般,直接訪問數據庫怎么處理?
設置條件查詢判斷,判斷redis緩存中是否有數據,沒有,然后去數據庫連接。分布式鎖,當然是利用redis單線程+多IO復用技術,原子性原理,讓其他線程請求等待,如果第一個線程進去拿到分布式鎖,就在查詢數據的途中down掉, 不能讓其他線程等待, 設置等待一定時間來判斷是否取回數據, 沒有, 遞歸調用自己的方法讓第二個線程繼續用分布式鎖查詢數據庫。當第二把鎖從數據庫中獲取數據時,將數據值設置到redis的數據庫緩存中,設置過期時間,避免占用內存,使用方便,提高效率。
(3)如果用戶一直在尋找一條不存在的數據,沒有緩存,沒有數據庫,那么會發生什么
如果數據不存在,緩存中沒有,沒有數據庫,當然如果不設置判斷,會一直調用數據庫,降低數據庫效率,訪問量大的時候甚至會down .
解決方法:從數據庫中查詢,如果數據庫沒有,則返回值為Null,判斷數據庫返回的值,如果為Null,則將用戶定義的字段保存到Redis中,使用key,value方法,jedis。 setex(key,"empty"),設置失敗時間視具體情況而定,然后調用String
json=jedis.get(key),判斷是否獲取值"empty".equal(json),如果相等,則拋出自定義異常,提示用戶,或者直接返回
無效的。這樣,當用戶再次查詢時,需要在 reids 緩存中查詢,redis 會有對應的 Key 獲取之前設置的 value 值,這樣就不會再次調用數據庫,影響效率等問題。
具體代碼如下:
@Override public SkuInfo getSkuInfo(String skuId) { try {
Thread.sleep(3*1000); // 從redis自定義工具類中jedis對象 Jedis jedis =
redisUtil.getJedis(); // 拼接字符串創建 Redis Inside Key value 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; 字符串
結果 = 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"); 返回空值;} skuInfoJson
= JSON.toJSONString(skuInfo); jedis.setex(skuInfoKey, JedisConst.TIME_OUT,
skuInfoJson); jedis.close(); 返回 skuInfo;} else {
// 假設后來有人拿了鎖 dang 沒了,遞歸調用自己找鑰匙。
System.out.println(Thread.currentThread().getName()+" 未獲得分布式鎖,開啟自旋模式,俗稱遞歸。");
// 等待 1 秒 Thread.sleep(1*1000); jedis.close(); 返回 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(); 返回
sku信息;} }catch (JedisConnectionException e){ e.printStackTrace(); } catch
(InterruptedException e) { e.printStackTrace(); } 返回 getSkuInfoDB(skuId);
以上就是關于“Redis解決高并發問題方案”的介紹,大家如果對此比較感興趣,想了解更多相關知識,不妨來關注一下動力節點的Redis教程,里面還有更豐富的知識等著大家去學習,希望對大家能夠有所幫助哦。
0基礎 0學費 15天面授
有基礎 直達就業
業余時間 高薪轉行
工作1~3年,加薪神器
工作3~5年,晉升架構
提交申請后,顧問老師會電話與您溝通安排學習