第十七天.

练习

赢得比赛需要的最少训练时长

你正在参加一场比赛,给你两个 正 整数 initialEnergy 和 initialExperience 分别表示你的初始精力和初始经验。

另给你两个下标从 0 开始的整数数组 energy 和 experience,长度均为 n 。

你将会 依次 对上 n 个对手。第 i 个对手的精力和经验分别用 energy[i] 和 experience[i] 表示。当你对上对手时,需要在经验和精力上都 严格 超过对手才能击败他们,然后在可能的情况下继续对上下一个对手。

击败第 i 个对手会使你的经验 增加 experience[i],但会将你的精力 减少  energy[i] 。

在开始比赛前,你可以训练几个小时。每训练一个小时,你可以选择将增加经验增加 1 或者 将精力增加 1 。

返回击败全部 n 个对手需要训练的 最少 小时数目。

 

示例 1:

输入:initialEnergy = 5, initialExperience = 3, energy = [1,4,3,2], experience = [2,6,3,1]
输出:8
解释:在 6 小时训练后,你可以将精力提高到 11 ,并且再训练 2 个小时将经验提高到 5 。
按以下顺序与对手比赛:
- 你的精力与经验都超过第 0 个对手,所以获胜。
  精力变为:11 - 1 = 10 ,经验变为:5 + 2 = 7 。
- 你的精力与经验都超过第 1 个对手,所以获胜。
  精力变为:10 - 4 = 6 ,经验变为:7 + 6 = 13 。
- 你的精力与经验都超过第 2 个对手,所以获胜。
  精力变为:6 - 3 = 3 ,经验变为:13 + 3 = 16 。
- 你的精力与经验都超过第 3 个对手,所以获胜。
  精力变为:3 - 2 = 1 ,经验变为:16 + 1 = 17 。
在比赛前进行了 8 小时训练,所以返回 8 。
可以证明不存在更小的答案。
示例 2:

输入:initialEnergy = 2, initialExperience = 4, energy = [1], experience = [3]
输出:0
解释:你不需要额外的精力和经验就可以赢得比赛,所以返回 0 。
 

提示:

n == energy.length == experience.length
1 <= n <= 100
1 <= initialEnergy, initialExperience, energy[i], experience[i] <= 100
class Solution {
    public int minNumberOfHours(int initialEnergy, int initialExperience, int[] energy, int[] experience) {
        int sum=0;
        for (int i : energy) {
            sum += i;//算出敌人的精力和
        }
        int num=Math.max(0,sum-initialEnergy+1);//算出自己与敌人的精力差,然后+1算出训练的次数
//设0的原因是为了保证自己的精力本身就大于敌人的精力和

        for (int i:experience) {
            if (i >= initialExperience) {//如果敌人的经验比自己的经验多
                num += i - initialExperience + 1;//算出经验差+1 训练这么多次数
                initialExperience = i + 1;//训练后正好比i多1点
            }
            initialExperience += i;//本身就比敌人经验多,就直接碾压获取对面的经验
        }
        return num;
    }
}

第一次跟y神一个思路,简单题果然很简单

但是写法就没y神精简了,我还多谢了三个变量用来计数和运算

结果y神一个math.max 给我省了俩,还有下面的if,我想着是选出来最大的,然后相加最大前面的合不合适,不合适就加两者相减+1

大神直接一个一个的比,如果不合格,就加到合格 确实没想到

解题思路

1.自己的精力一定要比敌人精力的数组和大1 所以算出敌人精力和-自己精力后剩下的 得出差多少

然后让相差的数据+1 就比敌人精力和多了

2.之后算经验,一定要比敌人经验数组里每一位的经验多,所以需要判断自己的经验是不是大于敌人的经验,如果不大于,则记录相差的数据+1(代表训练这么多次),然后再赋值给自己的经验

3.因为每次打败敌人会获取经验,所以再加上敌人的经验,最后算出最小次数

八股

如何避免 sql 注入

preparedStatement

使用正则表达式

使用字符串

让jsp网页验证是否有非法字符串

让jsp页面判断代码

什么是 XSS 攻击,如何避免

又称css,就是跨站脚本攻击,攻击者利用自己代码向网页写入恶意代码,当用户浏览网站就会自动执行,从而盗取用户的数据信息,达到查询修改删除的目的

需要对输入进行过滤,对输出进行编码

什么是 CSRF 攻击,如何避免

攻击者利用自己的网站伪造用户访问浏览器的请求,从而让网站误以为是用户的操作而执行命令,常用于盗号转账发布虚假信息。

验证http头自定义信息,使用令牌,使用验证码,用http referer字段

throw 和 throws 的区别?

前者是抛出具体的异常类型,后者是抛出所有异常信息,并向上查找到异常的方法

基于阳哥第二季的SpringCloud(第三天)

OpenFeign服务接口调用

概述

OpenFeign是什么

Feign是一个声明式的Web服务客户端,让编写Web服务客户端变得非常容易,只需创建一个接口并在接口上添加注解即可

GitHub

https://github.com/spring-cloud/spring-cloud-openfeign

能干嘛

 Feign能干什么
Feign旨在使编写Java Http客户端变得更容易。
前面在使用Ribbon+RestTemplate时,利用RestTemplate对http请求的封装处理,
形成了一套模版化的调用方法。
但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,
所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。
所以,Feign在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义。
在Feign的实现下,我们只需创建一个接口并使用注解的方式来配置它(以前是Dao接口上面标注Mapper注解,
现在是一个微服务接口上面标注一个Feign注解即可),即可完成对服务提供方的接口绑定,简化了使用Spring cloud Ribbon时,
自动封装服务调用客户端的开发量。
 
