真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

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

本篇內(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)站制作公司

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

1、秒殺邏輯

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

  1. 1.uid和proid非空判斷

  2. 2.連接redis

  3. 3.拼接key

    • 庫存key

    • 秒殺成功用戶key

  4. 4.獲取庫存,如果庫存為null,秒殺還沒開始

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

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

  7. 7.秒殺過程

    • 庫存-1

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

2、存在問題

2.1、連接超時(shí)

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

2.2、超賣

在并發(fā)的情況下發(fā)生的,就是在輸出沒有庫存(秒殺結(jié)束)后還有商品售出導(dǎo)致庫存數(shù)量為負(fù)數(shù)。
Redis實(shí)現(xiàn)秒殺的問題怎么解決

2.3、庫存遺留

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

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

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配置,然后注入對象即可)


    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事務(wù),樂觀鎖 + watch

//監(jiān)視庫存
jedis.watch(kcKey);//中間代碼忽略

//7 秒殺過程
//使用事務(wù)
Transaction multi = jedis.multi();//組隊(duì)操作
multi.decr(kcKey);multi.sadd(userKey,uid);//執(zhí)行
List results = multi.exec();if(results == null || results.size()==0) {
    System.out.println("秒殺失敗了....");
    jedis.close();
    return false;}

3.3、樂觀鎖導(dǎo)致的庫存遺留問題

使用Lua嵌入式腳本語言

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

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

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

  4. 利用 lua 腳本淘汰用戶,解決超賣問題。

  5. 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í)用文章!


本文題目:Redis實(shí)現(xiàn)秒殺的問題怎么解決
文章路徑:http://weahome.cn/article/ijigdp.html

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部