成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

搞了個(gè)線上故障,被老板罵了....

開(kāi)發(fā) 架構(gòu)
本文的案例有點(diǎn)特殊,訂單號(hào)是后端系統(tǒng)生成的,前后兩次請(qǐng)求無(wú)法區(qū)分重復(fù)狀態(tài),所以系統(tǒng)會(huì)創(chuàng)建兩條不同訂單 ID 記錄,繞過(guò)了「唯一索引約束」這個(gè)限制。

大家好,我是Tom哥。

前幾天跟一位小伙伴聊天,心情特別沮喪,剛被老板罵完.....

差點(diǎn)丟了飯碗,還好老板沒(méi)說(shuō) “滾”。

就今年這就業(yè)行情,滿眼都是淚哇。

小伙伴在一家初創(chuàng)公司,團(tuán)隊(duì)規(guī)模很小,老板為了節(jié)省成本,也沒(méi)配置什么豪華陣容。

他的工作時(shí)間也不長(zhǎng),負(fù)責(zé)交易訂單,前幾天接到用戶投訴,「我的訂單列表」有多條一模一樣的訂單。

雖沒(méi)造成什么資損,但嚴(yán)重影響用戶體驗(yàn)。

看到這里,有經(jīng)驗(yàn)的同學(xué)可能猜到,應(yīng)該是接口沒(méi)做防重控制。

日常開(kāi)發(fā)中,重復(fù)提交也是蠻常見(jiàn)問(wèn)題。

比如:用戶提交一個(gè)表單,鼠標(biāo)點(diǎn)的太快,正好前端又是個(gè)新兵蛋子,沒(méi)做任何控制,瞬間就會(huì)有多個(gè)請(qǐng)求發(fā)到后端系統(tǒng)。

如果后端同學(xué)也沒(méi)做兜底方案的話,悲劇就發(fā)生了。

常見(jiàn)的解決方案是借助數(shù)據(jù)庫(kù)自身的「唯一索引約束」,來(lái)保證數(shù)據(jù)的準(zhǔn)確性,這種方案一般在插入場(chǎng)景用的多些。

變種方案可以考慮單獨(dú)創(chuàng)建一個(gè)防重表。

本文的案例有點(diǎn)特殊,訂單號(hào)是后端系統(tǒng)生成的,前后兩次請(qǐng)求無(wú)法區(qū)分重復(fù)狀態(tài),所以系統(tǒng)會(huì)創(chuàng)建兩條不同訂單 ID 記錄,繞過(guò)了「唯一索引約束」這個(gè)限制,這.....

另外,MySQL 性能也單薄了點(diǎn),單機(jī) QPS 在「千」維度,如果是面對(duì)一個(gè)高并發(fā)接口,性能也有點(diǎn)吃緊。

接下來(lái),我們就來(lái)講下,借助 Redis 來(lái)實(shí)現(xiàn)接口防重復(fù)提交。

技術(shù)方案

首先,我們來(lái)看下整理的流程,如下圖所示:

圖片

大致步驟:

1、客戶端發(fā)送請(qǐng)求到服務(wù)端。

2、服務(wù)端接收請(qǐng)求,然后從請(qǐng)求參數(shù)中提取唯一標(biāo)識(shí)。這個(gè)標(biāo)識(shí)可以沒(méi)有什么特殊業(yè)務(wù)含義,client 端隨機(jī)生成即可。

3、服務(wù)端系統(tǒng)將唯一標(biāo)識(shí)先嘗試寫(xiě)入 Redis 緩存中,可以認(rèn)為是加鎖操作。

4、加鎖失敗,說(shuō)明請(qǐng)求還在處理,此次是重復(fù)請(qǐng)求,可以丟棄。

5、加鎖成功,繼續(xù)后面正常業(yè)務(wù)邏輯處理。

6、業(yè)務(wù)邏輯處理完成后,刪除加鎖的標(biāo)記。

7、最后,將處理成功的結(jié)果返回給客戶端。

注意事項(xiàng):

  • 重復(fù)提交場(chǎng)景一般都是在極短時(shí)間內(nèi),同時(shí)發(fā)送了多次請(qǐng)求(比如:頁(yè)面表單重復(fù)提交),我們只認(rèn)第一次請(qǐng)求為有效請(qǐng)求。
  • 鎖用完后,要記得手動(dòng)刪除。為了防止鎖沒(méi)有正常釋放,我們可以為鎖設(shè)置一個(gè)極短的過(guò)期時(shí)間(比如 10 秒)。

項(xiàng)目實(shí)戰(zhàn)

1、引入 redis 組件

實(shí)戰(zhàn)的項(xiàng)目采用 Spring Boot 搭建,這里需要引入 Redis 相關(guān)依賴。

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>

2、redis 變量配置

application.properties 配置文件中,添加redis相關(guān)服務(wù)配置。

spring.redis.host=127.0.0.1
spring.redis.port=6379

3、定義注解類

定義一個(gè)注解,配置在需要防重復(fù)的接口方法上,提高開(kāi)發(fā)效率,同時(shí)降低代碼的耦合度。

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented

public @interface IdempotentRule {

/**
* 業(yè)務(wù)自定義前綴
*/
String prefix() default "";

/**
* 業(yè)務(wù)重復(fù)標(biāo)識(shí)
*/
String key() default "";
}

4、接口攔截器

上面定義了IdempotentRule?注解,需要通過(guò)攔截器對(duì)正常的業(yè)務(wù)方法做攔截,增加一些特殊邏輯處理。