Feign集成了Ribbon
利用Ribbon维护了Payment的服务列表信息,并且通过轮询实现了客户端的负载均衡。
而与Ribbon不同的是,通过feign只需要定义服务绑定接口且以声明式的方法,
优雅而简单的实现了服务调用

Feign和OpenFeign两者区别

Feign是Spring Cloud组件中的一个轻量级RESTful的HTTP服务客户端

Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务

OpenFeign是Spring Cloud 在Feign的基础上支持了SpringMVC的注解,如@RequesMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-feign</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-openfeign</artifactId>

</dependency>

OpenFeign使用步骤

接口+注解

微服务调用接口+@FeignClient

新建cloud-consumer-feign-order80

Feign在消费端使用

POM

 <!--openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

YML

server:
  port: 80

eureka:
  client:
    register-with-eureka: false
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
 
 

主启动

@EnableFeignClients

@SpringBootApplication
@EnableFeignClients
public class OrderFeignMain80
{
    public static void main(String[] args)
    {
        SpringApplication.run(OrderFeignMain80.class,args);
    }
}
 

业务类

业务逻辑接口+@FeignClient配置调用provider服务

新建PaymentFeignService接口并新增注解@FeignClient

package com.atguigu.springcloud.service;

import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

/**
 * @auther zzyy
 * @create 2020-02-03 12:00
 */
@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
public interface PaymentFeignService
{
    @GetMapping(value = "/payment/get/{id}")
    CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);
}

@FeignClient

控制层Controller

package com.atguigu.springcloud.controller;

import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import com.atguigu.springcloud.service.PaymentFeignService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * @auther zzyy
 * @create 2020-02-03 14:10
 */
@RestController
public class OrderFeignController
{
    @Resource
    private PaymentFeignService paymentFeignService;

    @GetMapping(value = "/consumer/payment/get/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id)
    {
        return paymentFeignService.getPaymentById(id);
    }
}
 
 

测试

先启动2个eureka集群7001/7002

再启动2个微服务8001/8002

启动OpenFeign启动

http://localhost/consumer/payment/get/31

Feign自带负载均衡配置项

小总结

OpenFeign超时控制

超时设置,故意设置超时演示出错情况

服务提供方8001故意写暂停程序

    @GetMapping(value = "/payment/feign/timeout")
    public String paymentFeignTimeOut()
    {
        System.out.println("*****paymentFeignTimeOut from port: "+serverPort);
        //暂停几秒钟线程
        try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
        return serverPort;
    }

服务消费方80添加超时方法PaymentFeignService

    @GetMapping(value = "/payment/feign/timeout")
    String paymentFeignTimeOut();

服务消费方80添加超时方法OrderFeignController

   @GetMapping(value = "/consumer/payment/feign/timeout")
    public String paymentFeignTimeOut()
    {
        return paymentFeignService.paymentFeignTimeOut();
    }

测试

http://localhost/consumer/payment/feign/timeout

错误页面

OpenFeign默认等待1秒钟,超过后报错

是什么

默认Feign客户端只等待一秒钟,但是服务端处理需要超过1秒钟,导致Feign客户端不想等待了,直接返回报错。
为了避免这样的情况,有时候我们需要设置Feign客户端的超时控制。
 
 
yml文件中开启配置
 

OpenFeign默认支持Ribbon

YML文件里需要开启OpenFeign客户端超时控制


#设置feign客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
#指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
  ReadTimeout: 5000
#指的是建立连接后从服务器读取到可用资源所用的时间
  ConnectTimeout: 5000
 

OpenFeign日志打印功能

日志打印功能

是什么

Feign 提供了日志打印功能,我们可以通过配置来调整日志级别,从而了解 Feign 中 Http 请求的细节。
说白了就是对Feign接口的调用情况进行监控和输出

日志级别

 
NONE:默认的,不显示任何日志;
 
BASIC:仅记录请求方法、URL、响应状态码及执行时间;
 
HEADERS:除了 BASIC 中定义的信息之外,还有请求和响应的头信息;
 
FULL:除了 HEADERS 中定义的信息之外,还有请求和响应的正文及元数据。

配置日志bean

 
package com.atguigu.springcloud.cfgbeans;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import feign.Logger;

/**
 * @auther zzyy
 * @create 2019-11-10 17:00
 */
@Configuration
public class FeignConfig
{
    @Bean
    Logger.Level feignLoggerLevel()
    {
        return Logger.Level.FULL;
    }
}
 
 
 

YML文件里需要开启日志的Feign客户端


logging:
  level:
    # feign日志以什么级别监控哪个接口
    com.atguigu.springcloud.service.PaymentFeignService: debug

后台日志查看

Hystrix断路器

概述

分布式系统面临的问题

复杂分布式体系结构中的应用程序有数十个依赖关系,
每个依赖关系在某些时候将不可避免地失败。

服务雪崩
多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,
微服务B和微服务C又调用其它的微服务,
这就是所谓的“扇出”。
如果扇出的链路上某个微服务的调用响应时间过长或者不可用,
对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的“雪崩效应”.
 
对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上的所有资源都在几秒钟内饱和。
比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,
备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障。
这些都表示需要对故障和延迟进行隔离和管理,以便单个依赖关系的失败,
不能取消整个应用程序或系统。
所以,
通常当你发现一个模块下的某个实例失败后,这时候这个模块依然还会接收流量,
然后这个有问题的模块还调用了其他的模块,这样就会发生级联故障,或者叫雪崩。

是什么


Hystrix是一个用于处理分布式系统的延迟和容错的开源库,
在分布式系统里,许多依赖不可避免的会调用失败,
比如超时、异常等,Hystrix能够保证在一个依赖出问题的情况下,
不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。
 
“断路器”本身是一种开关装置,当某个服务单元发生故障之后,
通过断路器的故障监控(类似熔断保险丝),
向调用方返回一个符合预期的、可处理的备选响应(FallBack),
而不是长时间的等待或者抛出调用方无法处理的异常,
这样就保证了服务调用方的线程不会被长时间、不必要地占用,
从而避免了故障在分布式系统中的蔓延,乃至雪崩。
 

能干嘛

服务降级

服务熔断

接近实时的监控

。。。。。。

官网资料

https://github.com/Netflix/Hystrix/wiki/How-To-Use

Hystrix官宣,停更进维

https://github.com/Netflix/Hystrix

被动修复bugs

不再接受合并请求

不再发布新版本

Hystrix重要概念

服务降级

服务器忙,请稍后再试,不让客户端等待并立刻返回一个友好提示,fallback

哪些情况会出发降级

