Contents


Set up a multiserver environment for processing batch jobs with IBM WebSphere Liberty Java Batch

Comments

IBM® WebSphere® Liberty V8.5.5.6 supports JSR-352, the open standard for Java Batch. The IBM implementation in Liberty supports the core batch processing model and extends that model to allow multiple servers in a single batch environment. The batch environment can be set up to have servers function as batch dispatchers while other servers function as batch executors.

This tutorial shows you how to set up and configure a load-balancing multiserver environment for processing batch jobs in IBM WebSphere Liberty. It describes how to implement the "More Power" topology that is described in the WebSphere Liberty Batch white paper (see Related topics).

Required skills

Before you begin this tutorial, you need skills in the following areas:

  • Basic development experience in Java
  • Intermediate knowledge of JSR-352 and the Batch processing model
  • Basic knowledge of Apache® Derby databases, and JMS Embedded messaging

About the environment

In this tutorial, you create an environment that includes a batch dispatcher server and two executor servers. One executor processes only the BatchExecutor1Job requests, and the other processes the BatchExecutor2Job requests. The environment consists of four separate Liberty servers as shown in Figure 1. All four servers run on the same host.

Figure 1. Multiserver topology for one dispatcher and two executor servers
Multiserver topology for one dispatcher and two executor                     servers
Multiserver topology for one dispatcher and two executor servers

To keep things simple, this tutorial uses the embedded JMS in Liberty for communication and Apache Derby for the database. In a multiserver environment, the Job Repository must be shared. Thus, the client/server Derby Network Server allows the four servers to access the Job Repository table structures for storing and retrieving data. Table 1 shows the function and port information for each of these servers.

Table 1. Server functions and port numbers
Server NameServer FunctionHTTP/HTTPS PortsJMS/JMS SSL ports
BatchJMSMessageEngine JMS Server NA 7280/7290
BatchDispatcher Batch Job Dispatcher / JMS Client 9081/9444 NA
BatchExecutor1 Batch Job Executor #1 / JMS Client 9082/9445 NA
BatchExecutor2 Batch Job Executor #2 / JMS Client 9083/9446 NA

In this environment, jobs are submitted to the BatchDispatcher server through a REST client. Based on the JMS selector that is assigned to each executor, only certain jobs are processed on each of the two executor servers. Step 6 contains details about the JMS message selectors, but in essence the selectors specify that jobs of type A are always processed on one server, and jobs of type B are always processed on the other server.

So let's get started. The following steps guide you through the basics of setting up this environment from start to finish.

Step 1. Install the Liberty server

  1. Install IBM WebSphere V8.5.5.6 or greater for access to Liberty's batch-1.0 and batchManagement-1.0 features. The batch-1.0 feature is the equivalent to the Java EE 7 JSR-352 specification. The batchManagement-1.0 feature contains all the add-ons that IBM includes. Download the latest Liberty version available to ensure that you have the most current functionality. The server code can be download with a Java runtime at this link: https://developer.ibm.com/wasdev/getstarted.
  2. Unzip the \wlp folder into the location where you want to install Liberty (referred to here as <liberty_home>).

Step 2. Create the Liberty servers

  1. Create the four servers by running the server create command and specifying the name of the server to be created. Run the commands from the <liberty_home>\wlp\bin\ folder.
    1. Create the BatchJMSMessageEngine server: server create BatchJMSMessageEngine
    2. Create the BatchDispatcher server: server create BatchDispatcher
    3. Create the BatchExecutor1 server: server create BatchExecutor1
    4. Create the BatchExecutor2 server: server create BatchExecutor2
  2. These commands create a folder and its configuration for each server in the directory path <liberty_home>\wlp\usr\servers\. Figure 2 shows an example folder for Liberty servers.
    Figure 2. Folders created for the Liberty servers
    Folders created for the Liberty servers

Step 3. Install Apache® Derby

  1. Install Derby V10.12.1.1 or greater. Download the latest version from this link: https://db.apache.org/derby/derby_downloads.html
  2. Unzip the Derby distribution into the <liberty_home>\wlp\usr\shared\resources\derby\ directory. The \wlp\usr\shared\ directory has a property associated with it in Liberty. Therefore, when setting up the server.xml file, you can use the property of ${shared.resource.dir}\derby\lib to specify the Derby JDBC driver.
  3. After unzipping the Derby distribution, you have a file system under the <liberty_home>\wlp\usr\shared\resources folder similar to Figure 3.
    Figure 3. The Derby file structure created by the installation
    The Derby file structure created by the                             installation
    The Derby file structure created by the installation

