雪崩效应
在微服务架构中通常会有多个服务层调用,基础服务的故障可能会导致级联故障,进而造成整个系统不可用的情况,这种现象被称为服务雪崩效应。服务雪崩效应是一种因“服务提供者”的不可用导致“服务消费者”的不可用,并将不可用逐渐放大的过程。
如果下图所示:A作为服务提供者,B为A的服务消费者,C和D是B的服务消费者。A不可用引起了B的不可用,并将不可用像滚雪球一样放大到C和D时,雪崩效应就形成了。
熔断器(CircuitBreaker)
熔断器的原理很简单,如同电力过载保护器。它可以实现快速失败,如果它在一段时间内侦测到许多类似的错误,会强迫其以后的多个调用快速失败,不再访问远程服务器,从而防止应用程序不断地尝试执行可能会失败的操作,使得应用程序继续执行而不用等待修正错误,或者浪费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)来隔离资源.
Feign Hystrix
三个服务
spring-cloud-consumer-hystrix服务下
remove文件下
1、spring-cloud-consumer-hystrix服务中配置文件application.properties:
spring.application.name=spring-cloud-consumer-hystrix
server.port=9001
feign.hystrix.enabled=true
eureka.client.serviceUrl.defaultZone=http://localhost:8000/eureka/
2、controller文件下的ConsumerController 添加fallback属性
@RestController
public class ConsumerController {
@Autowired
HelloRemote HelloRemote;
@RequestMapping("/hello/{name}")
public String index(@PathVariable("name") String name) {
return HelloRemote.hello(name);
}
}
3、调用remove文件下HelloRemove,成功则调用spring-cloud-producer服务的/hello
@FeignClient(name= "spring-cloud-producer", fallback = HelloRemoteHystrix.class)
public interface HelloRemote {
@RequestMapping(value = "/hello")
public String hello(@RequestParam(value = "name") String name);
}
spring-cloud-producer服务下的/hello
@RestController
public class HelloController {
@RequestMapping("/hello")
public String index(@RequestParam String name) {
return "hello "+name+",this is first messge";
}
}
4、调用remove文件下HelloRemove,失败则回调fallback = HelloRemoteHystrix.class
@Component
public class HelloRemoteHystrix implements HelloRemote{
@Override
public String hello(@RequestParam(value = "name") String name) {
return "hello " +name+", this messge send failed ";
}
}
5、测试
那我们就来测试一下看看效果吧。
依次启动spring-cloud-eureka、spring-cloud-producer、spring-cloud-consumer三个项目。
浏览器中输入: http://localhost:9001/hello/neo
返回: hello neo,thisisfirst messge
说明加入熔断相关信息后,不影响正常的访问。接下来我们手动停止spring-cloud-producer项目再次测试:
浏览器中输入: http://localhost:9001/hello/neo
返回: hello neo,thismessge send failed
根据返回结果说明熔断成功。
示例代码:https://github.com/ityouknow/spring-cloud-starter
熔断监控Hystrix Dashboard和Turbine
Hystrix-dashboard是一款针对Hystrix进行实时监控的工具,通过Hystrix Dashboard我们可以在直观地看到各Hystrix Command的请求响应时间, 请求成功率等数据。但是只使用Hystrix Dashboard的话, 你只能看到单个应用内的服务信息, 这明显不够. 我们需要一个工具能让我们汇总系统内多个服务的数据并显示到Hystrix Dashboard上, 这个工具就是Turbine.
Hystrix Dashboard
我们在熔断示例项目spring-cloud-consumer-hystrix的基础上更改,重新命名为:spring-cloud-consumer-hystrix-dashboard。
1、添加依赖
-
<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-starter-hystrix</artifactId>
-
</dependency>
-
<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
-
</dependency>
-
<dependency>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-actuator</artifactId>
-
</dependency>
这三个包必须添加
2、启动类
启动类添加启用Hystrix Dashboard和熔断器
-
@SpringBootApplication
-
@EnableDiscoveryClient
-
@EnableFeignClients
-
@EnableHystrixDashboard
-
@EnableCircuitBreaker
-
public class ConsumerApplication {
-
-
public static void main(String[] args) {
-
SpringApplication.run(ConsumerApplication.class, args);
-
}
-
}
3、测试
启动工程后访问 http://localhost:9001/hystrix,将会看到如下界面:
图中会有一些提示:
Cluster via Turbine (default cluster): http://turbine-hostname:port/turbine.stream
Cluster via Turbine (custom cluster): http://turbine-hostname:port/turbine.stream?cluster=[clusterName]
Single Hystrix App: http://hystrix-app:port/hystrix.stream
大概意思就是如果查看默认集群使用第一个url,查看指定集群使用第二个url,单个应用的监控使用最后一个,我们暂时只演示单个应用的所以在输入框中输入: http://localhost:9001/hystrix.stream ,输入之后点击 monitor,进入页面。
如果没有请求会先显示 Loading...
,访问http://localhost:9001/hystrix.stream 也会不断的显示ping。
请求服务http://localhost:9001/hello/neo,就可以看到监控的效果了,首先访问http://localhost:9001/hystrix.stream,显示如下:
-
ping:
-
data: {"type":...}
-
data: {"type":...}
说明已经返回了监控的各项结果
到监控页面就会显示如下图:
其实就是http://localhost:9001/hystrix.stream返回结果的图形化显示,Hystrix Dashboard Wiki上详细说明了图上每个指标的含义,如下图:
到此单个应用的熔断监控已经完成。
Turbine
在复杂的分布式系统中,相同服务的节点经常需要部署上百甚至上千个,很多时候,运维人员希望能够把相同服务的节点状态以一个整体集群的形式展现出来,这样可以更好的把握整个系统的状态。 为此,Netflix提供了一个开源项目(Turbine)来提供把多个hystrix.stream的内容聚合为一个数据源供Dashboard展示。
1、添加依赖
-
<dependencies>
-
<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-starter-turbine</artifactId>
-
</dependency>
-
<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-netflix-turbine</artifactId>
-
</dependency>
-
<dependency>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-actuator</artifactId>
-
</dependency>
-
<dependency>
-
<groupId>org.springframework.cloud</groupId>
-
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
-
</dependency>
-
</dependencies>
2、配置文件
-
spring.application.name=hystrix-dashboard-turbine
-
server.port=8001
-
turbine.appConfig=node01,node02
-
turbine.aggregator.clusterConfig= default
-
turbine.clusterNameExpression= new String("default")
-
-
eureka.client.serviceUrl.defaultZone=http://localhost:8000/eureka/
-
turbine.appConfig
:配置Eureka中的serviceId列表,表明监控哪些服务 -
turbine.aggregator.clusterConfig
:指定聚合哪些集群,多个使用","分割,默认为default。可使用http://.../turbine.stream?cluster={clusterConfig之一}
访问 -
turbine.clusterNameExpression
: 1. clusterNameExpression指定集群名称,默认表达式appName;此时:turbine.aggregator.clusterConfig
需要配置想要监控的应用名称;2. 当clusterNameExpression: default时,turbine.aggregator.clusterConfig
可以不写,因为默认就是default;3. 当clusterNameExpression: metadata['cluster']时,假设想要监控的应用配置了eureka.instance.metadata-map.cluster:ABC
,则需要配置,同时turbine.aggregator.clusterConfig:ABC
3、启动类
启动类添加 @EnableTurbine
,激活对Turbine的支持
-
@SpringBootApplication
-
@EnableHystrixDashboard
-
@EnableTurbine
-
public class DashboardApplication {
-
-
public static void main(String[] args) {
-
SpringApplication.run(DashboardApplication.class, args);
-
}
-
-
}
到此Turbine(hystrix-dashboard-turbine)配置完成
4、测试
在示例项目spring-cloud-consumer-hystrix基础上修改为两个服务的调用者spring-cloud-consumer-node1和spring-cloud-consumer-node2
spring-cloud-consumer-node1项目改动如下: application.properties文件内容
-
spring.application.name=node01
-
server.port=9001
-
feign.hystrix.enabled=true
-
-
eureka.client.serviceUrl.defaultZone=http://localhost:8000/eureka/
spring-cloud-consumer-node2项目改动如下: application.properties文件内容
-
spring.application.name=node02
-
server.port=9002
-
feign.hystrix.enabled=true
-
-
eureka.client.serviceUrl.defaultZone=http://localhost:8000/eureka/
HelloRemote类修改:
-
@FeignClient(name= "spring-cloud-producer2", fallback = HelloRemoteHystrix.class)
-
public interface HelloRemote {
-
@RequestMapping(value = "/hello")
-
public String hello2(@RequestParam(value = "name") String name);
-
}
对应的 HelloRemoteHystrix
和 ConsumerController
类跟随修改,具体查看代码
修改完毕后,依次启动spring-cloud-eureka、spring-cloud-consumer-node1、spring-cloud-consumer-node1、hystrix-dashboard-turbine(Turbine)
打开eureka后台可以看到注册了三个服务:
访问 http://localhost:8001/turbine.stream
返回:
-
: ping
-
data: {"reportingHostsLast10Seconds":1,"name":"meta","type":"meta","timestamp":1494921985839}
并且会不断刷新以获取实时的监控数据,说明和单个的监控类似,返回监控项目的信息。进行图形化监控查看,输入:http://localhost:8001/hystrix,返回酷酷的小熊界面,输入: http://localhost:8001/turbine.stream,然后点击 Monitor Stream ,可以看到出现了俩个监控列表