发布服务就是将一个已有的后端服务在某个 CSB 实例上注册,并以选定的一种或多种协议开放成 API 供消费者使用,同时对服务的消费做一定的访问控制。

前提条件

在体验发布服务前,您需要完成以下操作:

背景信息

服务发布包含以下三个概念。
  • 接入服务:提供 API 对应的后端服务信息,让 CSB 能访问到这个已有的服务。
  • 开放服务:指明 API 开放的协议,以及开放的接口和后端服务接口如何对应。
  • 访问控制:指明 API 开放的策略,是否限流,对谁可见,访问是否需要授权。
发布服务架构

CSB 可以发布 RESTful、HSF、Web Service、Dubbo 和 JDBC 5 种协议类型的服务。

发布服务流程

  1. 进入发布服务页面
  2. 命名服务
  3. 设置接入协议
  4. 设置开放协议
  5. 设置访问限制
  6. 发布服务

进入发布服务页面

  1. 登录 CSB 控制台
  2. 在顶部页面顶部选择地域
  3. 在左侧导航栏单击实例列表
  4. 实例列表单击具体实例名称。
    注意 如果您使用共享实例,请参考创建共享实例中的表格使用 CSB 指定的共享实例,否则会导致发布失败。共享实例仅用于体验试用,不建议正式生产使用。
  5. 可选: CSB服务版本对话框中单击新版发布(推荐)
    说明 该对话框仅在第一次发布服务出现,您可以选中记住我的选择
    CSB 服务版本
  6. 在实例详情页面左侧导航栏选择发布者 > 发布服务

命名服务

发布服务页面的命名服务页签中设置参数,单击下一步
路由服务发布-命名服务

命名服务参数说明:

  • 服务全名:输入要发布的服务全名。
  • 服务版本:输入服务版本号。
  • 所属服务组:在下拉列表中选择该服务所属的服务组。在服务数量少时所属服务组可视作简单分类。
  • 服务别名:输入服务别名,用于标识该服务。
  • 归属:服务归属组织名、部门名称或者提供商名。
  • 服务说明:可以填写 API 的详细描述或者其它说明信息。最长 128 个汉字或字符。
说明
  • 服务全名+服务版本)在 CSB 实例上是唯一的。发布服务全名相同但服务版本不同的服务时,要确保在该实例下其他的相同服务全名的服务都已经处于注销状态。
  • 同一个服务全名的两个服务版本可以视为两个服务,即客户端调用的时候需要指定调用的服务全名服务版本