        程序运行异常
        超时
        服务熔断触发服务降级
        线程池/信号量打满也会导致服务降级
服务熔断

类比保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,

然后调用服务降级的方法并返回友好提示

就是保险丝

服务的降级->进而熔断->恢复调用链路

服务限流

秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟N个,有序进行

hystrix案例

构建

新建cloud-provider-hystrix-payment8001

POM

 <!--hystrix-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>

YML

server:
  port: 8001

spring:
  application:
    name: cloud-provider-hystrix-payment

eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      #defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
      defaultZone: http://eureka7001.com:7001/eureka

主启动

package com.atguigu.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

/**
 * @auther zzyy
 * @create 2020-02-04 13:04
 */
@SpringBootApplication
@EnableEurekaClient //本服务启动后会自动注册进eureka服务中
public class PaymentHystrixMain8001
{
    public static void main(String[] args)
    {
        SpringApplication.run(PaymentHystrixMain8001.class,args);
    }
}

业务类

service

 
package com.atguigu.springcloud.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;

import java.util.concurrent.TimeUnit;

/**
 * @auther zzyy
 * @create 2020-02-04 13:12
 */
@Service
public class PaymentService
{
    /**
     * 正常访问,一切OK
     * @param id
     * @return
     */
    public String paymentInfo_OK(Integer id)
    {
        return "线程池:"+Thread.currentThread().getName()+"paymentInfo_OK,id: "+id+"\t"+"O(∩_∩)O";
    }

    /**
     * 超时访问,演示降级
     * @param id
     * @return
     */
    public String paymentInfo_TimeOut(Integer id)
    {
        try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }
        return "线程池:"+Thread.currentThread().getName()+"paymentInfo_TimeOut,id: "+id+"\t"+"O(∩_∩)O,耗费3秒";
    }
}

controller

 
package com.atguigu.springcloud.controller;

import com.atguigu.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;

/**
 * @auther zzyy
 * @create 2019-11-22 13:02
 */
@RestController
@Slf4j
public class PaymentController
{
    @Autowired
    private PaymentService paymentService;

    @Value("${server.port}")
    private String serverPort;


    @GetMapping("/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id)
    {
        String result = paymentService.paymentInfo_OK(id);
        log.info("****result: "+result);
        return result;
    }

    @GetMapping("/payment/hystrix/timeout/{id}")
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id) throws InterruptedException
    {
        String result = paymentService.paymentInfo_TimeOut(id);
        log.info("****result: "+result);
        return result;
    }
}
 

正常测试

启动eureka7001

启动cloud-provider-hystrix-payment8001

访问

success的方法

http://localhost:8001/payment/hystrix/ok/31

每次调用耗费5秒钟

http://localhost:8001/payment/hystrix/timeout/31

上述module均OK

以上述为根基平台,从正确->错误->降级熔断->恢复

高并发测试

上述在非高并发情形下,还能勉强满足 but......

Jmeter压测测试

开启Jmeter,来20000个并发压死8001,20000个请求都去访问paymentInfo_TimeOut服务

再来一个访问

http://localhost:8001/payment/hystrix/ok/31

看演示结果

两个都在自己转圈圈

为什么会被卡死

tomcat的默认的工作线程数被打满 了,没有多余的线程来分解压力和处理。

Jmeter压测结论

上面还是服务提供者8001自己测试,假如此时外部的消费者80也来访问, 那消费者只能干等,最终导致消费端80不满意,服务端8001直接被拖死

看热闹不嫌弃事大,80新建加入

cloud-consumer-feign-hystrix-order80

新建

cloud-consumer-feign-hystrix-order80

POM

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>mscloud03</artifactId>
        <groupId>com.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-consumer-feign-hystrix-order80</artifactId>


    <dependencies>
        <!--openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--hystrix-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <!--eureka client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--一般基础通用配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>


</project>
 
 

YML

server:
  port: 80

eureka:
  client:
    register-with-eureka: false
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/
 

主启动


@EnableFeignClients

package com.atguigu.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.openfeign.EnableFeignClients;

/**
 * @auther zzyy
 * @create 2020-02-04 16:32
 */
@SpringBootApplication
@EnableFeignClients
public class OrderHystrixMain80
{
    public static void main(String[] args)
    {
        SpringApplication.run(OrderHystrixMain80.class,args);
    }
}
 
 

业务类

PaymentHystrixService

 @Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT")




package com.atguigu.springcloud.service;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

/**
 * @auther zzyy
 * @create 2020-02-04 16:34
 */
@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT")
public interface PaymentHystrixService
{
    @GetMapping("/payment/hystrix/ok/{id}")
    String paymentInfo_OK(@PathVariable("id") Integer id);

    @GetMapping("/payment/hystrix/timeout/{id}")
    String paymentInfo_TimeOut(@PathVariable("id") Integer id);
}
 
 

OrderHystirxController

package com.atguigu.springcloud.controller;

