久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

Redis實(shí)現(xiàn)秒殺的問(wèn)題怎么解決

共計(jì) 3771 個(gè)字符,預(yù)計(jì)需要花費(fèi) 10 分鐘才能閱讀完成。

本篇內(nèi)容介紹了“Redis 實(shí)現(xiàn)秒殺的問(wèn)題怎么解決”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓丸趣 TV 小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

1、秒殺邏輯

秒殺:解決計(jì)數(shù)器和人員記錄的事務(wù)操作

1.uid 和 proid 非空判斷

2. 連接 redis

3. 拼接 key

庫(kù)存 key

秒殺成功用戶 key

4. 獲取庫(kù)存,如果庫(kù)存為 null,秒殺還沒(méi)開始

5. 判斷用戶是否重復(fù)秒殺操作

6. 判斷商品數(shù)量,庫(kù)存數(shù)量小于 1,秒殺結(jié)束

7. 秒殺過(guò)程

庫(kù)存 -1

把秒殺成功用戶添加清單里面

2、存在問(wèn)題 2.1、連接超時(shí)

原因:由于大量創(chuàng)建連接,十分消耗性能,并且有時(shí)獲取連接不及時(shí),出現(xiàn)連接超時(shí)的情況

2.2、超賣

在并發(fā)的情況下發(fā)生的,就是在輸出沒(méi)有庫(kù)存(秒殺結(jié)束)后還有商品售出導(dǎo)致庫(kù)存數(shù)量為負(fù)數(shù)。

2.3、庫(kù)存遺留

使用樂(lè)觀鎖解決問(wèn)題 2 之后,出現(xiàn)問(wèn)題 3

如果庫(kù)存數(shù)量相對(duì)并發(fā)更多,由于使用樂(lè)觀鎖,第一個(gè)用戶秒殺成功后會(huì)修改庫(kù)存鍵的版本號(hào),其他搶到的用戶會(huì)因?yàn)榘姹咎?hào)不同導(dǎo)致無(wú)法繼續(xù)購(gòu)買,就會(huì)有庫(kù)存遺留問(wèn)題

3、解決 3.1、連接超時(shí)

使用連接池,工具類如下:

