高并發(fā)場景分析之redis+lua防重校驗(yàn)
高并發(fā)場景:redis+lua防重校驗(yàn)
大家平時(shí)在做有并發(fā)量下單的項(xiàng)目時(shí),代碼層面基本上就分為這么幾個(gè)步驟:參數(shù)校驗(yàn)--->防重校驗(yàn)--->庫存校驗(yàn)扣減--->下單成功--->支付。
最近公司有個(gè)商城項(xiàng)目說要30分鐘達(dá)到1億的并發(fā)量。當(dāng)時(shí)聽到突然猛了一下。真是牛逼克拉斯呀。
不過該說不說還是得開搞,所謂的并發(fā)無非就是要想辦法減少io的操作,盡量少查表,其余配置方面的問題就看公司舍不舍得花錢了。
其中防重校驗(yàn)這一部分選用了redis集合lua來做,來防止多次提交。
注意:真實(shí)下單操作是分為了訂單前置操作 (前置校驗(yàn)和生成防重令牌)和提交訂單兩個(gè)接口來寫的,這里為了測試簡單合并了
@RestController @RequestMapping("/lua") public class TestLuaController { @Autowired private StringRedisTemplate redisTemplate; private static final String ORDER_CHECK_TOKEN = "order_check_token"; private static final String ORDER_TOKEN_DEFAULT_VALUE = "value"; /** * 場景:最近公司有高并發(fā)場景,涉及到用令牌防重(防止有人多次提交訂單) * 可以使用redis執(zhí)行l(wèi)ua腳本 比較key值令牌是否存在,如果存在即刪除 */ @RequestMapping("/checkTempToken") public Long luaExecute(String checkToken){ //模擬提交訂單生成的防重令牌 redisTemplate.opsForValue().set(ORDER_CHECK_TOKEN + checkToken,ORDER_TOKEN_DEFAULT_VALUE,60, TimeUnit.SECONDS); String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1]\n" + "then\n" + " return redis.call(\"del\",KEYS[1])\n" + "else\n" + " return 0\n" + "end"; //執(zhí)行redis腳本操作的函數(shù) Long execute = redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Arrays.asList(ORDER_CHECK_TOKEN + checkToken), ORDER_TOKEN_DEFAULT_VALUE); System.out.println(execute); return execute; } }
結(jié)果:
redis+lua語言去重
1)redis
redis是一種鍵值對的單線程架構(gòu)模型,所以它是線程安全的,也是分布式緩存常用的解決方案。
2)lua
lua是基于c語言的一種腳本語言,它可以很輕便地被使用在嵌入式方面。我們不會(huì)去重寫redis,但是我們可以去使用lua來擴(kuò)展redis的功能。而redis也內(nèi)置了對lua支持的模塊。
3)redis+lua是我司基于分布式告警去重的一種解決方案,要達(dá)到的目的:堵住10是s內(nèi)的重復(fù)告警,主要應(yīng)用的場景是同一個(gè)告警,在不通的客戶端同時(shí)推送了一條告警數(shù)據(jù),此時(shí)要堵住
一條數(shù)據(jù)。
直接上代碼吧
@Component public class RedisLua { @Autowired private RedisTemplate<String,Object> redisTemplate; private DefaultRedisScript<Boolean> script; private static final String KEY_PREX = "alertInfo_"; @PostConstruct private void init(){ script = new DefaultRedisScript<Boolean>(); script.setResultType(Boolean.class); script.setScriptSource(new ResourceScriptSource(new ClassPathResource("lua/alert.lua")));//lua腳本文件 }public Boolean blockRepetition(String ruleId,String status,String ip,Object...args){ List<String> keys = new ArrayList<>(); keys.add(KEY_PREX + ip+ruleId+status);//key包括前綴+客戶端ip+告警規(guī)則id+狀態(tài) return redisTemplate.execute(script, keys, args); } }
下面是lua腳本
--[[ ARGV1表示redis生效時(shí)間,key表示存儲(chǔ)redis的key值]] local alert = redis.call('exists',KEYS[1]); if alert then return false else redis.call('set',KEYS[1],ngx.time()) redis.call('expire',KEYS[1],ARGV[1]) return true end
該方案主要用于微服務(wù)集群中,采用分布式鎖防和redis集群確保數(shù)據(jù)唯一。
使用腳本的好處如下:
1.減少網(wǎng)絡(luò)開銷:本來5次網(wǎng)絡(luò)請求的操作,可以用一個(gè)請求完成,原先5次請求的邏輯放在redis服務(wù)器上完成。使用腳本,減少了網(wǎng)絡(luò)往返時(shí)延。
2.原子操作:Redis會(huì)將整個(gè)腳本作為一個(gè)整體執(zhí)行,中間不會(huì)被其他命令插入。
3.復(fù)用:客戶端發(fā)送的腳本會(huì)永久存儲(chǔ)在Redis中,意味著其他客戶端可以復(fù)用這一腳本而不需要使用代碼完成同樣的邏輯。
到此這篇關(guān)于高并發(fā)場景分析之redis+lua防重校驗(yàn)的文章就介紹到這了,更多相關(guān)redis+lua防重內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
nestjs使用redis實(shí)現(xiàn)ip限流的步驟詳解
如果使用nestjs開發(fā)接口并部署之后,我們通常需要考慮到接口是否會(huì)被惡意盜刷消耗過多的資源,一個(gè)簡單的方式就是限制在單位時(shí)間內(nèi)的訪問次數(shù),所以本文給大家介紹了nestjs使用redis實(shí)現(xiàn)ip限流的步驟,需要的朋友可以參考下2025-01-01Redis實(shí)現(xiàn)分布式鎖的幾種方法總結(jié)
這篇文章主要介紹了Redis實(shí)現(xiàn)分布式鎖的幾種方法總結(jié)的相關(guān)資料, Redis實(shí)現(xiàn)與Zookeeper實(shí)現(xiàn)和數(shù)據(jù)庫實(shí)現(xiàn),需要的朋友可以參考下2017-07-07Windows中Redis安裝配置流程并實(shí)現(xiàn)遠(yuǎn)程訪問功能
很多在windows環(huán)境中安裝Redis總是出錯(cuò),今天小編抽空給大家分享在Windows中Redis安裝配置流程并實(shí)現(xiàn)遠(yuǎn)程訪問功能,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2021-06-06Redis延遲隊(duì)列的實(shí)現(xiàn)示例
Redis 延遲隊(duì)列是一種使用 Redis 實(shí)現(xiàn)的消息隊(duì)列,本文主要介紹了Redis延遲隊(duì)列的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-01-01redis的hGetAll函數(shù)的性能問題(記Redis那坑人的HGETALL)
這篇文章主要介紹了redis的hGetAll函數(shù)的性能問題,需要的朋友可以參考下2016-02-02redis cluster集群模式下實(shí)現(xiàn)批量可重入鎖
本文主要介紹了使用redis cluster集群版所遇到的問題解決方案及redis可重入鎖是否會(huì)有死鎖的問題等,具有一定的參考價(jià)值,感興趣的可以了解一下2024-02-02Redis 通過 RDB 方式進(jìn)行數(shù)據(jù)備份與還原的方法
這篇文章主要介紹了Redis 通過 RDB 方式進(jìn)行數(shù)據(jù)備份與還原,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03Redis基本數(shù)據(jù)類型String常用操作命令
這篇文章主要為大家介紹了Redis基本數(shù)據(jù)類型String常用操作命令,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05