Saturday, October 9, 2010

ActiveMQ Messaging server

Introduction

A robust, reliable, scalable, secure, compatible and maintainable system is the key to the success for the business.

Using a middleware for messaging gives the software development loosely coupled, more flexible and easy to scale and maintain.

Apache ActiveMQ is a message broker (middleware) for remote communication between different systems in different environment. Although ActiveMQ is written in Java, it supports many protocols and provides APIs for many other languages, including C/C++, .NET, Perl, PHP, Python, Ruby and more. It can be seen as a general messaging solution for a variety of development platforms.

It provides high performance, reliability, scalability, security, compatibility, and maintainability. In this document, I will overview these areas.

Concepts

Before going through those areas, here are the concepts used in the document.

*Producer - Message generator which has a one-to-one relationship with consumer
*Consumer - Message receiver which has a one-to-one relationship with producer
*Publisher - Message genertor which has a one-to-many relationship with subscribers
*Subscriber - Message receiver who receives publisher's messages
*Queue -A Queue implements point-to-point (PTP) messaging semantics. A single message will be received by exactly one consumer. If there are no consumers available at the time the message is sent it will be kept until a consumer is available that can process the message.
*Topic - A Topic implements publish and subscribe semantics. When you publish a message it goes to all the subscribers who are interested.
*Broker - A server delivering messages
*Destination - A unique identifier for sending and receiving messages.

Performance

ActiveMQ offical test produces 21-22,000 messages/second for 1-2K data delivery [1]. I test on my machine, it delivers about 7,000/second [2]. Of course, the broker, consumer and producer are all in the same machine.

According to ActiveMQ, a single broker can handle over 10,000 concurrent users, even just using ajax approach (jetty as its underline technology) [3].

Reliability

ActiveMQ provides several mechsnisms to ensure reliable message delivery. It has failover configuration, which has a master broker and slave brokers backup. Once the master broker fails, one slave takes over the role to become a master to continue message delivery.

It can be done by only one line xml configureation as following:
failover://(tcp://masterhost:61616,tcp://slavehost:61616)


It also provides message cache to ensure a message is delivered to the consumer when the consumer's connection is temporarily failed for some reason, such as mobile connection lost signal.
This configuration uses a XML format configurable policy for deciding which types of messages should be cached, how many and for how long.

You can even configure more complicated broker networks to have local and remote master, local and remote slave.

Scalability

ActiveMQ provides three ways to scale the messaging system, Vertical, Horizontal scaling and Traffic Partitioning.

The vertical scaling will improve connections and numbers of Queues on a single broker to achieve thousands of connections and Queues. The horizontal scaling will increase the number further to ensure tens of thousands of connections concurrently. Finally the traffic partitioning will balance scaling and performance.

Vertical Scaling

Vertical scaling increases the number of connections and load on a single ActiveMQ broker, so the borker can handle both a large number of concurrent connections and a large number of Queues.

By default, ActiveMQ will use blocking I/O to handle transport connections, which results in one thread per connection. ActiveMQ can be configured to use Non-blocking I/O, which creates a thread pool for dispatching messages for multiple client connections.

You can also control memory size allocation through configuration to ensure there is enough capacity for large traffic.

The default Queue configuration uses a separate thread for paging messages from the store into the Queue to be dispatched. For a large number of Queues, you can disable this to avoid out of memory.

Horizontal Scaling

Apart from scaling a single broker, you can use a broker cluster network to increase the number of ActiveMQ brokers available for a busy system.

As the network automatically pass messages to connected brokers that have interested consumers.

Traffic Partitioning

ActiveMQ also provides an application level splitting of destinations, or traffic partitioning. The client application decides what traffic should go to which broker(s).

Security

Apart from basic authentication to use ActiveMQ. It also provides two level of authorization, operation level authorization and message level authorization.

Operation Level Authorization

It defines three roles, Read, Write, and Admin.
  • Read - The ability to receive messages from the destination
  • Write - The ability to send messages to the destination
  • Admin - The ability to administer the destination

