The performance of each of these components is influential in the overall performance of the system:
The Application Server(s) topology and configuration.
The RIB deployment approach.
The hardware sizing and configuration of the RIB hosts.
The hardware sizing and configuration of the applications that are connected to the RIB.
The hardware sizing and configuration of the JMS provider host.
The hardware sizing and configuration of the RIB Hospitals hosts.
There are other factors that determine the performance of the overall system. Some of these factors in a RIB environment are:
Number of channels configured
Number of messages present in the topic
Size of the message
Database clustering
Application Server topology
Number of TAFR-s in the processing of the message
Message aggregation
The performance of the RIB is a complicated subsystem to measure and involves not only host level performance, but database and application server subsystems performance. To make measurement of the RIB components timing characteristics available for analysis, the kernel code has been instrumented to log events as it processes events. The logging of these events is though log4j.
The timings are logged per adapter. Once the timings are enabled the events are logging continuously to the file.
There is a post-processing tool included in RDMT to take the timing file and produce summary reports.
Control of the timing log is via the RIB Admin UI or the RIBLOGS log4j control file.
Once the timing logs are created, they need to be post-processed and analyzed. The process to do that is to use the RDMT Timing Log Utility to post-process the adapter.timing.log file. This creates a .csv file that can then be viewed and printed by a spreadsheet tool (e.g. Microsoft Excel).
The row headings that are displayed depend on the API type the adapter is interfaced to, PL/SQL or JavaEE and the adapter type; PUB, SUB, or TAFR. The above example is from a PL/SQL Publisher.
This table lists all of the column headings on the report and the definition of each.
TIMING_TYPE | The type is the predefined interval of time across two or more timings log statements. |
COUNT | Count of similar timing_types for this msgtype. |
AVERAGE_TIME (sec) | TIME_SUM/COUNT |
STANDARD_DEVIATION (sec) | Math.sqrt((TIME_SQUARED_SUM - (TIME_SUM * TIME_SUM/COUNT)))/(COUNT - 1). |
TIME_SUM (sec) | Sum of all time intervals for this timing_type. |
TIME_SQUARED_SUM (sec) | Individual squares of timing intervals for this timing_type. |
MIN_TIME (sec) | Least time interval for this timing_ type. |
MAX_TIME (sec) | Max time interval for this timing_type. |
THRESHOLD (sec) | Default Threshold is 10 sec, if any time interval takes more than 10 sec its tracked under over_threshold. |
OVER_THRESHOLD_COUNT | Number of over threshold intervals. |
OVER_THRESHOLD_SUM (sec) | Summation of all such intervals that are greater than threshold. |
OVER_THRESHOLD_AVG (sec) | Average all such intervals that are greater than threshold. |
This table lists the currently pre-defined time intervals interpreted by the timings logs processor utility. They are the row headings in the report under the column heading Timing Types. The description is the definition of interval calculation.
Timing Type | Description |
---|---|
PUB_B4_GETNXT_CALL | Time interval between start of the publisher and the actual GETNXT call. |
PUB_TIME_IN_GETNXT_CALL | Time taken by the GETNXT call to the plsql app. |
PUB_TIME_IN_EJB_PUBLISH_CALL | Time taken for the publish call in the EJB, includes RIB overhead surrounding the actual publish to the JMS. |
PUB_TOTAL_PUBLISH_TIME | Time taken for the complete PUB process = GETNXT + hospital dependency + publish + commit. |
PUB_TIME_IN_REAL_JMS_PUBLISH | Time taken to publish a message to the AQ JMS. |
SUB_TIME_IN_CONSUME_CALL | Time taken by the CONSUME call to the plsql app. |
SUB_TOTAL_SUBSCRIBE_TIME | Time taken for the complete SUB process = CONSUME/INJECT + hospital dependency + subscribe + commit. |
SUB_TIME_IN_EJB_SUBSCRIBE_CALL | Time taken for the subscribe call in the EJB, includes RIB overhead surrounding the actual subscribe. |
SUB_TIME_IN_INJECT_CALL | Time taken by the INJECT call to the java app. |
TAFR_TOTAL_MSGPROCESS_TIME | Time taken in the complete message tafring Process = TAFRing + hospital dependency + publish + RIB overhead |
TAFR_TIME_IN_EJB_CALL | Time taken for the TAFR call in the EJB, includes RIB overhead surrounding the actual TAFRing |
TAFR_TIME_IN_REAL_JMS_PUBLISH_EJB | Time taken by the TAFR to publish a message to the AQ JMS. |
This a partial extract of a post-processor report on an RMS Order_pub adapter timing log.
Timings for the Period 09:00:00 to 09:59:59
TIMING_TYPE | COUNT | AVG_TIME | STD_DEV | TIME_SUM |
---|---|---|---|---|
PUB_B4_GETNXT_CALL | 220 | 0.02239 | 0.00041 | 4.926 |
PUB_TIME_IN_GETNXT_CALL | 220 | 0.15503 | 0.0067 | 34.107 |
PUB_TIME_IN_EJB_PUBLISH_CALL | 220 | 1.82395 | 0.05014 | 401.269 |
PUB_TOTAL_PUBLISH_TIME | 220 | 2.11173 | 0.04992 | 464.58 |
PUB_TIME_IN_REAL_JMS_PUBLISH_EJB | 220 | 1.81753 | 0.05012 | 399.856 |
In this example the messages were published between 09:00 - 10:00 AM. In this example the messages were published between 09:00 - 10:00 AM.
T4 - PUB_TOTAL_PUBLISH_TIME is the total time taken for the complete PUB process.
T1 - PUB_B4_GETNXT_CALL is the time interval between start of the GETNXT EJB and the PL/SQL GETNXT API call.
T2 - PUB_TIME_IN_GETNXT_CALL is time taken by the PL/SQL API GETNXT call.
T3 - PUB_TIME_IN_EJB_PUBLISH_CALL is the time taken for the EJB publisher call.
T5 - PUB_TIME_IN_REAL_JMS_PUBLISH is the time taken to publish a message to the JMS
T3 = T5 + (RIB Overhead payload creation)
T4 = T1 + T2 + T3 + (Hospital Dependency Checks)
In this example the data points give these insights into the RIB performance.
"The average time to publish a message is 2.1 seconds.
The time spent in the PL/SQL API is 0.15 seconds/message
The time spent in the call to the JMS is 1.8 seconds/message
Note: This is an illustration and not a measure of actual through-put or numbers that can be extrapolated to indicate volume performance. The number of message needed to arrive at a calculation of through-put would require much higher counts and across a broad spectrum of time and system load. Other factor including average size of message used is also a factor. |
A channel is a solution approach to maintaining the previous RIB release concept of a "Logical Channel", also known as multi-threading.
Multi-channel is concept to logically partitioning the flow of messages within the JMS topic so that multiple publisher and subscriber can simultaneously use the same JMS topic without any contention or interference with each other and preserving publication message ordering within the logical channel.
Every adapter instance of a publisher, subscriber, or TAFR, configured in the RIB is considered to belong to a logical channel for processing messages. By multi-channel adapters we mean multiple adapter instances for the same message family, each processing messages asynchronously and in parallel.
There are critical rules of behavior that have to be observed and enforced to maintain the two primary RIB functional requirements of once-and-only-once successful delivery and guaranteed sequencing of messages within a message family.
To ensure that these rules are followed and to make the tasks of configuration of the RIB to support a multi-channel message flow as simple as possible, the process has been integrated into the RIB App Builder tools.
When multiple channels are being considered, they must be defined and configured across all publisher, subscriber, and TAFRs that participate in an end-to-end message flow to and from all Oracle Retail applications for that message family. The RIB App Builder tools have checks and verification logic to prevent deployment of incomplete flows.
Multi-channels can be a valuable tool to increase performance, but it does not help in every situation. There is overhead and complexity associated with implementing multiple channels so they should not be considered unless a defined and performance problem exists. The process of adding multi-channels to a message family should be part of a performance test and tuning process.
Each messaging RIB component involved in publishing or subscribing to a logical channel is distinctly identified by a JMS Message property known as "threadValue" with a specific value. This JMS message property and the value it contains define the logical channel.
JMS Message properties are user-defined additional properties that are included with the message. Message properties have types, and these types define application-specific information that message consumers can use to select the messages that interest them.
So each RIB subscriber has the "threadValue" property and this value as part of its JMS Durable Subscriber selector and each RIB publisher sets the "threadValue" JMS message property to a specific value for each message it publishes.
Oracle Retail RIB components are capable of being multi-channeled by making configuration changes to the system. The base RIB configuration, as shipped GA, provides each Message Family with one channel where all components set or look for "threadValue" of 1 (one). The naming convention and the RIB kernel code identify the RIB adapters by adding the logical channel to the end of the adapter class name.
Channels are calculated based on Business object ID(BOID) found in the RibMessages <id> tag. The algorithm used to calculate is as follows.
MOD(MD5(family + ":" + businessObjectId)%maxChannelNumber) + 1
First the algorithm calculates the message digest of the string family+":"+businessObjectId which produces a unique number.
Then this number is divided by the maxChannelNumber, which is calculated by the number of configured channels for that message family.
A 1 is added to the result so that the channel number is always greater than 0.
For example:
Family = Alloc BusinessObjectID (BOID) = 10202123 MaxChannelNumber = 7 (Total number of channels configured for the Alloc family) Then the channel number for the BOID is calculated as sMOD(MD5(Alloc + ":" + 10202123)%7) + 1 = 4 which means that all the messages that have BusinessObjectID of 10202123 are ALWAYS sent through channel 4 (Alloc_pub_4).
Note: The channels have to be configured throughout the integration flow using the rib-app builder tool. |
Example of a Message Family Flow with a TAFR:
Alloc_pub_1
Alloc_tafr_1
StockOrder_sub_1
Determine the Family to multi-channel
Examine the rib-integration-flows.xml to identify all participants in the full flow.
In the rib-home modify the appropriate configuration files for each of the rib-<apps>.
rib-<app>-adapters.xml
rib-<app>-adapter-resources.properties
For PL/SQL Application edit the RIB_SETTINGS table.
Compile and Deploy
This example is to configure the Alloc message flow with five channels. Alloc is a complex flow in that it has multiple Oracle Retail application subscribers and a TAFR that transforms the messages from one family to another; Alloc to StockOrder.
Backup the following files.
"rib-home/application-assembly-home/rib-rms/rib-rms-adapters.xml
rib-home/application-assembly-home/rib-rms/rib-rms-resources.properties.
The following is the message flow for the Alloc Family from rib-integration-flows.xml that this example uses.
<message-flow id="1"> <node id="rib-rms.Alloc_pub" app-name="rib-rms" adapter-class-def="Alloc_pub" type="DbToJms"> <in-db>default</in-db> <out-topic>etAllocFromRMS</out-topic> </node> <node id="rib-tafr.Alloc_tafr" app-name="rib-tafr" adapter-class-def="Alloc_tafr" type="JmsToJms"> <in-topic>etAllocFromRMS</in-topic> <out-topic name="topic-name-key-iso">etStockOrdersISO</out-topic> <out-topic name="topic-name-key-wh">etStkOrdersFromRIBToWH{*}</out-topic> </node> <node id="rib-sim.StockOrder_sub" app-name="rib-sim" adapter-class-def="StockOrder_sub" type="JmsToDb"> <in-topic>etStockOrdersISO</in-topic> <out-db>default</out-db> </node> <node id="rib-rwms.StockOrder_sub" app-name="rib-rwms" adapter-class-def="StockOrder_sub" type="JmsToDb"> <in-topic>etStkOrdersFromRIBToWH1</in-topic> <out-db>default</out-db> </node> </message-flow>
Modify rib-rms-adapters.xml to add multiple channels.
Here is a snippet of rib-rms-adapters.xml
<publishers> <timer-driven id="Alloc_pub_1" initialState="running" timeDelay="10"> <timer-task> <class name="com.retek.rib.app.getnext.impl.GetNextTimerTaskImpl"/> <property name="maxChannelNumber" value="5" /> </timer-task> </timer-driven> <timer-driven id="Alloc_pub_2" initialState="running" timeDelay="10"> <timer-task> <class name="com.retek.rib.app.getnext.impl.GetNextTimerTaskImpl"/> <property name="maxChannelNumber" value="5" /> </timer-task> </timer-driven> <timer-driven id="Alloc_pub_3" initialState="running" timeDelay="10"> <timer-task> <class name="com.retek.rib.app.getnext.impl.GetNextTimerTaskImpl"/> <property name="maxChannelNumber" value="5" /> </timer-task> </timer-driven> <timer-driven id="Alloc_pub_4" initialState="running" timeDelay="10"> <timer-task> <class name="com.retek.rib.app.getnext.impl.GetNextTimerTaskImpl"/> <property name="maxChannelNumber" value="5" /> </timer-task> </timer-driven> <timer-driven id="Alloc_pub_5" initialState="running" timeDelay="10"> <timer-task> <class name="com.retek.rib.app.getnext.impl.GetNextTimerTaskImpl"/> <property name="maxChannelNumber" value="5" /> </timer-task> </timer-driven>
Modify rib-rms-adapter-resources.properties.
Alloc_pub_1.name=Alloc Publisher, channel 1 Alloc_pub_1.desc=Publisher for the Alloc family through channel 1. Alloc_pub_2.name=Alloc Publisher, channel 2 Alloc_pub_2.desc=Publisher for the Alloc family through channel 2. Alloc_pub_3.name=Alloc Publisher, channel 3 Alloc_pub_3.desc=Publisher for the Alloc family through channel 3. Alloc_pub_4.name=Alloc Publisher, channel 4 Alloc_pub_4.desc=Publisher for the Alloc family through channel 4. Alloc_pub_5.name=Alloc Publisher, channel 5 Alloc_pub_5.desc=Publisher for the Alloc family through channel 5.
Modify rib-tafr--adapters.xml to add channels for a family.
<tafrs> <message-driven id="Alloc_tafr_1" initialState="running" tafr-business-impl="com.retek.rib.domain.tafr.bo.impl.AllocToStockOrderFromRibBOImpl" /> <message-driven id="Alloc_tafr_2" initialState="running" tafr-business-impl="com.retek.rib.domain.tafr.bo.impl.AllocToStockOrderFromRibBOImpl" /> <message-driven id="Alloc_tafr_3" initialState="running" tafr-business-impl="com.retek.rib.domain.tafr.bo.impl.AllocToStockOrderFromRibBOImpl" /> <message-driven id="Alloc_tafr_4" initialState="running" tafr-business-impl="com.retek.rib.domain.tafr.bo.impl.AllocToStockOrderFromRibBOImpl" /> <message-driven id="Alloc_tafr_5" initialState="running" tafr-business-impl="com.retek.rib.domain.tafr.bo.impl.AllocToStockOrderFromRibBOImpl" />
Modify rib-tafr-adapters-resources.properties.
Alloc_tafr_1.name=AllocToStockOrder TAFR, channel 1 Alloc_tafr_1.desc=TAFR for converting Allocation messages to StockOrders and routing them to the correct warehouse or store system Alloc_tafr_2.name=AllocToStockOrder TAFR, channel 2 Alloc_tafr_2.desc=TAFR for converting Allocation messages to StockOrders and routing them to the correct warehouse or store system Alloc_tafr_3.name=AllocToStockOrder TAFR, channel 3 Alloc_tafr_3.desc=TAFR for converting Allocation messages to StockOrders and routing them to the correct warehouse or store system Alloc_tafr_4.name=AllocToStockOrder TAFR, channel 4 Alloc_tafr_4.desc=TAFR for converting Allocation messages to StockOrders and routing them to the correct warehouse or store system Alloc_tafr_5.name=AllocToStockOrder TAFR, channel 5 Alloc_tafr_5.desc=TAFR for converting Allocation messages to StockOrders and routing them to the correct warehouse or store system
Modify rib-sim-adapters.xml to add channels for a family.
<subscribers> <message-driven id="StockOrder_sub_1" initialState="running"/> <message-driven id="StockOrder_sub_2" initialState="running"/> <message-driven id="StockOrder_sub_3" initialState="running"/> <message-driven id="StockOrder_sub_4" initialState="running"/> <message-driven id="StockOrder_sub_5" initialState="running"/>
Modify rib-sim-adapters-properties.properties.
StockOrder_sub_1.name=StockOrder Subscriber, channel 1 StockOrder_sub_1.desc=Subscriber for the StockOrder family through channel 1. StockOrder_sub_2.name=StockOrder Subscriber, channel 2 StockOrder_sub_2.desc=Subscriber for the StockOrder family through channel 2. StockOrder_sub_3.name=StockOrder Subscriber, channel 3 StockOrder_sub_3.desc=Subscriber for the StockOrder family through channel 3. StockOrder_sub_4.name=StockOrder Subscriber, channel 4 StockOrder_sub_4.desc=Subscriber for the StockOrder family through channel 4. StockOrder_sub_5.name=StockOrder Subscriber, channel 5 StockOrder_sub_5.desc=Subscriber for the StockOrder family through channel 5.
Modify rib-rwms-adapters.xml to add channels for a family.
<subscribers> <message-driven id="StockOrder_sub_1" initialState="running"/> <message-driven id="StockOrder_sub_2" initialState="running"/> <message-driven id="StockOrder_sub_3" initialState="running"/> <message-driven id="StockOrder_sub_4" initialState="running"/> <message-driven id="StockOrder_sub_5" initialState="running"/>
Modifyrib-rwms-adapters-properties.properties.
StockOrder_sub_1.name=StockOrder Subscriber, channel 1 StockOrder_sub_1.desc=Subscriber for the stockorder family through channel 1. StockOrder_sub_2.name=StockOrder Subscriber, channel 2 StockOrder_sub_2.desc=Subscriber for the stockorder family through channel 2. StockOrder_sub_3.name=StockOrder Subscriber, channel 3 StockOrder_sub_3.desc=Subscriber for the stockorder family through channel 3. StockOrder_sub_4.name=StockOrder Subscriber, channel 4 StockOrder_sub_4.desc=Subscriber for the stockorder family through channel 4. StockOrder_sub_5.name=StockOrder Subscriber, channel 5 StockOrder_sub_5.desc=Subscriber for the stockorder family through channel 5.
When a PL/SQL Publishing adapter is multi-channeled, the application code needs to designate the message to a specific thread. In order to do this, a change needs to be made in the RIB_SETTINGS table.
Find the Family of messages that is being multi-channeled, and adjust the column NUM_THREADS to the appropriate number. In this example the number will be set to 4 for the Alloc Family.
In order to improve performance of GETNEXT, messages are aggregated before publishing to the JMS. Aggregation of payloads is performed on a per family basis. These properties must be used when RIB is being integrated to the PL/SQL applications. Hence, modifications need to be made for the respective rib-<pl-sql> apps on the RIB end.
maxNodesPerMessages - Maximum number of ribMessages per one RibMessage Envelope.
messagePerCommit - Maximum number of RibMessage's sent for a commit. In order to not overload the JMS with huge payloads this property must be set.
These properties should exist in the rib-<pl-sql>.properties file.
Items.maxNodesPerMessages=2
Meaning 2 ribMessages per RibMessage.
Items.messagePerCommit=5
Meaning 2 ribMessages per commit.
rib-rms is taken as an example in this configuration.
Edit the following file in rib-home
rib-home/application-assembly-home/rib-rms/rib-rms.properties
Add the following properties
Items.maxNodesPerMessagess=5
Items.MessagePerCommit=2
Using the app-builder tool compile/deploy the application.
rib-app-compile.sh
rib-app-deployer.sh -deploy-rib-app-ear rib-rms
For example, if there are 15 payloads waiting to be published in RMS, based on the above configuration one should be able to see the following. The scenario is depicted pictorially in the figure below.