import com.atguigu.springcloud.service.PaymentHystrixService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * @auther zzyy
 * @create 2020-02-20 11:57
 */
@RestController
@Slf4j
public class OrderHystirxController
{
    @Resource
    private PaymentHystrixService paymentHystrixService;

    @GetMapping("/consumer/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id)
    {
        String result = paymentHystrixService.paymentInfo_OK(id);
        return result;
    }

    @GetMapping("/consumer/payment/hystrix/timeout/{id}")
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id)
    {
        String result = paymentHystrixService.paymentInfo_TimeOut(id);
        return result;
    }
}
 
 

正常测试

http://localhost/consumer/payment/hystrix/ok/31

高并发测试

2W个线程压8001

消费端80微服务再去访问正常的Ok微服务8001地址

http://localhost/consumer/payment/hystrix/ok/32

消费者80,o(╥﹏╥)o

要么转圈圈等待

要么消费端报超时错误

故障现象和导致原因

8001同一层次的其它接口服务被困死,

因为tomcat线程池里面的工作线程已经被挤占完毕

80此时调用8001,客户端访问响应缓慢,转圈圈

上诉结论

正因为有上述故障或不佳表现 才有我们的降级/容错/限流等技术诞生

如何解决?解决的要求

超时导致服务器变慢(转圈)

超时不再等待

出错(宕机或程序运行出错)

出错要有兜底

解决

对方服务(8001)超时了,调用者(80)不能一直卡死等待,必须有服务降级

对方服务(8001)down机了,调用者(80)不能一直卡死等待,必须有服务降级

对方服务(8001)OK,调用者(80)自己出故障或有自我要求(自己的等待时间小于服务提供者),自己处理降级

服务降级
降级配置

@HystrixCommand

8001先从自身找问题

设置自身调用超时时间的峰值,峰值内可以正常运行, 超过了需要有兜底的方法处理,作服务降级fallback

8001fallback

业务类启用


package com.atguigu.springcloud.service;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;

import java.util.concurrent.TimeUnit;

/**
 * @auther zzyy
 * @create 2020-02-04 13:12
 */
@Service
public class PaymentService
{
    /**
     * 正常访问,一切OK
     * @param id
     * @return
     */
    public String paymentInfo_OK(Integer id)
    {
        return "线程池:"+Thread.currentThread().getName()+"paymentInfo_OK,id: "+id+"\t"+"O(∩_∩)O";
    }

    /**
     * 超时访问,演示降级
     * @param id
     * @return
     */
    @HystrixCommand(fallbackMethod = "paymentInfo_TimeOutHandler",commandProperties = {
            @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="3000")
    })
    public String paymentInfo_TimeOut(Integer id)
    {
        int second = 5;
        try { TimeUnit.SECONDS.sleep(second); } catch (InterruptedException e) { e.printStackTrace(); }
        return "线程池:"+Thread.currentThread().getName()+"paymentInfo_TimeOut,id: "+id+"\t"+"O(∩_∩)O,耗费秒: "+second;
    }
    public String paymentInfo_TimeOutHandler(Integer id){
        return "/(ㄒoㄒ)/调用支付接口超时或异常:\t"+ "\t当前线程池名字" + Thread.currentThread().getName();
    }
}
 

@HystrixCommand报异常后如何处理

一旦调用服务方法失败并抛出了错误信息后, 会自动调用@HystrixCommand标注好的 fallbackMethod调用类中的指定方法

图示

上图故意制造两个异常:
   1  int age = 10/0; 计算异常
   2  我们能接受3秒钟,它运行5秒钟,超时异常。
 
   当前服务不可用了,做服务降级,兜底的方案都是paymentInfo_TimeOutHandler

主启动类激活

添加新注解@EnableCircuitBreaker

80fallback

80订单微服务,也可以更好的保护自己,自己也依样画葫芦进行客户端降级保护

题外话,切记

我们自己配置过的热部署方式对java代码的改动明显,

但对@HystrixCommand内属性的修改建议重启微服务

YML

 
server:
  port: 80

eureka:
  client:
    register-with-eureka: false
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/

feign:
  hystrix:
    enabled: true
 

主启动

@EnableHystrix

@SpringBootApplication
@EnableFeignClients
@EnableHystrix
public class OrderHystrixMain80
{
    public static void main(String[] args)
    {
        SpringApplication.run(OrderHystrixMain80.class,args);
    }
}
 

业务类

 
package com.atguigu.springcloud.controller;

import com.atguigu.springcloud.service.PaymentHystrixService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * @auther zzyy
 * @create 2020-02-04 16:35
 */
@RestController
@Slf4j
public class PaymentHystirxController
{
    @Resource
    private PaymentHystrixService paymentHystrixService;

    @GetMapping("/consumer/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id)
    {
        String result = paymentHystrixService.paymentInfo_OK(id);
        return result;
    }

@GetMapping("/consumer/payment/hystrix/timeout/{id}")
@HystrixCommand(fallbackMethod = "paymentTimeOutFallbackMethod",commandProperties = {
        @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="1500")
})
public String paymentInfo_TimeOut(@PathVariable("id") Integer id)
{
    String result = paymentHystrixService.paymentInfo_TimeOut(id);
    return result;
}
public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id)
{
    return "我是消费者80,对方支付系统繁忙请10秒钟后再试或者自己运行出错请检查自己,o(╥﹏╥)o";
}

}
 
 
 
 
 
 
目前问题

每个业务方法对应一个兜底的方法,代码膨胀

统一和自定义的分开

解决问题
每个方法配置一个???膨胀

feign接口系列

@DefaultProperties(defaultFallback = "")

说明

