微服务保护------之 Sentinel

一、背景

1、雪崩问题。

        当前大的系统采用的是微服务架构,微服务架构显著的一点就是为了解决服务解耦,一个项目存在多个服务。服务和服务之间的相互调用存在依赖关系。

        服务和服务的调用会延伸出服务和服务之间的雪崩问题,从而导致项目崩溃的问题。

        雪崩:微服务之间进行链路调用,由于调用链路的其中一微服务宕机,从而导致此链路上的多个微服务失效,进而影响更多的微服务之间的调用,从而导致服务挂掉的问题。

2、解决方案

1)超时处理

        设定超时时间,请求超过一定时间没有响应就返回错误信息,不会无休止等待。

    

        服务A调用服务B,若超过设定的超时时间,则不再等待,而是直接返回一个我们定义的一个超时默认返回结果。

超时处理问题:

        现在的服务A调用服务C的超时时间设定的是1秒,但是由于服务A调用服务C的调用频率较高,0.5秒调用一次,第一次调用服务A开辟一个新的线程来调用C服务,第二次调用的时候由于第一个线程还在等待超时时间,A服务就需要开辟一个新的线程来处理这个C服务的调用,随着这个并发量的增大。假设现在tomcat现存的线程是100,此时1秒钟进来200个请求,导致会出现无资源可用的情况,会导致别的服务之间的调用也出现问题。

2)舱壁模式 

        超时模式是设定时间,而舱壁模式 是限制资源。

        舱壁模式就是限制每个业务能够使用的线程数,避免耗尽整个tomcat的资源,因此也叫线程隔离。

        假设此时的服务C宕机了,但是我们的线程还是要分配10个线程去访问,相当于浪费了这10个线程。属于资源损耗。

3)熔断降级

        熔断降级:由断路器统计业务执行的异常比例,如果超出阈值则会熔断该业务,拦截访问该业务的一切请求。

        同时降级的话,也可以返回一些特定的信息来提升用户体验。

4)流量控制

        流量控制:限制业务访问的QPS,避免服务因流量的突增而故障。

        超时处理,舱壁模式,熔断降级都属于如何解决雪崩问题,流量控制属于预防雪崩问题。

5)总结--技术选型

        针对上述的四个方案,业界一般采用的是 Sentinel和Hystrix 这两个开源软件。

         针对上述的方案对比,我们采用的是Sentinel。而且Hystrix已经不再进行新的版本迭代了。

二、Sentinel介绍

1、什么是Sectinel

        Sentinel是阿里巴巴开源的一款微服务流量控制组件。官网地址:https://sentinelguard.io/zh-cn/index.html

2、优势

Sentinel 具有以下特征:

        丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。

        完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。

        广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。

        完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

3、Sentinel 下载

1)下载Sentinel的jar包

2)上传到linux机器上

3) nohup java -jar sentinel-dashboard-1.8.1.jar >myout.log 2>&1 & 

        后台启动    sentinel的jar包        输出日志文件是 myout.log   将  2>&1---标准错误级别输出到myout.log日志里面。

注意:如果你的linux没有安装JDK是不可以的。

        输入命令  jdk -version   如果没有具体版本就是无JDK,需要在linux机器上安装JDK,并配置环境变量。

        安装步骤:linux在线安装JDK 完美教程_java_home标红-CSDN博客

三、Sentinel 代码实战

1、使用步骤

1)引入POM文件

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

2)配置控制台地址 

spring:
    cloud:
      sentinel:
          transport:
            dashboard: http://47.93.32.133:8080/

3、因为sentinel采用的是监控模式,所以需要启动项目,调用接口。 

注意:

        需要将微服务和Sentinel处在同一个局域网中,否则簇点链路为空白,不显示数据。

原因:

        因为 sentinel 机器列表里显示的服务IP地址为内网地址。

        当发送请求的服务,所在的机器有多张网卡时,
     - win系统下,无影响 (sentinel 和 微服务 都在同一台win上)
     - 但是在Linux 中(虚拟机中),也将导致簇点链路显示为空。
       因为sentinel 机器列表里显示的服务IP地址不一定为系统真实IP,
       需要把其它无关的网卡全部关闭:
       具体虚拟机-->设置-->使用直连网络方式--> 点击VMware编辑-->虚拟机网络配置-->删除所有网络配置--->重启虚拟机,

sentinel 簇点链路为空白--不显示资源_sentinel簇点链路没有数据-CSDN博客

2、流控模式

        需求:给 /order/orderservice/order这个资源设置流控规则,QPS不能超过 5。然后利用jemeter测试。

对Jmeter不熟悉的用户: 

