《大香煮焦成品75的注意事项冲百度文库》剧情介绍:One SpaceMore Chance(一个空间无限选择)主题展大香煮焦成品75的注意事项冲百度文库从0为你讲解什么是服务降级如何实现服务降级原创2023-03-15 13:40·程序员小灰背景在系统运行时为了保证核心服务能正常提供服务不至于因为一些非核心功能而阻塞服务需要对服务进行分级当非核心服务影响到核心服务时能通过配置或者其他手段快速切断非核心服务从而保证核心服务能正常对用户提供服务如何切断非核心服务呢常用的方法有限流、熔断、降级市面上也有很多的组件能提供相应的功能这些组件都提供了很多强大的功能但引入这些开源组件的同时也会带来一些复杂的配置以及学习成本另外公司微服务是dubbo构建的引入spring-cloud的一些组件会比较复杂基于此我们决定自研一个降级组件集成到公司的各个服务里面提供最基础的降级服务服务故障的场景:服务故障分为接口级故障和系统级故障系统级的故障:例如机器宕机、机房故障、网络故障等问题这些系统级的故障虽然影响很大但发生概率较小接口级故障:在实际业务运行过程中该故障影响可能没有系统级那么大但发生的概率较高接口级故障的典型表现就是系统并没有宕机网络也没有中断但业务却出现问题了例如业务响应缓慢、大量访问超时、大量访问出现异常这类问题的主要原因在于系统压力太大、负载太高导致无法快速处理业务请求由此引发更多的后续问题例如最常见的数据库慢查询将数据库的服务器资源耗尽导致读写超时业务读写数据库时要么无法连接数据库、要么超时最终用户看到的现象就是访问很慢一会访问抛出异常一会访问又是正常结果接口故障如果处理不及时严重的时候甚至会引起系统级故障如数据库慢查询导致数据库cpu升高查询的服务短时间内频繁fullgc并因此形成连锁反应牵一发而动全身依赖该该服务的其他服务全都不可用蝴蝶效应引起核心服务的不可用故障应对策略优先保证核心业务和优先保证绝大部分用户降级降级指系统将某些业务或者接口的功能降低可以是只提供部分功能也可以是完全停掉所有功能降级的核心思想就是丢车保帅优先保证核心业务例如对于教育类App学习主链路是核心服务其他的各种礼品活动弹窗老师点评服务等如果出问题后不应该影响主学习链路这时可以停掉这些非核心服务常见的实现降级的方式有:系统后门(配置)降级为每一个可降级服务提供一个业务开关配置在业务出现故障后通过切换业务开关配置进行手动降级但主要缺点是如果服务器数量多需要一台一台去操作效率比较低这在故障处理争分夺秒的场景下是比较浪费时间的独立降级系统为了解决系统后门降级方式的缺点将降级操作独立到一个单独的系统中可以实现复杂的权限管理、批量操作等功能但引入独立系统运维集成等复杂度会相应提高 Hystrix,sentinel等都有相应功能实现熔断熔断和降级是两个比较容易混淆的概念因为单纯从名字上看好像都有禁止某个功能的意思但其实内在含义是不同的原因在于降级的目的是应对系统自身的故障而熔断的目的是应对依赖的外部系统故障的情况假设一个这样的场景:A 服务的 X 功能依赖 B 服务的某个接口当 B 服务的接口响应很慢的时候A 服务的 X 功能响应肯定也会被拖慢进一步导致 A 服务的线程都被卡在 X 功能处理上此时 A 服务的其他功能都会被卡住或者响应非常慢这时就需要熔断机制了即:A 服务不再请求 B 服务的这个接口A 服务内部只要发现是请求 B 服务的这个接口就立即返回错误从而避免 A 服务整个被拖慢甚至拖死熔断机制实现的关键是需要有一个统一的 API 调用层由 API 调用层来进行采样或者统计如果接口调用散落在代码各处就没法进行统一处理了熔断机制实现的另外一个关键是阈值的设计例如 1 分钟内 30% 的请求响应时间超过 1 秒就熔断这个策略中的1 分钟30%1 秒都对最终的熔断效果有影响实践中一般都是先根据分析确定阈值然后上线观察效果再进行调优限流降级是从系统功能优先级的角度考虑如何应对故障而限流则是从用户访问压力的角度来考虑如何应对故障限流指只允许系统能够承受的访问量进来超出系统访问能力的请求将被丢弃根据限流作用范围可以分为单机限流和分布式限流;根据限流方式又分为计数器、滑动窗口、漏桶限令牌桶限流 限流一般都是系统内实现的大致可以分为两类:基于请求限流基于请求限流指从外部访问的请求角度考虑限流常见的方式有:限制总量、限制时间量基于资源限流基于请求限流是从系统外部考虑的而基于资源限流是从系统内部考虑的即:找到系统内部影响性能的关键资源对其使用上限进行限制常见的内部资源有:连接数、文件句柄、线程数、请求队列等 基于资源限流相比基于请求限流能够更加有效地反映当前系统的压力但实践中设计也面临两个主要的难点:如何确定关键资源如何确定关键资源的阈值通常情况下这也是一个逐步调优的过程即:设计的时候先根据推断选择某个关键资源和阈值然后测试验证再上线观察如果发现不合理再进行优化排队排队实际上是限流的一个变种限流是直接拒绝用户排队是让用户等待一段时间最有名的排队当属12306网站排队了排队虽然没有直接拒绝用户但用户等了很长时间后进入系统体验并不一定比限流好由于排队需要临时缓存大量的业务请求单个系统内部无法缓存这么多数据一般情况下排队需要用独立的系统去实现例如使用 KafkaRocketMQ这类消息队列来消费用户请求starter原理springBoot starter基于约定大于配置思想使用spi机制及自动装配原理可以将一些通用的功能能够封装成一个独立组件并很方便的集成到不同的项目里面简化开发提升代码复用能力简单来讲就是引入了一些相关依赖和一些初始化的配置自定义一个降级starter组件自定义一个starter组件名spring官方starter通常命名为 spring-boot-starter-{name}如spring-boot-starter-webspring官方建议非官方starter命名应遵循 {name}-spring-boot-starter的格式 例如由mybatis提供的mybatis-spring-boot-starter因此我们自定义的降级组件就叫degrade-spring-boot-starter org.degrade.spring.boot degrade-spring-boot-starter ${version} 自动配置类自动配置类就是Bean实例的工厂将组件涉及的一些Bean配置信息交给spring容器管理目前降级组件定义了4种降级策略抛出异常取指定的默认值调用指定方法取apollo上配置的值 apollo相关请参考分布式配置中心 Apollo@Configuration@ConditionalOnProperty( name = {"degrade.enabled"}, matchIfMissing = true)public class DegradeAutoConfiguration { @Bean @ConditionalOnMissingBean public ServiceDegradeAspect createDegradeAspect() { //降级切面核心逻辑 return new ServiceDegradeAspect(); } @Bean(name = "CALL_METHOD") @ConditionalOnMissingBean public CallMethodHandler createCallMethodHandler(){ //调用指定方法降级 return new CallMethodHandler(); } @Bean(name = "DEFAULT_VALUE") @ConditionalOnMissingBean public DefaultValueHandler createDefaultValueHandler(){ //取指定的默认值降级 return new DefaultValueHandler(); } @Bean(name = "FETCH_CONFIG_VALUE") @ConditionalOnMissingBean public FetchConfigValueHandler createFetchConfigValueHandler(){ //取apollo上配置的值降级 return new FetchConfigValueHandler(); } @Bean(name = "THROW_EXCEPTION") @ConditionalOnMissingBean public ThrowExceptionHandler createThrowExceptionHandler(){ //抛出异常降级 return new ThrowExceptionHandler(); } @Bean @ConditionalOnMissingBean public NullValueProvider createNullValueProvider(){ return new NullValueProvider(); }}自定义降级注解降级注解里面标识了需要降级的业务场景降级后的结果降级结果就是核心支持四种策略的配置所以降级结果的配置也是放在注解里的@Target({ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Degrade { /** * 降级业务key */ String businessKey(); /** * 降级场景key */ String sceneKey() default StringUtils.EMPTY; /** * 降级后的结果(支持多种降级策略) */ DegradeResult result();}降级结果的注解public @interface DegradeResult { /** * 支持的降级处理枚举(降级策略) */ DegradeResultEnum resultType(); /** * 从apollo上获取指定值的key与DegradeResultEnum#FETCH_CONFIG_VALUE 配合使用 */ String fetchKey() default StringUtils.EMPTY; /** * 将获取的配置内容转变成指定的对象 */ Class> fetchResult() default Void.class; /** * 执行回调的方法名称与DegradeResultEnum#CALL_BACK_VALUE 配合使用 */ String methodName() default StringUtils.EMPTY; /** * 回调的class */ Class> methodClass() default Void.class; /** * 默认值提供者NullValueProvider默认提供自定义复杂对象的返回值构建可以实现该接口 */ Class extends DegradeValueProvider> defaultValueProvider() default NullValueProvider.class;}class NullValueProvider implements DegradeValueProvider { @Override public Void buildDegradeValue() { return null; }}降级配置组件采用了从apollo上获取业务配置的方式来进行降级与Apollo耦合比较严重如果不想采用apollo配置的方式进行业务降级配置可以采用@ConfigurationProperties把配置在yml或者properties配置文件中的配置参数信息封装到配置的bean里一般结合@EnableConfigurationProperties注解使用@Datapublic class ServiceDegradeConfig implements Serializable { private static final long serialVersionUID = -1628960982004214364L; /** * 降级总开关状态:true-全局开启服务降级;false-全局关闭服务降级 */ private Boolean state; /** * 场景开关 */ private Map sceneState;}降级处理器采用策略模式定义降级处理逻辑具体的降级策略实现该接口即可提供可扩展性的降级策略public interface DegradeHandler { /** * 降级处理 * * @return 处理后的结果 */ Object doDegrade(Degrade degrade, ProceedingJoinPoint point);}1.调用指定方法降级策略@Slf4jpublic class CallMethodHandler implements DegradeHandler { @Autowired private ApplicationContext applicationContext; @Override public Object doDegrade(Degrade degrade, ProceedingJoinPoint point) { DegradeResult result = degrade.result(); String methodName = result.methodName(); Class> handlerClass = result.methodClass(); Object target = point.getTarget(); Object targetObj = point.getThis(); if (handlerClass == Void.class) { handlerClass = target.getClass(); } else { targetObj = applicationContext.getBean(handlerClass); } Object[] args = point.getArgs(); Class>[] parameterTypes = ((MethodSignature) point.getSignature()).getMethod().getParameterTypes(); Method m = null; try { m = handlerClass.getMethod(methodName, parameterTypes); return m.invoke(targetObj, args); } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { log.error("degrade call method={} error,message={}", methodName, e.getMessage()); e.printStackTrace(); } return null; }}2.获取apollo上的降级配置信息进行降级策略public class FetchConfigValueHandler implements DegradeHandler { @Autowired private ApolloUtil apolloUtil; @Override public Object doDegrade(Degrade degrade, ProceedingJoinPoint point) { DegradeResult result = degrade.result(); Class> aClass = result.fetchResult(); String fetchKey = result.fetchKey(); if (StringUtils.isEmpty(fetchKey)) { return null; } Optional> resultOpt = apolloUtil.getMessage(fetchKey, aClass); return resultOpt.orElse(null); }}3.提供默认返回值的降级处理策略(常用)public class DefaultValueHandler implements DegradeHandler { @Autowired private ApplicationContext applicationContext; @Override @SuppressWarnings("rawtypes") public Object doDegrade(Degrade degrade, ProceedingJoinPoint point) { DegradeResult result = degrade.result(); Class extends DegradeValueProvider> providerClass = result.defaultValueProvider(); //获取指定的默认返回值构造提供者进行默认值构建并返回 DegradeValueProvider provider = applicationContext.getBean(providerClass); return provider.buildDegradeValue(); }}提供默认返回值的降级处理策略比较常用但是返回值的类型很多组件默认提供返回null对象的返回值但业务上存在其他对象如Boolean,以及自定义的复杂对象等因此这里提供了默认返回值提供者函数式接口方便扩展@FunctionalInterfacepublic interface DegradeValueProvider { /** * 构造服务降级后的返回值 * @return T */ T buildDegradeValue();}降级服务的核心逻辑切面实现@Slf4j@Aspectpublic class ServiceDegradeAspect { @Autowired private ApplicationContext applicationContext; //apollo配置业务上的降级场景 @ApolloJsonValue("${app.service.degrade.gray.config:{}}") private Map appDegradeConfigMap; @Around("@annotation(degrade)") public Object doDegrade(ProceedingJoinPoint proceedingJoinPoint, Degrade degrade) throws Throwable { //获取注解里面配置的降级key标识 String businessKey = degrade.businessKey(); String sceneKey = degrade.sceneKey(); if (StringUtils.isBlank(sceneKey)) { sceneKey = ((MethodSignature) proceedingJoinPoint.getSignature()).getMethod().getName(); } boolean needDegrade = false; try { //检查是否需要降级 needDegrade = checkNeedDegrade(businessKey, sceneKey); } catch (Exception e) { log.warn("checkNeedDegrade errorbusinessKey:{}, sceneKey:{}", businessKey, sceneKey, e); } if (needDegrade) { //执行降级 return doDegradeAction(degrade, proceedingJoinPoint); } return proceedingJoinPoint.proceed(); } private Object doDegradeAction(Degrade degrade, ProceedingJoinPoint point) { DegradeResult result = degrade.result(); DegradeResultEnum degradeResultEnum = result.resultType(); String name = degradeResultEnum.name(); //使用具体的降级策略进行降级 DegradeHandler handler = applicationContext.getBean(name, DegradeHandler.class); return handler.doDegrade(degrade, point); } private boolean checkNeedDegrade(String businessKey, String sceneKey) { if (StringUtils.isBlank(businessKey)) { return false; } ServiceDegradeConfig config = appDegradeConfigMap.get(businessKey); if (config.getState() == null) { return false; } return config.getState() || (StringUtils.isNotBlank(sceneKey) && Optional.ofNullable(config.getSceneState()) .map(m -> m.get(sceneKey)).orElse(false)); } @Around("@within(org.degrade.spring.boot.Degrade)") public Object degrade(ProceedingJoinPoint joinPoint) throws Throwable { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); //方法上的降级注解优先于类上的 Degrade degrade = AnnotationUtils.findAnnotation(signature.getMethod(), Degrade.class); if (Objects.isNull(degrade)) { degrade = AnnotationUtils.findAnnotation(joinPoint.getTarget().getClass(), Degrade.class); } Assert.notNull(degrade, "@Degrade must not be null!"); return doDegrade(joinPoint, degrade); }}starter里Bean的发现与注册META-INF目录下的spring.factories文件# Auto Configureorg.springframework.boot.autoconfigure.EnableAutoConfiguration=\org.degrade.spring.boot.DegradeAutoConfiguration降级功能使用例如针对app应用里面里程碑的一个活动功能进行降级当该活动出现问题时通过配置开关打开降级即可不发送里程碑活动的相关信息从而保证核心链路的正常访问不影响用户的核心学习功能@Degrade(businessKey = "milestone", sceneKey = "app", result = @DegradeResult(resultType = DegradeResultEnum.DEFAULT_VALUE))public void sendAppNotifyTemporary(ChallengeActivityMessageParam param) {//具体业务省略 }总结本文讲解了服务降级的概念并通过实际项目中的一个降级组件设计例子从0到1实现了一个starter另外通过对不同业务场景的配置我们的降级组件不仅可以对系统内部服务做降级还可以针对外部的一些依赖服务做没有阈值的手动熔断操作如结合限流组件的一些阈值指标下发现外部服务出故障即可手动配置降级组件实现针对外部服务的一个简单熔断好了对于服务降级我们就介绍到这里喜欢本文的朋友欢迎点赞和关注哦~~
《大香煮焦成品75的注意事项冲百度文库》视频说明:这当然是非常痛苦的事情但是龙人分身的魂魄却是提前遁出此刻就站在琅琊地灵的身边这让汪小菲怎么能不生气也正是被大S的这一系列骚操作气得太狠了这便有了7月13日凌晨汪小菲在直播间里的失态其中软银愿景基金部门在这一财年的亏损达4.3万亿日元较前一年2.55万亿日元的亏损进一步扩大亏损程度为有纪录以来最高
阳光渐渐明媚凌霄花的影子在白墙上拉得很长很长仿佛是大自然在这片古老街区上绘制的独特图案微风轻拂花朵轻轻摇曳墙影随之舞动仿佛一幅动态的画作让人不禁沉醉其中