使用Lua指令碼通過原子減防止超賣

2022-08-23 22:24:15 字數 1643 閱讀 5261

需求

雙十二要搞乙個一分錢門票搶購的活動。

分析

效能分析,搶購時會發生高併發,如果僅僅依靠mysql資料庫,有可能因為大量的請求頻繁訪問資料庫造成伺服器雪崩,所以考慮通過redis減庫存,最終的資料落地到db中。

在高併發的情況下,還要考慮到超賣的問題,因而打算使用lua指令碼完成原子減的操作。

在這裡,我們只針對減庫存的操作進行分析。

實現

不使用原子操作,出現超賣的情況。第一步:先從redis中查出庫存進行判斷,第二步:如果庫存》0,則進行減庫存的操作。

**實現:

1

//第一步:從redis中查出庫存

2 integer stock = (integer) redisutils.get("stock");34

//第二步:如果庫存》0,則進行減庫存的操作

5if (stock > 0) else

用多執行緒模擬併發請求:庫存為500,建立505個執行緒去搶購。

1

for(int i =1;i<=505;i++)

執行結果:出現超賣問題,原因是:查詢庫存及減庫存不是原子性操作。

使用原子性操作:直接減庫存。

1

public

void

run() else

89 }

lua指令碼實現減庫存操作:

/**

* 庫存不足

*/public

static

final

int low_stock = 0;

/*** 不限庫存

*/public

static

final

long uninitialized_stock = -1l;

/*** 執行扣庫存的指令碼

*/public

static

final

string stock_lua;

static

/*** 扣庫存**

@param

key 庫存key

* @return

扣減之前剩餘的庫存【0:庫存不足; -1:庫存未初始化; 大於0:扣減庫存之前的剩餘庫存】

*/public

static

long stock(string key)

//單機模式

else

if (nativeconnection instanceof

jedis)

return

uninitialized_stock;

}});

return

result;

}

執行結果:505個執行緒去搶500個商品,有五個執行緒會搶不到,測試結果與預期一致,解決了超賣的問題。

參考:

Redis使用Lua指令碼自定義原子操作

1 eval eval 指令碼內容 key個數 key列表 引數列表 127.0.0.1 6379 eval return hello keys 1 ar 1 1 redis why hello redis why 2 evalsha 先通過script load命令將lua指令碼載入到redis,...

lua指令碼保證Redis多條命令原子性

redis能執行lua指令碼,一段lua指令碼可以作為乙個整體,這樣將多條redis命令寫入lua,即可以實現事務的原子性,下面演示了jedis和redistemplate是如何呼叫lua指令碼的 完成的功能是 set my key1 my value1 ex 15 nx,lua指令碼很神奇不需要加...

Redis使用lua指令碼

版本 自2.6.0起可用。時間複雜度 取決於執行的指令碼。使用lua指令碼的好處 命令格式 eval script numkeys key key arg arg 說明 簡單例項 127.0.0.1 6379 eval return ar 1 0 100 100 127.0.0.1 6379 eva...