http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/ha/stop-server-failover/pom.xml ---------------------------------------------------------------------- diff --git a/examples/features/ha/stop-server-failover/pom.xml b/examples/features/ha/stop-server-failover/pom.xml new file mode 100644 index 0000000..7fb647c --- /dev/null +++ b/examples/features/ha/stop-server-failover/pom.xml @@ -0,0 +1,160 @@ +<?xml version='1.0'?> +<!-- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +--> + +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.activemq.examples.failover</groupId> + <artifactId>broker-failover</artifactId> + <version>1.0.1-SNAPSHOT</version> + </parent> + + <artifactId>stop-server-failover</artifactId> + <packaging>jar</packaging> + <name>ActiveMQ Artemis JMS Stop Server Failover Example</name> + + <properties> + <activemq.basedir>${project.basedir}/../../../..</activemq.basedir> + </properties> + + <dependencies> + <dependency> + <groupId>org.apache.activemq</groupId> + <artifactId>artemis-jms-client</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.activemq</groupId> + <artifactId>artemis-maven-plugin</artifactId> + <executions> + <execution> + <id>create0</id> + <goals> + <goal>create</goal> + </goals> + <configuration> + <ignore>${noServer}</ignore> + <instance>${basedir}/target/server0</instance> + <sharedStore>true</sharedStore> + <slave>false</slave> + <dataFolder>../data</dataFolder> + <failoverOnShutdown>true</failoverOnShutdown> + </configuration> + </execution> + <execution> + <id>create1</id> + <goals> + <goal>create</goal> + </goals> + <configuration> + <ignore>${noServer}</ignore> + <instance>${basedir}/target/server1</instance> + <sharedStore>true</sharedStore> + <slave>true</slave> + <dataFolder>../data</dataFolder> + <failoverOnShutdown>true</failoverOnShutdown> + </configuration> + </execution> + <execution> + <id>start0</id> + <goals> + <goal>cli</goal> + </goals> + <configuration> + <ignore>${noServer}</ignore> + <spawn>true</spawn> + <location>${basedir}/target/server0</location> + <testURI>tcp://localhost:61616</testURI> + <args> + <param>run</param> + </args> + <name>server0</name> + </configuration> + </execution> + <execution> + <id>start1</id> + <goals> + <goal>cli</goal> + </goals> + <configuration> + <ignore>${noServer}</ignore> + <spawn>true</spawn> + <location>${basedir}/target/server1</location> + <testURI>tcp://localhost:61617</testURI> + <args> + <param>run</param> + </args> + <name>server1</name> + </configuration> + </execution> + <execution> + <id>runClient</id> + <goals> + <goal>runClient</goal> + </goals> + <configuration> + <clientClass>org.apache.activemq.artemis.jms.example.StopServerFailoverExample</clientClass> + </configuration> + </execution> + <execution> + <id>stop0</id> + <goals> + <goal>cli</goal> + </goals> + <configuration> + <ignore>${noServer}</ignore> + <location>${basedir}/target/server0</location> + <args> + <param>stop</param> + </args> + </configuration> + </execution> + <execution> + <id>stop1</id> + <goals> + <goal>cli</goal> + </goals> + <configuration> + <ignore>${noServer}</ignore> + <location>${basedir}/target/server1</location> + <args> + <param>stop</param> + </args> + </configuration> + </execution> + </executions> + <dependencies> + <dependency> + <groupId>org.apache.activemq.examples.failover</groupId> + <artifactId>stop-server-failover</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + </plugin> + </plugins> + </build> + +</project>
http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/ha/stop-server-failover/readme.html ---------------------------------------------------------------------- diff --git a/examples/features/ha/stop-server-failover/readme.html b/examples/features/ha/stop-server-failover/readme.html new file mode 100644 index 0000000..9486cd6 --- /dev/null +++ b/examples/features/ha/stop-server-failover/readme.html @@ -0,0 +1,44 @@ +<!-- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +--> + +<html> + <head> + <title>ActiveMQ Artemis JMS Failover Without Transactions Example</title> + <link rel="stylesheet" type="text/css" href="../../../common/common.css" /> + <link rel="stylesheet" type="text/css" href="../../../common/prettify.css" /> + <script type="text/javascript" src="../../../common/prettify.js"></script> + </head> + <body onload="prettyPrint()"> + <h1>JMS Failover Without Transactions Example</h1> + + <pre>To run the example, simply type <b>mvn verify</b> from this directory, <br>or <b>mvn -PnoServer verify</b> if you want to start and create the server manually.</pre> + + + <p>This example demonstrates two servers coupled as a live-backup pair for high availability (HA), and a client + connection failing over from live to backup when the live server is crashed.</p> + <p>Failover behavior differs whether the JMS session is transacted or not.</p> + <p>When a <em>non-transacted</em> JMS session is used, once and only once delivery is not guaranteed + and it is possible some messages will be lost or delivered twice, depending when the failover to the backup server occurs.</p> + <p>It is up to the client to deal with such cases. To ensure once and only once delivery, the client must + use transacted JMS sessions (as shown in the example for <a href="../transaction-failover/readme.html">failover with transactions</a>).</p> + <p>For more information on ActiveMQ Artemis failover and HA, and clustering in general, please see the clustering + section of the user manual.</p> + + </body> +</html> http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/ha/stop-server-failover/src/main/java/org/apache/activemq/artemis/jms/example/StopServerFailoverExample.java ---------------------------------------------------------------------- diff --git a/examples/features/ha/stop-server-failover/src/main/java/org/apache/activemq/artemis/jms/example/StopServerFailoverExample.java b/examples/features/ha/stop-server-failover/src/main/java/org/apache/activemq/artemis/jms/example/StopServerFailoverExample.java new file mode 100644 index 0000000..38f06c0 --- /dev/null +++ b/examples/features/ha/stop-server-failover/src/main/java/org/apache/activemq/artemis/jms/example/StopServerFailoverExample.java @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.activemq.artemis.jms.example; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.JMSException; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.naming.InitialContext; + +/** + * A simple example that demonstrates failover of the JMS connection from one node to another + * when the live server crashes using a JMS <em>non-transacted</em> session. + */ +public class StopServerFailoverExample { + + public static void main(final String[] args) throws Exception { + final int numMessages = 10; + + Connection connection = null; + + InitialContext initialContext = null; + + try { + // Step 1. Get an initial context for looking up JNDI from the server #1 + initialContext = new InitialContext(); + + // Step 2. Look up the JMS resources from JNDI + Queue queue = (Queue) initialContext.lookup("queue/exampleQueue"); + ConnectionFactory connectionFactory = (ConnectionFactory) initialContext.lookup("ConnectionFactory"); + + // Step 3. Create a JMS Connection + connection = connectionFactory.createConnection(); + + // Step 4. Create a *non-transacted* JMS Session with client acknowledgement + Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE); + + // Step 5. Start the connection to ensure delivery occurs + connection.start(); + + // Step 6. Create a JMS MessageProducer and a MessageConsumer + MessageProducer producer = session.createProducer(queue); + MessageConsumer consumer = session.createConsumer(queue); + + // Step 7. Send some messages to server #1, the live server + for (int i = 0; i < numMessages; i++) { + TextMessage message = session.createTextMessage("This is text message " + i); + producer.send(message); + System.out.println("Sent message: " + message.getText()); + } + + // Step 8. Receive and acknowledge half of the sent messages + TextMessage message0 = null; + for (int i = 0; i < numMessages / 2; i++) { + message0 = (TextMessage) consumer.receive(5000); + System.out.println("Got message: " + message0.getText()); + } + message0.acknowledge(); + + // Step 9. Receive the 2nd half of the sent messages but *do not* acknowledge them yet + for (int i = numMessages / 2; i < numMessages; i++) { + message0 = (TextMessage) consumer.receive(5000); + System.out.println("Got message: " + message0.getText()); + } + + // Step 10. Crash server #0, the live server, and wait a little while to make sure + // it has really crashed + System.out.println("Stop the live server by logging into JConsole and then press any key to continue..."); + System.in.read(); + + // Step 11. Acknowledging the 2nd half of the sent messages will fail as failover to the + // backup server has occurred + try { + message0.acknowledge(); + } + catch (JMSException e) { + System.err.println("Got exception while acknowledging message: " + e.getMessage()); + } + + // Step 12. Consume again the 2nd half of the messages again. Note that they are not considered as redelivered. + for (int i = numMessages / 2; i < numMessages; i++) { + message0 = (TextMessage) consumer.receive(5000); + System.out.printf("Got message: %s (redelivered?: %s)\n", message0.getText(), message0.getJMSRedelivered()); + } + message0.acknowledge(); + } + finally { + // Step 13. Be sure to close our resources! + + if (connection != null) { + connection.close(); + } + + if (initialContext != null) { + initialContext.close(); + } + } + } +} http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/ha/stop-server-failover/src/main/resources/jndi.properties ---------------------------------------------------------------------- diff --git a/examples/features/ha/stop-server-failover/src/main/resources/jndi.properties b/examples/features/ha/stop-server-failover/src/main/resources/jndi.properties new file mode 100644 index 0000000..7f7a19f --- /dev/null +++ b/examples/features/ha/stop-server-failover/src/main/resources/jndi.properties @@ -0,0 +1,20 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +java.naming.factory.initial=org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory +connectionFactory.ConnectionFactory=tcp://localhost:61616?ha=true&retryInterval=1000&retryIntervalMultiplier=1.0&reconnectAttempts=-1 +queue.queue/exampleQueue=exampleQueue http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/ha/transaction-failover/pom.xml ---------------------------------------------------------------------- diff --git a/examples/features/ha/transaction-failover/pom.xml b/examples/features/ha/transaction-failover/pom.xml new file mode 100644 index 0000000..76a4a8e --- /dev/null +++ b/examples/features/ha/transaction-failover/pom.xml @@ -0,0 +1,104 @@ +<?xml version='1.0'?> +<!-- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +--> + +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.activemq.examples.failover</groupId> + <artifactId>broker-failover</artifactId> + <version>1.0.1-SNAPSHOT</version> + </parent> + + <artifactId>transaction-failover</artifactId> + <packaging>jar</packaging> + <name>ActiveMQ Artemis JMS Transaction Failover Example</name> + + <properties> + <activemq.basedir>${project.basedir}/../../../..</activemq.basedir> + </properties> + + <dependencies> + <dependency> + <groupId>org.apache.activemq</groupId> + <artifactId>artemis-cli</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.geronimo.specs</groupId> + <artifactId>geronimo-jms_2.0_spec</artifactId> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.activemq</groupId> + <artifactId>artemis-maven-plugin</artifactId> + <executions> + <execution> + <id>create0</id> + <goals> + <goal>create</goal> + </goals> + <configuration> + <instance>${basedir}/target/server0</instance> + <configuration>${basedir}/target/classes/activemq/server0</configuration> + <javaOptions>-Dudp-address=${udp-address}</javaOptions> + </configuration> + </execution> + <execution> + <id>create1</id> + <goals> + <goal>create</goal> + </goals> + <configuration> + <instance>${basedir}/target/server1</instance> + <configuration>${basedir}/target/classes/activemq/server1</configuration> + <javaOptions>-Dudp-address=${udp-address}</javaOptions> + </configuration> + </execution> + <execution> + <id>runClient</id> + <goals> + <goal>runClient</goal> + </goals> + <configuration> + <clientClass>org.apache.activemq.artemis.jms.example.TransactionFailoverExample</clientClass> + <args> + <param>${basedir}/target/server0</param> + <param>${basedir}/target/server1</param> + </args> + </configuration> + </execution> + </executions> + <dependencies> + <dependency> + <groupId>org.apache.activemq.examples.failover</groupId> + <artifactId>transaction-failover</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + </plugin> + </plugins> + </build> + +</project> http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/ha/transaction-failover/readme.html ---------------------------------------------------------------------- diff --git a/examples/features/ha/transaction-failover/readme.html b/examples/features/ha/transaction-failover/readme.html new file mode 100644 index 0000000..15f119f --- /dev/null +++ b/examples/features/ha/transaction-failover/readme.html @@ -0,0 +1,46 @@ +<!-- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +--> + +<html> + <head> + <title>ActiveMQ Artemis JMS Failover With Transaction Example</title> + <link rel="stylesheet" type="text/css" href="../../../common/common.css" /> + <link rel="stylesheet" type="text/css" href="../../../common/prettify.css" /> + <script type="text/javascript" src="../../../common/prettify.js"></script> + </head> + <body onload="prettyPrint()"> + <h1>JMS Failover With Transaction Example</h1> + + <pre>To run the example, simply type <b>mvn verify</b> from this directory.</pre> + + + <p>This example demonstrates two servers coupled as a live-backup pair for high availability (HA), and a client + connection failing over from live to backup when the live server is crashed.</p> + <p>Failover behavior differs whether the JMS session is transacter or not.</p> + <p>When a <em>transacted</em> JMS session is used, once-and-only once delivery is guaranteed.</p> + <ul> + <li>if the failover occurs while there is an in-flight transaction, the transaction will be flagged as <em>rollback only</em>. In that case, the JMS client + will need to retry the transaction work.</li> + <li>if the failover occurs while there is <em>no</em> in-flight transaction, the failover will be transparent to the user.</li> + </ul> + <p>ActiveMQ Artemis also provides an example for <a href="../non-transactional-failover/readme.html">non-transaction failover</a>.</p> + <p>For more information on ActiveMQ Artemis failover and HA, and clustering in general, please see the clustering + section of the user manual.</p> + </body> +</html> http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/ha/transaction-failover/src/main/java/org/apache/activemq/artemis/jms/example/TransactionFailoverExample.java ---------------------------------------------------------------------- diff --git a/examples/features/ha/transaction-failover/src/main/java/org/apache/activemq/artemis/jms/example/TransactionFailoverExample.java b/examples/features/ha/transaction-failover/src/main/java/org/apache/activemq/artemis/jms/example/TransactionFailoverExample.java new file mode 100644 index 0000000..58c514a --- /dev/null +++ b/examples/features/ha/transaction-failover/src/main/java/org/apache/activemq/artemis/jms/example/TransactionFailoverExample.java @@ -0,0 +1,167 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.activemq.artemis.jms.example; + +import org.apache.activemq.artemis.api.core.Message; +import org.apache.activemq.artemis.util.ServerUtil; + +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.jms.TextMessage; +import javax.jms.TransactionRolledBackException; +import javax.naming.InitialContext; + +/** + * A simple example that demonstrates failover of the JMS connection from one node to another + * when the live server crashes using a JMS <em>transacted</em> session. + */ +public class TransactionFailoverExample { + + // You need to guarantee uniqueIDs when using duplicate detection + // It needs to be unique even after a restart + // as these IDs are stored on the journal for control + // We recommend some sort of UUID, but for this example the Current Time as string would be enough + static String uniqueID = Long.toString(System.currentTimeMillis()); + + private static Process server0; + + private static Process server1; + + public static void main(final String[] args) throws Exception { + final int numMessages = 10; + + Connection connection = null; + + InitialContext initialContext = null; + + try { + server0 = ServerUtil.startServer(args[0], TransactionFailoverExample.class.getSimpleName() + "0", 0, 5000); + server1 = ServerUtil.startServer(args[1], TransactionFailoverExample.class.getSimpleName() + "1", 1, 5000); + + // Step 1. Get an initial context for looking up JNDI from the server #1 + initialContext = new InitialContext(); + + // Step 2. Look-up the JMS resources from JNDI + Queue queue = (Queue) initialContext.lookup("queue/exampleQueue"); + ConnectionFactory connectionFactory = (ConnectionFactory) initialContext.lookup("ConnectionFactory"); + + // Step 3. We create a JMS Connection + connection = connectionFactory.createConnection(); + + // Step 4. We create a *transacted* JMS Session + Session session = connection.createSession(true, 0); + + // Step 5. We start the connection to ensure delivery occurs + connection.start(); + + // Step 6. We create a JMS MessageProducer + MessageProducer producer = session.createProducer(queue); + + // Step 7. We create a JMS MessageConsumer + MessageConsumer consumer = session.createConsumer(queue); + + // Step 8. We send half of the messages, kill the live server and send the remaining messages + sendMessages(session, producer, numMessages, true); + + // Step 9. As failover occurred during transaction, the session has been marked for rollback only + try { + session.commit(); + } + catch (TransactionRolledBackException e) { + System.err.println("transaction has been rolled back: " + e.getMessage()); + } + + // Step 10. We resend all the messages + sendMessages(session, producer, numMessages, false); + + // Step 11. We commit the session successfully: the messages will be all delivered to the activated backup + // server + session.commit(); + + // Step 12. We are now transparently reconnected to server #0, the backup server. + // We consume the messages sent before the crash of the live server and commit the session. + for (int i = 0; i < numMessages; i++) { + TextMessage message0 = (TextMessage) consumer.receive(5000); + + if (message0 == null) { + throw new IllegalStateException("Example failed - message wasn't received"); + } + + System.out.println("Got message: " + message0.getText()); + } + + session.commit(); + + System.out.println("Other message on the server? " + consumer.receive(5000)); + } + finally { + // Step 13. Be sure to close our resources! + + if (connection != null) { + connection.close(); + } + + if (initialContext != null) { + initialContext.close(); + } + + ServerUtil.killServer(server0); + ServerUtil.killServer(server1); + } + } + + private static void sendMessages(final Session session, + final MessageProducer producer, + final int numMessages, + final boolean killServer) throws Exception { + + // We send half of messages + for (int i = 0; i < numMessages / 2; i++) { + TextMessage message = session.createTextMessage("This is text message " + i); + + message.setStringProperty(Message.HDR_DUPLICATE_DETECTION_ID.toString(), uniqueID + i); + + producer.send(message); + + System.out.println("Sent message: " + message.getText()); + } + + if (killServer) { + Thread.sleep(5000); + + ServerUtil.killServer(server0); + } + + // We send the remaining half of messages + for (int i = numMessages / 2; i < numMessages; i++) { + TextMessage message = session.createTextMessage("This is text message " + i); + + // We set the duplicate detection header - so the server will ignore the same message + // if sent again after failover + + message.setStringProperty(Message.HDR_DUPLICATE_DETECTION_ID.toString(), uniqueID + i); + + producer.send(message); + + System.out.println("Sent message: " + message.getText()); + } + } +} http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/ha/transaction-failover/src/main/resources/activemq/server0/broker.xml ---------------------------------------------------------------------- diff --git a/examples/features/ha/transaction-failover/src/main/resources/activemq/server0/broker.xml b/examples/features/ha/transaction-failover/src/main/resources/activemq/server0/broker.xml new file mode 100644 index 0000000..916fdf5 --- /dev/null +++ b/examples/features/ha/transaction-failover/src/main/resources/activemq/server0/broker.xml @@ -0,0 +1,98 @@ +<?xml version='1.0'?> +<!-- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +--> + +<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="urn:activemq" + xsi:schemaLocation="urn:activemq /schema/artemis-server.xsd"> + + <jms xmlns="urn:activemq:jms"> + <!--the queue used by the example--> + <queue name="exampleQueue"/> + </jms> + + <core xmlns="urn:activemq:core"> + + <bindings-directory>../data/bindings</bindings-directory> + + <journal-directory>../data/journal</journal-directory> + + <large-messages-directory>../data/largemessages</large-messages-directory> + + <paging-directory>../data/paging</paging-directory> + + <ha-policy> + <shared-store> + <master> + <failover-on-shutdown>true</failover-on-shutdown> + </master> + </shared-store> + </ha-policy> + + <!-- Connectors --> + + <connectors> + <connector name="netty-connector">tcp://localhost:61616</connector> + </connectors> + + <!-- Acceptors --> + <acceptors> + <acceptor name="netty-acceptor">tcp://localhost:61616</acceptor> + </acceptors> + + <broadcast-groups> + <broadcast-group name="bg-group1"> + <group-address>${udp-address:231.7.7.7}</group-address> + <group-port>9876</group-port> + <broadcast-period>1000</broadcast-period> + <connector-ref>netty-connector</connector-ref> + </broadcast-group> + </broadcast-groups> + + <discovery-groups> + <discovery-group name="dg-group1"> + <group-address>${udp-address:231.7.7.7}</group-address> + <group-port>9876</group-port> + <refresh-timeout>60000</refresh-timeout> + </discovery-group> + </discovery-groups> + + <cluster-connections> + <cluster-connection name="my-cluster"> + <address>jms</address> + <connector-ref>netty-connector</connector-ref> + <discovery-group-ref discovery-group-name="dg-group1"/> + </cluster-connection> + </cluster-connections> + <!-- Other config --> + + <security-settings> + <!--security for example queue--> + <security-setting match="jms.queue.exampleQueue"> + <permission type="createDurableQueue" roles="guest"/> + <permission type="deleteDurableQueue" roles="guest"/> + <permission type="createNonDurableQueue" roles="guest"/> + <permission type="deleteNonDurableQueue" roles="guest"/> + <permission type="consume" roles="guest"/> + <permission type="send" roles="guest"/> + </security-setting> + </security-settings> + + </core> +</configuration> http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/ha/transaction-failover/src/main/resources/activemq/server1/broker.xml ---------------------------------------------------------------------- diff --git a/examples/features/ha/transaction-failover/src/main/resources/activemq/server1/broker.xml b/examples/features/ha/transaction-failover/src/main/resources/activemq/server1/broker.xml new file mode 100644 index 0000000..055f04a --- /dev/null +++ b/examples/features/ha/transaction-failover/src/main/resources/activemq/server1/broker.xml @@ -0,0 +1,98 @@ +<?xml version='1.0'?> +<!-- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +--> + +<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="urn:activemq" + xsi:schemaLocation="urn:activemq /schema/artemis-server.xsd"> + + <jms xmlns="urn:activemq:jms"> + <!--the queue used by the example--> + <queue name="exampleQueue"/> + </jms> + + <core xmlns="urn:activemq:core"> + + <bindings-directory>../data/bindings</bindings-directory> + + <journal-directory>../data/journal</journal-directory> + + <large-messages-directory>../data/largemessages</large-messages-directory> + + <paging-directory>../data/paging</paging-directory> + + <ha-policy> + <shared-store> + <slave> + <failover-on-shutdown>true</failover-on-shutdown> + </slave> + </shared-store> + </ha-policy> + + <!-- Connectors --> + <connectors> + <connector name="netty-connector">tcp://localhost:61617</connector> + </connectors> + + <!-- Acceptors --> + <acceptors> + <acceptor name="netty-acceptor">tcp://localhost:61617</acceptor> + </acceptors> + + <broadcast-groups> + <broadcast-group name="bg-group1"> + <group-address>${udp-address:231.7.7.7}</group-address> + <group-port>9876</group-port> + <broadcast-period>1000</broadcast-period> + <connector-ref>netty-connector</connector-ref> + </broadcast-group> + </broadcast-groups> + + <discovery-groups> + <discovery-group name="dg-group1"> + <group-address>${udp-address:231.7.7.7}</group-address> + <group-port>9876</group-port> + <refresh-timeout>60000</refresh-timeout> + </discovery-group> + </discovery-groups> + + <cluster-connections> + <cluster-connection name="my-cluster"> + <address>jms</address> + <connector-ref>netty-connector</connector-ref> + <discovery-group-ref discovery-group-name="dg-group1"/> + </cluster-connection> + </cluster-connections> + + <!-- Other config --> + + <security-settings> + <!--security for example queue--> + <security-setting match="jms.queue.exampleQueue"> + <permission type="createDurableQueue" roles="guest"/> + <permission type="deleteDurableQueue" roles="guest"/> + <permission type="createNonDurableQueue" roles="guest"/> + <permission type="deleteNonDurableQueue" roles="guest"/> + <permission type="consume" roles="guest"/> + <permission type="send" roles="guest"/> + </security-setting> + </security-settings> + + </core> +</configuration> http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/ha/transaction-failover/src/main/resources/jndi.properties ---------------------------------------------------------------------- diff --git a/examples/features/ha/transaction-failover/src/main/resources/jndi.properties b/examples/features/ha/transaction-failover/src/main/resources/jndi.properties new file mode 100644 index 0000000..7f7a19f --- /dev/null +++ b/examples/features/ha/transaction-failover/src/main/resources/jndi.properties @@ -0,0 +1,20 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +java.naming.factory.initial=org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory +connectionFactory.ConnectionFactory=tcp://localhost:61616?ha=true&retryInterval=1000&retryIntervalMultiplier=1.0&reconnectAttempts=-1 +queue.queue/exampleQueue=exampleQueue http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/perf/perf/pom.xml ---------------------------------------------------------------------- diff --git a/examples/features/perf/perf/pom.xml b/examples/features/perf/perf/pom.xml new file mode 100644 index 0000000..bcab911 --- /dev/null +++ b/examples/features/perf/perf/pom.xml @@ -0,0 +1,156 @@ +<?xml version='1.0'?> +<!-- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +--> + +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.activemq.examples.soak</groupId> + <artifactId>perf-root</artifactId> + <version>1.0.1-SNAPSHOT</version> + </parent> + + <artifactId>perf</artifactId> + <packaging>jar</packaging> + <name>ActiveMQ Artemis JMS PerfExample Example</name> + + <properties> + <activemq.basedir>${project.basedir}/../../../..</activemq.basedir> + </properties> + + <dependencies> + <dependency> + <groupId>org.apache.activemq</groupId> + <artifactId>artemis-server</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.activemq</groupId> + <artifactId>artemis-jms-server</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.activemq</groupId> + <artifactId>artemis-core-client</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.activemq</groupId> + <artifactId>artemis-commons</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>io.netty</groupId> + <artifactId>netty-all</artifactId> + <version>${netty.version}</version> + </dependency> + <dependency> + <groupId>org.apache.activemq</groupId> + <artifactId>artemis-jms-client</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + + <profiles> + <profile> + <id>server</id> + <build> + <plugins> + <plugin> + <groupId>org.apache.activemq</groupId> + <artifactId>artemis-maven-plugin</artifactId> + <executions> + <execution> + <id>create</id> + <goals> + <goal>create</goal> + </goals> + </execution> + <execution> + <id>runClient</id> + <goals> + <goal>runClient</goal> + </goals> + <configuration> + <clientClass>org.apache.activemq.artemis.jms.example.Server</clientClass> + </configuration> + </execution> + </executions> + <dependencies> + <dependency> + <groupId>org.apache.activemq.examples.soak</groupId> + <artifactId>perf</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + </plugin> + </plugins> + </build> + </profile> + <profile> + <id>listener</id> + <build> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>exec-maven-plugin</artifactId> + <version>1.1</version> + <executions> + <execution> + <phase>package</phase> + <goals> + <goal>java</goal> + </goals> + </execution> + </executions> + <configuration> + <mainClass>org.apache.activemq.artemis.jms.example.PerfListener</mainClass> + </configuration> + </plugin> + </plugins> + </build> + </profile> + <profile> + <id>sender</id> + <build> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>exec-maven-plugin</artifactId> + <version>1.1</version> + <executions> + <execution> + <phase>package</phase> + <goals> + <goal>java</goal> + </goals> + </execution> + </executions> + <configuration> + <mainClass>org.apache.activemq.artemis.jms.example.PerfSender</mainClass> + </configuration> + </plugin> + </plugins> + </build> + </profile> + </profiles> + + +</project> http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/perf/perf/readme.html ---------------------------------------------------------------------- diff --git a/examples/features/perf/perf/readme.html b/examples/features/perf/perf/readme.html new file mode 100644 index 0000000..aa42266 --- /dev/null +++ b/examples/features/perf/perf/readme.html @@ -0,0 +1,39 @@ +<!-- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +--> + +<html> + <head> + <title>ActiveMQ Artemis JMS Queue Selector Example</title> + <link rel="stylesheet" type="text/css" href="../../common/common.css" /> + <link rel="stylesheet" type="text/css" href="../../common/prettify.css" /> + <script type="text/javascript" src="../../common/prettify.js"></script> + </head> + <body onload="prettyPrint()"> + <h1>JMS Simple Performance</h1> + + <p>To start the server run <code>mvn verify -Pexample</code></p> + + <p>To start the listener run <code>mvn -Plistener package</code></p> + + <p>To start the sender run <code>mvn -Psender package</code></p> + + <p>To configure the clients simply edit the <code>perf.properties</code> or <code>client.jndi.properties</code> in the + <code>src/main/resources</code> directory</p> + </body> +</html> http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/perf/perf/src/main/java/org/apache/activemq/artemis/jms/example/PerfBase.java ---------------------------------------------------------------------- diff --git a/examples/features/perf/perf/src/main/java/org/apache/activemq/artemis/jms/example/PerfBase.java b/examples/features/perf/perf/src/main/java/org/apache/activemq/artemis/jms/example/PerfBase.java new file mode 100644 index 0000000..bf18077 --- /dev/null +++ b/examples/features/perf/perf/src/main/java/org/apache/activemq/artemis/jms/example/PerfBase.java @@ -0,0 +1,409 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.activemq.artemis.jms.example; + +import javax.jms.BytesMessage; +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.jms.DeliveryMode; +import javax.jms.Destination; +import javax.jms.JMSException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageListener; +import javax.jms.MessageProducer; +import javax.jms.Session; +import javax.naming.InitialContext; +import java.io.FileInputStream; +import java.io.InputStream; +import java.util.Properties; +import java.util.Random; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicLong; +import java.util.logging.Logger; + +import org.apache.activemq.artemis.utils.TokenBucketLimiter; +import org.apache.activemq.artemis.utils.TokenBucketLimiterImpl; + +public abstract class PerfBase { + + private static final Logger log = Logger.getLogger(PerfSender.class.getName()); + + private static final String DEFAULT_PERF_PROPERTIES_FILE_NAME = "target/classes/perf.properties"; + + private static byte[] randomByteArray(final int length) { + byte[] bytes = new byte[length]; + + Random random = new Random(); + + for (int i = 0; i < length; i++) { + bytes[i] = Integer.valueOf(random.nextInt()).byteValue(); + } + + return bytes; + } + + protected static String getPerfFileName(final String[] args) { + String fileName; + + if (args.length > 0) { + fileName = args[0]; + } + else { + fileName = PerfBase.DEFAULT_PERF_PROPERTIES_FILE_NAME; + } + + return fileName; + } + + protected static PerfParams getParams(final String fileName) throws Exception { + Properties props = null; + + InputStream is = null; + + try { + is = new FileInputStream(fileName); + + props = new Properties(); + + props.load(is); + } + finally { + if (is != null) { + is.close(); + } + } + + int noOfMessages = Integer.valueOf(props.getProperty("num-messages")); + int noOfWarmupMessages = Integer.valueOf(props.getProperty("num-warmup-messages")); + int messageSize = Integer.valueOf(props.getProperty("message-size")); + boolean durable = Boolean.valueOf(props.getProperty("durable")); + boolean transacted = Boolean.valueOf(props.getProperty("transacted")); + int batchSize = Integer.valueOf(props.getProperty("batch-size")); + boolean drainQueue = Boolean.valueOf(props.getProperty("drain-queue")); + String destinationLookup = props.getProperty("destination-lookup"); + String connectionFactoryLookup = props.getProperty("connection-factory-lookup"); + int throttleRate = Integer.valueOf(props.getProperty("throttle-rate")); + boolean dupsOK = Boolean.valueOf(props.getProperty("dups-ok-acknowlege")); + boolean disableMessageID = Boolean.valueOf(props.getProperty("disable-message-id")); + boolean disableTimestamp = Boolean.valueOf(props.getProperty("disable-message-timestamp")); + + PerfBase.log.info("num-messages: " + noOfMessages); + PerfBase.log.info("num-warmup-messages: " + noOfWarmupMessages); + PerfBase.log.info("message-size: " + messageSize); + PerfBase.log.info("durable: " + durable); + PerfBase.log.info("transacted: " + transacted); + PerfBase.log.info("batch-size: " + batchSize); + PerfBase.log.info("drain-queue: " + drainQueue); + PerfBase.log.info("throttle-rate: " + throttleRate); + PerfBase.log.info("connection-factory-lookup: " + connectionFactoryLookup); + PerfBase.log.info("destination-lookup: " + destinationLookup); + PerfBase.log.info("disable-message-id: " + disableMessageID); + PerfBase.log.info("disable-message-timestamp: " + disableTimestamp); + PerfBase.log.info("dups-ok-acknowledge: " + dupsOK); + + PerfParams perfParams = new PerfParams(); + perfParams.setNoOfMessagesToSend(noOfMessages); + perfParams.setNoOfWarmupMessages(noOfWarmupMessages); + perfParams.setMessageSize(messageSize); + perfParams.setDurable(durable); + perfParams.setSessionTransacted(transacted); + perfParams.setBatchSize(batchSize); + perfParams.setDrainQueue(drainQueue); + perfParams.setConnectionFactoryLookup(connectionFactoryLookup); + perfParams.setDestinationLookup(destinationLookup); + perfParams.setThrottleRate(throttleRate); + perfParams.setDisableMessageID(disableMessageID); + perfParams.setDisableTimestamp(disableTimestamp); + perfParams.setDupsOK(dupsOK); + + return perfParams; + } + + private final PerfParams perfParams; + + protected PerfBase(final PerfParams perfParams) { + this.perfParams = perfParams; + } + + private ConnectionFactory factory; + + private Connection connection; + + private Session session; + + private Destination destination; + + private long start; + + private void init() throws Exception { + InitialContext ic = new InitialContext(); + System.out.println("ic = " + ic); + factory = (ConnectionFactory) ic.lookup(perfParams.getConnectionFactoryLookup()); + + destination = (Destination) ic.lookup(perfParams.getDestinationLookup()); + + connection = factory.createConnection(); + + session = connection.createSession(perfParams.isSessionTransacted(), perfParams.isDupsOK() ? Session.DUPS_OK_ACKNOWLEDGE : Session.AUTO_ACKNOWLEDGE); + + ic.close(); + } + + private void displayAverage(final long numberOfMessages, final long start, final long end) { + double duration = (1.0 * end - start) / 1000; // in seconds + double average = 1.0 * numberOfMessages / duration; + PerfBase.log.info(String.format("average: %.2f msg/s (%d messages in %2.2fs)", average, numberOfMessages, duration)); + } + + protected void runSender() { + try { + init(); + + if (perfParams.isDrainQueue()) { + drainQueue(); + } + + start = System.currentTimeMillis(); + PerfBase.log.info("warming up by sending " + perfParams.getNoOfWarmupMessages() + " messages"); + sendMessages(perfParams.getNoOfWarmupMessages(), perfParams.getBatchSize(), perfParams.isDurable(), perfParams.isSessionTransacted(), false, perfParams.getThrottleRate(), perfParams.getMessageSize()); + PerfBase.log.info("warmed up"); + start = System.currentTimeMillis(); + sendMessages(perfParams.getNoOfMessagesToSend(), perfParams.getBatchSize(), perfParams.isDurable(), perfParams.isSessionTransacted(), true, perfParams.getThrottleRate(), perfParams.getMessageSize()); + long end = System.currentTimeMillis(); + displayAverage(perfParams.getNoOfMessagesToSend(), start, end); + } + catch (Exception e) { + e.printStackTrace(); + } + finally { + if (session != null) { + try { + session.close(); + } + catch (Exception e) { + e.printStackTrace(); + } + } + if (connection != null) { + try { + connection.close(); + } + catch (JMSException e) { + e.printStackTrace(); + } + } + } + } + + protected void runListener() { + try { + init(); + + if (perfParams.isDrainQueue()) { + drainQueue(); + } + + MessageConsumer consumer = session.createConsumer(destination); + + connection.start(); + + PerfBase.log.info("READY!!!"); + + CountDownLatch countDownLatch = new CountDownLatch(1); + consumer.setMessageListener(new PerfListener(countDownLatch, perfParams)); + countDownLatch.await(); + long end = System.currentTimeMillis(); + // start was set on the first received message + displayAverage(perfParams.getNoOfMessagesToSend(), start, end); + } + catch (Exception e) { + e.printStackTrace(); + } + finally { + if (session != null) { + try { + session.close(); + } + catch (Exception e) { + e.printStackTrace(); + } + } + if (connection != null) { + try { + connection.close(); + } + catch (JMSException e) { + e.printStackTrace(); + } + } + } + } + + private void drainQueue() throws Exception { + PerfBase.log.info("Draining queue"); + + Session drainSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); + + MessageConsumer consumer = drainSession.createConsumer(destination); + + connection.start(); + + Message message = null; + + int count = 0; + do { + message = consumer.receive(3000); + + if (message != null) { + message.acknowledge(); + + count++; + } + } while (message != null); + + drainSession.close(); + + PerfBase.log.info("Drained " + count + " messages"); + } + + private void sendMessages(final int numberOfMessages, + final int txBatchSize, + final boolean durable, + final boolean transacted, + final boolean display, + final int throttleRate, + final int messageSize) throws Exception { + MessageProducer producer = session.createProducer(destination); + + producer.setDeliveryMode(perfParams.isDurable() ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT); + + producer.setDisableMessageID(perfParams.isDisableMessageID()); + + producer.setDisableMessageTimestamp(perfParams.isDisableTimestamp()); + + BytesMessage message = session.createBytesMessage(); + + byte[] payload = PerfBase.randomByteArray(messageSize); + + message.writeBytes(payload); + + final int modulo = 2000; + + TokenBucketLimiter tbl = throttleRate != -1 ? new TokenBucketLimiterImpl(throttleRate, false) : null; + + boolean committed = false; + for (int i = 1; i <= numberOfMessages; i++) { + producer.send(message); + + if (transacted) { + if (i % txBatchSize == 0) { + session.commit(); + committed = true; + } + else { + committed = false; + } + } + + if (display && i % modulo == 0) { + double duration = (1.0 * System.currentTimeMillis() - start) / 1000; + PerfBase.log.info(String.format("sent %6d messages in %2.2fs", i, duration)); + } + + if (tbl != null) { + tbl.limit(); + } + } + if (transacted && !committed) { + session.commit(); + } + } + + private class PerfListener implements MessageListener { + + private final CountDownLatch countDownLatch; + + private final PerfParams perfParams; + + private boolean warmingUp = true; + + private boolean started = false; + + private final int modulo; + + private final AtomicLong count = new AtomicLong(0); + + public PerfListener(final CountDownLatch countDownLatch, final PerfParams perfParams) { + this.countDownLatch = countDownLatch; + this.perfParams = perfParams; + warmingUp = perfParams.getNoOfWarmupMessages() > 0; + modulo = 2000; + } + + public void onMessage(final Message message) { + try { + if (warmingUp) { + boolean committed = checkCommit(); + if (count.incrementAndGet() == perfParams.getNoOfWarmupMessages()) { + PerfBase.log.info("warmed up after receiving " + count.longValue() + " msgs"); + if (!committed) { + checkCommit(); + } + warmingUp = false; + } + return; + } + + if (!started) { + started = true; + // reset count to take stats + count.set(0); + start = System.currentTimeMillis(); + } + + long currentCount = count.incrementAndGet(); + boolean committed = checkCommit(); + if (currentCount == perfParams.getNoOfMessagesToSend()) { + if (!committed) { + checkCommit(); + } + countDownLatch.countDown(); + } + if (currentCount % modulo == 0) { + double duration = (1.0 * System.currentTimeMillis() - start) / 1000; + PerfBase.log.info(String.format("received %6d messages in %2.2fs", currentCount, duration)); + } + } + catch (Exception e) { + e.printStackTrace(); + } + } + + private boolean checkCommit() throws Exception { + if (perfParams.isSessionTransacted()) { + if (count.longValue() % perfParams.getBatchSize() == 0) { + session.commit(); + + return true; + } + } + return false; + } + } + +} http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/perf/perf/src/main/java/org/apache/activemq/artemis/jms/example/PerfListener.java ---------------------------------------------------------------------- diff --git a/examples/features/perf/perf/src/main/java/org/apache/activemq/artemis/jms/example/PerfListener.java b/examples/features/perf/perf/src/main/java/org/apache/activemq/artemis/jms/example/PerfListener.java new file mode 100644 index 0000000..3f2c478 --- /dev/null +++ b/examples/features/perf/perf/src/main/java/org/apache/activemq/artemis/jms/example/PerfListener.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.activemq.artemis.jms.example; + +import java.util.logging.Logger; + +public class PerfListener extends PerfBase { + + private static final Logger log = Logger.getLogger(PerfListener.class.getName()); + + public static void main(final String[] args) { + try { + String fileName = PerfBase.getPerfFileName(args); + + PerfParams params = PerfBase.getParams(fileName); + + new PerfListener(params).run(); + } + catch (Exception e) { + e.printStackTrace(); + } + } + + private PerfListener(final PerfParams perfParams) { + super(perfParams); + } + + public void run() throws Exception { + runListener(); + } + +} http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/perf/perf/src/main/java/org/apache/activemq/artemis/jms/example/PerfParams.java ---------------------------------------------------------------------- diff --git a/examples/features/perf/perf/src/main/java/org/apache/activemq/artemis/jms/example/PerfParams.java b/examples/features/perf/perf/src/main/java/org/apache/activemq/artemis/jms/example/PerfParams.java new file mode 100644 index 0000000..c358171 --- /dev/null +++ b/examples/features/perf/perf/src/main/java/org/apache/activemq/artemis/jms/example/PerfParams.java @@ -0,0 +1,158 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.activemq.artemis.jms.example; + +import java.io.Serializable; + +/** + * Class that holds the parameters used in the performance examples + */ +public class PerfParams implements Serializable { + + private static final long serialVersionUID = -4336539641012356002L; + + private int noOfMessagesToSend = 1000; + + private int noOfWarmupMessages; + + private int messageSize = 1024; // in bytes + + private boolean durable = false; + + private boolean isSessionTransacted = false; + + private int batchSize = 5000; + + private boolean drainQueue = true; + + private String connectionFactoryLookup; + + private String destinationLookup; + + private int throttleRate; + + private boolean disableMessageID; + + private boolean disableTimestamp; + + private boolean dupsOK; + + public synchronized int getNoOfMessagesToSend() { + return noOfMessagesToSend; + } + + public synchronized void setNoOfMessagesToSend(final int noOfMessagesToSend) { + this.noOfMessagesToSend = noOfMessagesToSend; + } + + public synchronized int getNoOfWarmupMessages() { + return noOfWarmupMessages; + } + + public synchronized void setNoOfWarmupMessages(final int noOfWarmupMessages) { + this.noOfWarmupMessages = noOfWarmupMessages; + } + + public synchronized int getMessageSize() { + return messageSize; + } + + public synchronized void setMessageSize(final int messageSize) { + this.messageSize = messageSize; + } + + public synchronized boolean isDurable() { + return durable; + } + + public synchronized void setDurable(final boolean durable) { + this.durable = durable; + } + + public synchronized boolean isSessionTransacted() { + return isSessionTransacted; + } + + public synchronized void setSessionTransacted(final boolean isSessionTransacted) { + this.isSessionTransacted = isSessionTransacted; + } + + public synchronized int getBatchSize() { + return batchSize; + } + + public synchronized void setBatchSize(final int batchSize) { + this.batchSize = batchSize; + } + + public synchronized boolean isDrainQueue() { + return drainQueue; + } + + public synchronized void setDrainQueue(final boolean drainQueue) { + this.drainQueue = drainQueue; + } + + public synchronized String getConnectionFactoryLookup() { + return connectionFactoryLookup; + } + + public synchronized void setConnectionFactoryLookup(final String connectionFactoryLookup) { + this.connectionFactoryLookup = connectionFactoryLookup; + } + + public synchronized String getDestinationLookup() { + return destinationLookup; + } + + public synchronized void setDestinationLookup(final String destinationLookup) { + this.destinationLookup = destinationLookup; + } + + public synchronized int getThrottleRate() { + return throttleRate; + } + + public synchronized void setThrottleRate(final int throttleRate) { + this.throttleRate = throttleRate; + } + + public synchronized boolean isDisableMessageID() { + return disableMessageID; + } + + public synchronized void setDisableMessageID(final boolean disableMessageID) { + this.disableMessageID = disableMessageID; + } + + public synchronized boolean isDisableTimestamp() { + return disableTimestamp; + } + + public synchronized void setDisableTimestamp(final boolean disableTimestamp) { + this.disableTimestamp = disableTimestamp; + } + + public synchronized boolean isDupsOK() { + return dupsOK; + } + + public synchronized void setDupsOK(final boolean dupsOK) { + this.dupsOK = dupsOK; + } + +} http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/perf/perf/src/main/java/org/apache/activemq/artemis/jms/example/PerfSender.java ---------------------------------------------------------------------- diff --git a/examples/features/perf/perf/src/main/java/org/apache/activemq/artemis/jms/example/PerfSender.java b/examples/features/perf/perf/src/main/java/org/apache/activemq/artemis/jms/example/PerfSender.java new file mode 100644 index 0000000..6649bfa --- /dev/null +++ b/examples/features/perf/perf/src/main/java/org/apache/activemq/artemis/jms/example/PerfSender.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.activemq.artemis.jms.example; + +import java.util.logging.Logger; + +public class PerfSender extends PerfBase { + + private static final Logger log = Logger.getLogger(PerfSender.class.getName()); + + public static void main(final String[] args) { + try { + String fileName = PerfBase.getPerfFileName(args); + + PerfParams params = PerfBase.getParams(fileName); + + new PerfSender(params).run(); + } + catch (Exception e) { + e.printStackTrace(); + } + } + + private PerfSender(final PerfParams perfParams) { + super(perfParams); + } + + public void run() throws Exception { + runSender(); + } + +} http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/perf/perf/src/main/java/org/apache/activemq/artemis/jms/example/Server.java ---------------------------------------------------------------------- diff --git a/examples/features/perf/perf/src/main/java/org/apache/activemq/artemis/jms/example/Server.java b/examples/features/perf/perf/src/main/java/org/apache/activemq/artemis/jms/example/Server.java new file mode 100644 index 0000000..33ccd0e --- /dev/null +++ b/examples/features/perf/perf/src/main/java/org/apache/activemq/artemis/jms/example/Server.java @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.activemq.artemis.jms.example; + +public class Server { + + public static void main(String[] arg) { + System.out.println("***********************************************************************************"); + System.out.println("You need to start manually under ./target/server/bin just run ./artemis run"); + System.out.println("***********************************************************************************"); + } +} http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/perf/perf/src/main/resources/activemq/server0/broker.xml ---------------------------------------------------------------------- diff --git a/examples/features/perf/perf/src/main/resources/activemq/server0/broker.xml b/examples/features/perf/perf/src/main/resources/activemq/server0/broker.xml new file mode 100644 index 0000000..a642ac5 --- /dev/null +++ b/examples/features/perf/perf/src/main/resources/activemq/server0/broker.xml @@ -0,0 +1,46 @@ +<?xml version='1.0'?> +<!-- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +--> + +<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="urn:activemq" + xsi:schemaLocation="urn:activemq /schema/artemis-server.xsd"> + + <jms xmlns="urn:activemq:jms"> + <queue name="perfQueue"/> + </jms> + + <core xmlns="urn:activemq:core"> + + <security-enabled>false</security-enabled> + <persistence-enabled>true</persistence-enabled> + + <!-- Acceptors --> + <acceptors> + <acceptor name="netty-acceptor">tcp://localhost:61616?tcpNoDelay=false;tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576</acceptor> + </acceptors> + + <queues> + <queue name="perfQueue"> + <address>perfAddress</address> + </queue> + </queues> + + </core> +</configuration> http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/perf/perf/src/main/resources/jndi.properties ---------------------------------------------------------------------- diff --git a/examples/features/perf/perf/src/main/resources/jndi.properties b/examples/features/perf/perf/src/main/resources/jndi.properties new file mode 100644 index 0000000..bcf6926 --- /dev/null +++ b/examples/features/perf/perf/src/main/resources/jndi.properties @@ -0,0 +1,20 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +java.naming.factory.initial=org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory +connectionFactory.ConnectionFactory=tcp://localhost:61616?tcp-no-delay=false&tcp-send-buffer-size=1048576&tcp-receive-buffer-size=1048576 +queue.perfQueue=perfQueue http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/perf/perf/src/main/resources/perf.properties ---------------------------------------------------------------------- diff --git a/examples/features/perf/perf/src/main/resources/perf.properties b/examples/features/perf/perf/src/main/resources/perf.properties new file mode 100644 index 0000000..f5ca7be --- /dev/null +++ b/examples/features/perf/perf/src/main/resources/perf.properties @@ -0,0 +1,30 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +num-messages=100000 +num-warmup-messages=1000 +message-size=1024 +durable=false +transacted=false +batch-size=1000 +drain-queue=false +destination-lookup=perfQueue +connection-factory-lookup=ConnectionFactory +throttle-rate=-1 +dups-ok-acknowledge=false +disable-message-id=true +disable-message-timestamp=true http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/perf/pom.xml ---------------------------------------------------------------------- diff --git a/examples/features/perf/pom.xml b/examples/features/perf/pom.xml new file mode 100644 index 0000000..eaafdaf --- /dev/null +++ b/examples/features/perf/pom.xml @@ -0,0 +1,50 @@ +<?xml version='1.0'?> +<!-- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +--> + +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.activemq.examples</groupId> + <artifactId>artemis-examples</artifactId> + <version>1.0.1-SNAPSHOT</version> + </parent> + + <groupId>org.apache.activemq.examples.soak</groupId> + <artifactId>perf-root</artifactId> + <packaging>pom</packaging> + <name>ActiveMQ Artemis Performance Examples</name> + + <!-- Properties --> + <properties> + <!-- + Explicitly declaring the source encoding eliminates the following + message: [WARNING] Using platform encoding (UTF-8 actually) to copy + filtered resources, i.e. build is platform dependent! + --> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <activemq.basedir>${project.basedir}/../../..</activemq.basedir> + </properties> + + <modules> + <module>perf</module> + <module>soak</module> + </modules> +</project> http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/6b17d966/examples/features/perf/soak/README ---------------------------------------------------------------------- diff --git a/examples/features/perf/soak/README b/examples/features/perf/soak/README new file mode 100644 index 0000000..b69a1ac --- /dev/null +++ b/examples/features/perf/soak/README @@ -0,0 +1,85 @@ +**************************************************** +* Soak Test For Manual Reconnection of JMS Clients * +**************************************************** + +Running the Soak Tests +======================= + +Run The Server Standalone +========================== + +Use the Profile server + mvn -Pserver verify + +That will create a server under ./target/server0 + + +You can define the property server.dir under the same Profile to create other servers. or you could do it manually if desired using the regular ./artemis create + + $ mvn -Dserver.dir=server1 -Pserver verify + +server1 should contain a copy of configuration equivalent to that found under the server0 director with different +settings. + +To run a server with the same configuration but on a different host. Check out this source on the host machine and +change: +* activemq.remoting.netty.host property in broker.xml +* bindAddress and rmiBindAddress properties in activemq-beans.xml + + $ mvn verify -P server + + +To run the server just start it manually + +Configure Server Dump +===================== + +The server can "dump" info at regular interval. In broker.xml, set + + <server-dump-interval>10000</server-dump-interval> + +to have infos every 10s: + +**** Server Dump **** +date: Mon Aug 17 18:19:07 CEST 2009 +free memory: 500,79 MiB +max memory: 1,95 GiB +total memory: 507,13 MiB +available memory: 99,68% +total paging memory: 0,00 B +# of thread: 19 +# of conns: 0 +******************** + +Run The Clients +=============== + +The clients can be run separate from the server using: + + $ mvn verify -Premote + +Parameters are specified in soak.properties. + +The duration of the tests is configured by duration-in-minutes (defaults to 2 minutes, set to +-1 to run the test indefinitely). + +To configure the soak properties different to the defaults for the clients, use the system property +To specify the JNDI server to connect to, use the system property jndi.address + + $ mvn verify -Premote -Dsoak.props=<path to properties> -Pjndi.address=jnp:remote.host:1099 + +Every 1000th message, the clients will display their recent activity: + +INFO: received 10000 messages in 5,71s (total: 55s) + +At the end of the run, the sender and receiver will sum up their activity: + +INFO: Received 223364 messages in 2,01 minutes + +Kill The Server And Check Manual Reconnection +============================================== + +You can kill the server (ctl+c or kill -9), the clients are configured to reconnect +indefinitely to the same single server (even in case of clean shutdown) +Once the server restarts, all the clients will resume their activities after reconnecting +to the server.