国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

Retry & Fallback 是利器還是魔咒?

開發(fā) 前端
Retry 就是在調(diào)用遠(yuǎn)程接口失敗時(shí),Client 主動(dòng)發(fā)起重試請(qǐng)求,以期待獲得最終結(jié)果,從而完成整個(gè)流程。

1. 概覽

在分布式場景中,Retry 和 Fallback 是最常見的容災(zāi)方案。

  • Retry 就是在調(diào)用遠(yuǎn)程接口失敗時(shí),Client 主動(dòng)發(fā)起重試請(qǐng)求,以期待獲得最終結(jié)果,從而完成整個(gè)流程
  • Fallback 是在調(diào)用遠(yuǎn)程接口失敗時(shí),Client 不進(jìn)行重試而是調(diào)用一個(gè)特殊的 fallback 方法,從這個(gè)方法中獲取結(jié)果,使流程能夠繼續(xù)下去

那 Retry 和 Fallback 該怎么抉擇呢?

1.1. 背景

首先,先看下 Retry 和 Fallback 都是怎么幫助流程進(jìn)行自我恢復(fù)的。

1.1.1. Retry

現(xiàn)在有一個(gè)生產(chǎn)流程:

核心流程如下:

  • 從商品服務(wù)中獲取商品信息
  • 根據(jù)商品信息創(chuàng)建訂單
  • 將訂單保存到數(shù)據(jù)庫

如果發(fā)生網(wǎng)絡(luò)抖動(dòng),將導(dǎo)致生產(chǎn)失敗。

  • 在調(diào)用商品服務(wù)獲取商品時(shí),由于網(wǎng)絡(luò)異常,接口調(diào)用失敗
  • 由于無法獲取商品信息,生產(chǎn)流程被異常中斷

由于上產(chǎn)流程太過重要,系統(tǒng)需盡最大努力保障用戶能夠完成下單操作,那針對(duì)網(wǎng)絡(luò)抖動(dòng)這個(gè)問題,可以通過 Retry 進(jìn)行修復(fù)。

image

  • 在第一次獲取商品信息時(shí),由于網(wǎng)絡(luò)問題導(dǎo)致獲取失敗
  • 系統(tǒng)不會(huì)直接拋出異常,而是在等待一段時(shí)間后,重新發(fā)起第二次請(qǐng)求,也就是 Retry 操作
  • 網(wǎng)絡(luò)恢復(fù),第二次請(qǐng)求成功獲取商品信息
  • 流程繼續(xù)運(yùn)行,最終完成用戶生產(chǎn)

Retry 機(jī)制非常適合服務(wù)短時(shí)間不可用,或某個(gè)服務(wù)節(jié)點(diǎn)異常 這類場景。

1.1.2. Fallback

一個(gè)生產(chǎn)驗(yàn)證接口,主流程如下:

  • 調(diào)用商品服務(wù)的接口獲取商品信息
  • 根據(jù)商品和用戶信息判斷用戶是否能夠購買該商品

同樣,假設(shè)在訪問商品服務(wù)時(shí)出現(xiàn)網(wǎng)絡(luò)異常:

由于無法獲取商品信息,從而導(dǎo)致整個(gè)驗(yàn)證流程被異常中斷,用戶操作被迫終止。

聰明的你估計(jì)會(huì)說那就使用 Retry 呀,是的:

如果是短時(shí)不可用,通過 Retry 機(jī)制便可以恢復(fù)流程。

但,如果是商品服務(wù)壓力過大,響應(yīng)時(shí)間過長呢?比如,商品服務(wù)流量激增,導(dǎo)致 DB CPU 飆升,出現(xiàn)大量的慢 SQL,這時(shí)觸發(fā)了系統(tǒng)的 Retry 會(huì)是怎樣?

image

  • 在獲取商品失敗后,系統(tǒng)自動(dòng)觸發(fā) Retry 機(jī)制
  • 由于是商品服務(wù)本身出了問題,第二次請(qǐng)求仍舊失敗
  • 服務(wù)又觸發(fā)了第三次請(qǐng)求,仍未獲取結(jié)果
  • 達(dá)到最大重試次數(shù),仍舊無法獲取商品,只能通過異常中斷用戶請(qǐng)求

