SpringCloud學習記錄(二)負載均衡,服務熔斷,服務降級,服務限流

Ribbon實現負載均衡

負載均衡,英文名稱爲Load Balance,其含義就是指將負載(工作任務)進行平衡、分攤到多個操作單元上進行運行,例如FTP服務器、Web服務器、企業核心應用服務器和其它主要任務服務器等,從而協同完成工作任務。

  1. 導入pom依賴

單獨導入

  <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
            <version>2.2.1.RELEASE</version>
  </dependency>

整合依賴spring-cloud-starter-netflix-eureka-client裏面也包含了ribbon的依賴

  <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>2.2.1.RELEASE</version>
  </dependency>
  1. 在主啓動類所在包的上一級創建一個包,用來創建自定義負載均衡策略類
    在這裏插入圖片描述
    書寫自定義負載均衡策略類,先繼承AbstractLoadBalancerRule抽象類,該類是IRule接口的一個抽象實現類,繼承它,然後自定義自己的負載均衡策略,注入spring容器即可覆蓋原有的輪詢策略。
    在這裏插入圖片描述
public class HcodeRule extends AbstractLoadBalancerRule {
    //每個服務,訪問5次,然後循環所有服務
    private AtomicInteger total = new AtomicInteger(0); //服務被調用的次數
    private AtomicInteger currentIndex = new AtomicInteger(0); //當前被調用服務的下標
    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            return null;
        }
        Server server = null;

        while (server == null) {
            if (Thread.interrupted()) {
                return null;
            }
            //獲得活着的服務
            List<Server> upList = lb.getReachableServers();
            //獲得全部服務
            List<Server> allList = lb.getAllServers();

            int serverCount = allList.size();
            if (serverCount == 0) {

                return null;
            }
//            //生成區間隨機數
//            int index = chooseRandomInt(serverCount);
//            server = upList.get(index); //從或者的服務中隨機獲取一個
            /*============================================*/
            if(total.get()<5){
               server = upList.get(currentIndex.get());
                getAndIncrement(total);
            }else{
                total.set(0);
                getAndIncrement(currentIndex);
                if(currentIndex.get()>=upList.size()){
                    currentIndex.set(0);
                }
                server = upList.get(currentIndex.get());
                getAndIncrement(total);
            }

            /*==============================================*/
            if (server == null) {
                Thread.yield();
                continue;
            }

            if (server.isAlive()) {
                return (server);
            }

            // Shouldn't actually happen.. but must be transient or a bug.
            server = null;
            Thread.yield();
        }

        return server;

    }
    //自旋鎖防止高併發情況數據不一致性
    private final int getAndIncrement(AtomicInteger atomicInteger){
        int current;
        int next;
        do {
            current = atomicInteger.get();
            next = current >= 2147483647 ? 0 : current + 1;
        }while (!atomicInteger.compareAndSet(current,next));  //第一個參數是期望值,第二個參數是修改值是
        return next;
    }

    protected int chooseRandomInt(int serverCount) {
        return ThreadLocalRandom.current().nextInt(serverCount);
    }
    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
        // TODO Auto-generated method stub

    }
	@Override
	public Server choose(Object key) {
		return choose(getLoadBalancer(), key);
	}


}

再將該策略類注入IOC容器,當然如果不想寫自定義策略類,那就使用原有的IRule的實現類,將其注入IOC容器即可.下面兩種二選一

@Configuration
public class MyRule {

    @Bean  //使用自定義的
    public IRule HcodeRule(){
        return new HcodeRule();
    }
    //============================================================
    //AvailabilityFilteringRule : 先過濾掉出現故障的服務器,對剩下的服務進行輪詢
    //RoundRobinRule 輪詢 默認設置
    //RandomRule 隨機
    //WeightedResponseTimeRule 權重
    //RetryRule:先按照輪詢獲取,若獲取服務失敗,則在指定時間內進行重試

