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