通過 Retry 機(jī)制未能將流程從異常中恢復(fù)過來,也給下游的 商品服務(wù) 造成了巨大傷害。

  • 商品服務(wù)壓力大,響應(yīng)時(shí)間長
  • 上游系統(tǒng)由于超時(shí)觸發(fā)自動(dòng)重試
  • 自動(dòng)重試增大了對(duì)商品服務(wù)的調(diào)用
  • 商品服務(wù)請(qǐng)求量更大,更難以從故障中恢復(fù)

這就是常說的“讀放大”,假設(shè)用戶驗(yàn)證是否能夠購買請(qǐng)求的請(qǐng)求量為 n,那極端情況下 商品服務(wù)的請(qǐng)求量為 3n (其中 2n 是由 Retry 機(jī)制造成)

此時(shí),Retry 就不是一個(gè)好的方案。我們先退回業(yè)務(wù)場景進(jìn)行思考,如果無法獲取商品,驗(yàn)證接口是否可以直接放行,先讓用戶完成購買?

如果,這個(gè)業(yè)務(wù)假設(shè)能夠接受的話,那就到了 Fallback 上場的時(shí)候了。

  • 調(diào)用商品服務(wù)獲取商品信息失敗
  • 系統(tǒng)不會(huì)進(jìn)行重試,而是觸發(fā) fallback 機(jī)制
  • fallback 會(huì)調(diào)用指定的一個(gè)方法,并將返回值作為遠(yuǎn)程接口的返回值
  • 接下來的流程使用 fallback 方法的返回值完成業(yè)務(wù)邏輯

1.1.3. 場景思考

同樣是對(duì)商品服務(wù)接口(同一個(gè)接口)的調(diào)用,在不同的場景需要使用不同的策略用以恢復(fù)業(yè)務(wù)流程,通常情況下:

  1. Command 場景優(yōu)先使用 Retry
  2. 這種流量極為重要,最好能保障流程的完整性
  3. 通常寫流量比較小,小范圍 Retry 不會(huì)對(duì)下游系統(tǒng)造成巨大影響
  4. Query 場景優(yōu)選使用 Fallabck
  5. 大多數(shù)展示場景,哪怕部分信息沒有獲取到對(duì)整體的影響也比較小
  6. 通常讀場景流量較高,Retry 對(duì)下游系統(tǒng)的傷害不容忽視

那面對(duì)一個(gè)遠(yuǎn)程接口被多個(gè)場景使用,我們?cè)撛趺刺幚砟兀?/p>

  1. 提供兩組接口,一個(gè)具有 Retry 能力,一個(gè)具有 Fallback 能力,由使用方根據(jù)業(yè)務(wù)場景進(jìn)行選擇?
  2. 還是…

1.2. 目標(biāo)

  1. 遠(yuǎn)程接口具備 Retry 和 Fallback 能力
  2. 能夠根據(jù)上下文不同場景,在發(fā)生調(diào)用異常時(shí)動(dòng)態(tài)選擇 Retry 或 Fallback 進(jìn)行流程恢復(fù)

2. 快速入門

2.1. 準(zhǔn)備環(huán)境

項(xiàng)目主要依賴 spring retry 和 lego starter
首先,引入 spring-retry 依賴

<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>

此次,引入 lego-starter 依賴

<dependency>
<groupId>com.geekhalo.lego</groupId>
<artifactId>lego-starter</artifactId>
<version>0.1.17</version>
</dependency>

最后新建 RetryConfiguration 以開啟 Retry 能力

@EnableRetry
@Configuration
public class RetryConfiguration {
}

2.2. 構(gòu)建 ActionTypeProvider

在完成基本配置后,需要準(zhǔn)備一個(gè) ActionTypeProvider 用以提供上下文信息。
ActionTypeProvider 接口定義如下:

public interface ActionTypeProvider {
ActionType get();
}
public enum ActionType {
COMMAND, QUERY
}