@DefaultProperties(defaultFallback = "")
 
  1:1 每个方法配置一个服务降级方法,技术上可以,实际上傻X
 
  1:N 除了个别重要核心业务有专属,其它普通的可以通过@DefaultProperties(defaultFallback = "")  统一跳转到统一处理结果页面
 
  通用的和独享的各自分开,避免了代码膨胀,合理减少了代码量,O(∩_∩)O哈哈~ 

controller配置

 
package com.atguigu.springcloud.controller;

import com.atguigu.springcloud.service.PaymentHystrixService;
import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * @auther zzyy
 * @create 2020-02-04 16:35
 */
@RestController
@Slf4j
@DefaultProperties(defaultFallback = "payment_Global_FallbackMethod")
public class PaymentHystirxController
{
    @Resource
    private PaymentHystrixService paymentHystrixService;

    @GetMapping("/consumer/payment/hystrix/ok/{id}")
    public String paymentInfo_OK(@PathVariable("id") Integer id)
    {
        String result = paymentHystrixService.paymentInfo_OK(id);
        return result;
    }

    @GetMapping("/consumer/payment/hystrix/timeout/{id}")
    @HystrixCommand //加了@DefaultProperties属性注解,并且没有写具体方法名字,就用统一全局的
    public String paymentInfo_TimeOut(@PathVariable("id") Integer id)
    {
        String result = paymentHystrixService.paymentInfo_TimeOut(id);
        return result;
    }
    public String paymentTimeOutFallbackMethod(@PathVariable("id") Integer id)
    {
        return "paymentTimeOutFallbackMethod,对方系统繁忙,请10秒钟后再次尝试/(ㄒoㄒ)/";
    }

    public String payment_Global_FallbackMethod()
    {
        return "Global异常处理信息,请稍后再试,/(ㄒoㄒ)/~~";
    }
}
 
 
 
和业务逻辑混一起???混乱

服务降级,客户端去调用服务端,碰上服务端宕机或关闭

本次案例服务降级处理是在客户端80实现完成的,与服务端8001没有关系 只需要为Feign客户端定义的接口添加一个服务降级处理的实现类即可实现解耦

未来我们要面对的异常

运行

超时

宕机

再看我们的业务类PaymentController

混合在一块 ,每个业务方法都要提供一个。

修改cloud-consumer-feign-hystrix-order80

根据cloud-consumer-feign-hystrix-order80已经有的PaymentHystrixService接口, 重新新建一个类(PaymentFallbackService)实现该接口,统一为接口里面的方法进行异常处理

PaymentFallbackService类实现PaymentFeignClientService接口

 
package com.atguigu.springcloud.service;

import org.springframework.stereotype.Component;

/**
 * @auther zzyy
 * @create 2019-11-12 11:12
 */
@Component //必须加 //必须加 //必须加
public class PaymentFallbackService implements PaymentFeignClientService
{
    @Override
    public String getPaymentInfo(Integer id)
    {
        return "服务调用失败,提示来自:cloud-consumer-feign-order80";
    }
}
 

YML

 
server:
  port: 80

eureka:
  client:
    register-with-eureka: false
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
#logging:
#  level:
#    # feign日志以什么级别监控哪个接口
#    com.atguigu.springcloud.service.PaymentFeignClientService: debug

# 用于服务降级 在注解@FeignClient中添加fallbackFactory属性值
feign:
  hystrix:
   enabled: true #在Feign中开启Hystrix

PaymentFeignClientService接口

package com.atguigu.springcloud.service;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

/**
 * @auther zzyy
 * @create 2019-11-10 14:29
 */
@Component
@FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT",fallback = PaymentFallbackService.class)
public interface PaymentFeignClientService
{
    @GetMapping("/payment/hystrix/{id}")
    public String getPaymentInfo(@PathVariable("id") Integer id);
}



测试

单个eureka先启动7001

PaymentHystrixMain8001启动

正常访问测试

http://localhost/consumer/payment/hystrix/ok/31

故意关闭微服务8001

客户端自己调用提示

此时服务端provider已经down了,但是我们做了服务降级处理, 让客户端在服务端不可用时也会获得提示信息而不会挂起耗死服务器

服务熔断
断路器

一句话就是家里的保险丝

熔断是什么
熔断机制概述
熔断机制是应对雪崩效应的一种微服务链路保护机制。
当扇出链路的某个微服务出错不可用或者响应时间太长时,
会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。


当检测到该节点微服务调用响应正常后,恢复调用链路。
 
在Spring Cloud框架里,熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况,
当失败的调用到一定阈值,缺省是5秒内20次调用失败,就会启动熔断机制。
熔断机制的注解是@HystrixCommand。
 

大神论文

https://martinfowler.com/bliki/CircuitBreaker.html

实操

修改cloud-provider-hystrix-payment8001

PaymentService

 
//=========服务熔断
@HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = {
        @HystrixProperty(name = "circuitBreaker.enabled",value = "true"),
        @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"), 
        @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "10000"),
        @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "60"),
})
public String paymentCircuitBreaker(@PathVariable("id") Integer id)
{
    if(id < 0)
    {
        throw new RuntimeException("******id 不能负数");
    }
    String serialNumber = IdUtil.simpleUUID();

    return Thread.currentThread().getName()+"\t"+"调用成功,流水号: " + serialNumber;
}
public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id)
{
    return "id 不能负数,请稍后再试,/(ㄒoㄒ)/~~   id: " +id;
}

why配置这些参数

PaymentController

 
@GetMapping("/payment/circuit/{id}")
public String paymentCircuitBreaker(@PathVariable("id") Integer id)
{
    String result = paymentService.paymentCircuitBreaker(id);
    log.info("****result: "+result);
    return result;
}
 

测试

自测cloud-provider-hystrix-payment8001

正确

http://localhost:8001/payment/circuit/31

错误

http://localhost:8001/payment/circuit/-31