设置接入协议

  1. 接入协议页面选择路由策略

    接入协议有两种路由策略:直接路由基于内容的路由

    • 直接路由:实际上是直接接入,不需要路由,只能选择一种接入协议。
    • 基于内容的路由:单击新增,在编辑参数设置路由条件,即定义 Groovy 条件规则,把接入的请求根据参数值的不同,路由到多个不同的后端接入协议或者相同的接入协议不同的接入地址。设置路由条件

      格式为 exportRequest.query.arg0 =='change to your value'

      • exportRequest 表示开发入参。
      • query.arg0 表示 URL 中的参数 arg0
      • change to your value 表示参数值,HTTP 入参支持 query、body 或 header。
  2. 接入协议页面根据实际需求选择一个接入协议

    CSB 目前支持 5 种协议:RESTful-APIHSF-APIWebServiceDubboJDBC

  3. 接入协议页面根据选择的接入协议配置接入服务

    CSB 目前支持 5 种协议:RESTful-APIHSF-APIWebServiceDubboJDBC。不同的协议,接入服务的参数有所不同。

  4. 接入协议页面设置服务接口
    服务接口

    您可以选择服务接口,您也可以使用新接口包。

    手动的服务参数定义是一件繁琐的工作,CSB 控制台提供了自动的参数加载功能,有两种方式进行参数的加载:

    • 使用命名服务步骤中选择的服务组所定义的接口文件。
    • 自定义的接口文件(它覆盖服务组中定义的接口文件)。

    这样就可以在定义参数的时候通过选择接口和对应的方法自动添加接口文件(Java 类)中定义的参数。

  5. 接入协议页面编辑入参编辑出参

    根据接入协议,定义入参数和出参数,并设置参数的名称映射和参数顺序和层次。

    参数的名称映射是指发布入参数名为CSB开放的服务调用时候使用的参数名,发布出参数名为CSB接入后端服务的时候使用的的参数名。参数的命名只能是数字,字母或“_”。

    入参和出参请注意以下注意事项:

    • 参数的顺序要与接入服务要求的参数顺序一致。
    • 对于复杂的参数,需要定义参数的层次,来表示一个复杂的参数对象。

    每个参数都可以单独编辑,设置参数的属性信息:

    • 参数类型: 支持下拉的基本参数类型和复杂的自定类型。
    • 扩展类型: 参数的正常的参数类型,还是数组,列表或 Set, 例如方法 hello(String arg0, String[] arg1, List&ltString> arg2)
      • arg0 为正常扩展类型(它可以是简单类型或者复杂类型)。
      • arg1 为数组扩展类型。
      • arg2 为列表扩展类型。
    • 可选: 如果设置成参数可选,则调用时,发布的服务可以不输入该参数;如果是必选并且没有设置默认值,则调用时会报错。
    • 传递方式:包含 GETPOST
    • 默认值:如果不开放但又是后端服务必要的入参,需要指定默认值。
    • 示例值:生成接口文档时,提供参数的取值参考。
    说明 如果是透传的调用,如:restful2restful, ws2ws, HSF2HSF 可以不定义参数,发布的参数原样透传到后端的接入服务。

    手动的服务参数定义是一件繁琐的工作,CSB 控制台提供了自动的参数加载功能,有两种方式进行参数的加载:

  6. 接入协议设置完成后,单击下一步

设置开放协议

  1. 开发协议页面选择服务开放类型
    • 对于直接路由,开放协议是由所选择的接入协议决定。详情请参见协议转换种类
    • 对于基于内容的路由,开放协议目前只支持 RESTful 协议类型。
  2. 可选: (适用于 RESTful)在开发协议页面设置开放Path
  3. 可选: 开发协议页面选择服务发布目标实例

    服务发布目标实例多于一个时,用所选择的非本实例作为发布目标实例时,则代表当前服务要级联发布到该目标实例。即该服务可以在目标实例被调用,中间经过级联到达当前实例并最终调用到真正的接入服务。

    对于级联服务的要求:

    • 必须由管理员预先定义正确的级联发布规则,才可以在发布服务时候看到多个服务发布目标实例
    • 需要在要发布的目标实例上预先创建一个服务组,该服务组名称必须与当前发布的服务(源服务)所选择的服务组相同。这么做的目的是可以在目标实例上根据这个服务组(及这个组的所属用户)找到这个级联服务。
  4. 可选: 开发协议页面的编辑错误代码右侧单击添加错误码。在弹出的错误码编辑对话框中输入数据的错误代码处置建议错误说明,然后单击 确认
  5. 开发协议页面的模拟返回结果右侧单击编辑模拟返回结果,在弹出的mock结果编辑对话框中输入模拟返回结果,然后单击保存
  6. 开放协议设置完成后,单击下一步

设置访问限制

您可以设置发布的服务的每秒最大调用量,也可以打开或关闭公开访问开关。如果您关闭公开访问开关,则其他用户必须订阅您发布的服务才能使用该服务。

  1. 限制访问页面设置每秒最大调用量
    每秒最大调用量用于指定该服务能接受的访问频度限制,即每秒最多调用次数。设置为 0 或者为空时代表不限制访问频度。
  2. 限制访问页面根据实际需求打开或关闭公开访问开关,设置使用该服务是否需要订阅。
  3. 可选: 限制访问进行熔断设置
    说明 降级对服务的接入协议服务开放类型有所限制,详情请参见条件与约束。满足条件的服务还需要在配置接入服务时设置超时时间(ms)

    熔断参数配置说明:

    • 启用熔断:是否打开启用熔断开关。
    • 熔断触发条件:设置熔断触发的条件,例如 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();
            }
        }

发布服务

  1. 确认服务的基本信息、开发协议、接入协议、限制访问等设置是否无误。
  2. 确认无误后,单击完成发布