通常情況下,我們會(huì)使用 ThreadLocal 組件將 ActionType 存儲(chǔ)于線程上下文,在使用時(shí)從上下中獲取相關(guān)信息。

public class ActionContext {
private static final ThreadLocal<ActionType> ACTION_TYPE_THREAD_LOCAL = new ThreadLocal<>();
public static void set(ActionType actionType){
ACTION_TYPE_THREAD_LOCAL.set(actionType);
}
public static ActionType get(){
return ACTION_TYPE_THREAD_LOCAL.get();
}
public static void clear(){
ACTION_TYPE_THREAD_LOCAL.remove();
}
}

有了上下文之后,
ActionBasedActionTypeProvider 直接從 Context 中獲取 ActionType 具體如下

@Component
public class ActionBasedActionTypeProvider implements ActionTypeProvider {
@Override
public ActionType get(){
return ActionContext.get();
}
}

上下文中的 ActionType 又是怎么進(jìn)行管理的呢,包括信息綁定和信息清理?
最常用的方式便是:

  • 提供一個(gè)注解,在方法上添加注解用于對(duì) ActionType 的配置;
  • 提供一個(gè)攔截器,對(duì)方法調(diào)用進(jìn)行攔截。方法調(diào)用前,從注解中獲取配置信息并綁定到上下文;方法調(diào)用后,主動(dòng)清理上下文信息;

核心實(shí)現(xiàn)為:

@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Action {
ActionType type();
}
@Aspect
@Component
@Order(Integer.MIN_VALUE)
public class ActionAspect {
@Pointcut("@annotation(com.geekhalo.lego.faultrecovery.smart.Action)")
public void pointcut() {
}
@Around(value = "pointcut()")
public Object action(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Action annotation = methodSignature.getMethod().getAnnotation(Action.class);
ActionContext.set(annotation.type());
try {
return joinPoint.proceed();
}finally {
ActionContext.clear();
}
}
}

在這些組件的幫助下,我們只需在方法上基于 @Action 注解進(jìn)行標(biāo)記,便能夠?qū)?ActionType 綁定到上下文。

2.3. 使用 @SmartFault

在將 ActionType 綁定到上下文之后,接下來要做的便是對(duì) 遠(yuǎn)程接口 進(jìn)行配置。遠(yuǎn)程接口的配置工作主要由 @SmartFault 來完成。
其核心配置項(xiàng)包括:

配置項(xiàng)

含義

默認(rèn)配置

recover

fallback 方法名稱


maxRetry

最大重試次數(shù)

3

include

觸發(fā)重試的異常類型


exclude

不需要重新的異常類型


接下來,看一個(gè) demo

@Service
@Slf4j
@Getter
public class RetryService3 {
private int count = 0;
private int retryCount = 0;
private int fallbackCount = 0;
private int recoverCount = 0;
public void clean(){
this.retryCount = 0;
this.fallbackCount = 0;
this.recoverCount = 0;
}
/**
* Command 請(qǐng)求,啟動(dòng)重試機(jī)制
*/
@Action(type = ActionType.COMMAND)
@SmartFault(recover = "recover")
public Long retry(Long input) throws Throwable{
this.retryCount ++;
return doSomething(input);
}
/**
* Query 請(qǐng)求,啟動(dòng)Fallback機(jī)制
*/
@Action(type = ActionType.QUERY)
@SmartFault(recover = "recover")
public Long fallback(Long input) throws Throwable{
this.fallbackCount ++;
return doSomething(input);
}
@Recover
public Long recover(Throwable e, Long input){
this.recoverCount ++;
log.info("recover-{}", input);
return input;
}
private Long doSomething(Long input) {
// 偶數(shù)拋出異常
if (count ++ % 2 == 0){
log.info("Error-{}", input);
throw new RuntimeException();
}
log.info("Success-{}", input);
return input;
}
}

測試代碼如下:

@SpringBootTest(classes = DemoApplication.class)
public class RetryService3Test {
@Autowired
private RetryService3 retryService;
@BeforeEach
public void setup(){
retryService.clean();
}
@Test
public void retry() throws Throwable{
for (int i = 0; i < 100; i++){
retryService.retry(i + 0L);
}
Assertions.assertTrue(retryService.getRetryCount() > 0);
Assertions.assertTrue(retryService.getRecoverCount() == 0);
Assertions.assertTrue(retryService.getFallbackCount() == 0);
}
@Test
public void fallback() throws Throwable{
for (int i = 0; i < 100; i++){
retryService.fallback(i + 0L);
}
Assertions.assertTrue(retryService.getRetryCount() == 0);
Assertions.assertTrue(retryService.getRecoverCount() > 0);
Assertions.assertTrue(retryService.getFallbackCount() > 0);
}
}

運(yùn)行 retry 測試,日志如下:

[main] c.g.l.c.f.smart.SmartFaultExecutor       : action type is COMMAND
[main] c.g.l.faultrecovery.smart.RetryService3 : Error-0
[main] c.g.l.c.f.smart.SmartFaultExecutor : Retry method public java.lang.Long com.geekhalo.lego.faultrecovery.smart.RetryService3.retry(java.lang.Long) throws java.lang.Throwable use [0]
[main] c.g.l.faultrecovery.smart.RetryService3 : Success-0

可見,當(dāng) action type 為 COMMAND 時(shí):

  • 第一次調(diào)用時(shí),觸發(fā)異常,打印: Error-0
  • 此時(shí) SmartFaultExecutor 主動(dòng)進(jìn)行重試,打?。?Retry method xxxx
  • 方法重試成功,RetryService3 打?。?Success-0

方法主動(dòng)進(jìn)行重試,流程從異常中恢復(fù),處理過程和效果符合預(yù)期。

運(yùn)行 fallback 測試,日志如下:

[main] c.g.l.c.f.smart.SmartFaultExecutor       : action type is QUERY
[main] c.g.l.faultrecovery.smart.RetryService3 : Error-0
[main] c.g.l.c.f.smart.SmartFaultExecutor : recover From ERROR for method ReflectiveMethodInvocation: public java.lang.Long com.geekhalo.lego.faultrecovery.smart.RetryService3.fallback(java.lang.Long) throws java.lang.Throwable; target is of class [com.geekhalo.lego.faultrecovery.smart.RetryService3]
[main] c.g.l.faultrecovery.smart.RetryService3 : recover-0

可見,當(dāng) action type 為 QUERY 時(shí):

  • 第一次調(diào)用時(shí),觸發(fā)異常,打?。?Error-0
  • SmartFaultExecutor 執(zhí)行 Fallback 策略,打?。簉ecover From ERROR for method xxxx
  • 調(diào)用RetryService3的 recover 方法,獲取最終返回值。RetryService3 打?。簉ecover-0

異常后自動(dòng)執(zhí)行 fallback,將流程從異常中恢復(fù)過來,處理過程和效果符合預(yù)期。

3. 設(shè)計(jì)&擴(kuò)展

3.1 核心設(shè)計(jì)

image

整體流程如下:

  • ActionAspect 從 @Action 中讀取配置信息,將請(qǐng)求類型綁定到線程上下文
  • 然后執(zhí)行正常業(yè)務(wù)邏輯
  • 當(dāng)調(diào)用 @SmartFault 注解的方法時(shí),會(huì)被 SmartFaultMethodInterceptor 攔截器攔截
  1. 攔截器通過 ActionTypeProvider 獲取當(dāng)前的 ActionType
  2. 根據(jù) ActionType 對(duì)請(qǐng)求進(jìn)行路由
  3. 如果是 COMMAND 操作,將使用 RetryTemplate 執(zhí)行請(qǐng)求,在發(fā)生異常時(shí),通過重試配置進(jìn)行請(qǐng)求重發(fā),從而最大限度的獲得遠(yuǎn)程結(jié)果
  4. 如果是 QUERY 操作,將使用 FallbackTemplate(重試次數(shù)為0的 RetryTemplate)執(zhí)行請(qǐng)求,當(dāng)發(fā)生異常時(shí),調(diào)用 fallback 方法,執(zhí)行配置的 recover 方法,直接使用返回結(jié)果
  • 獲取遠(yuǎn)程結(jié)果后,執(zhí)行后續(xù)的業(yè)務(wù)邏輯
  • 最后,ActionAspect 將 ActionType 從線程上下文中移除

