Hystrix之服務降級代碼演示

服務降級就是指服務器忙,請稍候再試,不讓客戶端等待並立刻返回一個友好提示,fallback

哪些情況會觸發降級:程序運行異常,超時,服務熔斷觸發服務降級,線程池/信號量打滿也會導致服務降級;

服務降級分爲 服務端降級 和 客戶端降級,好比一雙筷子,你可以夾肉,也可以夾菜,不過一般是用來在客戶端降級使用,具體情況具體分析使用。下面分別舉例在服務端降級和 客戶端降級代碼演示。有個前提啊,就是項目中已經加入了Hystrix的包依賴支持,酌情選擇添加

    <!--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>

服務端降級

1、需要使用@HystrixCommand,設置兜底即fallback降級方法,設置攔截異常信息。8001服務正常timeout時間爲6s,但是服務降級做了5秒等待限制,超過了就不再等待,進行服務降級,調用fallback方法;

package com.king.springcloud.service;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * created by king on 2020/4/16 3:22 下午
 */
@Service
public class PaymentHystrixService {

    /**
     * 成功訪問
     *
     * @param id
     * @return
     */
    public String getOk(Integer id) {
        return "線程池:" + Thread.currentThread().getName() + " ID:" + id + "\t 訪問成功";
    }

    /**
     * 訪問超時
     *
     * @param id
     * @return
     * 5000是指5s
     */
    @HystrixCommand(fallbackMethod ="paymentFallback_handler",commandProperties = {
            @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "5000")
    })
    public String getTimeout(Integer id) {
        int timeout = 6;
        try {
            TimeUnit.SECONDS.sleep(timeout);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "線程池:" + Thread.currentThread().getName() + " ID:" + id + "\t 訪問超時,超時時間(秒):" + timeout;
    }

    public String paymentFallback_handler(Integer id){
        return "線程池:" + Thread.currentThread().getName() + " paymentFallback_handler---ID:" + id + "\t ";
    }
}

2、主啓動類加註解@EnableCircuitBreaker

package com.king.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;

/**
 * created by king on 2020/4/16 3:21 下午
 */
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class PaymentHystrixMain8001 {
    public static void main(String[] args) {
            SpringApplication.run(PaymentHystrixMain8001.class,args);
        }
}

3、測試結果展示

此時服務端的服務降級就完成代碼演示開發了,下面介紹客戶端服務降級演示

客戶端服務降級

80訂單微服務,也可以更好的保護自己,自己也依樣畫葫蘆進行客戶端降級保護。

服務降級,客戶端去調用服務端,碰上服務端宕機或關閉,本次案例服務降級處理是在客戶端80實現完成的,與服務端8001沒有關係,只需要爲Feign客戶端定義的接口添加一個服務降級處理的實現類即可實現解耦;未來我們要面對的異常有:運行時異常比如1/0的異常,超時異常 比如sleep(5),宕機 即服務端服務器宕機等等

1、首先需要配置yml,啓動feign的hystrix支持

feign:
  hystrix:
    #如果處理自身的容錯就開啓。開啓方式與生產端不一樣。
    enabled: true

2、主啓動類加上啓用註解@EnableHystrix

package com.king.springcloud;

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

/**
 * created by king on 2020/4/16 5:39 下午
 */
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@EnableHystrix
public class OrderFeignHystrixMain80 {
    public static void main(String[] args) {

            SpringApplication.run(OrderFeignHystrixMain80.class,args);
        }
}

3、在controller接口上加註解,配置fallback降級兜底方法,進行請求超時等情況下的服務降級

package com.king.springcloud.controller;

import com.king.springcloud.service.OrderFeignHystrixService;
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;

/**
 * created by king on 2020/4/16 5:43 下午
 */
@RestController
@Slf4j
public class OrderFeignHystrixController {
    @Resource
    private OrderFeignHystrixService orderFeignHystrixService;

