咖啡汪日志—— 回退兜底 及实用的服务降级策略

本汪作为一名资深的哈士奇
每天除了闲逛,拆家,就是啃博客了
作为不是在戏精,就是在戏精的路上的二哈
今天就来给大家说说在实际工作中
如何进行简单的回退兜底,熔断降级

一、 开篇有益

1.什么是Hystrix?
Hystrix是一个供分布式系统使用,提供延迟和容错功能,保证复杂的分布系统在面临不可避免的失败时,仍能有其弹性。

比如系统中有很多服务,当某些服务不稳定的时候,使用这些服务的用户线程将会阻塞,如果没有隔离机制,系统随时就有可能会挂掉,从而带来很大的风险。SpringCloud使用Hystrix组件提供断路器、资源隔离与自我修复功能。

eg: 在优惠券的分发微服务中,本汪调用了<优惠券的模板微服务> 和 <结算微服务>,当这两个服务不稳定而导致调用失败时,将会回退并返回相应无效数据,以防止线程阻塞。

在这里插入图片描述

二、在本汪面前,线程阻塞,不存在的,我们来看下实用代码示例(以优惠券分发微服务调用结算微服务为例)

1.启动入口配置注解

@EnableCircuitBreaker 允许使用断路器

/**
 * 分发系统启动入口
 * @EnableCircuitBreaker 熔断降级
 * **
 * Yuezejian  Created in 2020/11/25 下午8:09
 */
@EnableJpaAuditing
@EnableFeignClients
@EnableCircuitBreaker
@EnableEurekaClient
@SpringBootApplication
public class DistributionApplication {
    
    

    /**
     * rest 接口客户端,通过他可以访问其他HTTP接口
     * @LoadBalanced 由ribbon提供,实现对多实例的负载均衡
     * @return
     */
    @LoadBalanced
    @Bean
    RestTemplate restTemplate() {
    
    
        return new RestTemplate();
    }

    public static void main(String[] args) {
    
    
        SpringApplication.run(DistributionApplication.class,args);
    }

}


2.通过 Feign 来实现接口调用时,通过 fallback 配置熔断策略
@FeignClient(value = "eureka-client-coupon-settlement", fallback = SettlementClientHystrix.class)

import com.tencent.coupon.Feign.hystrix.SettlementClientHystrix;
import com.tencent.coupon.vo.BaseResponse;
import com.tencent.coupon.vo.SettlementInfo;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * <h1>优惠券结算微服务 Feign 接口定义</h1>
 *
 * **
 * Yuezejian  Created in 2020/12/5 下午7:01
 */
@FeignClient(value = "eureka-client-coupon-settlement",
        fallback = SettlementClientHystrix.class)
public interface SettlementClient {
    
    

    /**
     * <h2>优惠券计算规则<h2/>
     * @param settlementInfo
     * @return
     */
    @RequestMapping(value = "/coupon-settlement/settlement/compute",
            method = RequestMethod.POST)
    BaseResponse<SettlementInfo> computeRule(@RequestBody SettlementInfo settlementInfo);

}


  1. 定义结算微服务调用失败时的兜底策略,即返回相应无效数据

import com.tencent.coupon.Feign.SettlementClient;
import com.tencent.coupon.vo.BaseResponse;
import com.tencent.coupon.vo.SettlementInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Collections;

/**
 * 结算微服务熔断策略实现
 * **
 * Yuezejian  Created in 2020/12/5 下午7:43
 */
@Slf4j
@Component
public class SettlementClientHystrix implements SettlementClient {
    
    
    /**
     * <h2>优惠券计算规则<h2/>
     *
     * @param info {@link SettlementInfo}
     * @return
     */
    @Override
    public BaseResponse<SettlementInfo> computeRule(SettlementInfo info) {
    
    
        log.error("[eureka-client-coupon-settlement] computeRule request error");
        //TODO:是否使结算生效, 即核销
        info.setEmploy(false);
        //TODO: 设置无效结算金额,标识当前结算微服务不可以
        info.setCost(-1.0);
        BaseResponse response = new BaseResponse<>(-1,
                "[eureka-client-coupon-settlement] computeRule request error");
        response.setData(info);
        return response;
    }
}


三、系统降级

以上只是一个简单的代码示例
在实际工作中,并发量过大时,我们实际所采取的降级策略,要比这复杂的多

1、什么是降级?

所谓“降级”,就是当系统的容量达到一定峰值时,限制或关闭系统的某些非核心功能,从而把有限的资源保留给更核心的业务。

系统降级是一个目的明确,计划周详的执行流程,通常我们会设计一套可行性高的预案来配合执行。可以的话,最好把它系统化,这样就可以通过预案系统和开关系统来实现及时性更高的系统降级。

2、降级预案的设计
比如有的公司经常会推出类似5元腾讯会员月卡的秒杀活动,那么由于优惠的力度非常大,所以秒杀时的流量峰值也会非常大。

在这里插入图片描述
又比如 CF 官网经常会推出的神器秒杀活动,由于 CF 号称270万人同时在线,三亿鼠标的枪战梦想,所以秒杀是流量峰值也是非常的高。
官网地址:https://cf.qq.com/cp/a20201123bp/index.shtml

在这里插入图片描述
那么我们可以做出如下设计:
当秒杀流量达到 5w/s 时,把秒杀成功记录的展示从获取20条降级到只展示10条,或只展示5条,这个操作应该由一个简单的开关来实现,也就是设置一个能够从开关系统动态获取的系统参数。

那么我们都知道:
提交请求和返回该请求的响应之间使用的时间,一般比较关注平均响应时间。
常用的响应时间如下:
1.打开一个站点 ——> 大约几秒
2.数据库查询一条记录(有索引) ——>大约十几毫秒
3.机械磁盘一次寻址定位 ——> 4毫秒
4.从机械磁盘顺序读取1M数据 ——> 2毫秒
5.从SSD磁盘顺序读取1M数据 ——> 0.3毫秒
6.从远程分布式换成Redis读取一个数据 ——> 0.5毫秒
7.从内存读取1M数据 ——> 十几微妙
8.Java程序本地方法调用 ——> 几微妙
9.网络传输2Kb数据 ——> 1微妙
如果我们在降级策略中,对每一处细节,设置合适的参数,那么整体的提升将不只是一点点。

3、理解降级的实质
(1)执行降级,无疑是在系统性能和用户体验之间,选择了前者。
(2)我们要认识到的是,降级后,必然会影响一部分用户的体验,这是无法避免的。
(3)降级的目的,是为了牺牲次要的功能和用户体验来保证核心业务流程的安全稳定运行,是不得已的举措。

比如:当优惠券系统抗不住时,本汪将考虑是否临时降级商品详情页面的优惠券信息展示(实际上,秒杀的页面本来就已经是极致简化了,需要临时加载的信息已经最少化了),把有限的系统资源用在保障交易系统正确展示优惠信息上,以保证用户下单时会员月卡生效时间,价格等重要信息的正确性。

需要注意的是,实际处理和我们的预期,还是有较大差异的,降级策略的说明,点到为止,对于限流和拒绝服务,将会在后期持续。。。。。。

猜你喜欢

转载自blog.csdn.net/weixin_42994251/article/details/110723705