4. 項(xiàng)目信息

項(xiàng)目倉庫地址:https://gitee.com/litao851025/lego

項(xiàng)目文檔地址:https://gitee.com/litao851025/lego/wikis/support/smart-fault

責(zé)任編輯:武曉燕 來源: 今日頭條
相關(guān)推薦

2012-10-09 09:14:47

2013-03-06 16:06:31

2021-07-14 15:27:27

論文神器數(shù)據(jù)

2020-09-21 06:53:41

NoSQL高并發(fā)面試

2009-01-15 09:43:00

網(wǎng)絡(luò)病毒斷網(wǎng)

2012-09-24 15:26:56

云計(jì)算XTools

2012-05-22 11:20:07

虛擬化VDI

2024-02-04 08:05:48

DataX阿里云開源

2012-06-18 15:12:58

云存儲(chǔ)

2020-06-16 09:45:59

CIO上系統(tǒng)IT管理

2012-06-20 09:22:14

云存儲(chǔ)

2018-11-15 15:03:59

安全運(yùn)營中心SOC數(shù)據(jù)泄露

2020-03-21 16:10:00

物聯(lián)網(wǎng)IoT風(fēng)險(xiǎn)

2011-07-01 12:16:41

移動(dòng)ERP

2013-08-22 10:10:31

2011-07-29 14:19:12

2024-09-30 11:32:06

2011-08-12 09:35:27

Java 7

2013-07-15 13:42:34

手機(jī)游戲生命周期

2011-12-22 22:53:48

HTC禁售蘋果
點(diǎn)贊
收藏

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