Step 4. Configure the batch JMS message engine server

Configure the batch JMS (Java Messaging Services) message engine server by editing the server.xml file in the directory <liberty_home>\wlp\usr\servers\BatchJMSMessageEngine. This server is used by the other systems to communicate through the batchLibertyQueue queue, which is defined in the server configuration.

  1. Enable the wasJmsServer-1.0 feature to make the JMS embedded messaging available on the server.
    <!-- Enable features -->
    <featureManager>
        <feature>wasJmsServer-1.0</feature>
    </featureManager>
  2. Configure the JMS ports (7280 and 7290 for SSL) so that the server can communicate with the other JMS clients running on the servers in your environment. Specify the wasJmsEndpoint element and the wasJmsPort attributes as shown below
    <!-- Designate the JMS endpoint ports for the message server -->
    <wasJmsEndpoint host="*" wasJmsPort="7280"
        wasJmsSSLPort="7290" enabled="true">
    </wasJmsEndpoint>
  3. Configure the queue to be used for communicating between the dispatcher and executor servers. Specify the messageEngine element with the queue attribute as follows:
    <!-- Setup the communication queue utilized by the Batch environment -->
    <messagingEngine>
        <queue id="batchLibertyQueue" forceReliability="ReliablePersistent" receiveAllowed="true" />
    </messagingEngine>
  4. The final server.xml file for the BatchJMSMessageEngine server is included in the .zip file in Downloadable resources.

Step 5. Configure the batch dispatcher server

