本篇內(nèi)容介紹了“redis實(shí)現(xiàn)秒殺的問題怎么解決”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
我們提供的服務(wù)有:做網(wǎng)站、成都網(wǎng)站建設(shè)、微信公眾號開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、水城ssl等。為超過千家企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的水城網(wǎng)站制作公司
秒殺:解決計(jì)數(shù)器和人員記錄的事務(wù)操作
1.uid和proid非空判斷
2.連接redis
3.拼接key
庫存key
秒殺成功用戶key
4.獲取庫存,如果庫存為null,秒殺還沒開始
5.判斷用戶是否重復(fù)秒殺操作
6.判斷商品數(shù)量,庫存數(shù)量小于1,秒殺結(jié)束
7.秒殺過程
庫存-1
把秒殺成功用戶添加清單里面
原因:由于大量創(chuàng)建連接,十分消耗性能,并且有時(shí)獲取連接不及時(shí),出現(xiàn)連接超時(shí)的情況
在并發(fā)的情況下發(fā)生的,就是在輸出沒有庫存(秒殺結(jié)束)后還有商品售出導(dǎo)致庫存數(shù)量為負(fù)數(shù)。
使用樂觀鎖解決問題2之后,出現(xiàn)問題3
如果庫存數(shù)量相對并發(fā)更多,由于使用樂觀鎖,第一個(gè)用戶秒殺成功后會修改庫存鍵的版本號,其他搶到的用戶會因?yàn)榘姹咎柌煌瑢?dǎo)致無法繼續(xù)購買,就會有庫存遺留問題
使用連接池,工具類如下:
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配置,然后注入對象即可)
org.springframework.boot spring-boot-starter-data-redis redis.clients jedis 3.2.0
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;
使用Redis事務(wù),樂觀鎖 + watch
//監(jiān)視庫存 jedis.watch(kcKey);//中間代碼忽略 //7 秒殺過程 //使用事務(wù) Transaction multi = jedis.multi();//組隊(duì)操作 multi.decr(kcKey);multi.sadd(userKey,uid);//執(zhí)行 List
使用Lua嵌入式腳本語言
將復(fù)雜的或者多步的 Redis 操作,寫為一個(gè)腳本,一次提交給Redis運(yùn)行,減少反復(fù)連接 reids的次數(shù)。提升性能。
LUA腳本是類似 redis 事務(wù),有一定的原子性,不會被其他命令插隊(duì),可以完成redis事務(wù)性的操作
LUA腳本功能,在Redis 2.6以上的版本才可以使用
利用 lua 腳本淘汰用戶,解決超賣問題。
redis 2.6 版本以后,通過 lua 腳本解決爭搶問題,實(shí)際上是 redis 利用其單線程的特性,用任務(wù)隊(duì)列的方式解決多任務(wù)并發(fā)問題。
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; end 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); end return1; //最后一行return 1; 秒殺成功
完整代碼如下:
// 定義兩段Lua腳本(使用Lua腳本可以解決樂觀鎖帶來的庫存遺留問題) 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); // 通過jedis的scriptLoad方法加載Lua腳本 String sha1= jedis.scriptLoad(secKillScript); //通過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("搶購成功?。。?!"); }else if("2".equals( reString ) ) { System.err.println("該用戶已搶過??!"); }else{ System.err.println("搶購異常!!"); } jedis.close(); return true; }
“Redis實(shí)現(xiàn)秒殺的問題怎么解決”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!