Spring Cloud Alibaba Sentinel服务熔断Ribbon, 先来看一下Ribbon下Sentinel服务熔断, 主要是fallback和blockHandler方法的使用,处理运行时异常和Sentinel限流规则异常情况

现在使用Nacos+Sentinel+Ribbon完成负载均衡,服务架构图如下:

1. 9003 服务

先新建cloud-alibaba-provider-payment9003,另一个 cloud-alibaba-provider-payment90034 直接copy一份即可。

1.1 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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">
    <parent>
        <artifactId>live.yremp.springcloud</artifactId>
        <groupId>live.yremp</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-alibaba-provider-payment9003</artifactId>

    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</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>
        <dependency>
            <groupId>live.yremp</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
</project>

1.2 配置文件

server:
  port: 9003

spring:
  application:
    name: nacos-payment-provider
  cloud:
    nacos:
      discovery:
        server-addr: 39.105.173.178:8848 #配置Nacos地址

management:
  endpoints:
    web:
      exposure:
        include: '*'

1.3 主启动类

package live.yremp.springcloud.alibaba;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain9003 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentMain9003.class,args);
    }
}

1.4 业务代码

package live.yremp.springcloud.alibaba.controller;

import live.yremp.springcloud.entries.CommonResult;
import live.yremp.springcloud.entries.Payment;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import javax.websocket.server.PathParam;
import java.util.HashMap;

@RestController
public class PaymentController {
    @Value("${server.port}")
    private String serverPort;

    static HashMap<Long,Payment> hashMap =new HashMap<>();
    static {
        hashMap.put(1L,new Payment(1L,"550bc47a-bae7-4d5d-ab81-36b9efbe8e3a"));
        hashMap.put(2L,new Payment(2L,"959448fd-b519-4333-8a8e-e85a9cf1cf59"));
        hashMap.put(3L,new Payment(3L,"2c7b9970-1ba9-4634-9ba3-8d298fc18761"));
    }

    @GetMapping("/paymentSQL/{id}")
    public CommonResult<Payment> paymentSql(@PathVariable("id")Long id){
        Payment payment =hashMap.get(id);
        CommonResult<Payment> result = new CommonResult<>(200,"from serverport="+serverPort,payment);
        return result;

    }
}

1.5 服务测试

先去Nacos看看服务是否注册成功

Web接口访问测试

2. 9004服务

和9003基本一致,就是服务端口的不同,,只需要复制9903项目,然后修改和端口有关的配置即可

2.1 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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">
    <parent>
        <artifactId>live.yremp.springcloud</artifactId>
        <groupId>live.yremp</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-alibaba-provider-payment9004</artifactId>

    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</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>
        <dependency>
            <groupId>live.yremp</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
</project>

2.2 配置文件

server:
  port: 9004

spring:
  application:
    name: nacos-payment-provider
  cloud:
    nacos:
      discovery:
        server-addr: 39.105.173.178:8848 #配置Nacos地址

management:
  endpoints:
    web:
      exposure:
        include: '*'

2.3 修改主启动类

package live.yremp.springcloud.alibaba;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain9004 {
    public static void main(String[] args) {
        SpringApplication.run(PaymentMain9004.class,args);
    }
}

2.4 服务测试

启动服务,去Nacos控制台查看是否注册成功

Web接口访问测试

3. 服务消费者84

3.1 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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">
    <parent>
        <artifactId>live.yremp.springcloud</artifactId>
        <groupId>live.yremp</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-alibaba-consumer-order84</artifactId>

    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</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>
        <dependency>
            <groupId>live.yremp</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

</project>

3.2 配置文件

server:
  port: 84


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


#消费者将要去访问的微服务名称(注册成功进nacos的微服务提供者)
service-url:
  nacos-user-service: http://nacos-payment-provider

3.3 主启动类

package live.yremp.cloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class NacosOrderMain84 {
    public static void main(String[] args) {
        SpringApplication.run(NacosOrderMain84.class,args);
    }
}

3.4 配置类