Configure the batch dispatcher server by editing the server.xml file in the directory <liberty_home>\wlp\usr\servers\BatchDispatcher. The BatchDispatcher server must be configured as the batch dispatcher, and it must contain both the JMS queue setup and Derby database setup. Batch jobs are submitted to this server through the REST interface and dispatched to the executor servers in the environment.

  1. Enable the batchManager-1.0 feature; enabling this feature automatically enables the batch-1.0 feature. Enable the wasJmsClient-2.0 feature to allow communication with the JMS embedded messaging server.
    <!-- Enabled features -->
    <featureManager>
        <feature>wasJmsClient-2.0</feature>
        <feature>batchManagement-1.0</feature>
    </featureManager>
  2. Configure the batchJmsDispatcher element to indicate that this server is the batch dispatcher server.
    <batchJmsDispatcher connectionFactoryRef="batchConnectionFactory"
        queueRef="batchJobSubmissionQueue" />
  3. Use the jmsConnectionFactory element to configure the JMS Connection Factory so that the dispatcher server can communicate with the message engine server. The remoteServerAddress element uses the wasJmsPort port (7280) configured in the endpoint from the BatchJMSMessageEngine server, as shown in the following code.
    <jmsConnectionFactory id="batchConnectionFactory"
        jndiName="jms/batch/connectionFactory">
            <properties.wasJms remoteServerAddress="localhost:7280:BootstrapBasicMessaging" />
    </jmsConnectionFactory>
  4. Configure the JMS queue to reference the batchLibertyQueue queue, which is defined on the message engine server. Define the jmsQueue element as shown in the following code. This element ties the dispatcher to the JMS queue information on the BatchJMSMessageEngine server.
    <jmsQueue id="batchJobSubmissionQueue" jndiName="jms/batch/jobSubmissionQueue">
        <properties.wasJms deliveryMode="Persistent" queueName="batchLibertyQueue" 
                readAhead="AsConnection" timeToLive="0">
        </properties.wasJms>
  5. Use the httpEndpoint element to configure the HTTP ports so that the server can be accessed from a web browser. When you submit a job through REST, you'll use this port in the URL.
    <!-- Server HTTP port setup -->
    <httpEndpoint id="defaultHttpEndpoint" httpPort="9081" httpsPort="9444" />
  6. Configure batch persistence by defining the batchPersistence element. This element defines whether you are using a physical database or in-memory persistence (the default).
    <!-- Batch persistence config. References a databaseStore. --> 
    <batchPersistence jobStoreRef="BatchDatabaseStore" />
  7. Configure the databaseStore element to define the name of the batch database and the schema where the batch tables are created.
     <!-- The database store for the batch tables. -->
     <!-- Note this database store is referenced by the batchPersistence element. -->
     <databaseStore id="BatchDatabaseStore" createTables="true"
        dataSourceRef="batchDB" schema="JBATCH" tablePrefix="" />
  8. Configure the JDBC driver shared library by defining a library element, which includes the file set attribute where the derbyclient.jar file is located. Note the use of the ${shared.resource.dir} Liberty property when referencing the path of the driver location, which is stored in <liberty_home>\wlp\usr\shared\resources\derby\. For the Job Repository to be shared, use the derbyclient.jar file. This file is the Derby network client JAR file that allows multiple applications to interact with Derby in a client/server network.
     <!-- Derby JDBC driver -->
     <!-- Note this library is referenced by the dataSource element -->
     <library id="DerbyLib">
        <fileset dir="${shared.resource.dir}/derby/lib" includes="derbyclient.jar" />
     </library>
  9. Configure a dataSource element by using the JDBC driver. The properties.derby.client element defines the location of the physical database and the server, port, user, and password for the Derby network server.
     <!-- Data source for the batch tables. -->
     <!-- Note this data source is referenced by databaseStore element -->
    <dataSource id="batchDB" jndiName="jdbc/batch" type="javax.sql.XADataSource">
        <jdbcDriver libraryRef="DerbyLib" />
        <properties.derby.client createDatabase="create" 
            databaseName="${shared.resource.dir}/databases/BATCHDB"
            serverName="localhost"
            portNumber="1527" user="user" password="pass" />
    </dataSource>
  10. Configure a jdbcDriver element to set the javax.sql.ConnectionPoolDataSource and javax.sql.XADataSource attributes for your Derby driver. The element must reference the DerbyLib shared library.
    <jdbcDriver id="derbyDriver"
        javax.sql.ConnectionPoolDataSource="org.apache.derby.jdbc.ClientConnectionPoolDataSource"
        javax.sql.XADataSource="org.apache.derby.jdbc.ClientXADataSource"
        libraryRef="DerbyLib" />
  11. Configure the keyStore element that is used by the batchManagement-1.0 feature for accessing the REST API.
    <keyStore id="defaultKeyStore" password="Liberty" />
  12. Configure a basicRegistry element to configure the user IDs. These IDs are permitted to access the batch REST API to submit jobs and view job logs.
    <basicRegistry id="basic" realm="ibm/api">
        <user name="bob" password="bobpwd" />
    </basicRegistry>
  13. Configure the authorization-roles element to assign the security-role of batchAdmin to user bob. The batchAdmin role has unrestricted access to all batch operations. The roles of batchSubmitter and batchMonitor have less privileges as indicated by their names (submitter and monitor).
    <authorization-roles id="com.ibm.ws.batch">
        <security-role name="batchAdmin">
            <user name="bob" />
        </security-role>
    </authorization-roles>
  14. Optionally, you can enable tracing for batch on the dispatcher server by creating the logging element. Use the following attributes to configure which packages to trace, the name of the trace file, and the size and number of trace files to use.
    <!-- Enable Batch tracing for troubleshooting purposes -->
    <logging maxFileSize="200" maxFiles="10"
        traceSpecification="com.ibm.jbatch.*=all:com.ibm.ws.jbatch.*=all"
        traceFileName="trace.log" />
  15. The final server.xml file for the BatchDispatcher server is included in Downloadable resources.

Step 6. Configure the batch executor servers