一次正确一次错误trytry

重点测试

多次错误,然后慢慢正确,发现刚开始不满足条件,就算是正确的访问地址也不能进行

原理(小总结)

大神结论

熔断类型

熔断打开

请求不再进行调用当前服务,内部设置时钟一般为MTTR(平均故障处理时间),当打开时长达到所设时钟则进入半熔断状态

熔断关闭

熔断关闭不会对服务进行熔断

熔断半开

部分请求根据规则调用当前服务,如果请求成功且符合规则则认为当前服务恢复正常,关闭熔断

官网断路器流程图

官网步骤

断路器在什么情况下开始起作用

 
涉及到断路器的三个重要参数:快照时间窗、请求总数阀值、错误百分比阀值。
1:快照时间窗:断路器确定是否打开需要统计一些请求和错误数据,
而统计的时间范围就是快照时间窗,默认为最近的10秒。
 
2:请求总数阀值:在快照时间窗内,必须满足请求总数阀值才有资格熔断。默认为20
,意味着在10秒内,如果该hystrix命令的调用次数不足20次,
即使所有的请求都超时或其他原因失败,断路器都不会打开。
 
3:错误百分比阀值:当请求总数在快照时间窗内超过了阀值,比如发生了30次调用,
如果在这30次调用中,有15次发生了超时异常,也就是超过50%的错误百分比,
在默认设定50%阀值情况下,这时候就会将断路器打开。
 
 

断路器开启或者关闭的条件

当满足一定的阀值的时候(默认10秒内超过20个请求次数)

当失败率达到一定的时候(默认10秒内超过50%的请求失败)

到达以上阀值,断路器将会开启

当开启的时候,所有请求都不会进行转发

一段时间之后(默认是5秒),这个时候断路器是半开状态,会让其中一个请求进行转发。 如果成功,断路器会关闭,若失败,继续开启。重复4和5

断路器打开之后

 
1:再有请求调用的时候,将不会调用主逻辑,而是直接调用降级fallback。通过断路器,实现了自动地发现错误并将降级逻辑切换为主逻辑,减少响应延迟的效果。
 
2:原来的主逻辑要如何恢复呢?
对于这一问题,hystrix也为我们实现了自动恢复功能。
当断路器打开,对主逻辑进行熔断之后,hystrix会启动一个休眠时间窗,在这个时间窗内,降级逻辑是临时的成为主逻辑,
当休眠时间窗到期,断路器将进入半开状态,释放一次请求到原来的主逻辑上,如果此次请求正常返回,那么断路器将继续闭合,
主逻辑恢复,如果这次请求依然有问题,断路器继续进入打开状态,休眠时间窗重新计时。

All配置

