关于CPI开发中的性能优化

经历的第一个CPI项目即将结束,从刚开始的一头雾水到现在算是初步掌握,过程中也算是踩过很多坑,趁着在园区隔离,总结下关于CPI开发中性能优化这个点的一些心得吧。

  • 内容大小
    官方建议的有效负载大小为40MB,附件的大小为100MB,遵循这个建议可以很大程度上避免运行时内存资源瓶颈。
  • 集成流步骤数
    集成流的每个步骤都会消耗内存和时间,每增加一个步骤都会增加整体运行时间,尽可能减少不必要拆开的步骤。
  • 内存与数据库
    数据可以保存在内存中,也可以保存在租户的数据库中,保存在内存中(propery或者Header)访问更快,但是大批量的数据可能会引发其他风险,例如内存资源不足导致CPI运行失败;保存在数据库中会消耗额外的时间,但是可以避免内存不足的风险。
  • 并行处理
    一般来说,并行处理(Multicast step and the Splitter steps)是会提高运行效率的,但如果在并行中调用的后端系统或者CPI本身无法处理调用的负载,也可能引发问题,例如数据量过大;另外不是所有时候都可以使用并行处理,比如启用JDBC事务或者一些有先后关系的处理,则应该使用Sequential Multicast而不是Parallel Multicast。
  • 批处理
    操作多条目数据时,尽可能使用批处理,而不是每次只查询一条或者更新一条,关于CPI中批处理的使用方式可以参照我的另一篇总结:CPI中通过$batch处理http请求https://blog.csdn.net/DeveloperMrMeng/article/details/121694432
  • 跟踪和记录
    将CPI日志级别设置为Trace可以很方便的帮助我们排查CPI运行期间每个节点的数据及状态,但是需要注意,当Trace级别被设置时,性能会有所降低,因为系统需要收集和写入所有的跟踪数据,会消耗时间和资源,所以除非排查错误原因,正常使用时不建议开启;另外使用MPL附件记录错误内容,也是很有效的一种方法,但是过量大小的日志附件也会对性能产生影响,需要合理控制,在我目前这个项目上,没有使用到该功能,创建MPL附件使用方式如下:

    import com.sap.gateway.ip.core.customdev.util.Message;
    import java.util.HashMap;
    def Message processData(Message message) {
        //Body 
        def body = message.getBody();
        body = "this is a test MPL Attachment"
        def messageLog = messageLogFactory.getMessageLog(message)
        if (messageLog != null) {
            messageLog.addAttachmentAsString('Additional information Test', body, 'text/plain')
        }
        return message;
    }


    可以使用该方式在发生异常或者报错时,将错误信息记录在MPL附件中,这样即使不启用Trace也可以简单得知报错原因。

  • 多分支传输数据
    当使用多分支方式处理数据时,尽可能在分支结束前,清空后续不需要的所有数据,类似ABAP中的清空工作区及内表,因为分支中的内容会一直停留在内存中,直到整个iflow运行结束才会释放,你可以利用groovy脚本或者Content Modifier组件来清空属性,标头以及变量。

  • 大批量数据多分支传输
    如果你的有效负载中数据量会很大,尽可能避免使用多分支处理,因为假如有三个分支,有效负载将在内存中存储三次,一次用于原始交换,两次用于每一个分支,所以在数据量小的时候可以使用Exchange Propery进行数据交换,数据量大的时候可以使用持久化存储的方式来避免,关于使用交换属性Propery以及持久化存储的使用方式,在我的以下两篇帖子中有进行介绍:CPI中Exchange Property和 Write Variables控件的使用https://blog.csdn.net/DeveloperMrMeng/article/details/118897402
    CPI控件Data Store使用介绍https://blog.csdn.net/DeveloperMrMeng/article/details/123381562

  • 脚本中的变量
    及时清空脚本中包含大量数据的变量,因为会占用内存直到iflow运行结束,同时尽可能避免以下方式定义变量:
    name = "zhangsan";
    正确方式:
    def name = "zhangsan" 
    String name = "zhangsan"
  • 全局标头和属性
    同理及时清空后续步骤不需要的标头及属性。
  • XPATH条件
    尽量使用绝对路径,因为XPATH表达式非常消耗内存,解析器会在整个文档中检索指定元素。
    绝对路径:
    /Root/item/matnr
    相对路径:
    Root/item/matnr
  • 使用流式传输
    大批量的数据传输会导致处理时长增加,内存占用增加,最坏可能会导致内存不足而引发执行失败,例如以下场景:
    在访问解析有效负载中的XML内容时,我们一般的写法如下:
     
    def body = message.getBody(java.lang.String)
    
    //使用XmlSlurper解析
    def xml = new XmlSlurper().parseText(body)
    
    //使用XmlParser解析
    def xml = new XmlParser().parseText(body)

    以上两种解析方式都使用的是java.lang.String类型的body,大部分情况下都不会有问题,但是使用String类型进行转换会占用额外的内存,所以可以使用以下方式将内容转化为IO数据流再进行解析,将会避免额外的内存分配,包括JSON解析也是类似:

    def body = message.getBody(java.io.Reader)
    def xml = new XmlSlurper().parse(body)
    def body = message.getBody(java.io.Reader);
    def newBody = new JsonSlurper().parse(body)
  • 正确的使用下标
    通常情况使用下标访问数组时,是可以直接根据下标访问到对应数据的,但有时可能会因为使用方式不当导致效率低下,例如以下例子:

     脚本中定义了变量returnlist,类型为上图所示,实际上可以理解为一个具有深层结构的内表,toReturn是一个表类型字段,后续在循环访问每一行的Result字段时,以下两种方式在数据量大的时候在效率上会有非常明显的差距:

    //错误写法
    returnlist.toReturns[i].each{
        Messages = new MessagesStruc(
            HGUID: headerguid,
            MsgType: it.MsgType,
            MsgClass: it.MsgClass,
            MsgNo: it.MsgNo,
            Message: it.Message,
        )
        toMessages.add(Messages)
    }
    //正确写法
    returnlist[i].toReturns.each{
        Messages = new MessagesStruc(
            HGUID: headerguid,
            MsgType: it.MsgType,
            MsgClass: it.MsgClass,
            MsgNo: it.MsgNo,
            Message: it.Message,
        )
        toMessages.add(Messages)
    }

    就是一个小小的下标位置错误,导致在遍历数据效率上有极大差异,类似于ABAP中的LOOP多层嵌套。


    以上为经历了第一个CPI项目关于性能优化的一点心得,回顾整个开发周期,前期因为对这个产品的开发各种不熟悉,写出了很多在现在看来不完美的接口方案,简单总结一下,希望后面在开发过程中可以避免掉一些性能问题。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DeveloperMrMeng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值