Configure the batch executor servers by editing the server.xml file in the directories <liberty_home>\wlp\usr\servers\BatchExecutor1 and <liberty_home>\wlp\usr\servers\BatchExecutor2. In this tutorial, the configuration steps for the batch executor servers focus only on items that are different or are not covered in other sections. The database set-up, keystore, and security set-up for the executor servers is similar to that of the BatchDispatcher server. Unique HTTP or HTTPs ports must be assigned to each server as defined in Table 1. The BatchExecutor1 server has a unique value for messageSelector on the ActivationSpecification configuration with a value of BatchExecutor1Job.war. The BatchExecutor2 server has a different messageSelector value of BatchExecutor2Job.war. These message selectors define the criteria that are used to send jobs to the appropriate server, thus dispersing the load of the jobs over multiple servers.

  1. Enable the wasJmsClient-2.0 feature to allow communication with the JMS embedded messaging server. Enable the batchManager-1.0 feature to enable the batch function.
    <!-- Enable features -->
    <featureManager>
        <feature>wasJmsClient-2.0</feature>
        <feature>batchManagement-1.0</feature>
    </featureManager>
  2. Configure the batchJmsExecutor element to indicate that this server is a batch executor server. This element ties the executor to the JMS queue information.
    <batchJmsExecutor activationSpecRef="batchActivationSpec"
        queueRef="batchJobSubmissionQueue" />
  3. Configure the jmsActivationSpec element to connect to the JMS message server, and include a message selector to filter out certain jobs. The remoteServerAddress attribute contains the host and port of the JMS message server (the BatchJMSMessageEngine in our scenario). If you use something other than localhost as your hostname and port 7280 for JMS messaging, change these values to match your environment. The messageSelector attribute filters which type of job is processed by the executor server. There are 3 default filters:
    • com_ibm_ws_batch_applicationName. The name of the batch application for the job request.
    • com_ibm_ws_batch_moduleName. The module name of the batch application for the job request.
    • com_ibm_ws_batch_componentName. The component name of the batch application for the job request.

    You can also create custom filters. This tutorial uses the com_ibm_ws_batch_moduleName filter to route requests to the two executor servers.

    For the BatchExecutor1 server, use a message selector as follows:

    <jmsActivationSpec id="batchActivationSpec" maxEndpoints="5">
        <properties.wasJms maxBatchSize="3" maxConcurrency="5"
            messageSelector="com_ibm_ws_batch_moduleName = "
            destinationRef="batchJobSubmissionQueue" destinationType="javax.jms.Queue"
            remoteServerAddress="localhost:7280:BootstrapBasicMessaging">
        </properties.wasJms>
    </jmsActivationSpec>

    For the BatchExecutor2 server, use a message selector as follows:

    <jmsActivationSpec id="batchActivationSpec" maxEndpoints="5">
        <properties.wasJms maxBatchSize="3" maxConcurrency="5"
            messageSelector="com_ibm_ws_batch_moduleName = "
            destinationRef="batchJobSubmissionQueue" destinationType="javax.jms.Queue"
            remoteServerAddress="localhost:7280:BootstrapBasicMessaging">
        </properties.wasJms>
    </jmsActivationSpec>
  4. Configure the JMS queue to reference the batchLibertyQueue queue. This queue is defined on the message engine server by using the jmsQueue element. This element ties the executors to the JMS queue information on the BatchJMSMessageEngine server.
    <jmsQueue id="batchJobSubmissionQueue" jndiName="jms/batch/jobSubmissionQueue">
        <properties.wasJms deliveryMode="Persistent" queueName="batchLibertyQueue" 
            readAhead="AsConnection" timeToLive="0">
        </properties.wasJms>
    </jmsQueue>
  5. The final server.xml files for the BatchExecutor1 and BatchExecutor2 servers are included in Downloadable resources.

Step 7. Install the batch applications

To install the batch applications, copy the .war files into their associated folders:

  • <liberty_home>\wlp\usr\servers\BatchExecutor1\dropins\BatchExecutor1Job.war
  • <liberty_home>\wlp\usr\servers\BatchExecutor2\dropins\BatchExecutor2Job.war

The applications load automatically if your servers are started, otherwise they start after the servers initialize.

Step 8. Test the environment