Jmeter快速入门-CSDN博客

分析:QPS不能超过 5的意思就是说1s内这个接口的请求只能接收5个,超过之后就失败。

1)直接模式

直接:统计当前资源的请求,触发阈值时对当前资源直接限流,也是默认的模式

意思就是----某个接口设定一个QPS上限,超过这个上限的请求直接就失败。

2)关联模式

关联:统计与当前资源相关的另一个资源,触发阈值时,对当前资源限流

        使用场景:比如用户支付时需要修改订单状态,同时用户要查询订单。查询和修改操作会争抢数据库锁,产生竞争。业务需求是优先支付和更新订单的业务,因此当修改订单业务触发阈值时,需要对查询订单业务限流。

     

 关联限流记住一句话-----限流谁,点击谁。

注意:接口的关联调用可以不同的Controller层,但是不能跨服务进行关联。

满足下面条件可以使用关联模式: 两个有竞争关系的资源 一个优先级较高,一个优先级较低

3)链路模式

链路:统计从指定链路访问到本资源的请求,触发阈值时,对指定链路限流

链路模式:只针对从指定链路访问到本资源的请求做统计,判断是否超过阈值。

例如有两条请求链路:A接口会调用C方法    B接口也会调用C方法

此时的需求是A接口调用C方法达到QPS是5的时候限流,B接口调用C方法不限流。

业务场景:

        有查询订单和创建订单业务,两者都需要查询商品。针对从查询订单进入到查询商品的请求统计,并设置限流。也就是当查询订单会查询数据库,若是查询订单和创建订单的QPS都很大的情况下,为了优先创建订单,需要对查询订单限流。有点类似于直接限流模式,但是这个针对的是链路,颗粒度更小一点,一般针对的都是某个公共调用方法,为了减少这个公共方法的压力而设置的。

        关键注解--------@SentinelResource-----放在公共方法上

        我们知道,Sentinel是监控接口调用,监控的维度是接口级别。我们此时需要更细的颗粒度,方法级别,就需要通过注解@SentinelResource,同时也需要的是关闭默认的 context整合。

1、不加注解,没关闭context的情况

2、加了注解,没关闭context的情况

3、加了注解,关闭默认整合的情况

两个不同的接口触发同样的方法,一个被限流,一个未被限流。

3、流控效果

流控效果是指请求达到流控阈值时应该采取的措施。

1)快速失败

        快速失败:达到阈值后,新的请求会被立即拒绝并抛出FlowException异常。是默认的处理方式。

2)预热模式

        warm up:预热模式,对超出阈值的请求同样是拒绝并抛出异常。但这种模式阈值会动态变化,从一个较小值逐渐增加到最大阈值。

3)排队等待

        排队等待:让所有的请求按照先后次序排队执行,两个请求的间隔不能小于指定时长。

        当请求超过QPS阈值时,快速失败和warm up 会拒绝新的请求并抛出异常。

        而排队等待则是让所有请求进入一个队列中,然后按照阈值允许的时间间隔依次执行。后来的请求必须等待前面执行完成,如果请求预期的等待时间超出最大时长,则会被拒绝。

         例如:QPS = 5,意味着每200ms处理一个队列中的请求;timeout = 2000,意味着预期等待超过2000ms的请求会被拒绝并抛出异常。

         假设5秒钟进来12个线程,此时的QPS=1,timeout = 5000。也就是1s处理一个,则任务顺序是

 0  1  2  3  4  5  6  7  8  9  10  11     

        此时由于超时时间是5秒钟,也就是超时时间内可以处理5个线程,5秒内处理5个线程,一共处理10个线程,会有2个线程被舍弃。

大致公式--------总共线程数  - (处理时间*QPS/1 + 超时时间 *QPS/1) = 可以处理的数量。

(处理时间+超时时间)*QPS = 指定时间内可以处理的线程数量

(公式自己想的,不一定准确) 

4、参数限流

1)热点参数限流

        之前的限流是统计访问某个资源的所有请求,判断是否超过QPS阈值。而热点参数限流是分别统计参数值相同的请求,判断是否超过QPS阈值。更细的颗粒度。

也就是说,需要非默认资源才可以。非默认资源就是  @SentinelResource  修饰的方法。

5、隔离和降级

        虽然限流可以尽量避免因高并发而引起的服务故障,但服务还会因为其它原因而故障。而要将这些故障控制在一定范围,避免雪崩,就要靠线程隔离(舱壁模式)和熔断降级手段了。

        不管是线程隔离还是熔断降级,都是对客户端(调用方)的保护。