    //隨機訪問,只要將實現類注入到ICO容器,即可覆蓋
    @Bean //使用原有的實現類
    public IRule myRule(){
        return new RandomRule();
    }

}
  1. 主啓動類上加上註解,讓消費端服務能去使用自定義的負載均衡策略
@SpringBootApplication
@EnableEurekaClient
//在微服務啓動的時候就能去加載我們自定義的負載均衡Ribbon類,name爲微服務提供者註冊到註冊中心的服務名
@RibbonClient(name="SPRINGCLOUD-PROVIDER-DEPT",configuration = MyRule.class)
public class DeptConsumer_80 {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumer_80.class,args);
    }
}

相關概念理解

  1. 服務熔斷:當某個服務提供者出現問題(出現運行時無法處理的異常或者某些操作時間過長),卡死了,不能讓用戶一直等待,需要調用備用的響應方法向調用方返回特定響應,防止服務鏈路某一微服務模塊卡死,導致整體服務出現雪崩。(發生熔斷一般是某個微服務模塊,也就是微服務提供者)
  2. 服務降級:服務降級一般也是有多種情況,訪問量過大,微服務出現異常,或者微服務響應超時等等,一般服務降級觸發熔斷都在消費者端設置,當某個服務不可用時,直接返回備用響應。
  3. 服務限流:也是服務降級的一種方式,限流,比如秒殺場景,不能訪問用戶瞬間都訪問服務器,限制一次只可以有多少請求。

Hystrix 實現服務熔斷和服務降級

  1. 微服務提供者導入pom依賴

單獨導入依賴 org.springframework.cloud:spring-cloud-starter-hystrix:2.2.1.RELEASE

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

使用eureka整合客戶端pom就不用再導入單獨的hystrix

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
  1. 微服務提供者的controller層
@RestController
@DefaultProperties(defaultFallback = "Global_FallbackMethod") //沒有配置專屬熔斷器方法,就走全局熔斷器
public class TestController {

    @HystrixCommand //沒加特定方法,走全局
    @PostMapping("/global")
    public String test1(){
        return "(●'◡'●)全局熔斷器方法未觸發";
    }

    //全局響應Fallback方法 服務降級觸發熔斷
    public Object Global_FallbackMethod(){
        return "┭┮﹏┭┮全局熔斷器方法觸發了,嗚嗚嗚!";
    }



    //斷路器
    @HystrixCommand( fallbackMethod = "CircuitBreaker_fallback" , commandProperties = {
            @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),// 是否開啓斷路器
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),// 請求次數
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), //時間窗口期,失敗後經過多久嘗試恢復
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60")  //失敗率到達多少後跳閘
    })
    @GetMapping("/local")
    public String test2(){
        return "(●'◡'●)特定斷路器方法未觸發~";
    }

    public String CircuitBreaker_fallback(){ //參數可以跟原接口方法參數一致
        return "┭┮﹏┭┮特定限制方法熔斷器觸發了,嗚嗚嗚~";
    }
}
  1. 微服務提供者的主啓動類加上開啓斷路器的註解
@EnableCircuitBreaker //添加對服務熔斷的支持
  1. 客戶端導入的所需依賴跟提供者差不多,使用openfeign進行服務調用通信。
<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

然後配置yml,讓feign支持hystrix

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

然後再服務層接口加上註解。

@FeignClient(value = "hystrix-test-provider",fallback = DeptFallbackService.class) //服務名,備用的響應類
@Component
public interface testService {

    @GetMapping("/global")
    public String test1();
}

兜底用的備用響應類

@Component // 服務降級
public class DeptFallbackService implements testService{
    public String test1() {
        return "┭┮﹏┭┮該服務被降級了,目前無法使用";
    }
}

最後,主啓動類添加@EnableHystrix

@EnableHystrix

Sentinel實現服務熔斷,降級,限流

