0
点赞
收藏
分享

微信扫一扫

Biz-SIP业务中台案例实战(18)——调用App延迟服务

分布式事务是分布式系统架构设计中的一个技术难点,特别是在这几年越来越火的微服务架构中,服务拆分所带来的跨服务数据一致性问题亟待解决,而在金融系统中,这个问题更是备受关注。
在Biz-SIP金融业务中台中,是利用App延迟服务,来提供对分布式事务的支持,主要场景有:

  1. 重试通知:通知对方系统,如果对方系统没有响应,会重新发起通知交易,直到对方给出明确的回复响应。
  2. 向前补偿:调用第三方服务后,超时没有响应,系统会后续发起查询上笔交易状态的查询交易,如果对方系统还是没响应,会多次重试再发起交易状态查询,并根据查询交易状态来决定继续完成后续服务步骤(上笔交易终态查询结果为已成功)还是对以前服务步骤发起补偿(冲正)操作(上笔交易终态查询结果为未成功)。
  3. 向后补偿:调用第三方服务后,超时没有响应,系统会立即发起针对此交易的补偿交易,如果对方系统还是没响应,会多次重试再发起补偿交易。补偿成功后,会对以前服务步骤依次发起补偿(冲正)操作;如果补偿失败,会置交易失败,由人工介入处理。

调用App延迟服务案例,是通过Biz-SIP的开放API接口,调用App服务,再由App服务发起对App延迟服务的多次重试调用:
在这里插入图片描述

在以上案例中,有2个App服务:

  • /bean/sample15:正常的App服务,被开放API接口所调用,模拟在特定场景(发起重试通知、调用第三方应用后无响应)中调用App延迟服务;
  • /bean/sample15-delay:被调用的App延迟服务,模拟和第三方应用交互的不同场景(无响应、返回错误、返回成功)。

一、App层App服务的开发和配置

首先,我们需要编写一个App服务类(Sample15AppService.java):

@Slf4j
@Service
public class Sample15AppService implements AppBeanInterface {
    private BizMessageInterface bizMessageInterface
            = AppClientFactory.getDelayAppServiceClient(
            BizMessageInterface.class, "/bean/sample15-delay",
            0,1000, 2000, 4000, 8000, 16000);
    
    @Override
    public JSONObject process(JSONObject message) throws BizException {
        BizMessage<JSONObject> bizMessage = this.bizMessageInterface.call(message);
        return bizMessage.getData();
    }
}

Sample15AppService类继承了AppBeanInterface接口,实现了process()方法。
Sample15AppService类中申请了调用“/bean/sample15-delay”App延迟服务的调用接口bizMessageInterface,在process()方法中,通过这个接口,来调用App延迟服务。

接着,我们还需要编写一个App服务类作为App延迟服务(Sample15DelayAppService.java):

@Slf4j
@Service
public class Sample15DelayAppService implements AppBeanInterface {
    @Override
    public JSONObject process(JSONObject message) throws BizException {
        log.info("延迟App服务调用第[{}]次: \n{}",
                BizUtils.getDelayRetryCount(),
                BizUtils.buildJsonLog(message));
        int maxRetryCount = message.getInt("maxRetryCount");
        String result = (String) message.get("result");
        if (BizUtils.getDelayRetryCount() >= maxRetryCount) {
            if ("success".equalsIgnoreCase(result)) {
                log.info("返回成功!");
                return message;
            }
            else {
                log.info("返回错误!");
                throw new BizException(BizResultEnum.OTHER_ERROR,"Sample15DelayAppService调用错误!");
            }
        }
        log.info("抛出延迟App服务重试异常,触发下一次调用...");
        throw new BizException(BizResultEnum.RETRY_DELAY_APP_SERVICE);
    }
}

Sample15AppService类同样继承了AppBeanInterface接口,实现了process()方法。
Sample15AppService类中,会根据传入报文中的“maxRetryCount”来决定调用次数,在没达到maxRetryCount约定的最大重试次数时,会直接抛出App服务重试异常(异常错误码为BizResultEnum.RETRY_DELAY_APP_SERVICE);传入报文中的“result”为达到最大重试次数后是返回成功(result为“success”)还是直接抛出异常(除App服务重试异常以外的其它BizException异常)。

然后,在app.yml中,需要配置这二个App服务:

- app-service-id: /bean/sample15
  type: app-bean-service
  class-name: com.bizmda.bizsip.sample.app.service.Sample15AppService

- app-service-id: /bean/sample15-delay
  type: app-bean-service
  class-name: com.bizmda.bizsip.sample.app.service.Sample15DelayAppService

二、启动应用进行测试

启动SampleAppApplication应用,通过OpenAPI接口进行测试。
首先,请求报文中设置最大重试次数(maxRetryCount)为4,最终返回结果(result)为“success”。

$ curl -H "Content-Type:application/json" -H "Biz-Service-Id:/bean/sample15" -X POST --data '{"maxRetryCount":4,"result":"success"}' http://localhost:8888/api|jq

