本来RFC性能好于WebService是毋庸置疑的,但是最近总有兄弟说WebService或者Restful性能好于RFC,于是有了此篇文章,以正视听。
首先,在确定的服务器、客户端,接口逻辑和数据量一定的前提下,RFC的性能主要取决与两个地方,一是内表放到Tables还是Export下面,二是RFC的序列化协议。



一般来说,如果协议是典型序列化器(Classic Serializer),内表放到Export和放到Tables两者之间性能差别是非常大的,在检查RFC函数的时候,系统也会警告提示:
如果是其他协议,则放到哪儿都是一样的。
为了直观的对比各个场景的性能差异,我写了一个简单的对比程序,在同一个系统/不同系统、Export参数/Tables参数、不同序列化协议、不同数据量和调用次数,以及WebService的运行时间对比。
对比结果如下,后面的数值是所用时间,单位为微秒:
首先是小数据量(100条)的单次调用
其次是大数据量(内表100000条)的单次调用
最后是小数据量(内表100条)的多次(100次)调用
需要说明的是,程序运行在S4,而远程系统是ECC6,ECC6是不支持快速序列化的,所以跨系统RFC的快速序列化并没有特别的快。
结论:
1、如果是用Classic协议,内表一定不要在Export,否则性能极差。
2、BasXML协议是需要转成XML来传输的,性能不是太好。
3、快速序列化是性能最好的,但是老系统不支持,S4开始支持,如果可能请尽量使用此序列化协议。
4、WebService性能不如RFC,小数据量且调用次数较少时可以使用。
5、Restful因为可以自定义传输数据的格式,方法不同性能差别也很大,所以就不做比较了,但是大概可以参考WebService的性能。
附测试程序和函数:
REPORT ztestrfc NO STANDARD PAGE HEADING.
DATA: itab TYPE TABLE OF dd02l.
DATA: ws_proxy TYPE REF TO zwsco_zget_dd02l.
DATA: ws_input TYPE zwszget_dd02l.
DATA: ws_respo TYPE zwszget_dd02lresponse.
DATA: eoutab TYPE zwscnvmbt_dd02l_t,
toutab TYPE zwstable_of_dd02l,
initab TYPE zwsdd02l_tab WITH HEADER LINE.
DATA: t1 TYPE i,
t2 TYPE i.
PARAMETERS: p_dbcnt TYPE sy-dbcnt DEFAULT 3000.
PARAMETERS: p_count TYPE i DEFAULT 1.
AT SELECTION-SCREEN OUTPUT.
%_p_dbcnt_%_app_%-text = '内表条数'.
%_p_count_%_app_%-text = '连续调用次数'.
START-OF-SELECTION.
WRITE: '内表条目数:',p_dbcnt.
WRITE: / '调用次数:',p_count.
SKIP.
GET RUN TIME FIELD t1.
DO p_count TIMES.
CLEAR itab[].
CALL FUNCTION 'ZGET_DD02L'
EXPORTING
dbcnt = p_dbcnt
param = 'E'
IMPORTING
eoutab = itab.
ENDDO.
GET RUN TIME FIELD t2.
t1 = t2 - t1.
WRITE: /(30)'正常函数调用Export:', t1.
GET RUN TIME FIELD t1.
DO p_count TIMES.
CLEAR itab[].
CALL FUNCTION 'ZGET_DD02L'
EXPORTING
dbcnt = p_dbcnt
param = 'T'
TABLES
toutab = itab.
ENDDO.
GET RUN TIME FIELD t2.
t1 = t2 - t1.
WRITE: /(30)'正常函数调用Table:', t1.
***RFC Classic序列化器
SKIP.
WRITE '本系统RFC' COLOR 1.
GET RUN TIME FIELD t1.
DO p_count TIMES.
CALL FUNCTION 'RFC_CONNECTION_CLOSE'
EXPORTING
destination = 'DS4_185_C'
EXCEPTIONS
destination_not_open = 1.
CLEAR itab[].
CALL FUNCTION 'ZGET_DD02L' DESTINATION 'DS4_185_C'
EXPORTING
dbcnt = p_dbcnt
param = 'E'
IMPORTING
eoutab = itab.
ENDDO.
GET RUN TIME FIELD t2.
t1 = t2 - t1.
WRITE: /(30)'Classic序列化器 Export:', t1.
GET RUN TIME FIELD t1.
DO p_count TIMES.
CALL FUNCTION 'RFC_CONNECTION_CLOSE'
EXPORTING
destination = 'DS4_185_C'
EXCEPTIONS
destination_not_open = 1.
CLEAR itab[].
CALL FUNCTION 'ZGET_DD02L' DESTINATION 'DS4_185_C'
EXPORTING
dbcnt = p_dbcnt
param = 'T'
TABLES
toutab = itab.
ENDDO.
GET RUN TIME FIELD t2.
t1 = t2 - t1.
WRITE: /(30)'Classic序列化器 Table:', t1.
***BasXML
SKIP.
GET RUN TIME FIELD t1.
DO p_count TIMES.
CALL FUNCTION 'RFC_CONNECTION_CLOSE'
EXPORTING
destination = 'DS4_185_B'
EXCEPTIONS
destination_not_open = 1.
CLEAR itab[].
CALL FUNCTION 'ZGET_DD02L' DESTINATION 'DS4_185_B'
EXPORTING
dbcnt = p_dbcnt
param = 'E'
IMPORTING
eoutab = itab.
ENDDO.
GET RUN TIME FIELD t2.
t1 = t2 - t1.
WRITE: /(30)'BasXML Export:', t1.
GET RUN TIME FIELD t1.
DO p_count TIMES.
CALL FUNCTION 'RFC_CONNECTION_CLOSE'
EXPORTING
destination = 'DS4_185_B'
EXCEPTIONS
destination_not_open = 1.
CLEAR itab[].
CALL FUNCTION 'ZGET_DD02L' DESTINATION 'DS4_185_B'
EXPORTING
dbcnt = p_dbcnt
param = 'T'
TABLES
toutab = itab.
ENDDO.
GET RUN TIME FIELD t2.
t1 = t2 - t1.
WRITE: /(30)'BasXML Table:', t1.
***强制BasXML序列化器
SKIP.
GET RUN TIME FIELD t1.
DO p_count TIMES.
CALL FUNCTION 'RFC_CONNECTION_CLOSE'
EXPORTING
destination = 'DS4_185_O'
EXCEPTIONS
destination_not_open = 1.
CLEAR itab[].
CALL FUNCTION 'ZGET_DD02L' DESTINATION 'DS4_185_O'
EXPORTING
dbcnt = p_dbcnt
param = 'E'
IMPORTING
eoutab = itab.
ENDDO.
GET RUN TIME FIELD t2.
t1 = t2 - t1.
WRITE: /(30)'强制BasXML Export:', t1.
GET RUN TIME FIELD t1.
DO p_count TIMES.
CALL FUNCTION 'RFC_CONNECTION_CLOSE'
EXPORTING
destination = 'DS4_185_O'
EXCEPTIONS
destination_not_open = 1.
CLEAR itab[].
CALL FUNCTION 'ZGET_DD02L' DESTINATION 'DS4_185_O'
EXPORTING
dbcnt = p_dbcnt
param = 'T'
TABLES
toutab = itab.
ENDDO.
GET RUN TIME FIELD t2.
t1 = t2 - t1.
WRITE: /(30)'强制BasXML Table:', t1.
***快速序列化器
SKIP.
GET RUN TIME FIELD t1.
DO p_count TIMES.
CALL FUNCTION 'RFC_CONNECTION_CLOSE'
EXPORTING
destination = 'DS4_185_F'
EXCEPTIONS
destination_not_open = 1.
CLEAR itab[].
CALL FUNCTION 'ZGET_DD02L' DESTINATION 'DS4_185_F'
EXPORTING
dbcnt = p_dbcnt
param = 'E'
IMPORTING
eoutab = itab.
ENDDO.
GET RUN TIME FIELD t2.
t1 = t2 - t1.
WRITE: /(30)'快速序列化器 Export:', t1.
GET RUN TIME FIELD t1.
DO p_count TIMES.
CALL FUNCTION 'RFC_CONNECTION_CLOSE'
EXPORTING
destination = 'DS4_185_F'
EXCEPTIONS
destination_not_open = 1.
CLEAR itab[].
CALL FUNCTION 'ZGET_DD02L' DESTINATION 'DS4_185_F'
EXPORTING
dbcnt = p_dbcnt
param = 'T'
TABLES
toutab = itab.
ENDDO.
GET RUN TIME FIELD t2.
t1 = t2 - t1.
WRITE: /(30)'快速序列化器 Table:', t1.
***不同系统 ClassicRFC
SKIP.
WRITE '跨系统RFC' COLOR 1.
***Classic
GET RUN TIME FIELD t1.
DO p_count TIMES.
CALL FUNCTION 'RFC_CONNECTION_CLOSE'
EXPORTING
destination = 'HSD_125_C'
EXCEPTIONS
destination_not_open = 1.
CLEAR itab[].
CALL FUNCTION 'ZGET_DD02L' DESTINATION 'HSD_125_C'
EXPORTING
dbcnt = p_dbcnt
param = 'E'
IMPORTING
eoutab = itab.
ENDDO.
GET RUN TIME FIELD t2.
t1 = t2 - t1.
WRITE: /(30)'Classic序列化器 Export:', t1.
GET RUN TIME FIELD t1.
DO p_count TIMES.
CALL FUNCTION 'RFC_CONNECTION_CLOSE'
EXPORTING
destination = 'HSD_125_C'
EXCEPTIONS
destination_not_open = 1.
CLEAR itab[].
CALL FUNCTION 'ZGET_DD02L' DESTINATION 'HSD_125_C'
EXPORTING
dbcnt = p_dbcnt
param = 'T'
TABLES
toutab = itab.
ENDDO.
GET RUN TIME FIELD t2.
t1 = t2 - t1.
WRITE: /(30)'Classic序列化器 Table:', t1.
***BasXML
SKIP.
GET RUN TIME FIELD t1.
DO p_count TIMES.
CALL FUNCTION 'RFC_CONNECTION_CLOSE'
EXPORTING
destination = 'HSD_125_B'
EXCEPTIONS
destination_not_open = 1.
CLEAR itab[].
CALL FUNCTION 'ZGET_DD02L' DESTINATION 'HSD_125_B'
EXPORTING
dbcnt = p_dbcnt
param = 'E'
IMPORTING
eoutab = itab.
ENDDO.
GET RUN TIME FIELD t2.
t1 = t2 - t1.
WRITE: /(30)'BasXML Export:', t1.
GET RUN TIME FIELD t1.
DO p_count TIMES.
CALL FUNCTION 'RFC_CONNECTION_CLOSE'
EXPORTING
destination = 'HSD_125_B'
EXCEPTIONS
destination_not_open = 1.
CLEAR itab[].
CALL FUNCTION 'ZGET_DD02L' DESTINATION 'HSD_125_B'
EXPORTING
dbcnt = p_dbcnt
param = 'T'
TABLES
toutab = itab.
ENDDO.
GET RUN TIME FIELD t2.
t1 = t2 - t1.
WRITE: /(30)'BasXML Table:', t1.
***强制BasXML序列化器
SKIP.
GET RUN TIME FIELD t1.
DO p_count TIMES.
CALL FUNCTION 'RFC_CONNECTION_CLOSE'
EXPORTING
destination = 'HSD_125_O'
EXCEPTIONS
destination_not_open = 1.
CLEAR itab[].
CALL FUNCTION 'ZGET_DD02L' DESTINATION 'HSD_125_O'
EXPORTING
dbcnt = p_dbcnt
param = 'E'
IMPORTING
eoutab = itab.
ENDDO.
GET RUN TIME FIELD t2.
t1 = t2 - t1.
WRITE: /(30)'强制BasXML Export:', t1.
GET RUN TIME FIELD t1.
DO p_count TIMES.
CALL FUNCTION 'RFC_CONNECTION_CLOSE'
EXPORTING
destination = 'HSD_125_O'
EXCEPTIONS
destination_not_open = 1.
CLEAR itab[].
CALL FUNCTION 'ZGET_DD02L' DESTINATION 'HSD_125_O'
EXPORTING
dbcnt = p_dbcnt
param = 'T'
TABLES
toutab = itab.
ENDDO.
GET RUN TIME FIELD t2.
t1 = t2 - t1.
WRITE: /(30)'强制BasXML Table:', t1.
***快速序列化器
SKIP.
GET RUN TIME FIELD t1.
DO p_count TIMES.
CALL FUNCTION 'RFC_CONNECTION_CLOSE'
EXPORTING
destination = 'HSD_125_F'
EXCEPTIONS
destination_not_open = 1.
CLEAR itab[].
CALL FUNCTION 'ZGET_DD02L' DESTINATION 'HSD_125_F'
EXPORTING
dbcnt = p_dbcnt
param = 'E'
IMPORTING
eoutab = itab.
ENDDO.
GET RUN TIME FIELD t2.
t1 = t2 - t1.
WRITE: /(30)'快速序列化器 Export:', t1.
GET RUN TIME FIELD t1.
DO p_count TIMES.
CALL FUNCTION 'RFC_CONNECTION_CLOSE'
EXPORTING
destination = 'HSD_125_F'
EXCEPTIONS
destination_not_open = 1.
CLEAR itab[].
CALL FUNCTION 'ZGET_DD02L' DESTINATION 'HSD_125_F'
EXPORTING
dbcnt = p_dbcnt
param = 'T'
TABLES
toutab = itab.
ENDDO.
GET RUN TIME FIELD t2.
t1 = t2 - t1.
WRITE: /(30)'快速序列化器 Table:', t1.
***WebService
APPEND INITIAL LINE TO initab.
ws_input-toutab-item[] = initab[].
SKIP.
ws_input-dbcnt = p_dbcnt.
ws_input-param = 'E'.
GET RUN TIME FIELD t1.
TRY .
CREATE OBJECT ws_proxy.
DO p_count TIMES.
CALL METHOD ws_proxy->zget_dd02l
EXPORTING
input = ws_input
IMPORTING
output = ws_respo.
ENDDO.
CATCH cx_root.
ENDTRY.
GET RUN TIME FIELD t2.
t1 = t2 - t1.
WRITE: /(30) 'WebService Export:', t1.
ws_input-dbcnt = p_dbcnt.
ws_input-param = 'T'.
GET RUN TIME FIELD t1.
TRY .
CREATE OBJECT ws_proxy.
DO p_count TIMES.
CALL METHOD ws_proxy->zget_dd02l
EXPORTING
input = ws_input
IMPORTING
output = ws_respo.
ENDDO.
CATCH cx_root.
ENDTRY.
GET RUN TIME FIELD t2.
t1 = t2 - t1.
WRITE: /(30) 'WebService Table:', t1.两个系统的函数是一样的:

FUNCTION zget_dd02l.
*"----------------------------------------------------------------------
*"*"本地接口:
*" IMPORTING
*" VALUE(DBCNT) TYPE SY-DBCNT OPTIONAL
*" VALUE(PARAM) TYPE CHAR1 OPTIONAL
*" EXPORTING
*" VALUE(EOUTAB) TYPE CNVMBT_DD02L_T
*" TABLES
*" TOUTAB STRUCTURE DD02L OPTIONAL
*"----------------------------------------------------------------------
CHECK dbcnt IS NOT INITIAL.
CLEAR: eoutab[],toutab[].
SELECT SINGLE * INTO toutab FROM dd02l.
IF param = 'T'.
DO dbcnt TIMES.
APPEND toutab.
ENDDO.
ELSE.
DO dbcnt TIMES.
APPEND toutab TO eoutab.
ENDDO.
ENDIF.
ENDFUNCTION.
本文通过实测比较了RFC(RemoteFunctionCall)与WebService在不同序列化协议、数据量和调用次数下的性能,发现经典序列化器和BasXML性能较差,快速序列化效果最好,但需注意ECC6系统不支持快速序列化。同时指出WebService在某些场景下的性能表现。

3895

被折叠的 条评论
为什么被折叠?