老樣子,hystrix也是停止更新了,所以換新的纔是王道~況且阿里巴巴的sentinel就是繼承hystrix,兩者挺像的。

  • 官網下載:https://github.com/alibaba/Sentinel/releases
  • 特性:
    在這裏插入圖片描述
  • 核心庫(Java 客戶端)不依賴任何框架/庫,能夠運行於所有 Java 運行時環境,同時對 Dubbo / Spring Cloud 等框架也有較好的支持。
  • 控制檯(Dashboard)基於 Spring Boot 開發,打包後可以直接運行,不需要額外的 Tomcat 等應用容器。

下載好jar包sentinel-dashboard-1.7.0.jar後,直接命令行運行即可~
注意:該boot服務默認爲8080端口號。啓動後,訪問http://localhost:8080,賬號密碼都是sentinel。
在這裏插入圖片描述

服務提供者

  1. 導入pom
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
  1. 配置yml
server:
  port: 8666

spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848  # nacos註冊中心的地址
    sentinel:
      transport:
        dashboard: localhost:8080 # sentinel的地址
        port: 8719  #默認8719,假如被佔用了會自動從8719開始依次+1掃描。直至找到未被佔用的端口

# 暴露監控
management:
  endpoints:
    web:
      exposure:
        include: '*'
  1. 主啓動類添加註解
@EnableDiscoveryClient
@SpringBootApplication

  1. 控制層針對服務限流的備用方法,至於限流方式,就直接再sentinel控制檯直接添加即可,@SentinelResource的value參數就是對應的資源名,裏面也可以加fallback調用斷路器備用響應方法,使用跟@HystrixCommand差不多。
@RestController
@SentinelResource(fallbackClass = "Global_FallbackMethod")
public class TestController {
 
    @SentinelResource(value = "test",blockHandlerClass = CustomerBlockHandle.class,blockHandler ="deal_test")
    @GetMapping("/test")
    public String test(@RequestParam(value = "p") String p){
        return "(●'◡'●)沒有被限流";
    }
    
//    public String test(String p,BlockException blockException){
//        return "-------------deal list ┭┮﹏┭┮";
//    }
	    
	 //全局響應Fallback方法 服務降級觸發熔斷
    public Object Global_FallbackMethod(){
        return "┭┮﹏┭┮全局熔斷器方法觸發了,嗚嗚嗚!";
    }
}

統一處理限流的備用方法類

public class CustomerBlockHandle {
    public static String deal_test(String p, BlockException blockException){
        return "┭┮﹏┭┮被限流了";
    }
}
  1. 啓動後,再sentinel控制檯並沒有發現該服務,但是nacos卻已經發現該服務成功註冊了,是因爲需要發送一次請求,網頁訪問該服務,sentinel才能監控到(Sentinel採用的是懶加載)。
    在這裏插入圖片描述

微服務消費者(使用feign方式)

  1. 導入pom
		<dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-sentinel</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
         <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
 

  1. 配置yml
server:
  port: 80


spring:
  application:
    name: nacos-test-consumer
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    sentinel:
      transport:
        dashboard: localhost:8080
        port: 8719

service-url:
  nacos-user-service: http://cloudalibaba-sentinel-service

#對Feign的支持
feign:
  sentinel:
    enabled: true
  1. 配置接口以及接口的服務降級備用響應的實現類
@FeignClient(value = "cloudalibaba-sentinel-service",fallback = DeptFallbackService.class)
@Component
public interface TestService {

    @GetMapping("/test")
    public String test();
}
@Component // 服務降級
public class DeptFallbackService implements DeptService {
    public String test() {
        return "┭┮﹏┭┮服務被降級了,不能使用~";
    }
}
  1. controller層服務調用
@Autowired
 private TestService testService ;

@GetMapping(value = "/consumer/test")
public String test(){
    return testService.test();
}
  1. 主啓動類
@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients
public class test80
{
    public static void main(String[] args) {
        SpringApplication.run(test80.class, args);
    }
}
 

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