lua运行外部程序_一起聊聊redis(5)——c#的lua脚本应用实例之高并发抢口罩
本節(jié)內(nèi)容
展示Redis數(shù)據(jù)庫在高并發(fā)下實(shí)現(xiàn)搶口罩的例子,文章分3個(gè)實(shí)現(xiàn)的模式
前言
寫于2020.2.8日疫情嚴(yán)重之日,搶口罩成為每晚8點(diǎn)檔黃金時(shí)間必備節(jié)目,在報(bào)道上看到太多不知真假的求助病重不能得到及時(shí)醫(yī)治的,有感于世事無常,珍愛身邊人.
不加鎖
在這個(gè)例子中程序運(yùn)行是有bug的。當(dāng)多人同時(shí)搶口罩的時(shí)候,可能會(huì)出現(xiàn)搶到的人數(shù)比口罩的庫存多的情況。先看下面實(shí)現(xiàn)的主要代碼
搶口罩的邏輯,這里用到了哈希類型,使用這個(gè)類型主要是用它的自減方法。
初始化口罩庫存為3,Parallel實(shí)現(xiàn)并發(fā)搶口罩
運(yùn)行結(jié)果
如上圖所示,會(huì)出現(xiàn)庫存超賣的情況,原因是這樣的。由于程序在判斷庫存和庫存減1兩個(gè)操作沒有實(shí)現(xiàn)原子性,雖然Redis是單線程運(yùn)行的。但在某個(gè)客戶端的判斷庫存和庫存減1這兩個(gè)操作之間,會(huì)可能出現(xiàn)其他的客戶端的庫存減1的操作插在其中,造成以上的結(jié)果。
樂觀鎖
Redis中Watch命令是一個(gè)樂觀鎖,它可以在執(zhí)行Exec之前,監(jiān)視任意數(shù)量的數(shù)據(jù)庫鍵,當(dāng)其中至少一個(gè)發(fā)生改變后,它會(huì)拒絕執(zhí)行事務(wù),如下圖所示。
在c#的StackExchange.Redis中沒有Watch命令,但它有事務(wù)的實(shí)現(xiàn)。
事務(wù)的條件用AddContidion方法添加,類似于Watch某個(gè)鍵值
運(yùn)行結(jié)果,由于添加了鎖,所以不再存在超賣的情況。
Lua腳本
Lua腳本會(huì)在一個(gè)Redis服務(wù)端的偽客戶端執(zhí)行代碼。天生自帶原子屬性,意味著lua的代碼都原子執(zhí)行。另外使用Lua的腳本,可以代碼復(fù)用,以后其他語言編寫的客戶端也可以使用,這好處相當(dāng)于存儲(chǔ)過程和數(shù)據(jù)庫的類比。
詳細(xì)的代碼和結(jié)果見下圖:
這里為了演示方便,通常都是上傳腳本到服務(wù)端,讓服務(wù)端返回SHA1碼,下次執(zhí)行直接傳SHA1碼
c#生成Sha1
在實(shí)際過程中,通常不會(huì)傳一大段lua腳本到服務(wù)端,就等于你不會(huì)傳一個(gè)存儲(chǔ)過程的邏輯到數(shù)據(jù)庫一個(gè)道理,根據(jù)上一節(jié)的內(nèi)容,通常上傳完lua腳本到服務(wù)端會(huì)返回一個(gè)sha1的字符串,下次可以通過傳該字符串到服務(wù)端,服務(wù)端進(jìn)行比對(duì)后找回對(duì)應(yīng)的腳本執(zhí)行。下面的代碼展示怎么在c#中生成sha1
總結(jié):
用Lua腳本是最好的個(gè)人覺得,因?yàn)樗梢苑庋b好這一部分的邏輯,甚至這些邏輯改動(dòng)了都不需重新編譯客戶端,只是修改腳本就好,當(dāng)然腳本就不能在程序中硬編碼。
總結(jié)
以上是生活随笔為你收集整理的lua运行外部程序_一起聊聊redis(5)——c#的lua脚本应用实例之高并发抢口罩的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 王者荣耀李白技能
- 下一篇: 1. 加签和会签的区别