欢迎来到菜鸟SpringCloud实战入门系列(SpringCloudForNoob),该系列经过层层递进的实战视角,来一步步学习和理解SpringCloud。html
本系列适合有必定Java以及SpringBoot基础的同窗阅读。git
每篇文章末尾都附有本文对应的Github源代码,方便同窗调试。github
Github仓库地址:web
你能够经过如下两种途径查看菜鸟SpringCloud实战入门系列:spring
前文回顾:express
关于熔断器的解释,这里引用一大段:后端
熔断器适用于实现快速失败,若是它在一段时间内侦测到许多相似的错误,会强迫其之后的多个调用快速失败,再也不访问远程服务器,从而防止应用程序不断地尝试执行可能会失败的操做,使得应用程序继续执行而不用等待修正错误,或者浪费CPU时间去等到长时间的超时产生。熔断器也可使应用程序可以诊断错误是否已经修正,若是已经修正,应用程序会再次尝试调用操做。缓存
熔断器模式就像是那些容易致使错误的操做的一种代理。这种代理可以记录最近调用发生错误的次数,而后决定使用容许操做继续,或者当即返回错误。 熔断器开关相互转换的逻辑以下图:安全
熔断器就是保护服务高可用的最后一道防线。
Hystrix特性
1.断路器机制
断路器很好理解, 当Hystrix Command请求后端服务失败数量超过必定比例(默认50%), 断路器会切换到开路状态(Open). 这时全部请求会直接失败而不会发送到后端服务. 断路器保持在开路状态一段时间后(默认5秒), 自动切换到半开路状态(HALF-OPEN). 这时会判断下一次请求的返回状况, 若是请求成功, 断路器切回闭路状态(CLOSED), 不然从新切换到开路状态(OPEN). Hystrix的断路器就像咱们家庭电路中的保险丝, 一旦后端服务不可用, 断路器会直接切断请求链, 避免发送大量无效请求影响系统吞吐量, 而且断路器有自我检测并恢复的能力.
2.Fallback
Fallback至关因而降级操做. 对于查询操做, 咱们能够实现一个fallback方法, 当请求后端服务出现异常的时候, 可使用fallback方法返回的值. fallback方法的返回值通常是设置的默认值或者来自缓存.
3.资源隔离
在Hystrix中, 主要经过线程池来实现资源隔离. 一般在使用的时候咱们会根据调用的远程服务划分出多个线程池. 例如调用产品服务的Command放入A线程池, 调用帐户服务的Command放入B线程池. 这样作的主要优势是运行环境被隔离开了. 这样就算调用服务的代码存在bug或者因为其余缘由致使本身所在线程池被耗尽时, 不会对系统的其余服务形成影响. 可是带来的代价就是维护多个线程池会对系统带来额外的性能开销. 若是是对性能有严格要求并且确信本身调用服务的客户端代码不会出问题的话, 可使用Hystrix的信号模式(Semaphores)来隔离资源.
依然使用上一章创建的子模块:Service-Feign
pom文件不须要变化,由于spring-cloud-starter-openfeign已经自带了Hystrix。
修改配置文件application.yml,增长以下:
feign:
hystrix:
enabled: true
复制代码
在我这里,因为Springboot使用了2.0.3,引入的是openfeign,因此出现了:
起初觉得这条指令没法生效,折腾了以后才发现是生效的。
推测是openfeign的问题,不是spring boot 1.X的spring-cloud-starter-feign,IDEA判断失误了。
接着新建类ServiceHiHystrix继承ServiceHi接口,里面实现了失败下的返回信息:
import org.springframework.stereotype.Component;
@Component
public class ServiceHiHystrix implements ServiceHi {
@Override
public String sayHiFromServiceHi(String name) {
return "hello" + name +", this message send failed";
}
}
复制代码
更改ServiceHi接口,添加上fallback类为刚才新建的类:
@FeignClient(value = "service-hi", fallback = ServiceHiHystrix.class)
复制代码
大功告成,启动server-feign,eureka-hi和eureka测试:
打开:http://localhost:8765/hello/rude3knife
接着,关掉服务提供者eureka-hi,来模拟服务宕机的状况,从新访问:http://localhost:8765/hello/rude3knife
返回了新建的错误信息。
Hystrix-dashboard是一款针对Hystrix进行实时监控的工具,经过Hystrix Dashboard咱们能够在直观地看到各Hystrix Command的请求响应时间, 请求成功率等数据。
咱们只须要在上一章中的server-feign模块继续修改,由于上一章已经在该模块加了熔断器。
首先添加依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<!--spring boot 1.X:spring-cloud-starter-hystrix-->
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<!--spring boot 1.X:spring-cloud-starter-hystrix-dashboard-->
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
复制代码
启动类修改:
@EnableHystrixDashboard
@EnableCircuitBreaker
复制代码
启动工程访问:
http://localhost:8765/hystrix,将会看到以下界面:
图中会有一些提示:
大概意思就是若是查看默认集群使用第一个url,查看指定集群使用第二个url,单个应用的监控使用最后一个,咱们暂时只演示单个应用的因此在输入框中输入: http://localhost:8765/hystrix.stream ,输入以后点击 monitor,进入页面。
若是没有请求会先显示Loading ...,访问http://localhost:9001/hystrix.stream 也会不断的显示ping。
请求服务http://localhost:8765/hello/rude3knife,就能够看到监控的效果了,首先访问http://localhost:8765/hystrix.stream,显示以下:
出错了!
随机谷歌了下问题,网友给出了问题解决方案:
答主经过查看源码后给出的解决方案是:
评论区给出更为方便且优雅的方案:
在配置文件中加入management.endpoints.web.exposure.include=*,将端口暴露就不须要声明bean了,访问地址要变一下/actuator/hystrix.stream
因而咱们在yml中加入:
# 熔断器DashBoard: actuator在boot2.0调整后开关web端点的配置,*表明开启全部
management:
endpoints:
web:
exposure:
include: "*"
复制代码
从新运行模块,而后在网址一栏输入:
http://localhost:8765/actuator/hystrix.stream
页面会不停显示Loading,不用慌,不显示Unable to connect to Command Metric Stream.了。显示Loading是由于由于尚未请求过来。
以后咱们尝试发一次请求,在地址栏对server-feign的8765端口发送请求:
http://localhost:8765/hello/1232312
再来看以前的页面,大功告成。
到此单个应用的熔断监控已经完成。
可是只使用Hystrix Dashboard的话, 你只能看到单个应用内的服务信息, 这明显不够. 咱们须要一个工具能让咱们汇总系统内多个服务的数据并显示到Hystrix Dashboard上, 这个工具就是Turbine.
在复杂的分布式系统中,相同服务的节点常常须要部署上百甚至上千个,不少时候,运维人员但愿可以把相同服务的节点状态以一个总体集群的形式展示出来,这样能够更好的把握整个系统的状态。
注意:
为了演示Turbine,在这里从新新建一个子模块,名为hystrix-dashboard-turbine,建立步骤请看以前的第一章。
建立新模块做为单独的监控节点模块,是由于演示dashboard的时候是耦合在了server-feign中,而Turbine须要同时监控多个服务消费者,把他耦合在一个消费者里显得不合时宜。
建立后,pom.xml中引入:
<dependency>
<groupId>org.springframework.cloud</groupId>
<!--spring boot 1.X:spring-cloud-starter-hystrix-dashboard-->
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-turbine</artifactId>
</dependency>
复制代码
启动类中@EnableTurbine和@EnableHystrixDashboard:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.cloud.netflix.turbine.EnableTurbine;
@SpringBootApplication
@EnableTurbine
@EnableHystrixDashboard
public class HystrixDashboardTurbineApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixDashboardTurbineApplication.class, args);
}
}
复制代码
yml中:
server:
# 服务端口号
port: 8767
spring:
application:
# 服务名,即serviceId
name: hystrix-dashboard-turbine
eureka:
client:
serviceUrl:
# 安全认证的服务注册中心地址
defaultZone: http://localhost:8761/eureka
# 熔断器turbine
turbine:
aggregator:
cluster-config: default
cluster-name-expression: new String("default")
app-config: SERVICE-FEIGN, SERVICE-FEIGN-2
复制代码
代码重点:
完成这些步骤后,咱们还须要调整下服务提供者,咱们须要两个服务提供者同时运行。
将8765(SERVICE-FEIGN)的服务提供者改成8766,名称改成:SERVICE-FEIGN-2,运行起来,别忘了在运行设置中设置容许多个实例运行。修改后的SERVICE-FEIGN的yml是:
server:
# 服务端口号
port: 8766
spring:
application:
# 服务名,即serviceId
name: service-feign-2
eureka:
client:
serviceUrl:
# 安全认证的服务注册中心地址
defaultZone: http://localhost:8761/eureka
# 熔断器设置
feign:
hystrix:
enabled: true
# 熔断器DashBoard: actuator在boot2.0调整后开关web端点的配置,*表明开启全部
management:
endpoints:
web:
exposure:
include: "*"
复制代码
运行后结构如图:
访问 http://localhost:8767/turbine.stream
能够看到ping的信息流,这时说明8767正在不断ping指定的两个服务
进行图形化监控查看,输入:http://localhost:8767/hystrix ,返回酷酷的小熊界面,输入: http://localhost:8767/turbine.stream ,而后点击 Monitor Stream ,能够看到出现了监控列表:
咦?为啥只有一个监控呢,说好的聚合监控列表呢。
这里有个坑,或者说是理解上的误区:
监控不一样的服务熔断,首先得是不一样的rpc调用,也就是消费者的熔断函数要是两个不一样的,或者,消费者去调用的是两个不一样的服务提供者!这样才会有多个监控表。否则,有何意义?
想明白这一步,你就应该知道怎么把多个表弄出来了。
你须要让消费者有一个:
修改server-feign子模块
@FeignClient(value = "service-hi-2", fallback = ServiceHiHystrix.class)
public interface ServiceHi {
/**
* <p>经过Feign伪Http客户端调用service-hi提供的服务</p>
* @author hanchao 2018/5/19 17:59
**/
@GetMapping("/hi/{name}")
String sayHiFromServiceHi2(@PathVariable(value = "name") String name);
}
复制代码
@Component
public class ServiceHiHystrix implements ServiceHi {
@Override
public String sayHiFromServiceHi2(String name) {
return "hello" + name +", this message send failed. By Hystrix.";
}
}
复制代码
return serviceHi.sayHiFromServiceHi2
@RestController
public class HelloController {
/** 注入服务"service-hi"的Feign客户端ServiceHi */
@Autowired
private ServiceHi serviceHi;
/**
* 调用Feign客户端提供的服务,自带负载均衡
* @param name
* @return
*/
@GetMapping("/hello/{name}")
public String sayHi(@PathVariable String name){
//调用Feign客户端ScheduleServiceHi的接口
return serviceHi.sayHiFromServiceHi2(name);
}
}
复制代码
这样改完后,重启这个8766的服务消费者
结构依然不变:
咱们获得了:
这里确实比较难理解哈,坑了我很久。
springcloud(四):熔断器Hystrix
www.ityouknow.com/springcloud…
springcloud(五):熔断监控Hystrix Dashboard和Turbine
www.ityouknow.com/springcloud…
菜鸟SpringCloud实战入门专栏全导航:经过如下两种途径查看
我是蛮三刀把刀,后端开发。主要关注后端开发,数据安全,爬虫等方向。
来微信和我聊聊:yangzd1102
Github我的主页:
同步更新公众号及如下所有博客:
1. Csdn
2. 知乎
3. 掘金
4. 简书
若是文章对你有帮助,不妨收藏起来并转发给您的朋友们~