这两个图,分别是 线程隔离(舱壁模式)    和         熔断降级。

 1)FeignClient整合Sentinel

        SpringCloud中,微服务调用都是通过Feign来实现的,因此做客户端保护必须整合Feign和Sentinel。

        1、修改OrderService的application.yml文件,开启Feign的Sentinel功能

2、给FeignClient编写失败后的降级逻辑

        方式一:FallbackClass,无法对远程调用的异常做处理。

        方式二:FallbackFactory,可以对远程调用的异常做处理,推荐这种。

(要走降级,一定要在 @FeignClient 注解后面写上  降级处理类 

fallbackFactory = UserClientFallbackFactory.class )

@FeignClient(value = "userservice", fallbackFactory = UserClientFallbackFactory.class)
public interface UserClient {

    @GetMapping("/user/{id}")
    User findById(@PathVariable("id") Long id);

    @GetMapping("/user/user1/{id}")
    User findById1(@PathVariable("id") Long id);
}
@Slf4j
public class UserClientFallbackFactory implements FallbackFactory<UserClient> {
    @Override
    public UserClient create(Throwable throwable) {
        return new UserClientImpl();
    }
}

@Slf4j
public class UserClientImpl implements UserClient {
    @Override
    public User findById(Long id) {
        log.error("查询第一个接口用户异常**********");
        return new User();
    }

    @Override
    public User findById1(Long id) {
        log.error("查询第二个接口用户异常=========");
        return new User();
    }
}

要交给IOC

        Feign接口里卖弄上述有两个远程调用的Feign 方法,这个接口降级实现类会重写对应两个两个方法,此时哪个方法调用出问题,就走哪个方法的降级逻辑

现象: 

但是切记,要想走降级的逻辑。Sentinel的设定需设定下列图中的参数。

也就是说下列标红的属于Feign接口调用,设定流控或热点等,达到上限会走降级逻辑。

2)隔离

线程的隔离有两种方式:线程池隔离,信号量隔离(Sentinel默认采用)

线程隔离

        优点:支持主动超时,支持异步调用

        缺点:线程的额外开销比较大

        场景:低扇出-----也就是用户请求调用的服务数量比较少

信号量隔离:  

        优点:轻量级,无额外开销

        缺点:不支持主动超时,不支持异步调用

        场景:高扇出-----也就是用户请求调用的服务数量比较多

线程隔离(舱壁模式)

QPS:就是每秒的请求数

线程数:是该资源能使用用的tomcat线程数的最大值。也就是通过限制线程数量,实现舱壁模式。 

线程隔离的两种手段:信号量隔离,线程隔离。

信号量隔离的特点:基于计数器模式,简单,开销小。

线程池隔离的特点:基于线程池模式,有额外开销,但隔离控制更强。

3)熔断降级 

        隔离指的是QPS当达到一定的调用信号量或者线程调用达到一定数量的时候,后续的用户请求会被拦截住,直接返回失败信息。使服务之间相互隔离,防止出现雪崩效应。

        熔断类似于保险丝,当服务调用的异常比例、慢请求比例达到一定的阈值之后,会如同隔离一样,禁止后面的用户请求,但是他会在熔断一段时间之后,自动恢复。、

        简单来说隔离和熔断效果相似,只是二者的触发条件不同。隔离是调用量来判断,是否隔离。熔断是由断路器统计服务调用的异常比例、慢请求比例,如果超出阈值则会熔断该服务。即拦截访问该服务的一切请求;而当服务恢复时,断路器会放行访问该服务的请求。

        Sentinel 的定位是流量控制,它有两个维度的控制,一个是控制并发线程数,另一个是控制 QPS,它们都是针对某个具体的接口来设置的,其实说资源比较准确,Sentinel 把控制的粒度定义为 Resource。 

    服务熔断:牺牲局部,保全全局,服务出问题时,切断该服务与系统的联系。
    服务降级:服务不可用时(如熔断后),提供一个低级服务返回信息。
    服务隔离:使服务之间相互隔离,防止出现雪崩效应。
    服务限流:使某服务一段时间内只接收指定数量的请求,通过上面的三种手段,即可达到服务的限流。

    雪崩效应:服务多级调用时,一个服务拥堵,从而导致多级服务都拥堵。

断路器熔断策略有三种:慢调用、异常比例、异常数

范围:

  

        熔断针对的的单一接口,假设上面的 /order 接口熔断之后,此时order1 这个接口是可以正常范围访问的,而并非了 针对 整个服务。

1、慢调用

慢调用:业务的响应时长(RT)大于指定的时长的请求认定为慢调用请求,也即是请求超时了。