To test out the environment you've just created, follow these steps:

  1. Start the Derby network server by running the startNetworkServer.bat file located in the <liberty_home>\wlp\usr\shared\resources\derby\bin\ folder. The output from starting the network server indicates the port on which it is listening. Ensure that this port (1527 in the example in Figure 4) matches what you configured in the data source element of the BatchDispatcher, BatchExecutor1, and BatchExecutor2 servers.
    Figure 4. Starting the Derby network server
    Starting the Derby network server
    Starting the Derby network server
  2. From the <liberty_home>\wlp\bin\ folder, run the server start <server_name> command to start the four servers you've just created (BatchJMSMessageEngine, BatchDispatcher, BatchExecutor1, and BatchExecutor2).
  3. Submit a request to process a job on the BatchExecutor1 server. You can use any REST client or your own REST-based application. This tutorial uses the Poster plugin-in for Mozilla® Firefox®.

    NOTE: You can also submit jobs by using the batchManager command-line client utility that is installed through the batch management feature. This command-line interface uses the Batch REST API to submit jobs.

    1. Select Tools -> Poster to open Poster from the Mozilla Firefox browser.
    2. In the URL field, enter the following request to the BatchDispatcher server running on port 9444: https://localhost:9444/ibm/api/batch/jobinstances
    3. In the Content to Send field, enter the following JSON data:
      {
      "applicationName" : "BatchExecutor1Job",
      "moduleName" : "BatchExecutor1Job.war",
       "jobXMLName" : "executor1Job"
      }
    4. Figure 5 shows an example response from Poster:
      Figure 5. Submitting a request to the BatchExecutor1 server
      Submitting a request to the BatchExecutor1                                     server
      Submitting a request to the BatchExecutor1 server
    5. Click the POST button.
    6. When you are prompted for authentication (Figure 6), enter bob/bobpwd as configured in the basicRegistry element of the BatchDispatcher's server.xml file.
      Figure 6. Authenticating to the BatchExecutor1 server
      Authenticating to the BatchExecutor1 server
      Authenticating to the BatchExecutor1 server
    7. You receive a response with an HTTP "201 Created" message similar to Figure 7.
      Figure 7. The POST response after submitting a job to the BatchExecutor1 server
      The POST response after submitting a job to the                                     BatchExecutor1 server
      The POST response after submitting a job to the BatchExecutor1 server
    8. From this response you can see that instanceId of 156 is created for this particular batch job.
    9. You can check the status of your job by issuing an HTTP GET request to the following URL: https://localhost:9444/ibm/api/batch/jobinstances/156.

      The job status is COMPLETED as shown in Figure 8.

      Figure 8. The job status for executor1Job after an HTTP GET request
      The job status for executor1Job after an HTTP GET                                     request
      The job status for executor1Job after an HTTP GET request
  4. Submit a request to process a job on the BatchExecutor2 server. Repeat the process you used for testing the BatchExecutor1 server.
    1. Enter the following JSON snippet in the Content to Send field to run the application on that server:
      {
      "applicationName" : "BatchExecutor2Job",
      "moduleName" : "BatchExecutor2Job.war",
      "jobXMLName" : "executor2Job"
      }
    2. Obtain the value of the instanceId from the response and check the details for the job by issuing an HTTP GET request to the following URL: https://localhost:9444/ibm/api/batch/jobinstances/<instanceId>

      The job state is COMPLETED (Figure 9).

      Figure 9. The job status for executor2Job after an HTTP GET request
      The job status for executor2Job after an HTTP GET                                     request
      The job status for executor2Job after an HTTP GET request

Troubleshooting the Environment

Here are a few problems that might occur when you test out the environment.

  1. The following error indicates that the Derby database server isn't running, or the servers have configuration issues that prohibit them from reaching the Derby database (for example, a wrong port is configured).
    Error 500: javax.batch.operations.BatchRuntimeException: Failed to load JPA PersistenceServiceUnit.
  2. Your jobs hang and you see the messages batchStatus = 'STARTING' and instanceState = 'JMS_QUEUED' (Figure 10). This issue indicates that your messageSelector is not working properly. The batch job is queued, but no executors are processing that particular type of message. Ensure that you have created the correct messageSelector for your batch job.
    Figure 10. Job status when a messageSelector is not working
    Job status when a messageSelector is not                             working
    Job status when a messageSelector is not working
  3. For other errors, enable trace on the BatchDispatcher, BatchExecutor1, and BatchExecutor2 servers, and consult the information that is generated when you run your jobs.

Conclusion

This tutorial showed how to set up a multiserver Java EE 7 batch environment in IBM WebSphere Liberty. You learned how to configure the embedded JMS messaging server, dispatcher server, and multiple executor servers. You also configured message selectors to load balance jobs among the servers.

Resources


Downloadable resources


Comments

Sign in or register to add and subscribe to comments.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Middleware
ArticleID=1030811
ArticleTitle=Set up a multiserver environment for processing batch jobs with IBM WebSphere Liberty Java Batch
publish-date=05032016