首頁> 資料庫> Redis> 主體

一起聊聊Redis實現秒殺的問題

WBOY
發布: 2022-05-27 21:00:06
轉載
3149 人瀏覽過

這篇文章為大家帶來了關於Redis的相關知識,其中主要介紹了關於實現秒殺的相關內容,包括了秒殺邏輯、存在的連結超時、超賣和庫存遺留的問題,下面一起來看一下,希望對大家有幫助。

一起聊聊Redis實現秒殺的問題

推薦學習:Redis影片教學

#1、秒殺邏輯

##秒殺:解決計數器和人員記錄的事務操作

    1.uid和proid非空判斷
  1. 2.連接redis
  2. 3.拼接key
    • 庫存key
    • 秒殺成功用戶key
  3. #4.取得庫存,如果庫存為null,秒殺還沒開始
  4. 5.判斷使用者是否重複秒殺操作
  5. 6.判斷商品數量,庫存數量小於1,秒殺結束
  6. 7.秒殺過程
    • #庫存-1
    • 把秒殺成功使用者加入清單裡面
2、存在問題

2.1、連線逾時

原因:由於大量創建連接,十分消耗性能,有時獲取連接不及時,出現連接超時的情況

2.2、超賣

在並發的情況下發生的,就是在輸出沒有庫存(秒殺結束)後還有商品售出導致庫存數量為負數。


一起聊聊Redis實現秒殺的問題

2.3、庫存遺留

使用樂觀鎖定解決問題2之後,出現問題3

如果庫存數量相對並發更多,由於使用樂觀鎖,第一個用戶秒殺成功後會修改庫存鍵的版本號,其他搶到的用戶會因為版本號不同導致無法繼續購買,就會有庫存遺留問題

3、解決

3.1、連接逾時

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

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;
登入後複製
3.2、超賣問題

使用Redis事務,樂觀鎖定watch

//监视库存 jedis.watch(kcKey);//中间代码忽略 //7 秒杀过程 //使用事务 Transaction multi = jedis.multi();//组队操作 multi.decr(kcKey);multi.sadd(userKey,uid);//执行 List results = multi.exec();if(results == null || results.size()==0) { System.out.println("秒杀失败了...."); jedis.close(); return false;}
登入後複製
3.3、樂觀鎖導致的庫存遺留問題

#使用Lua嵌入式腳本語言

    將複雜的或多步驟的Redis 操作,寫為腳本,一次提交給Redis運行,減少重複連接reids的次數。提升性能。
  1. LUA腳本是類似redis 事務,有一定的原子性,不會被其他命令插隊,可以完成redis事務性的操作
  2. LUA腳本功能,在Redis 2.6以上的版本才可以使用
  3. 利用lua 腳本淘汰用戶,解決超賣問題。
  4. redis 2.6 版本以後,透過
  5. lua 腳本解決爭搶問題,實際上是redis 利用其單執行緒的特性,用任務佇列的方式解決多任務並發問題
  6. local userid=KEYS[1]; //1、2行定义两个变量, 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)
    登入後複製
完整程式碼如下:

// 定义两段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)推薦學習:

Redis影片教學

登入後複製

以上是一起聊聊Redis實現秒殺的問題的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:csdn.net
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!