The Oracle Enterprise Messaging Service (OEMS) provides a robust architecture for integrating business-critical applications. It is built on Java 2 Enterprise Edition (J2EE) standards such as the Java Message Service (JMS) and the J2EE ConnectorArchitecture (JCA). In addition, OEMS reduces the time, cost, and effort required to build integrated and distributed applications. Through a common interface, JMS, OEMS offers developers a quality of service (QoS) choice for persisting messages.
RIB will be certified with several JMS providers, starting with the OEMS JMS Database persistence option, which is the JMS interface to the Oracle Database Streams Advanced Queuing (AQ) feature. Subsequent releases will add certification of the WLS JMS (for the file and memory-persistence version) that is bundled with the WebLogic Application Server, as well as other JMS standard providers.
For more details on OEMS, see the Oracle® Containers for J2EE Services Guide - Using Oracle Enterprise Messaging Service.
The AQ JMS is a database and needs to be installed, configured, and tuned to support the anticipated transaction loads for a retailer's production message volumes.
The RIB team and the Database Administrators should consider the following.
It is strongly recommended that the Oracle Database Instance that is configured to be the AQ JMS provider is not shared with any other applications and is not on the same host (physical or logical) with any other applications.
AQ, on the server side is I/O intensive. Pay close attention to the disk layout.
AQ JMS as used by RIB has high transaction rates. Consider this when configuring the redo logs.
AQ JMS should be run in archive log mode. If the database crashes, it must be recoverable to a point-in-time, or messages (business events) will be lost.
RIB is a client of the AQ database and uses JDBC connections through the aqapi client. The average message size for a given interface affects the network and overall performance behavior.
AQ JMS sizing to avoid out-of-space situations is critical.
The QMON processes are optional background processes for Oracle Streams Advanced Queuing (AQ) which monitor and maintain all the system and user owned AQ objects. They provide the mechanism for message expiration, retry, and delay, maintain queue statistics, remove processed messages from the queue table and maintain the dequeue IOT.
The number of queue monitor processes is controlled by the dynamic initialization parameter AQ_TM_PROCESSES. There can be a maximum of 10 QMON processes. The parameter AQ_TM_PROCESSES can be set in the PFILE or SPFILE:
aq_tm_processes=4
alter system set aq_tm_processes=4
Starting with Oracle RDBMS release 10.1, Oracle automatically manages the QMON monitor processes depending on the system load. Explicitly setting AQ_TM_PROCESSES is not required. However, monitoring the workload and making adjustments as necessary is recommended. If the QMON processes lag behind, there is a chance of expired messages remaining in the queue and the tablespace eventually running out of space.
If explicitly setting AQ_TM_PROCESSES, the recommended value is between 2 and 8. Do not set the value to the maximum allowed value of 10 in Oracle, because all explicitly started QMON processes work only with persistent messages. Oracle can automatically start processes to maintain buffered messages. Setting AQ_TM_PROCESSES to a maximum value of 8 still leaves two processes for Oracle that can be started to maintain buffered messages.
The AQ database performance must be tuned according to Oracle database tuning practices.
To tune the SGA, use tools such as Statspack, Oracle Enterprise Manager and SQL trace to identify bottlenecks. An inefficiently configured SGA slows down enqueue and dequeue transactions.
To tune the Server Resources, check server CPU, memory, I/O, and network utilization. Tools such as nmon, sar, iostat, vmstat, and glance can be used to collect system statistics. Use shared memory and semaphore parameters that are recommended for the Oracle database on that type of server.
Tuning Physical Schema setup entails creating right tablespaces, placements of datafiles, tables, and indexes.
Note: See also Oracle® Database Administrator's Guide 12c Release 1 (12.1), Oracle® Streams Advance Queuing User's Guide, and Reference 12c Release 2 (12.1) |
The RIB team and Database Administrators provide the following considerations for sizing the deployment of RIB on AQ JMS:
The enqueuing/dequeuing rate for the messages per message family affects the requirement for the number of available database segments.
By default, all RIB topics are created in a single tablespace. AQ creates multiple tables for each topic within that tablespace. A topic (message family) with a high transaction rate can quickly consume available segments. If the tablespace is not sized appropriately, a single interface can negatively impact all interfaces.
The QMON background process that is responsible for space management will not keep up the transaction rates of some RIB interfaces. In this case, the transaction rate is defined as the rate of enqueuing versus dequeuing. Messages that are subscribed (consumed) are not removed from the AQ tables immediately. It is the normal case that the enqueue rate will be faster than the dequeue rate. This time lag should be a sizing consideration.
The total tablespace sizing must be calculated based on the business requirement for the number of messages that have to be retained per message family if a subscribing application is off-line.
It is very common for a subscribing application to go off-line. This means that messages must be retained (persisted) on the JMS until the subscriber comes back on-line. The general sizing guideline for any RIB JMS sub-system is for the disk (mount points or database) to be able to handle 24 hours of maximum messages per topic as defined by the site's projected volume requirements. For example, OrdersFromRMS may be specified to retain 355,000 details (such as 1000 1M messages = 1GB). This calculation must be performed for each of the 90+ topics in the GA RIB system and based on the customer's estimated volume per interface.
A process is a "thread of control," or a mechanism in an operating system, that can run a series of steps. (Some operating systems use the terms "job" or "task.") A process normally has its own private memory area in which it runs.
When RIB is configured to use the Oracle AQ JMS, there are considerations that affect RDBMS tuning and the configuration of database processes. This section is intended to outline these considerations.
The processes in an Oracle database system are categorized into two major groups:
User processes run the application or Oracle tool code.
Oracle database processes run the Oracle database server code. They include server processes and background processes.
The number of RIB related server side processes can grow based on activity. It is related to the way the application server container manages jdbc connections. The following rules apply:
Each subscriber uses one JDBC connection to AQ JMS.
Each Publisher or Hospital Retry may use one or more connections, depending on volume and activity.
When a RIB adapter (Java code) asks for a connection, the application server may decide to get more than one connection and add it to its pool.
RIB Adapter Type | Total Adapters in RIB |
---|---|
rib-app Subscriber | 81 |
TAFR Subscriber | 21 |
rib-app Polling Publisher | 33 |
rib-app Request-driven Publisher | 18 |
TAFR Publishers | 21 |
Hospital Retry - Polling Publisher | 16 |
Total | 190 |
At any time, depending on deployment options in a non-multiple channel deployment, RIB can have at least 190 AQ connections. The application server may ask for more than 190 from the database.
These numbers will increase if there are multiple retry adapters configured and if message flows are configured for multiple channels. So the calculation includes the base numbers plus one for each additional retry--and one for each multiple channel publisher or subscriber. Always assume that the result is the lowest number of connections, because the container can ask for more.
RIB Adapter Type | Total Adapters in RIB |
---|---|
Subscriber | 36 |
Polling Publisher | 23 |
Hospital Retry - Polling Publisher | 3 |
Total | 62 |
At any time, depending on deployment option, the rib-rms app can have at least 62 AQ connections. The application server may ask for more than 62 from the database.
RIB Adapter Type | Total Adapters in RIB |
---|---|
Subscriber | 16 |
Polling Publisher | 8 |
Hospital Retry - Polling Publisher | 2 |
Total | 26 |
At any time, depending on deployment option, the rib-rwms application can have at least 27 AQ connections. The application server may ask for more than 27 from the database.
RIB Adapter Type | Total Adapters in RIB |
---|---|
Subscriber | 21 |
Request Driven Publishers | 12 |
Hospital Retry - Polling Publisher | 2 |
Total | 35 |
At any time, depending on deployment option, the rib-sim app can have at least 35 AQ connections. The application server may ask for more than 35 from the database.
RIB Adapter Type | Total Adapters in RIB |
---|---|
Subscriber | 21 |
Publishers | 21 |
Hospital Retry - Polling Publisher | 2 |
Total | 44 |
At any time, depending on deployment option, the rib-tafr app can have at least 46 AQ connections. The application server may ask for more than 46 from the database.
RIB Adapter Type | Total Adapters in RIB |
---|---|
Subscriber | 0 |
Request Driven Publisher | 3 |
Hospital Retry - Polling Publisher | 1 |
Total | 4 |
At any time, depending on deployment option, the rib-rpm app can have at least four AQ connections. The application server may ask for more than four from the database.
RIB Adapter Type | Total Adapters in RIB |
---|---|
Subscriber | 1 |
Polling Publisher | 2 |
Hospital Retry - Polling Publisher | 3 |
Total | 6 |
At any time, depending on deployment option, the rib-rfm app can have at least six AQ connections. The application server may ask for more than six from the database.
RIB Adapter Type | Total Adapters in RIB |
---|---|
Subscriber | 7 |
Request Driven Publisher | 1 |
Hospital Retry - Polling Publisher | 2 |
Total | 10 |
At any time, depending on deployment option, the rib-oms app can have at least nine AQ connections. The application server may ask for more than four from the database.
It is strongly recommended that, for the production RIB deployment, the Oracle database instance configured as the AQ JMS be separate from all other uses. There are performance considerations as well as architectural reasons for maintaining this separation.
For the testing and QA phases of the deployment life cycle, co-location is not recommended. Regardless of the life cycle phase, the AQ JMS should not be configured with any other applications, including the rib-app, Error Hospital.
If the option to co-locate is chosen, work with the database administrators to determine and set the appropriate maximum database sessions and processes, depending on the RIB environment setup (single channel or multiple channel, for example.) Note that the result may be more than 500 processes. The issues that may arise from having this many processes can be obscure, and it is difficult to isolate their root cause.
Employing multiple JMS servers allows for the isolation of flows (for example, high volume versus low, custom versus base, and message families) for performance and operational QoS.
To meet the JMS agnostic requirement for RIB, a unique JMS server ID (jms-server-id) is assigned to each RIB adapter. Accordingly, each RIB adapter can identify the JMS server to which it is associated. As the default, out-of-the-box adapters are configured to be on jms-server, jms1.
For each new jms-server-ID, a new resource adapter must be configured to point the application server to the JMS provider's resource. The adapter communicates with the JMS server and is deployed as part of the application. Where customization is required, the adapter can be configured to point to a different JMS server.
The rib-app-builder performs several validation checks, as listed below. To prevent the rib-app-builder compilation process from failing, the following criteria must be met:
Each jms-server-id is unique where more than one JMS server is configured.
Within a message flow, the jms-server-id is the same for all applications.
A jms-server-id is present in the rib-deployment-env-info.xml and present in at least one of the rib-<app>-adapters.xml files.
A jms-server-id is present in rib-<app>-adapters.xml and present in the rib-deployment-env-info.xml file.
Multiple channels configured for a given family are on the same JMS server.
Proper hospitals are configured for all JMS servers. (Where additional JMS servers are configured, the rib-app-builder checks to see if hospital adapters are configured for all JMS servers.)
This section describes the process for setting up multiple JMS servers.
The following are basic steps.
Determine the family to be configured.
Examine the rib-integration-flows.xml to identify all RIB applications in the full integration flow.
Add a new JMS server by updating rib-deployment-env-info.xml.
In the rib-home, modify the appropriate files for each of the rib-<apps> participating in the integration flow. Point the adapters to the correct JMS server:
rib-<app>-adapters.xml
rib-<app>-adapter-resources.properties
Compile all applicable rib-<apps>.
Run prepare-jms for the newly created JMS server.
Deploy.
Consider the following recommendations.
The default ID for out-of-the-box JMS servers is jms1. It is recommended that the same naming convention is followed when additional JMS servers are configured (for example, jms2).
If multiple JMS servers require configuration, it is recommended that the application (for example, rib-rms) be completely removed (or undeployed) before the new deployment begins.
Following are portions of the Items message flow from rib-integration-flows.xml. The message originates from RMS and flows through a TAFR. The TAFR sends the message to two topics, and the message is subscribed by RWMS and SIM. The samples below assume that a new jms-server-id (jms2) is required for the message flow.
<message-flow id="6"> <node id="rib-rms.Items_pub" app-name="rib-rms" adapter-class-def="Items_pub" type="DbToJms"> <in-db>default</in-db> <out-topic>etItemsFromRMS</out-topic> </node> <node id="rib-tafr.ItemsToItemsTL_tafr" app-name="rib-tafr" adapter-class-def="ItemsToItemsTL_tafr" type="JmsToJms"> <in-topic>etItemsFromRMS</in-topic> <out-topic>etItemsTLFromRIB</out-topic> </node> <node id="rib-tafr.ItemsToItemsISO_tafr" app-name="rib-tafr" adapter-class-def="ItemsToItemsISO_tafr" type="JmsToJms"> <in-topic>etItemsFromRMS</in-topic> <out-topic>etItemsISO</out-topic> </node> <node id="rib-rwms.Items_sub" app-name="rib-rwms" adapter-class-def="Items_sub" type="JmsToDb"> <in-topic>etItemsTLFromRIB</in-topic> <out-db>default</out-db> </node> <node id="rib-sim.Items_sub" app-name="rib-sim" adapter-class-def="Items_sub" type="JmsToDb"> <in-topic>etItemsISO</in-topic> <out-db>default</out-db> </node> </message-flow>
Note: The following are the configuration changes required for the message flow. The example assumes that all applications apply (RMS, TAFR, SIM, and RWMS). |
A new JMS server with jms-server-id="jms2" is added in rib-deployment-env-info.xml file as follows:
<aq-jms-servers> <aq-jms-server jms-server-id="jms1"> <jms-server-home>user@host:/u00/db</jms-server-home> <jms-url>jdbc:oracle:thin:@host:port:SID</jms-url> <jms-port><port></jms-port> <jms-user-alias>aq1</jms-user-alias> </aq-jms-server> <aq-jms-server jms-server-id="jms2"> <jms-server-home>user@host:/u00/db</jms-server-home> <jms-url>jdbc:oracle:thin:@host:port:SID</jms-url> <jms-port><port></jms-port> <jms-user-alias>aq2</jms-user-alias> </aq-jms-server> </aq-jms-servers>
To configure the RIB-RMS application, complete the following steps:
For rib-rms-adapters.xml, do the following.
Edit $RIB_HOME/application-assembly-home/rib-rms/rib-rms-adapters.xml, where $RIB_HOME is the rib-home directory.
Point the Items_pub_1 adapter to jms-server-id "jms2" as follows.
<timer-driven id="Items_pub_1" initialState="stopped" timeDelay="10" jms-server-id="jms2"> <timer-task> <class name="com.retek.rib.app.getnext.impl.GetNextTimerTaskImpl"/> <property name="maxChannelNumber" value="1" /> </timer-task></timer-driven>
Add hospital adapters for jms-server-id jms2, as follows.
<!-Hospital adapter configuration starts here --><timer-driven id="sub_hosp_2" initialState="stopped" timeDelay="10" jms-server-id="jms2"> <timer-task> <class name="com.retek.rib.j2ee.ErrorHospitalRetryTimerTask"/> <property name="reasonCode" value="SUB"/> </timer-task></timer-driven><timer-driven id="pub_hosp_2" initialState="stopped" timeDelay="10" jms-server-id="jms2"> <timer-task> <class name="com.retek.rib.j2ee.ErrorHospitalRetryTimerTask"/> <property name="reasonCode" value="PUB"/> </timer-task></timer-driven><timer-driven id="jms_hosp_2" initialState="stopped" timeDelay="10" jms-server-id="jms2"> <timer-task> <class name="com.retek.rib.j2ee.ErrorHospitalRetryTimerTask"/> <property name="reasonCode" value="JMS"/> </timer-task></timer-driven>
Add the following properties to the resource file:
sub_hosp-2.name=SUB Hospital Retry jms2
sub_hosp-2.desc=Inject messages into the Error Hospital.
pub_hosp-2.name=PUB Hospital Retry jms2
pub_hosp-2.desc=Re-publish messages to JMS.
jms_hosp-2.name=JMS Hospital Retry jms2
jms_hosp-2.desc=Re-publish messages from the Error Hospital to JMS after JMS is brought up again.
To configure the RIB-TAFR application, complete the following steps.
For rib-tafr-adapters.xml, do the following.
Edit $RIB_HOME/application-assembly-home/rib-tafr/rib-tafr-adapters.xml, where $RIB_HOME is the rib-home directory.
Point the ItemsToItemsTL_tafr_1 adapter to jms-server-id "jms2", as shown below.
Point the ItemsToItemsISO_tafr_1 adapter to jms-server-id "jms2", as shown below:
<tafrs> <message-driven id="ItemsToItemsTL_tafr_1" initialState="stopped" tafr-business-impl="com.retek.rib.domain.tafr.bo.impl.ItemsToItemsTLFromRibBOImpl" jms-server-id="jms2" /> <message-driven id="ItemsToItemsISO_tafr_1" initialState="stopped" tafr-business-impl="com.retek.rib.domain.tafr.bo.impl.ItemsToItemsISOFromRibBOImpl" jms-server-id="jms2" /></tafrs>
Add hospital adapters for jms-server-id jms2.
<!-Hospital adapter configuration starts here --><timer-driven id="sub_hosp_0" initialState="stopped" timeDelay="20" jms-server-id="jms2"> <timer-task> <class name="com.retek.rib.j2ee.ErrorHospitalRetryTimerTask"/> <property name="reasonCode" value="SUB"/> </timer-task> </timer-driven><timer-driven id="jms_hosp_0" initialState="stopped" timeDelay="30" jms-server-id="jms2"> <timer-task> <class name="com.retek.rib.j2ee.ErrorHospitalRetryTimerTask"/> <property name="reasonCode" value="JMS"/> </timer-task></timer-driven>
Add the following properties to the resource file:
sub_hosp-2.name=SUB Hospital Retry jms2
sub_hosp-2.desc=Inject messages into the Error Hospital.
jms_hosp-2.name=JMS Hospital Retry jms2
jms_hosp-2.desc=Re-publish messages from the Error Hospital to JMS after JMS is brought up again.
To configure the RIB-SIM application, complete the following steps:
For rib-sim-adapters.xml, do the following.
Edit $RIB_HOME/application-assembly-home/rib-sim/rib-sim-adapters.xml, where $RIB_HOME is the rib-home directory.
<subscribers> <message-driven id="Items_sub_1" initialState="running" jms-server-id="jms2"/></subscribers>
Add hospital adapters for jms-server-id jms2.
<!-Hospital adapter configuration starts here --><timer-driven id="sub_hosp_0" initialState="stopped" timeDelay="20" jms-server-id="jms2"> <timer-task> <class name="com.retek.rib.j2ee.ErrorHospitalRetryTimerTask"/> <property name="reasonCode" value="SUB"/> </timer-task></timer-driven><timer-driven id="jms_hosp_0" initialState="stopped" timeDelay="30" jms-server-id="jms2"> <timer-task> <class name="com.retek.rib.j2ee.ErrorHospitalRetryTimerTask"/> <property name="reasonCode" value="JMS"/> </timer-task></timer-driven>
Add the following properties to the resources file:
sub_hosp-2.name=SUB Hospital Retry jms2
sub_hosp-2.desc=Inject messages into the Error Hospital.
jms_hosp-2.name=JMS Hospital Retry jms2
jms_hosp-2.desc=Re-publish messages from the Error Hospital to JMS after JMS is brought up again.
To configure the RIB-RWMS application, complete the following steps.
For rib-rwms-adapters.xml, do the following.
Edit $RIB_HOME/application-assembly-home/rib-rwms/rib-rwms-adapters.xml
Point the Items_sub_1 adapter to jms-server-id jms2.
<subscribers> <message-driven id="Items_sub_1" initialState="running" jms-server-id="jms2"/></subscribers>
Add hospital adapters for jms-server-id jms2.
<!-Hospital adapter configuration starts here --><timer-driven id="sub_hosp_0" initialState="stopped" timeDelay="20" jms-server-id="jms2"> <timer-task> <class name="com.retek.rib.j2ee.ErrorHospitalRetryTimerTask"/> <property name="reasonCode" value="SUB"/> </timer-task>
</timer-driven>
<timer-driven id="jms_hosp_0" initialState="stopped" timeDelay="30" jms-server-id="jms2">
</timer-task> <class name="com.retek.rib.j2ee.ErrorHospitalRetryTimerTask"/> <property name="reasonCode" value="JMS"/> </timer-task></timer-driven>
Add the following properties to the resources file:
sub_hosp-2.name=SUB Hospital Retry jms2
sub_hosp-2.desc=Inject messages into the Error Hospital.
jms_hosp-2.name=JMS Hospital Retry jms2
jms_hosp-2.desc=Re-publish messages from the Error Hospital to JMS after JMS is brought up again.
To configure the RIB-RFM application, complete the following steps.
For rib-rfm-adapters.xml, do the following.
Edit $RIB_HOME/application-assembly-home/rib-rfm/rib-rfm-adapters.xml
Point the Items_sub_1 adapter to jms-server-id jms2.
<subscribers> <message-driven id="ShipInfo_sub_1" initialState="running" jms-server-id="jms2"/></subscribers>
Add hospital adapters for jms-server-id jms2.
<!-Hospital adapter configuration starts here --><timer-driven id="sub_hosp_0" initialState="stopped" timeDelay="20" jms-server-id="jms2"> <timer-task> <class name="com.retek.rib.j2ee.ErrorHospitalRetryTimerTask"/> <property name="reasonCode" value="SUB"/> </timer-task>
</timer-driven>
<timer-driven id="jms_hosp_0" initialState="stopped" timeDelay="30" jms-server-id="jms2">
</timer-task> <class name="com.retek.rib.j2ee.ErrorHospitalRetryTimerTask"/> <property name="reasonCode" value="JMS"/> </timer-task></timer-driven>
Add the following properties to the resources file:
sub_hosp-2.name=SUB Hospital Retry jms2
sub_hosp-2.desc=Inject messages into the Error Hospital.
jms_hosp-2.name=JMS Hospital Retry jms2
jms_hosp-2.desc=Re-publish messages from the Error Hospital to JMS after JMS is brought up again.