So far, we have been discussing data transmission as part of a protocol. Whether it is a protocol implemented at the Application Layer or a Transport Layer, we were stuck with the idea of implementing a “protocol” for any data transmission to happen. Before we leap into the concept of messaging, let us agree to get on to another level of abstraction! We shall start using the term “messaging” going forward. That messaging has an underlying protocol that it operates with, is our abstraction.
After it was established that two users could effectively communicate through a certain messaging solution, the next goal was to overcome the issue of varying speeds of the message producers and the message consumers (hereafter referred to as producers and consumers respectively). Sometimes producers were faster than the consumers, and it resulted in loss of messages as the consumers could not keep up. Other times, consumers were idling away while producers did not have too many messages to send. As an attempt to work around this issue, the concept of a buffer was introduced between the producer and the consumer. The buffer’s job was simple. It was supposed to keep the messages in transit in a transient space, until the consumer was ready for it. This approach helped to a certain extent; it would help the consumer catch-up while the producer was generating more messages than it could take. Although, when the producer started raining-in messages relentlessly, to the point that the buffer was full, then the consumer would start losing messages. This introduced an age-old problem called the Producer-Consumer Problem. It is also referred to as the bounded-buffer problem and this was the fundamental problem to solve and it remains so to this day!
The solution to the above problem came in myriad ways. In some implementations, the producer was sent to “sleep” when the buffer (also referred to as a queue) was full and brought back from sleep when it was empty again. Introduction of a “broker” came as a huge leap in messaging. Broker was no more just a buffer, rather it was the intermediary, a full-fledged server, that would manage the buffer. Messaging solutions started dedicating resources to the broker, as that was solving a lot of the producer-consumer problems. In fact, what was initially considered a hop between the message producers and consumers, soon became the most critical component to configure. Users started configuring the queues they would need, along with various other properties like reserved buffer space, encryption, compression etc. The introduction of a centralized server also helped with implementing another messaging pattern, publish-subscribe. While we save our discussion of messaging patterns for another day, suffice to say, a queue essentially serves the purpose of point-to-point messaging, while a topic serves the publish-subscribe messaging pattern.
Since we are talking messaging solutions, it is about time we talk a little bit about JMS (Java Message Service) Specification. With JMS, it is as important to understand what it is NOT, as to what it is! Firstly, JMS Specification is not a protocol. Secondly, it is not a messaging solution by itself. JMS Specification came into existence as a standard specification for messaging when a consortium of message-broker developers came together for interoperability among different broker-based messaging solutions. As message broker implementations thrived in solving enterprise messaging solutions, soon they saw a need to standardize these messages. Implementation of this specification helped consumers with parsing the messages irrespective of whether the producer is registered to the same broker or a different one.
Going back to our discussion on broker-based implementations, overtime, having a centralized server for a messaging solution (hub-and-spoke architecture) started showing its limitations for certain use-cases. The message throughput needs were changing drastically. On one side there was a rising need to cater to the exponential growth of events within enterprises – what used to be an acceptable latency due to broker management tasks was starting to become an impediment in catering for larger throughput requirements. On the other side, there was a surge in adoption of distributed computing. And when the two roads crossed, a new architectural pattern emerged. The centralized server gave way for a cluster of nodes, and as a result multiple brokers worked together as one server. The load on the server was finally distributed across nodes. This also meant the data could be distributed, not just the computing. This also meant the data could be replicated for fault-tolerance. Having a cluster manage broker duties also came with the flexibility of adding or removing nodes (scaling-up or scaling-down) based on the needed service. There would hardly be any server maintenance down-time for the distributed-broker!
If you thought a distributed broker was a panacea, well, stay tuned and wait until the next part! We shall discuss exciting stuff on paradigm shifts in processing data and we will see how event-based systems and streaming systems shot into prominence! Prowess Software has rich experience in implementing all kinds of messaging and integration, and reach us out, if you are looking for discovery, analysis, and/or implementation.