高并發(fā)場景分析之redis+lua防重校驗
高并發(fā)場景:redis+lua防重校驗
大家平時在做有并發(fā)量下單的項目時,代碼層面基本上就分為這么幾個步驟:參數(shù)校驗--->防重校驗--->庫存校驗扣減--->下單成功--->支付。
最近公司有個商城項目說要30分鐘達到1億的并發(fā)量。當時聽到突然猛了一下。真是牛逼克拉斯呀。
不過該說不說還是得開搞,所謂的并發(fā)無非就是要想辦法減少io的操作,盡量少查表,其余配置方面的問題就看公司舍不舍得花錢了。
其中防重校驗這一部分選用了redis集合lua來做,來防止多次提交。
注意:真實下單操作是分為了訂單前置操作 (前置校驗和生成防重令牌)和提交訂單兩個接口來寫的,這里為了測試簡單合并了
@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;
}
}結果:

redis+lua語言去重
1)redis
redis是一種鍵值對的單線程架構模型,所以它是線程安全的,也是分布式緩存常用的解決方案。
2)lua
lua是基于c語言的一種腳本語言,它可以很輕便地被使用在嵌入式方面。我們不會去重寫redis,但是我們可以去使用lua來擴展redis的功能。而redis也內(nèi)置了對lua支持的模塊。
3)redis+lua是我司基于分布式告警去重的一種解決方案,要達到的目的:堵住10是s內(nèi)的重復告警,主要應用的場景是同一個告警,在不通的客戶端同時推送了一條告警數(shù)據(jù),此時要堵住
一條數(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生效時間,key表示存儲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該方案主要用于微服務集群中,采用分布式鎖防和redis集群確保數(shù)據(jù)唯一。
使用腳本的好處如下:
1.減少網(wǎng)絡開銷:本來5次網(wǎng)絡請求的操作,可以用一個請求完成,原先5次請求的邏輯放在redis服務器上完成。使用腳本,減少了網(wǎng)絡往返時延。
2.原子操作:Redis會將整個腳本作為一個整體執(zhí)行,中間不會被其他命令插入。
3.復用:客戶端發(fā)送的腳本會永久存儲在Redis中,意味著其他客戶端可以復用這一腳本而不需要使用代碼完成同樣的邏輯。
到此這篇關于高并發(fā)場景分析之redis+lua防重校驗的文章就介紹到這了,更多相關redis+lua防重內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
nestjs使用redis實現(xiàn)ip限流的步驟詳解
如果使用nestjs開發(fā)接口并部署之后,我們通常需要考慮到接口是否會被惡意盜刷消耗過多的資源,一個簡單的方式就是限制在單位時間內(nèi)的訪問次數(shù),所以本文給大家介紹了nestjs使用redis實現(xiàn)ip限流的步驟,需要的朋友可以參考下2025-01-01
Windows中Redis安裝配置流程并實現(xiàn)遠程訪問功能
很多在windows環(huán)境中安裝Redis總是出錯,今天小編抽空給大家分享在Windows中Redis安裝配置流程并實現(xiàn)遠程訪問功能,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧2021-06-06
redis的hGetAll函數(shù)的性能問題(記Redis那坑人的HGETALL)
這篇文章主要介紹了redis的hGetAll函數(shù)的性能問題,需要的朋友可以參考下2016-02-02
redis cluster集群模式下實現(xiàn)批量可重入鎖
本文主要介紹了使用redis cluster集群版所遇到的問題解決方案及redis可重入鎖是否會有死鎖的問題等,具有一定的參考價值,感興趣的可以了解一下2024-02-02
Redis 通過 RDB 方式進行數(shù)據(jù)備份與還原的方法
這篇文章主要介紹了Redis 通過 RDB 方式進行數(shù)據(jù)備份與還原,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-03-03
Redis基本數(shù)據(jù)類型String常用操作命令
這篇文章主要為大家介紹了Redis基本數(shù)據(jù)類型String常用操作命令,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-05-05