亚洲第一区视频| 韩国女主播一区二区三区| 亚洲视频一区二区免费在线观看| 日韩福利在线| 亚洲91中文字幕无线码三区| 欧美激情一区二区久久久| 欧洲av不卡| 亚洲成人av在线| 成人免费看片| 欧美精品视频www在线观看| 免费观看v片在线观看| 日本一区二区三区高清不卡| 亚洲精品无码国产| 韩国理伦片一区二区三区在线播放| 久久99精品久久久水蜜桃| 亚洲电影影音先锋| 成人精品一区二区三区电影免费| 国产精品入口久久| 欧洲亚洲女同hd| 精品久久久久久久久久久aⅴ| 日韩av大片免费看| 成人精品影视| 91亚洲永久免费精品| 欧美久久影院| 99r国产精品视频| 很黄很黄激情成人| 久久96国产精品久久99软件| 亚洲国产精品一区| 欧美精品国产精品久久久 | 欧美日韩一区在线观看视频| 亚洲精品男同| 欧美日韩一区二| 强制捆绑调教一区二区| 97超碰免费观看| 99re6这里只有精品视频在线观看| www.玖玖玖| 亚洲视频你懂的| 亚洲啪啪aⅴ一区二区三区9色| 欧美视频在线看| 日本在线视频站| 精品一区二区三区三区| 成人深夜福利| 97在线精品视频| 91精品国产自产在线观看永久∴ | 国产成人在线中文字幕| 日本免费久久高清视频| 久久影院一区| 欧美一级二级三级| 九九久久精品视频| 日本一本二本在线观看| 亚洲欧美日本韩国| av在线1区2区| 国产亚洲欧洲高清| jazzjazz国产精品久久| 成人激情视频免费在线| 爽好多水快深点欧美视频| 成人av一级片| 欧美午夜片欧美片在线观看| 波多野结衣在线高清| 久久国内精品一国内精品| 欧美中文一区二区| 一区二区三区精品国产| 国产精品久久久久久久久久久免费看| 免费黄色在线视频网站| 亚洲视频在线视频| 成人aaaa| 18禁裸男晨勃露j毛免费观看| 亚洲小说欧美激情另类| 两个人看的在线视频www| 欧美在线视频a| 日韩福利视频网| 亚洲国产天堂久久国产91 | 日韩高清dvd| 久久久影院官网| 精品乱码一区二区三四区视频 | 久久精品国产成人精品| 日韩一区二区中文| avove在线观看| 有坂深雪av一区二区精品| 日本大胆在线观看| 欧美专区第一页| 热久久一区二区| 中文字幕123| 亚洲一区第一页| 欧美日韩伊人| 成人女人a毛片在线看| 亚洲成年人在线播放| 久久99性xxx老妇胖精品| 水蜜桃亚洲精品| 亚洲成人av中文| 国内欧美日韩| 免费久久99精品国产自| 亚洲线精品一区二区三区| av在线一区不卡| 国产综合18久久久久久| 久久色中文字幕| 丰满诱人av在线播放| 国产一区香蕉久久| 日本一区二区三区视频视频| 丁香花高清在线观看完整版| 成人网页在线免费观看| 欧美激情在线一区二区| 欧美7777| 精品一区二区三区国产| 亚洲午夜av在线| 国产精品网在线观看| www.在线观看av| 日韩av有码在线| 久久精品人人做人人爽电影蜜月| 一色桃子在线| 庆余年2免费日韩剧观看大牛| 成人综合激情网| 日本中文字幕中出在线| 成人自拍视频网站| 精品久久久久久国产91| 亚洲人成网站77777在线观看| 丰满少妇被猛烈进入高清播放| 日韩av在线不卡| 日本三级亚洲精品| 亚洲男同gay网站| 精品国产电影| 欧美精品久久久久久久多人混战 | 91亚洲精品久久久久久久久久久久| 中文字幕精品三区| 日韩制服诱惑| 久久www视频| 亚洲亚裔videos黑人hd| 黄网站免费久久| 大香伊人中文字幕精品| 欧洲高清一区二区| 欧美第一区第二区| 日本在线播放一区二区三区| 国产白丝在线观看| 在线视频不卡一区二区三区| 精品久久久久av影院| 日本成人在线一区| 17videosex性欧美| 四虎精品欧美一区二区免费| 亚洲最新中文字幕| 久久久综合视频| 欧美美女啪啪| 超级碰碰视频| 国产精品吊钟奶在线| 亚洲成人免费av| 女人天堂亚洲aⅴ在线观看| a中文在线播放| 日韩高清av| 一本色道久久综合狠狠躁篇的优点| 国产高清无密码一区二区三区| 国产精品一区二区美女视频免费看 | 一区二区三区高清在线| av一区二区在线观看| 亚洲男男gay视频| 亚洲综合色av| 欧美一区二区啪啪| 豆国产96在线|亚洲| 国产精品一区二区三区av| 91制片厂毛片| 国产在线观看91精品一区| 欧美性一二三区| 精品无码三级在线观看视频| **精品中文字幕一区二区三区| 网上成人av| 国产精选一区二区| 亚洲精品视频在线播放| 国产精品人妖ts系列视频| 中文无码久久精品| 手机在线理论片| 免费高清成人| 成人免费在线一区二区三区| 日韩精品久久久久| 中文字幕亚洲欧美在线不卡| 禁久久精品乱码| 亚洲性色av| 777.av| 国产偷久久久精品专区| 亚洲天堂2020| 亚洲超碰精品一区二区| 秋霞午夜鲁丝一区二区老狼| 日韩一区二区三区精品| 免费在线高清av| 免费人成自慰网站| 国产日韩在线精品av| 国产偷国产偷亚洲清高网站| 亚洲丝袜自拍清纯另类| 美女网站久久| 午夜欧洲一区| 美女精品视频| 国产三级免费观看| 一区二区三视频| 亚州成人av在线| 欧美一级国产精品| 国产午夜精品在线观看| 国产精品视频久久一区| 久久草在线视频| 日本性爱视频在线观看| 日本一二区视频| 国产精品视频二| 精品国产一区二区三区久久久久久| 久久久久久尹人网香蕉|