SpringCloud 系列 --5.SpringCloud-Hystrix

本贴最后更新于 1833 天前,其中的信息可能已经沧海桑田

#搭建 Eureka 服务
pom.xml

<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"> <modelVersion>4.0.0</modelVersion> <groupId>org.crazyit.cloud</groupId> <artifactId>first-hystrix-server</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>1.5.4.RELEASE</version> </dependency> </dependencies> </project>

applicaiton.yml

server: port: 8761 eureka: client: registerWithEureka: false fetchRegistry: false logging: level: com.netflix: INFO

启动类

package org.crazyit.cloud; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication @EnableEurekaServer public class ServerApplication { public static void main(String[] args) { new SpringApplicationBuilder(ServerApplication.class).run(args); } }

搭建 provider

pom.xml

<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"> <modelVersion>4.0.0</modelVersion> <groupId>org.crazyit.cloud</groupId> <artifactId>spring-hystrix-provider</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.SR1</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> </dependencies> </project>

application.yml

spring: application: name: spring-hystrix-provider eureka: instance: hostname: localhost client: serviceUrl: defaultZone: http://localhost:8761/eureka/

实体类 Person

package org.crazyit.cloud; public class Person { private Integer id; private String name; private Integer age; private String message; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }

启动类

package org.crazyit.cloud; import java.util.Scanner; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient public class ProviderApplication { public static void main(String[] args) { // 设置启动的服务器端口 new SpringApplicationBuilder(ProviderApplication.class).properties( "server.port=8080").run(args); } }

Controller 类

package org.crazyit.cloud; import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.UUID; import javax.servlet.http.HttpServletRequest; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @RestController public class PersonController { @RequestMapping(value = "/person/{personId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) public Person findPerson(@PathVariable("personId") Integer personId, HttpServletRequest request) { Person person = new Person(); person.setId(personId); person.setName("Crazyit"); person.setAge(33); person.setMessage(request.getRequestURL().toString()); return person; } @RequestMapping(value = "/hello", method = RequestMethod.GET) public String hello() throws Exception { Thread.sleep(800); return "Hello World"; } @RequestMapping(value = "/persons", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) public List<Person> findPersons(@RequestBody List<Integer> personIds, HttpServletRequest request) { List<Person> result = new ArrayList<Person>(); for(Integer id : personIds) { Person person = new Person(); person.setId(id); person.setName("angus"); person.setAge(new Random().nextInt(30)); person.setMessage(request.getRequestURL().toString()); result.add(person); } return result; } }

搭建调用方

pom.xml
<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"> <modelVersion>4.0.0</modelVersion> <groupId>org.crazyit.cloud</groupId> <artifactId>spring-hystrix-invoker</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.SR1</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> <version>1.5.3.RELEASE</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.2</version> </dependency> </dependencies> </project>
application.yml
server: port: 9000 spring: application: name: spring-hystrix-invoker eureka: instance: hostname: localhost client: serviceUrl: defaultZone: http://localhost:8761/eureka/ feign: hystrix: enabled: true hystrix: command: HelloClient#hello(): execution: isolation: thread: timeoutInMilliseconds: 500 circuitBreaker: requestVolumeThreshold: 3
InvokerApplication 在启动类上面加入断路器注解 @EnableCircuitBreaker
package org.crazyit.cloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.ServletComponentScan; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.netflix.feign.EnableFeignClients; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringBootApplication @EnableDiscoveryClient @EnableCircuitBreaker @ServletComponentScan @EnableFeignClients public class InvokerApplication { @LoadBalanced @Bean public RestTemplate getRestTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(InvokerApplication.class, args); } }
InvokerController
package org.crazyit.cloud; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Future; import org.crazyit.cloud.cache.CacheService; import org.crazyit.cloud.collapse.CollapseService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @RestController @Configuration public class InvokerController { @Autowired private PersonService personService; @Autowired private CacheService cacheService; @Autowired private CollapseService collapseService; @RequestMapping(value = "/router/{personId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) public Person router(@PathVariable Integer personId) { Person p = personService.getPerson(personId); return p; } @RequestMapping(value = "/testConfig", method = RequestMethod.GET) public String testConfig() { String result = personService.testConfig(); return result; } @RequestMapping(value = "/testException", method = RequestMethod.GET) public String testException() { String result = personService.testException(); return result; } @RequestMapping(value = "/cache1/{personId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) public Person testCacheResult(@PathVariable Integer personId) { // 调用多次服务 for(int i = 0; i < 3; i++) { Person p = cacheService.getPerson(personId); System.out.println("控制器调用服务 " + i); } return new Person(); } @RequestMapping(value = "/cache2", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) public String testCacheRemove() { for(int i = 0; i < 3; i++) { cacheService.cacheMethod("a"); System.out.println("控制器调用服务 " + i); } // 清空缓存 cacheService.updateMethod("a"); System.out.println("========== 清空了缓存"); // 再执行多次 for(int i = 0; i < 3; i++) { cacheService.cacheMethod("a"); System.out.println("控制器调用服务 " + i); } return ""; } @RequestMapping(value = "/collapse", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) public String testCollapse() throws Exception { // 连续执行3次请求 Future<Person> f1 = collapseService.getSinglePerson(1); Future<Person> f2 = collapseService.getSinglePerson(2); Future<Person> f3 = collapseService.getSinglePerson(3); Person p1 = f1.get(); Person p2 = f2.get(); Person p3 = f3.get(); System.out.println(p1.getId() + "---" + p1.getName()); System.out.println(p2.getId() + "---" + p2.getName()); System.out.println(p3.getId() + "---" + p3.getName()); return ""; } }
Person
package org.crazyit.cloud; public class Person { Integer id; String name; int age; String message; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
PersonService
package org.crazyit.cloud; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; @Component public class PersonService { @Autowired private RestTemplate restTemplate; @HystrixCommand(fallbackMethod = "getPersonFallback") public Person getPerson(Integer id) { // 使用RestTemplate调用Eureka服务 Person p = restTemplate.getForObject( "http://spring-hystrix-provider/person/{personId}", Person.class, id); return p; } /** * 回退方法,返回一个默认的Person */ public Person getPersonFallback(Integer id) { Person p = new Person(); p.setId(0); p.setName("Crazyit"); p.setAge(-1); p.setMessage("request error"); return p; } /** * 测试配置,对3个key进行命名 * 设置命令执行超时时间为1000毫秒 * 设置命令执行的线程池大小为1 */ @HystrixCommand( fallbackMethod="testConfigFallback", groupKey="MyGroup", commandKey="MyCommandKey", threadPoolKey="MyCommandPool", commandProperties={ @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000") }, threadPoolProperties={ @HystrixProperty(name = "coreSize", value = "1") }) public String testConfig() { try { Thread.sleep(500); } catch (Exception e) { e.printStackTrace(); } return "ok"; } public String testConfigFallback() { return "error"; } /** * 声明了忽略MyException,如果方法抛出MyException,则不会触发回退 */ @HystrixCommand(ignoreExceptions = {MyException.class}, fallbackMethod="testExceptionFallBack") public String testException() { throw new MyException(); } public String testExceptionFallBack() { return "error"; } }
HystrixFilter
package org.crazyit.cloud; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.annotation.WebFilter; import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext; @WebFilter(urlPatterns = "/*", filterName = "hystrixFilter") public class HystrixFilter implements Filter { public void init(FilterConfig filterConfig) throws ServletException { } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HystrixRequestContext context = HystrixRequestContext .initializeContext(); try { chain.doFilter(request, response); } finally { context.shutdown(); } } public void destroy() { } }
CacheService
package org.crazyit.cloud.cache; import org.crazyit.cloud.Person; import org.springframework.stereotype.Component; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheRemove; import com.netflix.hystrix.contrib.javanica.cache.annotation.CacheResult; @Component public class CacheService { @CacheResult @HystrixCommand public Person getPerson(Integer id) { System.out.println("执行 getPerson 方法"); Person p = new Person(); p.setId(id); p.setName("angus"); return p; } /** * 测试删除缓存 * * @param name * @return */ @CacheResult() @HystrixCommand(commandKey = "removeKey") public String cacheMethod(String name) { System.out.println("执行命令"); return "hello"; } @CacheRemove(commandKey = "removeKey") @HystrixCommand public String updateMethod(String name) { return "update"; } }
CollapseService
package org.crazyit.cloud.collapse; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Future; import org.crazyit.cloud.Person; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCollapser; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; @Component public class CollapseService { // 配置收集1秒内的请求 @HystrixCollapser(batchMethod = "getPersons", collapserProperties = { @HystrixProperty(name = "timerDelayInMilliseconds", value = "1000") } ) public Future<Person> getSinglePerson(Integer id) { System.out.println("执行单个获取的方法"); return null; } @HystrixCommand public List<Person> getPersons(List<Integer> ids) { System.out.println("收集请求,参数数量:" + ids.size()); List<Person> ps = new ArrayList<Person>(); for (Integer id : ids) { Person p = new Person(); p.setId(id); p.setName("crazyit"); ps.add(p); } return ps; } }
feign 相关
HelloClient
package org.crazyit.cloud.feign; import org.crazyit.cloud.feign.HelloClient.HelloClientFallback; import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import feign.Feign; @FeignClient(name = "spring-hystrix-provider", fallback = HelloClientFallback.class) public interface HelloClient { @RequestMapping(method = RequestMethod.GET, value = "/hello") public String hello(); @Component static class HelloClientFallback implements HelloClient { public String hello() { return "error hello"; } } }
HelloController
package org.crazyit.cloud.feign; import java.util.Collection; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import com.netflix.hystrix.HystrixCircuitBreaker; import com.netflix.hystrix.HystrixCommandKey; import com.netflix.hystrix.HystrixCommandMetrics; /** * Feign与Hystrix整合 * * @author 杨恩雄 * */ @RestController public class HelloController { @Autowired HelloClient helloClient; @RequestMapping(value = "/feign/hello", method = RequestMethod.GET) public String feignHello() { // hello方法会超时 String helloResult = helloClient.hello(); // 获取断路器 HystrixCircuitBreaker breaker = HystrixCircuitBreaker.Factory .getInstance(HystrixCommandKey.Factory .asKey("HelloClient#hello()")); System.out.println("断路器状态:" + breaker.isOpen()); return helloResult; } }
TestFeignClient
package org.crazyit.cloud.feign; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import org.slf4j.LoggerFactory; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.LoggerContext; public class TestFeignClient { public static void main(String[] args) throws Exception { LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory(); Logger logger = loggerContext.getLogger("root"); logger.setLevel(Level.toLevel("INFO")); // 创建默认的HttpClient final CloseableHttpClient httpclient = HttpClients.createDefault(); // 调用多次服务并输出结果 for(int i = 0; i < 6; i++) { // 建立线程访问接口 Thread t = new Thread() { public void run() { try { String url = "http://localhost:9000/feign/hello"; // 调用 GET 方法请求服务 HttpGet httpget = new HttpGet(url); // 获取响应 HttpResponse response = httpclient.execute(httpget); // 根据 响应解析出字符串 System.out.println(EntityUtils.toString(response.getEntity())); } catch (Exception e) { e.printStackTrace(); } } }; t.start(); } // 等待完成 Thread.sleep(15000); } }
访问 http://localhost:9000/router/111

image.png

把 provider 服务停止后

image.png

可见 @HystrixCommand 注解的 PersonService.getPerson 方法断路器生效了。

默认配置
对于一些默认的配置,例如命令组的key等,可以使用@DefaultProperties注解,这样就减少了@HystrixCommand注解的代码量
package org.crazyit.cloud; import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; @DefaultProperties(groupKey = "GroupPersonKey") public class PersonService2 { @HystrixCommand //groupKey将使用GroupPersonKey public String hello(){ return ""; } }
缓存注解:
* 缓存与合并请求功能需要先初始化请求上下文才能实现,所有才有了上面的HystrixFilter * CacheService中getPerson方法使用注解`@CacheResult`

调用 http://localhost:9000/cache1/22

输出:

执行 getPerson 方法 控制器调用服务 0 控制器调用服务 1 控制器调用服务 2

可见 @CacheResult 注解的 getPerson 方法其实只执行了一次,缓存生效。

缓存主要 3 个注解:

  • @CacheResult: 注释方法,标识被注解的方法返回结构将会被缓存,需要与 @HystrixCommand 一起使用
  • @CacheRemove: 用于修饰方法让缓存失效,需要与 @CacheResult 的缓存 key 关联。
  • @CacheKey: 用于修饰方法参数,标识该参数作为缓存的 key.

如上述代码 CacheService 中,先调用 cacheMethod 方法会把结果存储起来,再次调用则不会执行方法,然后调用 updateMethod 方法可以清除对应的缓存,下次再调用 cacheMethod 方法则会执行具体的方法逻辑。

访问 http://localhost:9000/cache2
输出如下:

执行命令 控制器调用服务 0 控制器调用服务 1 控制器调用服务 2 ========== 清空了缓存 执行命令 控制器调用服务 0 控制器调用服务 1 控制器调用服务 2

注意: 这里说的缓存指的是在一次请求中,如果单独请求多次,则每次都会执行对应的方法。

合并请求注解 见代码 CollapseService

最后真实执行的方法为 getPersons,getSinglePerson 方法使用了 @HystrixCollapser 注解,会收集 1s 内调用 getSinglePerson 的请求,放到 getPersons 方法中进行批处理。

访问 http://localhost:9000/collapse
控制台输出:

收集请求,参数数量:3 1---crazyit 2---crazyit 3---crazyit
Feign 与 Hystrix 整合
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency>
feign: hystrix: enabled: true

启动类加对应注解:

@SpringBootApplication @EnableDiscoveryClient @EnableCircuitBreaker @ServletComponentScan @EnableFeignClients

新建 Feign 接口

package org.crazyit.cloud.feign; import org.crazyit.cloud.feign.HelloClient.HelloClientFallback; import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import feign.Feign; @FeignClient(name = "spring-hystrix-provider", fallback = HelloClientFallback.class) public interface HelloClient { @RequestMapping(method = RequestMethod.GET, value = "/hello") public String hello(); @Component static class HelloClientFallback implements HelloClient { public String hello() { return "error hello"; } } }

调用服务提供者 spring-hystrix-provider 的 /hello 服务,默认情况下 Hystrix 超时时间为 1s,让服务端睡眠 800 毫秒

@RequestMapping(value = "/hello", method = RequestMethod.GET) public String hello() throws Exception { Thread.sleep(800); return "Hello World"; }

然后配置 hystrix 超时为 500 毫秒

hystrix: command: HelloClient#hello(): execution: isolation: thread: timeoutInMilliseconds: 500 circuitBreaker: requestVolumeThreshold: 3

如果全局配置超时可以使用
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds
默认时间段内发生的请求数:
hystrix.command.default.circuitBreaker.requestVolumeThreshold
如果针对某个客户端,使用下面的配置片段(CommandKey):
hystrix.command.CommandKey.circuitBreaker.requestVolumeThreshold

Feign 与 Hystrix 整合使用时,会自动帮我们生产 CommandKey,格式为:Feign 客户端接口名#房法名().例如本例中的客户端为 HelloClient,方法为 hello,生成的 CommandKey 为 HelloClient#hello()。默认情况下,生成的 GroupKey 为 @FeignClient 注解的 name 属性。

在 HelloController 中调用 helloClient 的 hello 方法. 由于配置请求超过 3 次并且失败率超过 50% 断路器将会被打开。

运行 TestFeignClient 输出:

断路器状态:false 断路器状态:false 断路器状态:false 断路器状态:false 断路器状态:true 断路器状态:true

可见到第 4 个请求之后断路器被打开了,但是为什么是第四个之后 ,莫非是设置的 requestVolumeThreshold + 1 得到的?(经测试如果设置 requestVolumeThreshold 为 1,则(第二个之后)第三个会输出断路器状态 true).

Hystrix 监控
加入Actuator
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> <version>1.5.3.RELEASE</version> </dependency>

访问 http://localhost:9000/hystrix.stream 会输出 stream 数据
image.png

新建一个监控项目加入依赖:
<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"> <modelVersion>4.0.0</modelVersion> <groupId>org.crazyit.cloud</groupId> <artifactId>hystrix-dashboard</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.SR1</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> <version>1.5.3.RELEASE</version> </dependency> </dependencies> </project>

打开 @EnableHystrixDashboard 注解:

package org.crazyit.cloud; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; @SpringBootApplication @EnableHystrixDashboard public class MyApplication { public static void main(String[] args) { // 设置启动的服务器端口 new SpringApplicationBuilder(MyApplication.class).properties( "server.port=8082").run(args); } }

启动项目访问: http://localhost:8082/hystrix
并输入我们刚才的 stream 地址:
image.png

image.png
可以看到 HelloClient#hello()断路器被打开了。

如果需要监控整个集群的情况,可以使用 Turbine 框架。

  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    946 引用 • 1460 回帖 • 1 关注
  • Hystrix
    7 引用

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...