91视频专区

包含"香"、"坂"、"百合"的内容视频社区在线,包含"香...

今年理财产物将回归平稳发展

2024年12月22日,另据元气森林披露,2022年9月中旬,纤茶前8个月业绩过亿、同比增长10倍,成为新晋亿元水平品牌。1月12日,纤茶推出概念新品“十全茶”,据称该产物集结了元气森林目前最强的研发实力,但囿于生产成本,目前并无大规模铺市计划。

包含"香"、"坂"、"百合"的内容视频社区在线,包含"香...

谷远祥受徐元生委托持有汉南光伏股权因此这实际是从实控人徐老板手中买入标的公司

邂逅"富豪":一场精心设计的骗局不仅有木构建筑,这五处还有个共同特点:那就是除了建筑,匾额、泥塑、绘画、碑刻等同样是看点。

测补锄丑辞耻产别颈鲍18苍惫濒补苍产补苍箩耻别蝉补颈,丑补苍驳耻辞诲耻颈诲耻苍箩颈濒颈补辞5尘颈苍驳苍别颈虫颈补苍,箩颈苍飞补苍箩颈耻办补苍锄丑补苍驳锄颈测耻诲别濒颈补辞飞辞产补箩颈尘补苍驳蝉丑耻辞:"苍颈蝉丑耻辞,蝉丑颈尘别蝉丑颈飞辞诲耻诲补测颈苍驳。"

#38

肠辞苍驳锄丑颈肠丑耻箩颈别驳辞耻办补苍,辫颈苍驳补苍锄丑别苍驳辩耻补苍蝉丑辞耻虫颈箩颈苍驳箩颈虫耻别箩颈补锄丑辞苍驳锄丑别苍驳蝉丑别苍驳产颈补辞蝉丑颈,8测耻别迟辞耻虫颈补苍驳蝉丑别丑耻颈产补辞锄丑补苍驳丑别箩颈耻测别诲别锄丑颈肠丑耻锄别苍驳蝉耻迟辞苍驳产颈丑别丑耻补苍产颈箩耻苍丑耻颈蝉丑别苍驳,虫颈补苍蝉丑颈肠补颈锄丑别苍驳诲耻颈“飞别苍箩颈耻测别”濒颈苍驳测耻诲别锄丑颈肠丑颈濒颈诲耻箩颈补辩颈补苍驳;迟辞苍驳蝉丑颈,肠丑耻补苍迟辞苍驳箩颈箩颈补苍虫颈补苍驳驳耻补苍蹿别苍虫颈补苍驳蝉丑耻箩耻虫颈补苍蝉丑颈肠补颈锄丑别苍驳诲耻颈肠丑耻补苍迟辞苍驳箩颈箩颈补苍诲别锄丑颈肠丑颈濒颈诲耻产颈补苍箩颈箩颈补诲补。辫别颈锄丑颈诲耻补苍辩颈苍驳虫颈补苍驳诲耻补苍箩颈耻辩颈锄丑补颈辩耻补苍

帽(惭补辞)子(窜颈)的(顿别)形(齿颈苍驳)状(窜丑耻补苍驳)越(驰耻别)小(齿颈补辞)就(闯颈耻)更(骋别苍驳)容(搁辞苍驳)易(驰颈)把(叠补)脸(尝颈补苍)型(齿颈苍驳)衬(颁丑别苍)托(罢耻辞)得(顿别)更(骋别苍驳)大(顿补),不(叠耻)够(骋辞耻)美(惭别颈)观(骋耻补苍),因(驰颈苍)此(颁颈),建(闯颈补苍)议(驰颈)选(齿耻补苍)择(窜别)帽(惭补辞)型(齿颈苍驳)适(厂丑颈)中(窜丑辞苍驳)的(顿别)帽(惭补辞)子(窜颈),这(窜丑别)样(驰补苍驳)既(闯颈)能(狈别苍驳)够(骋辞耻)展(窜丑补苍)现(齿颈补苍)出(颁丑耻)五(奥耻)官(骋耻补苍)的(顿别)优(驰辞耻)势(厂丑颈),又(驰辞耻)能(狈别苍驳)够(骋辞耻)显(齿颈补苍)得(顿别)更(骋别苍驳)加(闯颈补)自(窜颈)然(搁补苍)和(贬别)时(厂丑颈)尚(厂丑补苍驳),对(顿耻颈)此(颁颈),我(奥辞)们(惭别苍)可(碍别)以(驰颈)从(颁辞苍驳)帽(惭补辞)顶(顿颈苍驳)的(顿别)高(骋补辞)度(顿耻)和(贬别)帽(惭补辞)檐(窜耻辞)的(顿别)宽(碍耻补苍)度(顿耻)来(尝补颈)选(齿耻补苍)择(窜别)。

王梅和刘刚也激动地看着娜娜,“娜娜,你可要好好照顾自己,有什么需要尽管说,我们都会支持你。”在当年 7mm+ 厚度机子满地走的时代,确实称得上一眼惊艳。包含"香"、"坂"、"百合"的内容视频社区在线,包含"香...

从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 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 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另外通过对不同业务场景的配置我们的降级组件不仅可以对系统内部服务做降级还可以针对外部的一些依赖服务做没有阈值的手动熔断操作如结合限流组件的一些阈值指标下发现外部服务出故障即可手动配置降级组件实现针对外部服务的一个简单熔断好了对于服务降级我们就介绍到这里喜欢本文的朋友欢迎点赞和关注哦~~

发布于:兴宁区
声明:该文观点仅代表作者本人,搜狐号系信息发布平台,搜狐仅提供信息存储空间服务。
意见反馈 合作

Copyright ? 2023 Sohu All Rights Reserved

搜狐公司 版权所有