@Aspect
@Component
@Slf4j
public class IdempotentAspect {

@Autowired
private RedisTemplate<String, Serializable> idempotentRedisTemplate;

@Around("execution(public * *(..)) && @annotation(com.onyone.idempotent.annotation.IdempotentRule)")
public Object limit(ProceedingJoinPoint pjp) {
MethodSignature signature = (MethodSignature) pjp.getSignature();


Object[] params = pjp.getArgs();
String[] paramNames = signature.getParameterNames();

Method method = signature.getMethod();
IdempotentRule idempotentRule = method.getAnnotation(IdempotentRule.class);
String key = idempotentRule.key();
String prefix = idempotentRule.prefix();

ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = new StandardEvaluationContext();
context.setVariable(paramNames[0], params[0]);
String repeatKey = (String) parser.parseExpression(key).getValue(context);

try {
// 先在緩存中做個(gè)標(biāo)記
Boolean lockResult = idempotentRedisTemplate.opsForValue().setIfAbsent(prefix + repeatKey, "正在處理....", 20, TimeUnit.SECONDS);
if (lockResult) {
// 業(yè)務(wù)邏輯處理
return pjp.proceed();
} else {
throw new Exception("重復(fù)提交..................");
}
} catch (Throwable e) {
e.printStackTrace();
} finally {
// 處理完成后,將標(biāo)記刪除
idempotentRedisTemplate.delete(prefix + repeatKey);
}

return null;
}


}

這里,比較特殊的是提取請(qǐng)求的唯一標(biāo)識(shí),由于不同的業(yè)務(wù)請(qǐng)求唯一標(biāo)識(shí)不一樣。

所以,這里采用 SPEL 表達(dá)式,將規(guī)則設(shè)置能力開(kāi)放出去,由業(yè)務(wù)方自己定義,比如:

@IdempotentRule(key = "#userParam.cardNumber", prefix = "repeat_")。

攔截器根據(jù) SPEL 表達(dá)式( 如 "#userParam.cardNumber")以及請(qǐng)求參數(shù)對(duì)象,計(jì)算當(dāng)前請(qǐng)求唯一標(biāo)識(shí)的值,

然后將值寫(xiě)入 Redis 中,并設(shè)置過(guò)時(shí)間。

如果設(shè)置成功,說(shuō)明是第一次請(qǐng)求,繼續(xù)下面的業(yè)務(wù)邏輯處理;否則,判定為重復(fù)請(qǐng)求,直接丟棄。

5、上層業(yè)務(wù)接口

@RestController
@RequestMapping("/user")
public class UserController {
/**
* 創(chuàng)建一個(gè)新的用戶
*/
@RequestMapping(value = "/create_user")
@IdempotentRule(key = "#userParam.cardNumber", prefix = "repeat_")
public String createUser(@RequestBody UserParam userParam) {
// 模擬業(yè)務(wù)處理

return "創(chuàng)建用戶成功!";
}
}
@Data
public class UserParam {
private String cardNumber;
private String name;
}

測(cè)試結(jié)果

1、構(gòu)造客戶端請(qǐng)求,第一次處理成功。

圖片

2、 Redis 緩存中,能查到請(qǐng)求設(shè)置的鎖標(biāo)記。

圖片

3、模擬重復(fù),連續(xù)多次快速提交請(qǐng)求,請(qǐng)求會(huì)被攔截,并拋出異常。

圖片

責(zé)任編輯:姜華 來(lái)源: 微觀技術(shù)
相關(guān)推薦

2022-03-23 18:00:34

循環(huán)CPU線程

2022-07-28 14:22:50

元宇宙AI

2023-04-24 08:12:59

2024-09-10 14:50:00

2024-08-12 00:00:00

NPMCTOJavaScrip

2020-07-09 09:08:24

Java系統(tǒng)故障

2020-07-13 07:49:38

Kubernetes容器架構(gòu)

2009-10-28 09:14:43

員工分析軟件

2022-04-08 08:48:16

線上事故日志訂閱者

2021-09-27 10:15:10

故障業(yè)務(wù)方電腦

2020-04-13 17:17:28

MySQL8.0功能

2024-03-11 08:51:08

JVMSWAP內(nèi)存

2021-08-05 06:46:39

P0故障公司

2021-05-12 09:15:48

Facebook 開(kāi)發(fā)技術(shù)

2021-04-13 17:17:08

線上故障交付

2019-06-27 22:23:56

谷歌Android開(kāi)發(fā)者

2020-07-15 08:10:00

瀏覽器安全Fetch

2019-03-29 10:22:08

Linux系統(tǒng)故障技巧

2020-05-18 07:50:47

線上故障排查

2022-02-07 15:12:17

系統(tǒng)日志定位
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 久久久久久久久久久一区二区 | 国产一级视频在线观看 | 欧美久久视频 | 日韩视频一区二区 | 一区二区三区在线看 | 精品成人免费一区二区在线播放 | 每日更新av | 欧美一区二区三区在线播放 | 日韩欧美三区 | 欧美成人手机在线 | 精品国产91久久久久久 | 亚洲一级淫片 | 黄网站免费在线观看 | 一区二区视频在线 | 国产一区二区三区网站 | 国产精品视频久久 | 国产在线精品一区二区三区 | 色天天综合 | 99久久99久久精品国产片果冰 | 亚洲 欧美 日韩在线 | 亚洲精品视频二区 | 999热视频| 国产一级淫片免费视频 | 国产精品.xx视频.xxtv | 欧美黄色一级毛片 | 日本一区二区电影 | 玖草资源 | 一级黄色毛片子 | 日韩高清成人 | 九九热在线免费视频 | av网站免费观看 | 最新国产福利在线 | 国产在线一区二 | 日日操视频 | 日日噜噜噜夜夜爽爽狠狠视频, | 亚洲欧美视频一区二区 | 福利av在线 | 亚洲一区中文字幕在线观看 | 国产福利视频 | 久久久久一区二区三区 | 日韩av成人|