spring cloud:三、斷路器(hystrix)

在分佈式系統中,根據業務來拆分成一個個的微服務,服務與服務之間可以相互調用(RPC),在spring cloud 中可以用RestTemplate+ribbon和feign來調用。爲了保證其高可用,單個服務有時候會集羣部署,由於網絡或程序自躾 的原因,服務並不能保證百分百可靠可用,如果單個服務出現問題,調用這個服務就出現線程阻塞,此時若有大量的請求涌入,servlet容器的線程資源就會被消耗完畢導致服務癱瘓。服務與服務之間的依賴性,故障會傳播,會對整個微服務系統造成不可估量的嚴重後果,這就是常說的服務故障的“雪崩效應”。爲了解決這個問題,有人就提出了一種解決問題的思路,斷路器模型。就是每一個調用服務的接口處加一個斷路器,默認是關閉的,當對服務調用時,不可用的次數達到一個閥值時,斷路器就會打開,通過回調方法迅速返回一個值結束調用,避免出現連鎖故障。

 

一、改造上一篇文章的zhangsanService(ribbon+restTemplate方式),在pom.xml中加入hystrix的依賴

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

改造啓動類ZhangsanServiceApplication.java:

package com.gaox.zhangsanService;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableEurekaClient
@EnableHystrix
@RestController
public class ZhangsanServiceApplication {

   public static void main(String[] args) {
      SpringApplication.run(ZhangsanServiceApplication.class, args);
   }
   @Bean
   @LoadBalanced
   public RestTemplate restTemplate(){
      return new RestTemplate();
   }

   @Autowired
   private RestTemplate restTemplate;

   @RequestMapping("/hello")
   @HystrixCommand(fallbackMethod = "helloError")
   public String hello(String name){
      String result=restTemplate.getForObject("http://HELLOSERVICE/hello?name="+name,String.class);
      return result;

   }
   public String helloError(String name){
      return "hello  ,"+name+"!  sorry ,error !";
   }
}

 

依次啓動,serviceCenter,helloService:8762,helloService:8763,zhangsanService,在瀏覽器中訪問http://localhost:8764/hello?name=zhangsan

瀏覽器依次會顯示

你好,zhangsan我是helloService,端口是8762

你好,zhangsan。我是helloService,端口是8763

此時關閉helloService:8763, http://localhost:8764/hello?name=zhangsan

瀏覽器依次會顯示

你好,zhangsan。我是helloService,端口是8762

hello ,zhangsan! sorry ,error !

這說明當zhangsanService調用的服務helloService:8763不可用時,會執行快速失敗,直接返回一個字符串,而不是等待響應超時,這就很好的控制了當大量請求涌入的時候線程不會阻塞

 

二、feign是自帶斷路器的,spring cloud的有些版本中,默認是關閉的,需要在配置文件中打開它,下面上一篇文章中的lisiService爲基礎來改造一下

Application.properties:

server.port=8765
spring.application.name=lisiService
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
feign.hystrix.enabled=true

 

LisiServiceApplication.java:

package com.gaox.lisiService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@RestController
public class LisiServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(LisiServiceApplication.class, args);
    }


    @FeignClient(value = "helloService" ,fallback = HelloError.class)
    public interface HelloService {
        @RequestMapping(value = "/hello", method = RequestMethod.GET)
         String hello(@RequestParam("name") String name);
    }
    @Component
    public class HelloError implements HelloService {
        @Override
        public String hello(String name){
            return "hello  ,"+name+"!  sorry ,error !";
        }
    }
    @Autowired
   private HelloService helloService;

    @RequestMapping("/hello")
    public String hello(@RequestParam("name")String name){
    return helloService.hello(name);
    }
}

依次啓動serviceCenter,helloService:8762,helloService:8763,lisiService,然後在瀏覽器輸入http://localhost:8765/hello?name=lisi,瀏覽器會交替顯示

你好,lisi。我是helloService,端口是8762

你好,lisi。我是helloService,端口是8763

此時關閉helloService:8763, http://localhost:8764/hello?name=zhangsan

瀏覽器依次會顯示

你好,lisi。我是helloService,端口是8762

hello , lisi! sorry ,error !

這說明斷路器起作用了,當lisiService調用的服務helloService:8763不可用時,會執行快速失敗,直接返回一個字符串,而不是等待響應超時,這就很好的控制了當大量請求涌入的時候線程不會阻塞

三、在feign中使用hystrix dashboard(儀表盤)功能

Pom.xml添加以下內容:

<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>
</dependency>
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
</dependency>
LisiServiceApplication.java啓動類上加兩個註解@EnableHystrixDashboard
和@EnableCircuitBreaker

package com.gaox.lisiService;

import
org.springframework.beans.factory.annotation.Autowired;
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;
import
org.springframework.cloud.netflix.feign.EnableFeignClients;
import
org.springframework.cloud.netflix.feign.FeignClient;
import
org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import
org.springframework.stereotype.Component;
import
org.springframework.web.bind.annotation.RequestMapping;
import
org.springframework.web.bind.annotation.RequestMethod;
import
org.springframework.web.bind.annotation.RequestParam;
import
org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@RestController
@EnableHystrixDashboard
@EnableCircuitBreaker
publicclass LisiServiceApplication {

   
public static void main(String[]args) {
        SpringApplication.run(LisiServiceApplication.
class, args);
   
}


   
@FeignClient(value = "helloService",fallback = HelloError.class)
   
public interface HelloService{
       
@RequestMapping(value = "/hello", method =RequestMethod.GET)
         String
hello(@RequestParam("name") Stringname);
   
}
   
@Component
   
public class HelloError implements HelloService{
       
@Override
       
public String hello(Stringname){
           
return "hello  ,"+name+"!  sorry ,error !";
       
}
    }
   
@Autowired
  
private HelloService helloService;

   
@RequestMapping("/hello")
   
public String hello(@RequestParam("name")Stringname){
   
return helloService.hello(name);
   
}
}

打開瀏覽器:訪問http://localhost:8765/hystrix,界面如下

第一個輸入框:http://localhost:8765/hystrix.stream

Delay:默認不變即可

Title:(這個可以隨便輸入)


然後點擊按鈕進入,如圖


四、在ribbon中使用hystrix dashboard(儀表盤)功能

Pom.xml添加以下內容:


<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>
LisiServiceApplication.java啓動類上加個註解@EnableHystrixDashboard
package com.gaox.zhangsanService;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableEurekaClient
@EnableHystrix
@EnableHystrixDashboard
@RestController
public class ZhangsanServiceApplication {

   public static void main(String[] args) {
      SpringApplication.run(ZhangsanServiceApplication.class, args);
   }
   @Bean
   @LoadBalanced
   public RestTemplate restTemplate(){
      return new RestTemplate();
   }

   @Autowired
   private RestTemplate restTemplate;

   @RequestMapping("/hello")
   @HystrixCommand(fallbackMethod = "helloError")
   public String hello(String name){
      String result=restTemplate.getForObject("http://HELLOSERVICE/hello?name="+name,String.class);
      return result;

   }
   public String helloError(String name){
      return "hello  ,"+name+"!  sorry ,error !";
   }
}
然後打開瀏覽器之後的操作和上面feign方法的一樣。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章