当 CSB 接入的目标服务(后端端点)不可用或响应过慢时,为了保证调用方(CSB 客户端)整体服务的可用性,可以通过设置熔断和降级逻辑以提高响应速度,待目标服务恢复后再恢复正常调用。

背景信息

  • 熔断:如果某个目标服务调用慢或者有大量调用超时,熔断该服务的调用,对后续请求进行调用降级或直接返回,快速释放资源,待目标服务情况好转再恢复调用。
  • 降级:在目标服务调用超时、失败或者服务进入熔断状态时,返回默认值或调用降级服务以避免原目标服务不可用导致服务调用失败。

条件与约束

  • 熔断和降级服务要先在设置接入协议时配置超时时间。
  • 熔断后尝试请求目标服务的最小间隔为 5 秒,查看目标服务是否已恢复。
  • CSB 无法区分目标服务的异常,超时和其他异常都会触发熔断。
  • 开放协议和接入协议符合下表中的服务才支持的降级配置。
    开放协议 接入协议 降级默认值 降级端点 默认值格式
    RESTful(普通服务和级联服务) RESTful-API 支持 支持 JSON
    RESTful(普通服务和级联服务) WebService 支持 不支持 JSON
    RESTful(普通服务和级联服务) HSF 支持 不支持 JSON
    RESTful(普通服务和级联服务) DUBBO 支持 不支持 JSON
    RESTful JDBC 不支持 不支持 -
    WebService(普通服务和级联服务) RESTful-API 支持 支持 JSON
    WebService(普通服务和级联服务) WebService 支持 不支持 XML
    WebService(普通服务和级联服务) HSF 支持 不支持 JSON
    WebService(普通服务和级联服务) DUBBO 支持 不支持 JSON
    WebService JDBC 不支持 不支持 -
    HSF 级联 HSF 支持 不支持 文本(只支持 Hessian2 序列化)

配置熔断和降级

熔断和降级是在发布服务过程中配置的,发布服务的详细步骤请参见发布服务,本文仅说明发布过程中如何配置熔断和降级。

  1. 进入发布服务页面,详情请参见进入发布服务页面进入级联发布页面
  2. 命名服务页面设置服务基本参数。详情请参见命名服务
  3. 接入协议页面选择接入协议并配置相关参数,详情请参见设置接入协议
    注意 在配置接入服务时,必须配置超时时间,否则熔断和降级配置服务不生效。
  4. 开发协议页面设置开发协议,详情请参见设置开放协议
  5. 限制访问页面设置访问限制,并进行熔断设置
    设置访问设置请参见设置访问限制,本文主要熔断设置。

    熔断参数配置说明:

    • 启用熔断:是否打开启用熔断开关。
    • 熔断触发条件:设置熔断触发的条件,例如 10 秒内服务请求数超过 100次,且错误率大于 40%
    • 启用降级:是否打开启用降级开关。当启用熔断不启用降级时,在熔断状态下会抛出熔断异常。
    • 降级逻辑:输入降级逻辑代码。降级逻辑包含默认值和降级端点两种方式。
      • 如果您已有备用的端点,可配置降级端点。
      • 如果您没有备用的端点,可配置默认值,以保证服务调用可以正常进行。

      下面分别提供默认值和降级端点的配置示例。

      • 降级端点(和 RESTful 端点对应,熔断状态或原端点服务异常情况下调用降级端点的服务)示例:
        http://service.ken.com:8080/fallback/item/{name}
      • 默认值(返回调用方指定结果)示例(RESTful ):

        {
        "msg": "FALLBACK",
        "result": {
        "quantity": 9999
        },
        "code": "0",
        "innerMsg": "DefaultValue"
        }

        HSF 或 Dubbo方法返回值对应的 JSON(JSON.toJSONString(result))。

        对于 HSF 级联发布的服务,需要使用 Hessian2 序列化之后的字符串作为默认值,即调用 Hessian2Encoder.encodeToString(result) 获得的字符串。示例代码如下(需要先在 pom.xml 中添加 Dubbo 和 Hessian 的依赖):

        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.7.5</version>
        </dependency>
        <dependency>
            <groupId>com.taobao.hsf.hessian</groupId>
            <artifactId>hessian</artifactId>
            <version>4.0.7.bugfix12-tuning3</version>
        </dependency>
        import org.apache.dubbo.common.io.UnsafeByteArrayInputStream;
        import org.apache.dubbo.common.io.UnsafeByteArrayOutputStream;
        import com.taobao.hsf.com.caucho.hessian.io.Hessian2Input;
        import com.taobao.hsf.com.caucho.hessian.io.Hessian2Output;
        import com.taobao.hsf.com.caucho.hessian.io.SerializerFactory;
        
        public class Hessian2Encoder {
            private static final SerializerFactory factory = new com.taobao.hsf.com.caucho.hessian.io.SerializerFactory();
            private static final String chars = "0123456789ABCDEF";
        
            public static byte[] encode(Object object) throws Exception {
                UnsafeByteArrayOutputStream byteArray = new UnsafeByteArrayOutputStream();
                Hessian2Output output = new Hessian2Output(byteArray);
                output.setSerializerFactory(factory);
                output.writeObject(object);
                output.close();
                byte[] bytes = byteArray.toByteArray();
                return bytes;
            }
        
            public static String encodeToString(Object object) throws Exception {
                byte[] bytes = encode(object);
                return bytesToHexString(bytes);
            }
        
            private static String bytesToHexString(byte[] bytes) {
                StringBuilder result = new StringBuilder(bytes.length);
                String s;
                for (int i = 0; i < bytes.length; i++) {
                    s = Integer.toHexString(0xFF & bytes[i]);
                    if (s.length() < 2) {
                        result.append(0);
                    }
                    result.append(s.toUpperCase());
                }
                return result.toString();
            }
        }
  6. 发布服务页面确认设置,单击完成发布

结果验证

熔断和降级配置完成后,在调用该服务时,返回的 HTTP Response 包含以下 Header 信息,您可以根据各参数的返回值判断熔断和降级是否生效。

HTTP Response 中 Header 信息的参数说明如下:

  • Response-Source

    EndPoint(源端点响应)| FallbackDefaultValue(默认值) | FallbackEndPoint(降级端点响应)

  • SuccessfulExecution:执行是否成功
  • ResponseRejected:是否拒绝
  • ResponseTimedOut:是否超时
  • ResponseShortCircuited:是否熔断(断路)
  • ResponseFromFallback:是否降级响应