package live.yremp.cloud.config;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ApplicationContextConfig {
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

3.5 业务代码

package live.yremp.cloud.controller;

import live.yremp.springcloud.entries.CommonResult;
import live.yremp.springcloud.entries.Payment;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;


@RestController
public class OrderNacosController
{
    @Resource
    private RestTemplate restTemplate;

    @Value("${service-url.nacos-user-service}")
    private String serverURL;

    @GetMapping(value = "/consumer/fallback/{id}")
    public CommonResult<Payment> paymentInfo(@PathVariable("id") Long id)
    {
        CommonResult<Payment>   result = restTemplate.getForObject(serverURL+"/paymentSQL/"+id,CommonResult.class);
        if(id==4){
            throw new IllegalArgumentException("IllegalArgumentException,非法参数异常");
        }else if(result.getData()==null){
            throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");
        }
        return result;

    }

}

3.6 服务测试

服务注册测试,先去Nacos查看服务是否注册成功

服务请求接口测试

4. 配置Fallback

修改Controller如下,添加hanlerFallback方法作为异常兜底方法

package live.yremp.cloud.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import live.yremp.springcloud.entries.CommonResult;
import live.yremp.springcloud.entries.Payment;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;


@RestController
public class OrderNacosController
{
    @Resource
    private RestTemplate restTemplate;

    @Value("${service-url.nacos-user-service}")
    private String serverURL;

    @GetMapping(value = "/consumer/fallback/{id}")
    @SentinelResource(value = "fallback",fallback = "handlerFallback")
    public CommonResult<Payment> paymentInfo(@PathVariable("id") Long id)
    {
        CommonResult<Payment>   result = restTemplate.getForObject(serverURL+"/paymentSQL/"+id,CommonResult.class);
        if(id==4){
            throw new IllegalArgumentException("IllegalArgumentException,非法参数异常");
        }else if(result.getData()==null){
            throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");
        }
        return result;

    }

    public CommonResult handlerFallback(@PathVariable("id") Long id,Throwable e){
        Payment payment =new Payment(id,null);
        return new CommonResult(444,"兜底异常handlerFallback,exception"+e.getMessage(),payment);
    }

}

重启测试

6. blockHandler配置

6.1 修改Controller

package live.yremp.cloud.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import live.yremp.springcloud.entries.CommonResult;
import live.yremp.springcloud.entries.Payment;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.swing.text.BadLocationException;


@RestController
public class OrderNacosController
{
    @Resource
    private RestTemplate restTemplate;

    @Value("${service-url.nacos-user-service}")
    private String serverURL;

    @GetMapping(value = "/consumer/fallback/{id}")
//  @SentinelResource(value = "fallback",fallback = "handlerFallback")
    @SentinelResource(value = "fallback",blockHandler ="blockHandler" )
    public CommonResult<Payment> paymentInfo(@PathVariable("id") Long id)
    {        CommonResult<Payment>   result = restTemplate.getForObject(serverURL+"/paymentSQL/"+id,CommonResult.class);
        if(id==4){
            throw new IllegalArgumentException("IllegalArgumentException,非法参数异常");
        }else if(result.getData()==null){
            throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");
        }
        return result;

    }

    public CommonResult handlerFallback(@PathVariable("id") Long id,Throwable e){
        Payment payment =new Payment(id,null);
        return new CommonResult(444,"兜底异常handlerFallback,exception"+e.getMessage(),payment);
    }

    public CommonResult blockHandler(@PathVariable("id") Long id, BlockException exception){
        Payment payment =new Payment(id,null);
        return new CommonResult(445,"blockHandler 限流,无此流水,blockexception"+exception.getMessage(),payment);
    }

}

6.2 添加限流规则

测试正常异常情况

触发流控的异常情况

7. 同时配置Fallback和BlockHandler

Fallblock可以处理运行时的异常,而BlockHandler则只能处理Sentinel的限流等异常,二者结合是比较完备的方式。

7.1 修改代码

修改Controller中方法上的@Resource注解

package live.yremp.cloud.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import live.yremp.springcloud.entries.CommonResult;
import live.yremp.springcloud.entries.Payment;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.swing.text.BadLocationException;


@RestController
public class OrderNacosController
{
    @Resource
    private RestTemplate restTemplate;

    @Value("${service-url.nacos-user-service}")
    private String serverURL;

    @GetMapping(value = "/consumer/fallback/{id}")
//  @SentinelResource(value = "fallback",fallback = "handlerFallback")
//  @SentinelResource(value = "fallback",blockHandler ="blockHandler")
    @SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler ="blockHandler")
    public CommonResult<Payment> paymentInfo(@PathVariable("id") Long id)
    {        CommonResult<Payment>   result = restTemplate.getForObject(serverURL+"/paymentSQL/"+id,CommonResult.class);
        if(id==4){
            throw new IllegalArgumentException("IllegalArgumentException,非法参数异常");
        }else if(result.getData()==null){
            throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");
        }
        return result;
    }

    public CommonResult handlerFallback(@PathVariable("id") Long id,Throwable e){
        Payment payment =new Payment(id,null);
        return new CommonResult(444,"兜底异常handlerFallback,exception"+e.getMessage(),payment);
    }

    public CommonResult blockHandler(@PathVariable("id") Long id, BlockException exception){
        Payment payment =new Payment(id,null);
        return new CommonResult(445,"blockHandler 限流,无此流水,blockexception"+exception.getMessage(),payment);
    }

}

