The Parking Lot Pattern has been leveraged in many Oracle SOA Suite deployments to handle complex batching, message correlation, and complex processing flows. One scenario that is a frequent topic of discussion is throttling SOA Suite so as not to overwhelm slower downstream systems. Most often this is accomplished via the tuning knobs within SOA Suite and WebLogic Server. However, there are times when the built-in tuning cannot be tweaked enough to stop flooding slower systems. SOA design patterns can be leveraged when product features do not address these edge use cases. This blog will focus on using The Parking Lot Pattern as one implementation for throttling. Also note a working example is provided.
The key piece to this pattern is the database table that will be used for the parking lot. The table is very simple and comprised of 3 columns:
Column | Description | ||||||||||
ID (NUMBER) | This is the unique ID/key for the row in the table. | ||||||||||
STATE (VARCHAR) |
|
||||||||||
PAYLOAD (CLOB) | The message that would normally be associated with a component is stored here as an XML clob. |
Without the parking lot, the normal flow for this use case would be:
1. | Some client applications call SOA Suite via Web Service, JMS, etc. |
2. | An asynchronous BPEL instance is created and invokes the slower system for every client request within the tuning parameters of the SOA engine |
3. | The slower system cannot handle the volume and gets flooded |
How the flow is changed with the parking lot:
1. | Some client applications call SOA Suite via Web Service, JMS, etc. |
2. | Each client request is inserted into the parking lot table as an XML clob with STATE = ‘N’. |
3. | A composite containing a polling database adapter will select 1 row with STATE = ‘N’ and the count of rows with STATE = ‘P’ are less than a throttle value (e.g., 5). |
4. | If the in-flight interactions with the slower system are less than the throttle value, the database adapter gets the next available row and marks it as being processed (STATE = ‘P’). |
5. | This row is handed off to an asynchronous BPEL process that will invoke a different BPEL process responsible for interacting with the slower system. |
6. | When the slower system responds and this response propagates back to the initiating BPEL process, the row is marked as complete (STATE = ‘C’). |
7. | Go to step 3 until all records have been processed. |
The throttle control value represents the maximum number of in-flight BPEL processes that are interacting with the slower system. We will see later how this value can be changed at runtime through the SOA Suite Enterprise Manager console.
The database adapter is the gate for flow control via the polling SQL statement. And “expert polling” configuration is required in order to setup the appropriate SQL statement. This configuration is a combination of getting artifacts created in JDeveloper using the DBAdapter Configuration Wizard and then manually tweaking the generated artifacts. The important steps in the wizard consist of:
1. | Operation Type: Poll for New or Changed Records in a Table |
2. | After Read: Delete the Row(s) that were Read |
3. | Make sure Distributed Polling is checked |
4. | Add Parameter: MaxRowsProcessing |
When the wizard finishes and the artifacts are created, there will be a file with the following naming convention: [Service Name]-or-mappings.xml (please note that you may have to edit this file outside of JDeveloper with 12c). It is in this file we will make changes that are considered “expert polling” configuration steps. The steps are not complicated:
1. | Locate the <query ...> element. If there are any child <criteria ...></criteria> elements, remove them and all their children elements. |
2. | Between the <query ...> element and <arguments> element, add <call xsi:type="sql-call"></call> |
3. | Within the <call …> element add a <sql></sql> |
4. | Within the <sql> element add the polling query. The blog example looks like: |
SELECT ID, "STATE", PAYLOAD FROM THROTTLE_PARKINGLOT WHERE (((SELECT COUNT("STATE") FROM THROTTLE_PARKINGLOT WHERE "STATE" = 'P') < #MaxRowsProcessing) AND ("STATE" = 'N')) ORDER BY ID ASC FOR UPDATE SKIP LOCKED
5. | Locate the closing queries element (</queries>) |
6. | Between the </queries> element and </querying> element insert <delete-query></delete-query> |
7. | Within the <delete-query> element, add a <call xsi:type="sql-call"></call> |
8. | Within the <call ...> element add a <sql></sql> |
9. | Within the <sql> element add the logical delete query. The blog example looks like: |
<delete-query> <call xsi:type="sql-call"> <sql> UPDATE THROTTLE_PARKINGLOT SET "STATE" = 'P' WHERE (ID = #ID) </sql> </call> </delete-query>
Now that the polling adapter is configured, we need an asynchronous BPEL process to handle the state management of the message. In the blog example, it is a very straightforward process:
1. | Convert CLOB into payload for the slow system |
2. | Invoke the slow system |
3. | Receive the response from the slow system |
4. | Update row in the database with a complete state |
The state update is done through another DBAdapter configuration where the Operation Type is Update Only and the column is the STATE column. The state management BPEL process simply updates the STATE to ‘C’ using the row ID it already has as the key.
The blog example has one more BPEL process called SlowSystemSimulatorBPELProcess. This is an asynchronous BPEL process that will randomly generate a wait time in seconds between 20 and 240. It then uses a Wait activity to simulate a very slow and sporadic downstream system.
I have provided two SOA Suite 12c projects for the example:
1. | ThrottleParkingLotTableLoader (sca_ThrottleParkingLotTableLoader_rev1.0.jar) |
2. | ThrottleParkingLotBlogExample (sca_ThrottleParkingLotBlogExample_rev1.0.jar) |
Each project contains the necessary SQL scripts to get things setup in the database. Once the user and the table are set up, you will have to configure your database adapter for accessing the THROTTLE_PARKINGLOT table via the ATeam_Example user. To make it easier on you, use eis/DB/ATeamExample as the JNDI Name for the DBAdapter. Otherwise this will need to be changed in the .jca files before deploying the projects to your SOA server.
Once the projects are deployed, you can run a stress test on the ThrottleParkingLotTableLoader / AddPayloadToParkingLotMediator_ep to fill the parking lot with records. Once the parking lot has records they should start being processed by the ThrottleParkingLotBlogExample composite. The initial setting for the MaxRowsProcessing property is 5, so the number in in-flight instances will be limited to 5:
Within the SOA Suite Enterprise Manager, we can change the value of MaxRowsProcessing:
Now we see that the number of in-flight instances has changed:
This will allow runtime tweaking of load on the downstream system. The value for MaxRowsProcessing can also be set to 0 (zero) to stop messages flowing to the downstream system. If you noticed, the polling sequence also leverages SKIP LOCKED which should allow this to work in a clustered environment. However, I have not tested this so feel free to try it out and provide feedback on your findings
I do hope you find this a valuable option for finer grained throttling within SOA Suite.
Previous Post
Next Post