    @GetMapping(value = "/payment/ok/{id}")
    public String getOK(@PathVariable("id") Integer id) {
        return orderFeignHystrixService.getOk(id);
    }

    @GetMapping(value = "/payment/timeout/{id}")
    @HystrixCommand(fallbackMethod = "fallbackHystrix_handler_order",
            commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1500")})
    public String getTimeout(@PathVariable("id") Integer id) {
        return orderFeignHystrixService.getTimeout(id);
    }

    public String fallbackHystrix_handler_order(@PathVariable("id") Integer id){
        return "80請求服務失敗";
    }
}

此處設置的請求超時時間爲1500毫秒,而8001提供的服務超時時間是3000毫秒,所以客戶端請求會直接請求超時,調用服務降級fallback方法,結果展示

上面是簡單的服務降級舉例,但是每個業務方法對應一個兜底的fallback方法,會造成代碼膨脹。而降級fallback方法和業務代碼混亂在一起,所以一般會進行處理,將統一和自定義的進行區分開,或者將fallback方法從業務代碼中抽取出來;

統一和自定義分開:

一、在客戶端服務降級,統一處理方式

  •   在controller上加統一@DefaultProperties(defaultFallback = "globle_fallbackHystrix_handler")註解
  •   在接口上統一加 @HystrixCommand註解
  •   自定義的降級處理方法,扔參照timeout的接口自定義服務降級處理方法
package com.king.springcloud.controller;

import com.king.springcloud.service.OrderFeignHystrixService;
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;

/**
 * created by king on 2020/4/16 5:43 下午
 */
@RestController
@Slf4j
@DefaultProperties(defaultFallback = "globle_fallbackHystrix_handler")
public class OrderFeignHystrixController {
    @Resource
    private OrderFeignHystrixService orderFeignHystrixService;

    @GetMapping(value = "/payment/ok/{id}")
    @HystrixCommand
    public String getOK(@PathVariable("id") Integer id) {
        return orderFeignHystrixService.getOk(id);
    }

    @GetMapping(value = "/payment/timeout/{id}")
    @HystrixCommand(fallbackMethod = "fallbackHystrix_handler_order",
            commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1500")})
    public String getTimeout(@PathVariable("id") Integer id) {
        return orderFeignHystrixService.getTimeout(id);
    }

    public String fallbackHystrix_handler_order(@PathVariable("id") Integer id){
        return "80請求服務失敗";
    }

    public String globle_fallbackHystrix_handler(){
        return "請求服務失敗,返回全局服務降級處理方法";
    }
}

二、將降級方法從業務代碼中抽取出來,不再糅合的處理方法

  •   去掉上述方法中 在controller上加統一@DefaultProperties(defaultFallback = "globle_fallbackHystrix_handler")註解
  •   去掉在接口上統一加 @HystrixCommand註解
  •   保留 yml中的feign啓用hystrix的配置
  •   新建FallbackServiceHandler類,實現接口OrderFeignHystrixService,並重寫每一個方法,作爲兜底fallback服務降級
  •   在OrderFeignHystrixService的feign註解配置上,指定兜底fallback服務降級類
package com.king.springcloud.service;

import org.springframework.stereotype.Component;

/**
 * created by king on 2020/4/17 1:31 下午
 */
@Component
public class FallbackServiceHandler implements OrderFeignHystrixService {

    public String getOk(Integer id) {
        return null;
    }

    public String getTimeout(Integer id) {
        return null;
    }
}
package com.king.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;

/**
 * created by king on 2020/4/16 5:40 下午
 */
@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE-HYSTRIX",fallback = FallbackServiceHandler.class)
public interface OrderFeignHystrixService {


    @GetMapping(value = "/payment/ok/{id}")
    public String getOk(@PathVariable("id") Integer id);

    @GetMapping(value = "/payment/timeout/{id}")
    public String getTimeout(@PathVariable("id") Integer id);
}

測試結果如下

 

 

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