{
  "code": 0,
  "message": "success",
  "extMessage": null,
  "appServiceId": "/bean/sample15",
  "traceId": "35a40e4bace44883bcb6511a3b016b82",
  "parentTraceId": null,
  "timestamp": 1648358690842,
  "data": {
    "maxRetryCount": 4,
    "result": "success"
  }
}

SampleAppApplication应用中被调用的Sample15DelayAppService类打印日志:

[bizsip-integrator:192.169.1.103:8888] 13:24:50 INFO 70936 [7a36a3f4c22e40a49792931645570553] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-4] c.b.b.s.a.s.Sample15DelayAppService      延迟App服务调用第[1]次: 
{
    "maxRetryCount": 4,
    "result": "success"
}
[bizsip-integrator:192.169.1.103:8888] 13:24:50 INFO 70936 [7a36a3f4c22e40a49792931645570553] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-4] c.b.b.s.a.s.Sample15DelayAppService      抛出延迟App服务重试异常,触发下一次调用...
[bizsip-integrator:192.169.1.103:8888] 13:24:51 INFO 70936 [7a36a3f4c22e40a49792931645570553] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-3] c.b.b.s.a.s.Sample15DelayAppService      延迟App服务调用第[2]次: 
{
    "maxRetryCount": 4,
    "result": "success"
}
[bizsip-integrator:192.169.1.103:8888] 13:24:51 INFO 70936 [7a36a3f4c22e40a49792931645570553] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-3] c.b.b.s.a.s.Sample15DelayAppService      抛出延迟App服务重试异常,触发下一次调用...
[bizsip-integrator:192.169.1.103:8888] 13:24:53 INFO 70936 [7a36a3f4c22e40a49792931645570553] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-2] c.b.b.s.a.s.Sample15DelayAppService      延迟App服务调用第[3]次: 
{
    "maxRetryCount": 4,
    "result": "success"
}
[bizsip-integrator:192.169.1.103:8888] 13:24:53 INFO 70936 [7a36a3f4c22e40a49792931645570553] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-2] c.b.b.s.a.s.Sample15DelayAppService      抛出延迟App服务重试异常,触发下一次调用...
[bizsip-integrator:192.169.1.103:8888] 13:24:58 INFO 70936 [7a36a3f4c22e40a49792931645570553] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-1] c.b.b.s.a.s.Sample15DelayAppService      延迟App服务调用第[4]次: 
{
    "maxRetryCount": 4,
    "result": "success"
}
[bizsip-integrator:192.169.1.103:8888] 13:24:58 INFO 70936 [7a36a3f4c22e40a49792931645570553] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-1] c.b.b.s.a.s.Sample15DelayAppService      返回成功!

可以看到Sample15DelayAppService类一共被调用了4次,最后返回成功,中间的时间间隔分别为1秒、2秒、5秒(时间精确度关系,略有误差)。

其次,请求报文中设置最大重试次数(maxRetryCount)为3,最终返回结果(result)为“fail”。

$ curl -H "Content-Type:application/json" -H "Biz-Service-Id:/bean/sample15" -X POST --data '{"maxRetryCount":3,"result":"fail"}' http://localhost:8888/api|jq

{
  "code": 0,
  "message": "success",
  "extMessage": null,
  "appServiceId": "/bean/sample15",
  "traceId": "a60d017e00554dd6a779a478ced2c7f5",
  "parentTraceId": null,
  "timestamp": 1648359627667,
  "data": {
    "maxRetryCount": 3,
    "result": "fail"
  }
}

SampleAppApplication应用中被调用的Sample15DelayAppService类打印日志:

[bizsip-integrator:192.169.1.103:8888] 13:40:27 INFO 70936 [2b2564ca72d74251b3e1d7bac2a99242] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-5] c.b.b.s.a.s.Sample15DelayAppService      延迟App服务调用第[1]次: 
{
    "maxRetryCount": 3,
    "result": "fail"
}
[bizsip-integrator:192.169.1.103:8888] 13:40:27 INFO 70936 [2b2564ca72d74251b3e1d7bac2a99242] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-5] c.b.b.s.a.s.Sample15DelayAppService      抛出延迟App服务重试异常,触发下一次调用...
[bizsip-integrator:192.169.1.103:8888] 13:40:28 INFO 70936 [2b2564ca72d74251b3e1d7bac2a99242] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-4] c.b.b.s.a.s.Sample15DelayAppService      延迟App服务调用第[2]次: 
{
    "maxRetryCount": 3,
    "result": "fail"
}
[bizsip-integrator:192.169.1.103:8888] 13:40:28 INFO 70936 [2b2564ca72d74251b3e1d7bac2a99242] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-4] c.b.b.s.a.s.Sample15DelayAppService      抛出延迟App服务重试异常,触发下一次调用...
[bizsip-integrator:192.169.1.103:8888] 13:40:30 INFO 70936 [2b2564ca72d74251b3e1d7bac2a99242] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-3] c.b.b.s.a.s.Sample15DelayAppService      延迟App服务调用第[3]次: 
{
    "maxRetryCount": 3,
    "result": "fail"
}
[bizsip-integrator:192.169.1.103:8888] 13:40:30 INFO 70936 [2b2564ca72d74251b3e1d7bac2a99242] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-3] c.b.b.s.a.s.Sample15DelayAppService      返回错误!