public class JedisPoolUtil {
 private static volatile JedisPool jedisPool = null;
 private JedisPoolUtil() {public static JedisPool getJedisPoolInstance() {if (null == jedisPool) {synchronized (JedisPoolUtil.class) {if (null == jedisPool) {JedisPoolConfig poolConfig = new JedisPoolConfig();
 poolConfig.setMaxTotal(200);
 poolConfig.setMaxIdle(32);
 poolConfig.setMaxWaitMillis(100 * 1000);
 poolConfig.setBlockWhenExhausted(true);
 poolConfig.setTestOnBorrow(true);
 jedisPool = new JedisPool(poolConfig,  127.0.0.1 , 6379, 60000);
 return jedisPool;
 }}// 使用 JedisPool jedisPoolInstance = JedisPoolUtil.getJedisPoolInstance();Jedis jedis = jedisPoolInstance.getResource();

springBoot 版本 (pom.xml 引入,application.yml 配置,然后注入對(duì)象即可)

dependency 
  groupId org.springframework.boot /groupId 
  artifactId spring-boot-starter-data-redis /artifactId /dependency dependency 
  groupId redis.clients /groupId 
  artifactId jedis /artifactId 
  version 3.2.0 /version /dependency
spring:
 redis:
 host: 127.0.0.1 port: 6379
 database: 0
 timeout: 1800000
 lettuce:
 pool:
 max-active: 20
 max-wait: -1
 max-idle: 5
 min-idle: 0
 @Autowired
 private RedisTemplate redisTemplate;

3.2、超賣問(wèn)題

使用 Redis 事務(wù),樂(lè)觀鎖 + watch

// 監(jiān)視庫(kù)存
jedis.watch(kcKey);// 中間代碼忽略
//7  秒殺過(guò)程
// 使用事務(wù)
Transaction multi = jedis.multi();// 組隊(duì)操作
multi.decr(kcKey);multi.sadd(userKey,uid);// 執(zhí)行
List Object  results = multi.exec();if(results == null || results.size()==0) {
 System.out.println( 秒殺失敗了.... 
 jedis.close();
 return false;}

3.3、樂(lè)觀鎖導(dǎo)致的庫(kù)存遺留問(wèn)題

使用 Lua 嵌入式腳本語(yǔ)言

將復(fù)雜的或者多步的 Redis 操作,寫為一個(gè)腳本,一次提交給 Redis 運(yùn)行,減少反復(fù)連接 reids 的次數(shù)。提升性能。

LUA 腳本是類似 redis 事務(wù),有一定的原子性,不會(huì)被其他命令插隊(duì),可以完成 redis 事務(wù)性的操作

LUA 腳本功能,在 Redis 2.6 以上的版本才可以使用

利用 lua 腳本淘汰用戶,解決超賣問(wèn)題。

redis 2.6 版本以后,通過(guò) lua 腳本解決爭(zhēng)搶問(wèn)題,實(shí)際上是 redis 利用其單線程的特性,用任務(wù)隊(duì)列的方式解決多任務(wù)并發(fā)問(wèn)題。

local userid=KEYS[1]; //1、2 行定義兩個(gè)變量,local prodid=KEYS[2];
local qtkey= sk: ..prodid.. :qt //3,4 行定義拼接 key
local usersKey= sk: ..prodid.. :usr 
local userExists=redis.call(sismember ,usersKey,userid); //5-8,判斷用戶是否存在,不存在 return 2
if tonumber(userExists)==1 then
 return2;
local num=redis.call(get ,qtkey); //9-11,判斷商品是否存在
if tonumber(num) =0 then
 return 0;
else //12-15, 用戶和商品操作
 redis.call(decr ,qtkey);
 redis.call(sadd ,usersKey,userid);
return1;  // 最后一行 return 1;  秒殺成功 

完整代碼如下:

//  定義兩段 Lua 腳本 (使用 Lua 腳本可以解決樂(lè)觀鎖帶來(lái)的庫(kù)存遺留問(wèn)題)
 static String secKillScript =
 local userid=KEYS[1];\r\n  +
 local prodid=KEYS[2];\r\n  +
 local qtkey= sk: ..prodid..\ :qt\ \r\n  +
 local usersKey= sk: ..prodid..\ :usr\ \r\n  +
 local userExists=redis.call(\ sismember\ ,usersKey,userid);\r\n  +
 if tonumber(userExists)==1 then \r\n  +
  return 2;\r\n  +
 end\r\n  +
 local num= redis.call(\ get\  ,qtkey);\r\n  +
 if tonumber(num) =0 then \r\n  +
  return 0;\r\n  +
 else \r\n  +
  redis.call(\ decr\ ,qtkey);\r\n  +
  redis.call(\ sadd\ ,usersKey,userid);\r\n  +
 end\r\n  +
 return 1  ;
 
 
 public static boolean doSecKill(String uid,String prodid) throws IOException {
 
 JedisPool jedispool = JedisPoolUtil.getJedisPoolInstance();
 Jedis jedis=jedispool.getResource();
 jedis.select(2);
 
 //  通過(guò) jedis 的 scriptLoad 方法加載 Lua 腳本
 String sha1= jedis.scriptLoad(secKillScript);
 // 通過(guò) jedis 的 evalsha 方法調(diào)用 Lua 腳本
 Object result= jedis.evalsha(sha1, 2, uid,prodid);
 
 String reString=String.valueOf(result);
 if (0 .equals( reString ) ) {System.err.println( 已搶空!!}else if(1 .equals( reString ) ) {System.out.println( 搶購(gòu)成功!!!!}else if(2 .equals( reString ) ) {System.err.println( 該用戶已搶過(guò)!!}else{
 System.err.println( 搶購(gòu)異常!!jedis.close();
 return true;
 }

“Redis 實(shí)現(xiàn)秒殺的問(wèn)題怎么解決”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注丸趣 TV 網(wǎng)站,丸趣 TV 小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

正文完
 
丸趣
版權(quán)聲明:本站原創(chuàng)文章,由 丸趣 2023-07-13發(fā)表,共計(jì)3771字。
轉(zhuǎn)載說(shuō)明:除特殊說(shuō)明外本站除技術(shù)相關(guān)以外文章皆由網(wǎng)絡(luò)搜集發(fā)布,轉(zhuǎn)載請(qǐng)注明出處。
評(píng)論(沒(méi)有評(píng)論)
主站蜘蛛池模板: 唐山市| 乐亭县| 隆昌县| 合川市| 波密县| 永昌县| 如皋市| 泰兴市| 秦皇岛市| 宁蒗| 绥江县| 庆安县| 克山县| 昆明市| 秦皇岛市| 宝兴县| 平陆县| 济阳县| 秦安县| 五峰| 寿光市| 石首市| 灵川县| 星子县| 德州市| 万州区| 景德镇市| 鱼台县| 会同县| 临沂市| 渑池县| 谷城县| 平潭县| 海丰县| 宁波市| 石景山区| 屏山县| 济南市| 左贡县| 津市市| 娱乐|