熔断降级

最近更新时间:2024-01-25 16:42:12

我的收藏

操作场景

本文介绍在本地开发 Java 应用,通过 polaris-sdk 的方式接入 TSE 治理中心(北极星网格),并实现熔断降级功能。

前提条件

在开发前,请确保您已经下载并安装了 Java 和 Maven。

操作步骤

步骤1:引入北极星依赖

1. 引入 polaris sdk 依赖

修改应用根目录下的pom.xml,为polaris-java添加dependencyManagement
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-dependencies</artifactId>
<version>${version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
说明:
polaris-sdk 版本信息请参见:版本信息

2. 引入 polaris starter

<dependencies>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-all</artifactId>
</dependency>
</dependencies>:

步骤2:添加北极星配置文件 polaris.yaml

1. 在项目的 main/resources 目录下创建 polaris.yml 文件用于初始化 polaris-java SDK。
2. 在 polaris.yml 文件中配置应用名、polaris(北极星)服务端地址等信息。服务端地址查看详细参见:引擎管理 > 客户端访问地址
global:
serverConnectors:
- id: polaris
protocol: grpc
addresses:
# 地址需要替换成您创建的北极星引擎的客户端访问地址。
- 127.0.0.1:8091
#描述: 监控及日志数据上报相关配置
statReporter:
#描述: 是否启用上报
enable: true
plugin:
prometheus:
type: push
# 描述: 设置 pushgateway 的地址, 仅 type == push 时生效
# 地址需要替换成您创建的北极星引擎的客户端访问地址。
address: 127.0.0.1:9091
#描述:设置metric数据推送到pushgateway的执行周期
#范围:[1s:...],默认值:10s
pushInterval: 10s
更多 polaris.yml 配置信息,请参见 default-config.yml

步骤3:使用说明

北极星支持三种维度的熔断降级:服务级、接口级、实例级。

1. 控制台配置熔断规则

请参见服务治理指南 > 服务治理 > 熔断降级相关文档,相关界面如下:


熔断规则配置示例:针对 default 命名空间下所有的服务,对于时延大于500毫秒,或者返回码为500的请求,标识为错误请求,一旦一分钟内错误率30%及以上或连续错误数在5个以上,则对服务进行熔断。

2. 客户端使用 SDK 进行熔断判断

方法说明:

北极星 Java SDK 提供以下熔断相关的方法,所有的方法都在com.tencent.polaris.circuitbreak.api.CircuitBreakAPI接口中提供。
check:检查资源是否可被调用,并对资源获取调用申请。对于半开的资源,如果半开的调用配额申请成功,返回 true,否则返回 false。
report:该方法供用户在资源调用完成后,上报调用的结果,包括返回码、时延等信息,供熔断逻辑判断。
makeFunctionalDecorator:创建一个函数调用装饰器 FunctionalDecorator,装饰器可以对 Java 的函数接口进行装饰。装饰后的逻辑,会在函数逻辑调用前,先通过 check 方法检查资源是否可被调用,如果不能被调用,会抛出资源熔断异常(CallAbortedException)。调用完成后,会通过 report 接口上报本次调用结果。
FunctionalDecorator包含以下方法:
decorateSupplier:对函数接口 Supplier 进行封装。
decorateConsumer:对函数接口 Consumer 进行封装。
decorateFunction:对函数 Function 进行封装。
decoratePredicate:对函数接口 Predicate 进行封装。

2.2 服务级熔断

// 创建CircuitBreakAPI实例
CircuitBreakAPI circuitBreakAPI = CircuitBreakAPIFactory.createCircuitBreakAPI();

// 通过传入服务名(testService1)和命名空间(default),创建FunctionalDecorator
FunctionalDecoratorRequest makeDecoratorRequest = new FunctionalDecoratorRequest();
makeDecoratorRequest.setService(new ServiceKey("default", "testService1"));
FunctionalDecorator decorator = circuitBreakAPI.makeFunctionalDecorator(makeDecoratorRequest);

// 封装函数接口
Consumer<Integer> integerConsumer = decorator.decorateConsumer(new Consumer<Integer>() {
@Override
public void accept(Integer object) {
// 执行服务调用...
}
});

// 通过执行函数接口,进行服务调用
// 在调用过程中,如果出现熔断,会抛出CallAbortedException异常
for (int i = 0; i < 500; i++) {
try {
integerConsumer.accept(i);
} catch(CallAbortedException e) {
e.printStackTrace();
}
}

2.3 接口级熔断

// 创建CircuitBreakAPI实例
CircuitBreakAPI circuitBreakAPI = CircuitBreakAPIFactory.createCircuitBreakAPI();

// 通过传入服务名(testService1)、命名空间(default)和方法名(foo),创建FunctionalDecorator
FunctionalDecoratorRequest makeDecoratorRequest = new FunctionalDecoratorRequest();
makeDecoratorRequest.setService(new ServiceKey("default", "testService1"));
makeDecoratorRequest.setMethod("foo");
FunctionalDecorator decorator = circuitBreakAPI.makeFunctionalDecorator(makeDecoratorRequest);

// 封装函数接口
Consumer<Integer> integerConsumer = decorator.decorateConsumer(new Consumer<Integer>() {
@Override
public void accept(Integer object) {
// 执行服务接口调用...
}
});

// 通过执行函数接口,进行服务调用
// 在调用过程中,如果出现熔断,会抛出CallAbortedException异常
for (int i = 0; i < 500; i++) {
try {
integerConsumer.accept(i);
} catch(CallAbortedException e) {
e.printStackTrace();
}
}


2.4 实例级熔断

当实例被熔断时,该实例会暂时不接收请求,原本路由到该实例的请求会路由到其他实例。这个过程在服务路由过程中自动完成,用户无需进行额外的熔断状态判断等操作。
执行服务路由:
import com.tencent.polaris.factory.api.DiscoveryAPIFactory;


public static void main(String[] args) throws Exception {
ConsumerAPI consumerAPI = DiscoveryAPIFactory.createConsumerAPI();
// 执行服务路由,筛选出单个实例,在这个过程中,会自动剔除熔断的实例
GetOneInstanceRequest getOneInstanceRequest = new GetOneInstanceRequest();
getOneInstanceRequest.setNamespace("default");
getOneInstanceRequest.setService("testService1");
InstancesResponse oneInstance = consumerAPI.getOneInstance(getOneInstanceRequest);
Instance targetInstance = oneInstance.getInstances()[0];
// 执行服务调用
// invoke rpc call with targetInstance
// 上报调用结果,调用结果用于进行熔断判断
ServiceCallResult result = new ServiceCallResult();
result.setNamespace(namespace);
result.setService(service);
result.setHost(targetInstance.getHost());
result.setPort(targetInstance.getPort());
// 设置返回码
result.setRetCode(code);
// 设置调用时延
result.setDelay(delay);
// 使用updateServiceCallResult上报调用结果
consumerAPI.updateServiceCallResult(result);
}