Message Level Authorization

In some situations you might want to authorize access to only particular messages in a destination. You can create a message level authorization, which will check if the consumer has the right to receive certain messages.

Broker Level Operations

Broker operations includes such items as adding consumers and producers to the broker, committing transactions in the broker, adding and removing connections to the broker, etc. This gives the flexibility for clients to add their whitelabels.

Compatability

ActiveMQ supports many different transport protocols HTTP, HTTPS, SSL, Websocket, TCP, and many message protocols, Openwire, REST, RSS, XMPP, STOMP(Streaming Text Orientated Messaging Protocol). For instance, the server-side publishes messages via TCP, the front-end can choose HTTPS or Websocket to connect to the broker. This gives many choices for the clients to use depending on their environment. On the message protocol, for example, a C++ or Java client can use high performance binary protocol, Openwire, to send/receive messages, while, for scripting languages, such as PHP, Python, can use STOMP.

Mantanability

ActiveMQ provides messaging support system. You can monitor how many consumers are currently connected. How many messages are received and delivered.

It has Advisory messages, which are system messages generated by brokers. Typically, an advisory message will be generated every time a new administered object (Connection, Destination, Consumer, Producer) joins or leaves the broker. It can also report a warning about the ActiveMQ broker reaching system limits.

References

[1] ActiveMQ performance http://activemq.apache.org/performance.html

[2] JMS (ActiveMQ) Performance Verification http://liukeye.blogspot.com/2010/10/jms-activemq-performance-verification.html

[3] Jetty Continuations http://docs.codehaus.org/display/JETTY/Continuations

JMS (ActiveMQ) Performance Verification

Here is the performance report from my local machine.

Specs:
* Machine: Fedora 11, Quad CPU, 4GB DDR2 667MHz RAM, 2.1GB of which is already used.
* JDK version: 1.6
* Message size: 1024 bytes (1kb)

The Broker ran with:
* Two Transport Connectors
* One Message Producer
* Two Message Consumer (One Java and One PHP)

broker.addConnector("tcp://localhost:61616");
broker.addConnector("stomp://localhost:61613");


20,000 messages are produced in two different languages, Java and PHP. The result is shown on Table 1 and 2.

As you can see, overall, Java performs better. Although PHP as a message producer can generate more messages (about 7000 per second), the latency is too much for consuming message as PHP is a single threaded language.

Java produced less message per second, however, this is due to ActiveMQ Broker, and both message producer and consumer (three instances) are running on the same JVM. When I only run JAVA producer, which still share JVM with the Broker, the rate is about the same as PHP, about 7000 per second.

Also, PHP can only use STOMP (Streaming Text Orientated Messaging Protocol), but Java can use TCP, SSL, NIO (New I/O), UDP, multicast and VM (Virtual Machine) protocol. According to ActiveMQ documentation, NIO should performance better as it uses less resources when the traffic is heavy.

Table 1 Java as Message Producer

TypeProtocolNo. of MsgStart Timestamp
(ms)
End Timestamp
(ms)
First Msg
Latency (ms)
Last Msg
Latency (ms)
Total Time to
handle 20,000 msg(ms)

Rate
(msg/sec)
Java ProducerTCP20,00012699687511301269968755299 41694797
Java ConsumerTCP20,0001269968751176 126996875529946less than 141234850
PHP ConsumerSTOMP20,0001269968751143126996875875513345676122627

Table 2 PHP as Message Producer

TypeProtocolNo. of MsgStart Timestamp
(ms)

End Timestamp
(ms)
First Msg
Latency (ms)
Last Msg
Latency (ms)
Total Time to
handle 20,000 msg(ms)

Rate
(msg/sec)
PHP ProducerSTOMP20,00012699690492871269969052019 27327321
PHP ConsumerSTOMP20,0001269969049383126996905637596435669922860
JAVA ConsumerTCP20,000126996904932912699690521274210827987148