可以看到Sample15DelayAppService类一共被调用了3次,最后返回失败,中间的时间间隔分别为1秒、2秒。

最后,请求报文中设置最大重试次数(maxRetryCount)为8,最终返回结果(result)为“success”。

$ curl -H "Content-Type:application/json" -H "Biz-Service-Id:/bean/sample15" -X POST --data '{"maxRetryCount":8,"result":"success"}' http://localhost:8888/api|jq

{
  "code": 0,
  "message": "success",
  "extMessage": null,
  "appServiceId": "/bean/sample15",
  "traceId": "19e559c658954b35861a32369b08f5b1",
  "parentTraceId": null,
  "timestamp": 1648359793722,
  "data": {
    "maxRetryCount": 8,
    "result": "success"
  }
}

SampleAppApplication应用中被调用的Sample15DelayAppService类打印日志:

[bizsip-integrator:192.169.1.103:8888] 13:43:13 INFO 70936 [6040bebfe86545e5a5bdbf36e4e25376] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-2] c.b.b.s.a.s.Sample15DelayAppService      延迟App服务调用第[1]次: 
{
    "maxRetryCount": 8,
    "result": "success"
}
[bizsip-integrator:192.169.1.103:8888] 13:43:13 INFO 70936 [6040bebfe86545e5a5bdbf36e4e25376] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-2] c.b.b.s.a.s.Sample15DelayAppService      抛出延迟App服务重试异常,触发下一次调用...
[bizsip-integrator:192.169.1.103:8888] 13:43:14 INFO 70936 [6040bebfe86545e5a5bdbf36e4e25376] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-1] c.b.b.s.a.s.Sample15DelayAppService      延迟App服务调用第[2]次: 
{
    "maxRetryCount": 8,
    "result": "success"
}
[bizsip-integrator:192.169.1.103:8888] 13:43:14 INFO 70936 [6040bebfe86545e5a5bdbf36e4e25376] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-1] c.b.b.s.a.s.Sample15DelayAppService      抛出延迟App服务重试异常,触发下一次调用...
[bizsip-integrator:192.169.1.103:8888] 13:43:16 INFO 70936 [6040bebfe86545e5a5bdbf36e4e25376] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-5] c.b.b.s.a.s.Sample15DelayAppService      延迟App服务调用第[3]次: 
{
    "maxRetryCount": 8,
    "result": "success"
}
[bizsip-integrator:192.169.1.103:8888] 13:43:16 INFO 70936 [6040bebfe86545e5a5bdbf36e4e25376] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-5] c.b.b.s.a.s.Sample15DelayAppService      抛出延迟App服务重试异常,触发下一次调用...
[bizsip-integrator:192.169.1.103:8888] 13:43:20 INFO 70936 [6040bebfe86545e5a5bdbf36e4e25376] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-4] c.b.b.s.a.s.Sample15DelayAppService      延迟App服务调用第[4]次: 
{
    "maxRetryCount": 8,
    "result": "success"
}
[bizsip-integrator:192.169.1.103:8888] 13:43:20 INFO 70936 [6040bebfe86545e5a5bdbf36e4e25376] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-4] c.b.b.s.a.s.Sample15DelayAppService      抛出延迟App服务重试异常,触发下一次调用...
[bizsip-integrator:192.169.1.103:8888] 13:43:28 INFO 70936 [6040bebfe86545e5a5bdbf36e4e25376] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-3] c.b.b.s.a.s.Sample15DelayAppService      延迟App服务调用第[5]次: 
{
    "maxRetryCount": 8,
    "result": "success"
}
[bizsip-integrator:192.169.1.103:8888] 13:43:28 INFO 70936 [6040bebfe86545e5a5bdbf36e4e25376] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-3] c.b.b.s.a.s.Sample15DelayAppService      抛出延迟App服务重试异常,触发下一次调用...
[bizsip-integrator:192.169.1.103:8888] 13:43:44 INFO 70936 [6040bebfe86545e5a5bdbf36e4e25376] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-2] c.b.b.s.a.s.Sample15DelayAppService      延迟App服务调用第[6]次: 
{
    "maxRetryCount": 8,
    "result": "success"
}
[bizsip-integrator:192.169.1.103:8888] 13:43:44 INFO 70936 [6040bebfe86545e5a5bdbf36e4e25376] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-2] c.b.b.s.a.s.Sample15DelayAppService      抛出延迟App服务重试异常,触发下一次调用...
[bizsip-integrator:192.169.1.103:8888] 13:43:44 WARN 70936 [6040bebfe86545e5a5bdbf36e4e25376] [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-2] c.b.b.a.l.DelayAppServiceQueueListener   延迟App服务重试次数超过次数[6],服务失败!

可以看到Sample15DelayAppService类一共被调用了6次,最后提示“延迟App服务重试次数超过次数[6],服务失败!”,中间的时间间隔分别为1秒、2秒、4秒、8秒、16秒。

举报

相关推荐

0 条评论