//========================All
@HystrixCommand(fallbackMethod = "str_fallbackMethod",
        groupKey = "strGroupCommand",
        commandKey = "strCommand",
        threadPoolKey = "strThreadPool",

        commandProperties = {
                // 设置隔离策略,THREAD 表示线程池 SEMAPHORE:信号池隔离
                @HystrixProperty(name = "execution.isolation.strategy", value = "THREAD"),
                // 当隔离策略选择信号池隔离的时候,用来设置信号池的大小(最大并发数)
                @HystrixProperty(name = "execution.isolation.semaphore.maxConcurrentRequests", value = "10"),
                // 配置命令执行的超时时间
                @HystrixProperty(name = "execution.isolation.thread.timeoutinMilliseconds", value = "10"),
                // 是否启用超时时间
                @HystrixProperty(name = "execution.timeout.enabled", value = "true"),
                // 执行超时的时候是否中断
                @HystrixProperty(name = "execution.isolation.thread.interruptOnTimeout", value = "true"),
                // 执行被取消的时候是否中断
                @HystrixProperty(name = "execution.isolation.thread.interruptOnCancel", value = "true"),
                // 允许回调方法执行的最大并发数
                @HystrixProperty(name = "fallback.isolation.semaphore.maxConcurrentRequests", value = "10"),
                // 服务降级是否启用,是否执行回调函数
                @HystrixProperty(name = "fallback.enabled", value = "true"),
                // 是否启用断路器
                @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),
                // 该属性用来设置在滚动时间窗中,断路器熔断的最小请求数。例如,默认该值为 20 的时候,
                // 如果滚动时间窗(默认10秒)内仅收到了19个请求, 即使这19个请求都失败了,断路器也不会打开。
                @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "20"),
                // 该属性用来设置在滚动时间窗中,表示在滚动时间窗中,在请求数量超过
                // circuitBreaker.requestVolumeThreshold 的情况下,如果错误请求数的百分比超过50,
                // 就把断路器设置为 "打开" 状态,否则就设置为 "关闭" 状态。
                @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50"),
                // 该属性用来设置当断路器打开之后的休眠时间窗。 休眠时间窗结束之后,
                // 会将断路器置为 "半开" 状态,尝试熔断的请求命令,如果依然失败就将断路器继续设置为 "打开" 状态,
                // 如果成功就设置为 "关闭" 状态。
                @HystrixProperty(name = "circuitBreaker.sleepWindowinMilliseconds", value = "5000"),
                // 断路器强制打开
                @HystrixProperty(name = "circuitBreaker.forceOpen", value = "false"),
                // 断路器强制关闭
                @HystrixProperty(name = "circuitBreaker.forceClosed", value = "false"),
                // 滚动时间窗设置,该时间用于断路器判断健康度时需要收集信息的持续时间
                @HystrixProperty(name = "metrics.rollingStats.timeinMilliseconds", value = "10000"),
                // 该属性用来设置滚动时间窗统计指标信息时划分"桶"的数量,断路器在收集指标信息的时候会根据
                // 设置的时间窗长度拆分成多个 "桶" 来累计各度量值,每个"桶"记录了一段时间内的采集指标。
                // 比如 10 秒内拆分成 10 个"桶"收集这样,所以 timeinMilliseconds 必须能被 numBuckets 整除。否则会抛异常
                @HystrixProperty(name = "metrics.rollingStats.numBuckets", value = "10"),
                // 该属性用来设置对命令执行的延迟是否使用百分位数来跟踪和计算。如果设置为 false, 那么所有的概要统计都将返回 -1。
                @HystrixProperty(name = "metrics.rollingPercentile.enabled", value = "false"),
                // 该属性用来设置百分位统计的滚动窗口的持续时间,单位为毫秒。
                @HystrixProperty(name = "metrics.rollingPercentile.timeInMilliseconds", value = "60000"),
                // 该属性用来设置百分位统计滚动窗口中使用 “ 桶 ”的数量。
                @HystrixProperty(name = "metrics.rollingPercentile.numBuckets", value = "60000"),
                // 该属性用来设置在执行过程中每个 “桶” 中保留的最大执行次数。如果在滚动时间窗内发生超过该设定值的执行次数,
                // 就从最初的位置开始重写。例如,将该值设置为100, 滚动窗口为10秒,若在10秒内一个 “桶 ”中发生了500次执行,
                // 那么该 “桶” 中只保留 最后的100次执行的统计。另外,增加该值的大小将会增加内存量的消耗,并增加排序百分位数所需的计算时间。
                @HystrixProperty(name = "metrics.rollingPercentile.bucketSize", value = "100"),
                // 该属性用来设置采集影响断路器状态的健康快照(请求的成功、 错误百分比)的间隔等待时间。
                @HystrixProperty(name = "metrics.healthSnapshot.intervalinMilliseconds", value = "500"),
                // 是否开启请求缓存
                @HystrixProperty(name = "requestCache.enabled", value = "true"),
                // HystrixCommand的执行和事件是否打印日志到 HystrixRequestLog 中
                @HystrixProperty(name = "requestLog.enabled", value = "true"),
        },
        threadPoolProperties = {
                // 该参数用来设置执行命令线程池的核心线程数,该值也就是命令执行的最大并发量
                @HystrixProperty(name = "coreSize", value = "10"),
                // 该参数用来设置线程池的最大队列大小。当设置为 -1 时,线程池将使用 SynchronousQueue 实现的队列,
                // 否则将使用 LinkedBlockingQueue 实现的队列。
                @HystrixProperty(name = "maxQueueSize", value = "-1"),
                // 该参数用来为队列设置拒绝阈值。 通过该参数, 即使队列没有达到最大值也能拒绝请求。
                // 该参数主要是对 LinkedBlockingQueue 队列的补充,因为 LinkedBlockingQueue
                // 队列不能动态修改它的对象大小,而通过该属性就可以调整拒绝请求的队列大小了。
                @HystrixProperty(name = "queueSizeRejectionThreshold", value = "5"),
        }
)
public String strConsumer() {
    return "hello 2020";
}
public String str_fallbackMethod()
{
    return "*****fall back str_fallbackMethod";
}
 
服务限流

后面高级篇讲解alibaba的Sentinel说明

hystrix工作流程

https://github.com/Netflix/Hystrix/wiki/How-it-Works

Hystrix工作流程

官网图例

步骤说明

1创建 HystrixCommand(用在依赖的服务返回单个操作结果的时候) 
 或 HystrixObserableCommand(用在依赖的服务返回多个操作结果的时候) 对象。

2命令执行。其中 HystrixComand 实现了下面前两种执行方式;
而 HystrixObservableCommand 实现了后两种执行方式:
execute():同步执行,从依赖的服务返回一个单一的结果对象,
 或是在发生错误的时候抛出异常。queue():异步执行, 直接返回 一个Future对象, 
 其中包含了服务执行结束时要返回的单一结果对象。
observe():返回 Observable 对象,它代表了操作的多个结果,
 它是一个 Hot Obserable(不论 "事件源" 是否有 "订阅者",
 都会在创建后对事件进行发布,
 所以对于 Hot Observable 的每一个 "订阅者" 都有可能是从 "事件源" 的中途开始的,
 并可能只是看到了整个操作的局部过程)。
toObservable(): 同样会返回 Observable 对象,也代表了操作的多个结果,
 但它返回的是一个Cold Observable(没有 "订阅者" 的时候并不会发布事件,
 而是进行等待,直到有 "订阅者" 之后才发布事件,
 所以对于 Cold Observable 的订阅者,它可以保证从一开始看到整个操作的全部过程)。

3若当前命令的请求缓存功能是被启用的, 并且该命令缓存命中, 
 那么缓存的结果会立即以 Observable 对象的形式 返回。

4检查断路器是否为打开状态。如果断路器是打开的,那么Hystrix不会执行命令,
 而是转接到 fallback 处理逻辑(第 8 步);
 如果断路器是关闭的,检查是否有可用资源来执行命令(第 5 步)。

5线程池/请求队列/信号量是否占满。
 如果命令依赖服务的专有线程池和请求队列,
 或者信号量(不使用线程池的时候)已经被占满,
 那么 Hystrix 也不会执行命令, 而是转接到 fallback 处理逻辑(第8步)。

6Hystrix 会根据我们编写的方法来决定采取什么样的方式去请求依赖服务。
 HystrixCommand.run() :返回一个单一的结果,或者抛出异常。
 HystrixObservableCommand.construct(): 
  返回一个Observable 对象来发射多个结果,或通过 onError 发送错误通知。

7Hystrix会将 "成功"、"失败"、"拒绝"、"超时" 等信息报告给断路器, 
 而断路器会维护一组计数器来统计这些数据。
 断路器会使用这些统计数据来决定是否要将断路器打开,
 来对某个依赖服务的请求进行 "熔断/短路"。