含义:/test 这个接口请求,如果10s内,请求数量达到10次,并且这10次请求里面有5个或者5个以上的请求时长大于0.5s的话,会熔断,熔断时间是5s。 5s之后,进入half-open状态,放行一次请求做测试。如果失败,再次等待5s,循环往复,直到请求恢复。

2、异常比例或异常数

异常比例或异常数:统计指定时间内的调用,如果调用次数超过指定请求数,并且出现异常的比例达到设定的比例阈值(或超过指定异常数),则触发熔断。 

含义:/test 这个接口请求,如果1s内,请求数量达到10次,并且这10次请求里面有4个或者4个以上的请求失败的话,会熔断,熔断时间是5s。 5s之后,进入half-open状态,放行一次请求做测试。如果失败,再次等待5s,循环往复,直到请求恢复。 

含义:/test 这个接口请求,如果1s内,请求数量达到10次,并且这10次请求里面有2个或者2个以上的请求失败的话,会熔断,熔断时间是5s。 5s之后,进入half-open状态,放行一次请求做测试。如果失败,再次等待5s,循环往复,直到请求恢复。  

3、总结

Sentinel熔断降级的策略:慢调用比例,异常比例,异常数。

        慢调用比例:超过指定时长的调用为慢调用,统计单位时长内慢调用的比例,超过阈值则熔断。

        异常比例:统计单位时长内异常调用的比例,超过阈值则熔断。

        异常数:统计单位时长内异常调用的次数,超过阈值则熔断

 

6、授权规则 

        授权规则可以对调用方的来源做控制,有白名单和黑名单两种方式。

        白名单:来源(origin)在白名单内的调用者允许访问。

        黑名单:来源(origin)在黑名单内的调用者不允许访问。

有点类似于过滤器,拦截器这种。本质上的实现也就是通过 过滤器,拦截器实现。

Sentinel的具体授权的规则:

        Sentinel 监控粒度是接口层次,当你访问这个接口的时候,会被Sentinel 给拦截,通过获取请求的来源。会检查你的来源里面是否有白名单的数据。如果有就返回 default,如果是返回别的数据,则校验不通过。需要特别注意的是,Sentinel 的拦截校验 默认返回deault,也就是默认对所有的请求不拦截。而我们如果需要对这个请求进行拦截校验,需要重写parseOrigin接口,因为Sentinel是通过RequestOriginParser这个接口的parseOrigin来获取请求的来源的。

        需求:校验规则是访问接口需要携带名称是 sentinel_cloud 的请求头,请求头是 orderservice 才可以访问,否则会失败。

package com.hihonor.sentinel;

import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

@Component
public class HeaderOriginParser implements RequestOriginParser {
    @Override
    public String parseOrigin(HttpServletRequest httpServletRequest) {
        String sentinelCloud = httpServletRequest.getHeader("sentinel_cloud");
        if (!"orderservice".equals(sentinelCloud)){
            return "blank";
        }
        return "default";
    }
}

注意:

        

        如果我们没有重写这个RequestOriginParser接口,只是单纯的进行授权,此时的授权是无效的。不会进行流控。

      

        默认情况下,发生限流、降级、授权拦截时,都会抛出异常到调用方。如果要自定义异常时的返回结果,需要实现BlockExceptionHandler接口:

 

7、Sentinel的规则持久化 

Sentinel的控制台规则管理有三种模式:

7.1原始模式        

        原始模式:控制台配置的规则直接推送到Sentinel客户端,也就是我们的应用。然后保存在内存中,服务重启则丢失。

        如果生产上使用过的是原始模式,每次生产上服务重启都需要重新掉一次接口,配置一次规则,极其不推荐。

7.2  pull模式

        pull模式:控制台将配置的规则推送到Sentinel客户端,而客户端会将配置规则保存在本地文件或数据库中。以后会定时去本地文件或数据库中查询,更新本地规则。

        相当于将规则持久化到数据库,然后定期读取数据库。

        这样的缺点就是定期读取存在数据延迟的情况,可能存在规则更新了,但是我们还未读取,存在时效性问题。

7.3push模式 

        push模式:控制台将配置规则推送到远程配置中心,例如Nacos。Sentinel客户端监听Nacos,获取配置变更的推送消息,完成本地配置更新。

        通过前面的梳理,我们明白了规则需要的是两个核心---- 持久化和时效性。

        持久化可以通过数据库或者配置文件实现,时效性的话通过监听实现。

      

Sentinel的三种配置管理模式:

        原始模式:保存在内存

        pull模式:保存在本地文件或数据库,定时去读取

        push模式:保存在nacos,监听变更实时更新 

Sentinel的规则持久化操作文档-CSDN博客

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值