Java异常由Fallback处理,Sentinel违规由BlockHandler处理

7.2 异常测试

先测试运行时异常

Sentinel限流

当头同时有Java运行时异常和Sentinel异常时,则会以Sentinel的异常为准,具体如上图。

8. exceptionsToIgnore

异常忽略,忽略指定的异常,以下面的代码为例

package live.yremp.cloud.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import live.yremp.springcloud.entries.CommonResult;
import live.yremp.springcloud.entries.Payment;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.swing.text.BadLocationException;


@RestController
public class OrderNacosController
{
    @Resource
    private RestTemplate restTemplate;

    @Value("${service-url.nacos-user-service}")
    private String serverURL;

    @GetMapping(value = "/consumer/fallback/{id}")
//  @SentinelResource(value = "fallback",fallback = "handlerFallback")
//  @SentinelResource(value = "fallback",blockHandler ="blockHandler")
    @SentinelResource(value = "fallback",
            fallback = "handlerFallback",
            blockHandler ="blockHandler",
            exceptionsToIgnore = {IllegalArgumentException.class})
    public CommonResult<Payment> paymentInfo(@PathVariable("id") Long id)
    {        CommonResult<Payment>   result = restTemplate.getForObject(serverURL+"/paymentSQL/"+id,CommonResult.class);
        if(id==4){
            throw new IllegalArgumentException("IllegalArgumentException,非法参数异常");
        }else if(result.getData()==null){
            throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");
        }
        return result;
    }

    public CommonResult handlerFallback(@PathVariable("id") Long id,Throwable e){
        Payment payment =new Payment(id,null);
        return new CommonResult(444,"兜底异常handlerFallback,exception"+e.getMessage(),payment);
    }

    public CommonResult blockHandler(@PathVariable("id") Long id, BlockException exception){
        Payment payment =new Payment(id,null);
        return new CommonResult(445,"blockHandler 限流,无此流水,blockexception"+exception.getMessage(),payment);
    }

}

忽略 IllegalArgumentException的异常,重启进行测试:

此时已经不再执行fallback方法,而是直接Error page

标签云

ajax AOP Bootstrap cdn Chevereto CSS Docker Editormd GC Github Hexo IDEA JavaScript jsDeliver JS樱花特效 JVM Linux Live2D markdown Maven MyBatis MyBatis-plus MySQL Navicat Oracle Pictures QQ Sakura SEO Spring Boot Spring Cloud Spring Cloud Alibaba SpringMVC Thymeleaf Vue Web WebSocket Wechat Social WordPress Yoast SEO 代理 分页 图床 小幸运 通信原理

Spring Cloud Alibaba Sentinel服务熔断Ribbon
Spring Cloud Alibaba Sentinel服务熔断Ribbon