8当命令执行失败的时候, Hystrix 会进入 fallback 尝试回退处理,
 我们通常也称该操作为 "服务降级"。
而能够引起服务降级处理的情况有下面几种:
 第4步: 当前命令处于"熔断/短路"状态,断路器是打开的时候。
 第5步: 当前命令的线程池、 请求队列或 者信号量被占满的时候。
 第6步:HystrixObservableCommand.construct() 或 HystrixCommand.run() 抛出异常的时候。

9当Hystrix命令执行成功之后, 它会将处理结果直接返回或是以Observable 的形式返回。
tips:如果我们没有为命令实现降级逻辑或者在降级处理逻辑中抛出了异常,
  Hystrix 依然会返回一个 Observable 对象, 但是它不会发射任何结果数据,
  而是通过 onError 方法通知命令立即中断请求,
 并通过onError()方法将引起命令失败的异常发送给调用者。

服务监控hystrixDashboard

概述

除了隔离依赖服务的调用以外,
Hystrix还提供了准实时的调用监控(Hystrix Dashboard),
Hystrix会持续地记录所有通过Hystrix发起的请求的执行信息,
并以统计报表和图形的形式展示给用户,
包括每秒执行多少请求多少成功,多少失败等。
Netflix通过hystrix-metrics-event-stream项目实现了对以上指标的监控
Spring Cloud也提供了Hystrix Dashboard的整合,对监控内容转化成可视化界面。

仪表盘9001

新建cloud-consumer-hystrix-dashboard9001

POM

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
        </dependency>

YML

 
server:
  port: 9001
 

HystrixDashboardMain9001+新注解@EnableHystrixDashboard

package com.atguigu.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;

/**
 * @auther zzyy
 * @create 2019-11-12 14:31
 */
@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboardMain9001
{
    public static void main(String[] args)
    {
        SpringApplication.run(MainApp9001.class,args);
    }
}
 
 

所有Provider微服务提供类(8001/8002/8003)都需要监控依赖配置

   <!-- actuator监控信息完善 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
 
 

启动cloud-consumer-hystrix-dashboard9001该微服务后续将监控微服务8001

http://localhost:9001/hystrix

断路器演示(服务监控hystrixDashboard)

修改cloud-provider-hystrix-payment8001

注意:新版本Hystrix需要在主启动类MainAppHystrix8001中指定监控路径

 
package com.atguigu.springcloud;

import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.context.annotation.Bean;

/**
 * @auther zzyy
 * @create 2019-11-05 21:20
 */
@SpringBootApplication
@EnableEurekaClient //本服务启动后会自动注册进eureka服务中
@EnableCircuitBreaker//对hystrixR熔断机制的支持
public class MainAppHystrix8001
{
    public static void main(String[] args)
    {
        SpringApplication.run(MainAppHystrix8001.class,args);
    }

/**
 *此配置是为了服务监控而配置,与服务容错本身无关,springcloud升级后的坑
 *ServletRegistrationBean因为springboot的默认路径不是"/hystrix.stream",
 *只要在自己的项目里配置上下面的servlet就可以了
 */
@Bean
public ServletRegistrationBean getServlet() {
    HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
    ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
    registrationBean.setLoadOnStartup(1);
    registrationBean.addUrlMappings("/hystrix.stream");
    registrationBean.setName("HystrixMetricsStreamServlet");
    return registrationBean;
}

}

Unable to connect to Command Metric Stream.

404

监控测试

启动1个eureka或者3个eureka集群均可

观察监控窗口

9001监控8001

1:Delay:该参数用来控制服务器上轮询监控信息的延迟时间,默认为2000毫秒,可以通过配置该属性来降低客户端的网络和CPU消耗。
 
2:Title:该参数对应了头部标题Hystrix Stream之后的内容,默认会使用具体监控实例的URL,可以通过配置该信息来展示更合适的标题。

填写监控地址

http://localhost:8001/hystrix.stream

测试地址

http://localhost:8001/payment/circuit/31

http://localhost:8001/payment/circuit/-31

上述测试通过

ok

先访问正确地址,再访问错误地址,再正确地址,会发现图示断路器都是慢慢放开的。

监控结果,成功

监控结果,失败

如何看?

7色

1圈

 
实心圆:共有两种含义。它通过颜色的变化代表了实例的健康程度,
它的健康度从绿色<黄色<橙色<红色递减。
该实心圆除了颜色的变化之外,它的大小也会根据实例的请求流量发生变化,
流量越大该实心圆就越大。所以通过该实心圆的展示,
就可以在大量的实例中快速的发现故障实例和高压力实例。
 

1线

曲线:用来记录2分钟内流量的相对变化,可以通过它来观察到流量的上升和下降趋势。

整图说明

整图说明2

搞懂一个才能看懂复杂的

总结一下

现在是18.39.16

我特么,光听还好说,问题就是边听边写代码 还要记笔记

我是听了一会再记笔记的,然后,我就发现,我听课速度跟我记笔记速度是一样的

也就是说我听20分钟课就要记上20分钟笔记(包括暂停改代码),中间出个bug又得卡老半天

所以我先准备 cv把笔记粘贴一波,然后哪有问题我再改

头很痛,下午五点三十几分开始的,中间上了个厕所,然后手机要填表花了几分钟,一直写到现在,没错,现在已经18.42.33了 时间怎么过的这么快

太离谱了

课还没听一小时呢笔记先写了一小时,再去看看课还有多长,至少两小时多

今天给我的感觉 记笔记那是 珍妃(真废) 时间

今天直接给这章节笔记全干完了,但是还有两小时课没听,明天继续,但是看今天的笔记

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值