php短视频系统,提升系统健壮性离不开重试机制

news/2024/11/13 9:22:23/文章来源:https://www.cnblogs.com/yunbaomengnan/p/18413383

php短视频系统,提升系统健壮性离不开重试机制
随着互联网的发展php短视频系统中的业务功能越来越复杂,有一些基础服务我们不可避免的会去调用一些第三方的接口或者公司内其他项目中提供的服务,但是远程服务的健壮性和网络稳定性都是不可控因素。

在测试阶段可能没有什么异常情况,但php短视频系统上线后可能会出现调用的接口因为内部错误或者网络波动而出错或返回系统异常,因此我们必须考虑加上重试机制

重试机制 可以提高php短视频系统的健壮性,并且减少因网络波动依赖服务临时不可用带来的影响,让系统能更稳定的运行。

1. 手动重试

手动重试:使用 while 语句进行重试:

@Service
public class OrderServiceImpl implements OrderService {public void addOrder() {int times = 1;while (times <= 5) {try {// 故意抛异常int i = 3 / 0;// addOrder} catch (Exception e) {System.out.println("重试" + times + "");Thread.sleep(2000);times++;if (times > 5) {throw new RuntimeException("不再重试!");}}}}
}

 

运行上述代码:

 

上述代码看上去可以解决重试问题,但实际上存在一些弊端:

由于没有重试间隔,很可能远程调用的服务还没有从网络异常中恢复,所以有可能接下来的几次调用都会失败
代码侵入式太高,调用方代码不够优雅
项目中远程调用的服务可能有很多,每个都去添加重试会出现大量的重复代码

2. 静态代理

上面的处理方式由于需要对业务代码进行大量修改,虽然实现了功能,但是对原有代码的侵入性太强,可维护性差。所以需要使用一种更优雅一点的方式,不直接修改业务代码,那要怎么做呢?

其实很简单,直接在业务代码的外面再包一层就行了,代理模式在这里就有用武之地了。

@Service
public class OrderServiceProxyImpl implements OrderService {@Autowiredprivate OrderServiceImpl orderService;@Overridepublic void addOrder() {int times = 1;while (times <= 5) {try {// 故意抛异常int i = 3 / 0;orderService.addOrder();} catch (Exception e) {System.out.println("重试" + times + "");try {Thread.sleep(2000);} catch (InterruptedException ex) {ex.printStackTrace();}times++;if (times > 5) {throw new RuntimeException("不再重试!");}}}}
}

 

这样,重试逻辑就都由代理类来完成,原业务类的逻辑就不需要修改了,以后想修改重试逻辑也只需要修改这个类就行了

代理模式虽然要更加优雅,但是如果依赖的服务很多的时候,要为每个服务都创建一个代理类,显然过于麻烦,而且其实重试的逻辑都大同小异,无非就是重试的次数和延时不一样而已。如果每个类都写这么一长串类似的代码,显然,不优雅!

3. JDK 动态代理

这时候,动态代理就闪亮登场了。只需要写一个代理处理类就 ok 了

public class RetryInvocationHandler implements InvocationHandler {private final Object subject;public RetryInvocationHandler(Object subject) {this.subject = subject;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {int times = 1;while (times <= 5) {try {// 故意抛异常int i = 3 / 0;return method.invoke(subject, args);} catch (Exception e) {System.out.println("重试【" + times + "】次");try {Thread.sleep(2000);} catch (InterruptedException ex) {ex.printStackTrace();}times++;if (times > 5) {throw new RuntimeException("不再重试!");}}}return null;}public static Object getProxy(Object realSubject) {InvocationHandler handler = new RetryInvocationHandler(realSubject);return Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), handler);}}

 

测试:

@RestController
@RequestMapping("/order")
public class OrderController {@Qualifier("orderServiceImpl")@Autowiredprivate OrderService orderService;@GetMapping("/addOrder")public String addOrder() {OrderService orderServiceProxy = (OrderService)RetryInvocationHandler.getProxy(orderService);orderServiceProxy.addOrder();return "addOrder";}}

 

动态代理可以将重试逻辑都放到一块,显然比直接使用代理类要方便很多,也更加优雅。

这里使用的是JDK动态代理,因此就存在一个天然的缺陷,如果想要被代理的类,没有实现任何接口,那么就无法为其创建代理对象,这种方式就行不通了

4. CGLib 动态代理

既然已经说到了 JDK 动态代理,那就不得不提 CGLib 动态代理了。使用 JDK 动态代理对被代理的类有要求,不是所有的类都能被代理,而 CGLib 动态代理则刚好解决了这个问题

@Component
public class CGLibRetryProxyHandler implements MethodInterceptor {private Object target;@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {int times = 1;while (times <= 5) {try {// 故意抛异常int i = 3 / 0;return method.invoke(target, objects);} catch (Exception e) {System.out.println("重试【" + times + "】次");try {Thread.sleep(2000);} catch (InterruptedException ex) {ex.printStackTrace();}times++;if (times > 5) {throw new RuntimeException("不再重试!");}}}return null;}public Object getCglibProxy(Object objectTarget){this.target = objectTarget;Enhancer enhancer = new Enhancer();enhancer.setSuperclass(objectTarget.getClass());enhancer.setCallback(this);Object result = enhancer.create();return result;}}

 

测试:

@GetMapping("/addOrder")
public String addOrder() {OrderService orderServiceProxy = (OrderService) cgLibRetryProxyHandler.getCglibProxy(orderService);orderServiceProxy.addOrder();return "addOrder";
}

 

这样就很棒了,完美的解决了 JDK 动态代理带来的缺陷。优雅指数上涨了不少。

但这个方案仍旧存在一个问题,那就是需要对原来的逻辑进行侵入式修改,在每个被代理实例被调用的地方都需要进行调整,这样仍然会对原有代码带来较多修改

5. 手动 Aop

考虑到以后可能会有很多的方法也需要重试功能,咱们可以将重试这个共性功能通过 AOP 来实现,使用 AOP 来为目标调用设置切面,即可在目标方法调用前后添加一些重试的逻辑

<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId>
</dependency>

 

自定义注解:

@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyRetryable {// 最大重试次数int retryTimes() default 3;// 重试间隔int retryInterval() default 1;}
@Slf4j
@Aspect
@Component
public class RetryAspect {@Pointcut("@annotation(com.hcr.sbes.retry.annotation.MyRetryable)")private void retryMethodCall(){}@Around("retryMethodCall()")public Object retry(ProceedingJoinPoint joinPoint) throws InterruptedException {// 获取重试次数和重试间隔MyRetryable retry = ((MethodSignature)joinPoint.getSignature()).getMethod().getAnnotation(MyRetryable.class);int maxRetryTimes = retry.retryTimes();int retryInterval = retry.retryInterval();Throwable error = new RuntimeException();for (int retryTimes = 1; retryTimes <= maxRetryTimes; retryTimes++){try {Object result = joinPoint.proceed();return result;} catch (Throwable throwable) {error = throwable;log.warn("调用发生异常,开始重试,retryTimes:{}", retryTimes);}Thread.sleep(retryInterval * 1000L);}throw new RuntimeException("重试次数耗尽", error);}}

 

给需要重试的方法添加注解 @MyRetryable:

@Service
public class OrderServiceImpl implements OrderService {@Override@MyRetryable(retryTimes = 5, retryInterval = 2)public void addOrder() {int i = 3 / 0;// addOrder
    }}

 

这样即不用编写重复代码,实现上也比较优雅了:一个注解就实现重试。

以上就是php短视频系统,提升系统健壮性离不开重试机制, 更多内容欢迎关注之后的文章

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/796893.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端基本功——面试必问系列(1):都2024了,还没吃透Promise?一文搞懂

该系列文章是为了帮助大家不管面试还是开发对前端的一些基本但是很重要的知识点认识更加深入和全面。想写这个系列文章的初衷是:我发现前端的很多基本知识。为什么用?怎么用会更好?原理是什么?很多人并不清楚写在前面: 大家好,我是山里看瓜,该系列文章是为了帮助大家不管…

2390. 从字符串中移除星号

给你一个包含若干星号 * 的字符串 s 。 在一步操作中,你可以: 选中 s 中的一个星号。 移除星号 左侧 最近的那个 非星号 字符,并移除该星号自身。 返回移除 所有 星号之后的字符串。 注意: 生成的输入保证总是可以执行题面中描述的操作。 可以证明结果字符串是唯一的。 示例…

软工作业:用python实现论文查重

github项目地址这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/CSGrade22-34这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/homework/13229这个作业的目标 python实现论文查重并进行单元测试我的github仓库链接:https://github.com/LilaS…

modbus调试助手/mqtt调试工具/超轻巧物联网组件/多线程实时采集/各种协议支持

一、前言说明 搞物联网开发很多年,用的最多的当属modbus协议,一个稳定好用的物联网组件是物联网平台持续运行多年的基石,所以这个物联网组件从一开始就定位于自研,为了满足各种场景的需求,当然最重要的一点就是大大提升了自己对该协议的深度理解和应用,尤其是面对各种场景…

VMware NSX Advanced Load Balancer (NSX ALB) 22.1.7 发布下载,新增功能概览

VMware NSX Advanced Load Balancer (NSX ALB) 22.1.7 发布下载,新增功能概览VMware NSX Advanced Load Balancer (NSX ALB) 22.1.7 - 多云负载均衡平台 应用交付:多云负载均衡、Web 应用防火墙和容器 Ingress 服务 请访问原文链接:https://sysin.org/blog/vmware-nsx-alb-2…

4、循环单链表

1、代码实现#include<stdio.h> #include<malloc.h> #include<assert.h> typedef int ElemType;typedef struct Node{ElemType data;struct Node* next; }Node,*PNode;typedef struct SCList{PNode first;PNode last;int size; }SCList;void initSCList(SCLis…

论文分享 《Timing Side-channel Attacks and Countermeasures in CPU Microarchitectures》

Attack 概述 传统攻击(CONVENTIONAL ATTACKS) 在传统攻击中,Attacker 通常:与 Victim 共享硬件资源 (比如说 LLC,BP,Prefetcher 等) 可以观察,改变微架构状态攻击步骤本文作者将传统攻击分为以下三步,如 Fig 1 所示:定位“漏洞”:该漏洞包括“代码漏洞”(vulnerab…

PbootCMS访问页面出现PHP Fatal error: Allowed memory size of 13421

当访问 PbootCMS 页面时出现 PHP Fatal error: Allowed memory size of 13421 的错误,通常是由于 PHP 的内存限制过低导致的。这个错误表明 PHP 脚本在运行过程中耗尽了分配给它的内存。 解决方案增加 PHP 内存限制 检查 PHP 配置文件 (php.ini) 在脚本中动态增加内存限制详细…

什么是 PHP? 为什么用 PHP? 有谁在用 PHP?

PHP,全称“PHP: Hypertext Preprocessor”,是一种开源的服务器端脚本语言,主要用于网页开发,能够产生动态交互性数据。它由Rasmus Lerdorf在1994年创建,并随着时间的推移不断更新迭代,以适应互联网技术的发展。为什么使用 PHP? 开源免费:PHP作为一个开源项目,用户可以…

系统配置nginx环境运行pbootcms访问首页直接404的问题

在安装 PbootCMS 时遇到访问首页返回 404 错误的问题,尤其是在 Windows + Nginx + PHP 的环境下,可能涉及到多个方面的配置问题。根据你的描述,填写授权码后问题得以解决。以下是详细的分析和解决方案,希望能帮助遇到类似问题的朋友。 问题分析与解决方案 1. 配置 Nginx 伪…

基于Java+Springboot+Vue开发的在线摄影预约管理系统

项目简介该项目是基于Java+Springboot+Vue开发的在线摄影预约管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的在线摄影管理系统项目,大学生可以在实践…

【痛点解决】跨网跨区域的文件传输摆渡解决办法指南

跨网跨区域的文件传输摆渡,顾名思义就是需要跨越不同网络、不同地区,或者是不同安全域的文件传输,一般有这样传输需求的机构,在组织架构、网络结构,或者传输需求上,都会比较复杂。 跨网跨区域文件传输是什么样的场景? 跨网跨区域文件传输涉及在不同的网络和地理区域之间…