斷路器,AOP實現斷路器模式 ------------Hystrix

斷路器:https://martinfowler.com/bliki/CircutiBreaker.htmlhtml

核心思想:java

  在斷路器對象中封裝受保護的方法調用。web

  該斷路器監控調用和斷路狀況spring

  調用失敗觸發閾值後,後續調用直接由短路器返回錯誤,再也不執行實際調用。服務器

理解:網絡

  客戶端經過circuit breaker調用服務提供者,正常的時候能夠調用。若是服務提供方出現了問題,發生了超時, 前幾回能夠超時處理, 到達一個閥值能夠經過斷路器進行處理, 就再也不向服務方發起請求。app

  

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

@Aspect
@Component
@Slf4j
public class CircuitBreakerAspect {
    // 閥值
    private static final Integer THRESHOLD = 3;
    //記錄失敗的次數
    private Map<String, AtomicInteger> counter = new ConcurrentHashMap<>();
    // 記錄被保護的次數
    private Map<String, AtomicInteger> breakCounter = new ConcurrentHashMap<>();

    /**
     *
     * @param pjp 程序鏈接點
     * @return
     * @throws Throwable
     */
    @Around("execution(* 攔截的區域")
    public Object doWithCircuitBreaker(ProceedingJoinPoint pjp) throws Throwable {
        // 獲取當前執行的方法
        String signature = pjp.getSignature().toLongString();
        log.info("Invoke {}", signature);
        Object retVal;
        try {
            if (counter.containsKey(signature)) {
                // 失敗次數達到預製,若是保護次數沒到,返回null
                if (counter.get(signature).get() > THRESHOLD &&
                        breakCounter.get(signature).get() < THRESHOLD) {
                    log.warn("Circuit breaker return null, break {} times.",
                            breakCounter.get(signature).incrementAndGet());
                    return null;
                }
            } else {
                counter.put(signature, new AtomicInteger(0));
                breakCounter.put(signature, new AtomicInteger(0));
            }
            retVal = pjp.proceed();
            counter.get(signature).set(0);
            breakCounter.get(signature).set(0);
        } catch (Throwable t) {
            log.warn("Circuit breaker counter: {}, Throwable {}",
                    counter.get(signature).incrementAndGet(), t.getMessage());
            breakCounter.get(signature).set(0);
            throw t;
        }
        return retVal;
    }
}

 

Hystrix

Hystrix [hɪst'rɪks],中文含義是豪豬,因其背上長滿棘刺,從而擁有了自我保護的能力。本文所說的Hystrix是Netflix開源的一款容錯框架,一樣具備自我保護能力。爲了實現容錯和自我保護,下面咱們看看Hystrix如何設計和實現的。框架

Hystrix設計目標ide

  • 對來自依賴的延遲和故障進行防禦和控制——這些依賴一般都是經過網絡訪問的
  • 阻止故障的連鎖反應
  • 快速失敗並迅速恢復
  • 回退並優雅降級
  • 提供近實時的監控

 

 

實現了斷路服務器模式ui

在須要服務熔斷的方法上添加@HystrixCommand註解, fallbackMethod指定熔斷的地址,默認狀況下@HystrixCommand是在另一個線程執行的。能夠作一些超時的處理。

@HystrixProperty(name="excution.isolation.strategy",value="SEMAPHORE")設置爲信號

  

 

 Hystrix配置項參考:

Spring cloud 支持

  spring-cloud-starter-netfixi-hystrix

  @EnableCircuitBreaker

Feign支持

  feign.hystrix.enable=true

  @FeignClient

    fallback / fallbackFactory

簡單示例:

  pom引入

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

  application.properties

 
 
feign.client.config.default.connect-timeout=500
feign.client.config.default.read-timeout=500


#開啓feign支持 feign.hystrix.enabled
=true

#cousul鏈接配置
spring.cloud.consul.host=localhost
spring.cloud.consul.port=8500
spring.cloud.consul.discovery.prefer-ip-address=true
 

bootstarp.properties

spring.application.name=name-service

開啓註解:

@EnableDiscoveryClient // 註冊發現服務
@EnableFeignClients // feign的支持
@EnableCircuitBreaker // feignClient的演示
  //Spring  cloud 支持
    @PostMapping("/order")
    @HystrixCommand(fallbackMethod = "fallbackCreateOrder")
    public CoffeeOrder createOrder() {
     /*業務代碼*/
        return order;
    }


    public CoffeeOrder fallbackCreateOrder() {
        log.warn("Fallback to NULL order.");
        return null;
    }
//FeignClient 的支持


import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

@FeignClient(name = "waiter-service", contextId = "coffee",
        qualifier = "coffeeService", path="/coffee",
        fallback = FallbackCoffeeService.class)
// 若是用了Fallback,不要在接口上加@RequestMapping,path能夠用在這裏
public interface TestService {

    @GetMapping("/{id}")
    Product getById(@PathVariable Long id);

}

/*實現TestService*/


import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Collections;
import java.util.List;

@Slf4j
@Component
public class FallbackTestService implements TestService{


    @Override
    public Product getById(Long id) {
        /**發送了壟斷的邏輯代碼*/
        return null;
    }
    
}
/**Controller調用*/

    @GetMapping("testGetById")
    public  String  testGetById() {
            TestService.getById((long) 1);
        return "";
    }
相關文章
相關標籤/搜索