Tutorial: AMQP with Golang Implementing RabbitMQ with Golang

 


Tutorial: AMQP with Golang
Implementing RabbitMQ with Golang

What is AMQP?

The abbreviation AMQP stands for “Advanced Message Queuing Protocol.” It can be described as a messaging protocol employed for asynchronous communication among microservices, achieved through the exchange of messages within queues. AMQP offers an advanced messaging model characterized by features such as message queuing, adaptable routing, and delivery confirmation.

AMQP finds its primary utility in scenarios necessitating resilient and fault-tolerant asynchronous communication. It excels in managing events, handling background processing tasks, and facilitating communication among microservices that don’t demand immediate responses.

AMQP is a specific protocol that defines how clients and servers should communicate to send and receive messages asynchronously. Some popular implementations of AMQP include RabbitMQ and Apache Qpid.

AMQP (Advanced Message Queuing Protocol) is a messaging protocol used for communication between applications. In Go, you can use the github.com/streadway/amqp library to interact with AMQP servers, such as RabbitMQ.


What are its pros and cons?

Pros

  • Delivery Guarantee
    AMQP ensures a dependable message delivery guarantee, assuring that messages remain intact and are conveyed precisely once, even in the event of failures.
  • Asynchronous communication
    It enables asynchronous communication between applications and microservices, fostering the separation of processing logic and autonomy among system components.
  • Scalability
    Systems employing AMQP exhibit high scalability, allowing you to expand capacity by incorporating additional producers, consumers, or brokers as your workload increases.
  • Flexible routing
    Thanks to configurable exchanges and routing rules, AMQP offers substantial flexibility in the distribution of messages to message queues and consumers.
  • Security
    AMQP boasts robust security mechanisms, encompassing authentication and encryption, to safeguard the integrity and confidentiality of transmitted messages.
  • Interoperability
    AMQP stands as a widely embraced open standard, affording you the capability to employ various implementations of AMQP brokers and clients to ensure seamless interoperability.

Cons

  • Complexity
    The configuration and administration of an AMQP system can prove intricate, particularly when contrasted with more straightforward approaches like REST. It necessitates a deeper understanding of message queues, exchanges, and routing rules.
  • Low latency performance
    In scenarios demanding low-latency and synchronous communication, AMQP may not be the optimal choice, as asynchronous communication inherently introduces some latency owing to message queuing and routing processes.
  • Protocol Overload
    AMQP has some protocol overhead due to message serialization and communication through brokers, which can affect performance in applications that require high data transfer rates.
  • Broker dependency
    Systems relying on AMQP are dependent on messaging brokers for their functionality. Any issues encountered by the broker could potentially impact the availability of communication.

What is RabbitMQ?

RabbitMQ is an open source messaging software used to facilitate communication between distributed applications or systems, especially in microservices-based architectures. It provides an asynchronous messaging system based on the AMQP (Advanced Message Queuing Protocol) protocol and is widely used in enterprise environments and high-concurrency systems.

RabbitMQ is especially useful in situations where asynchronous communication and scalability between different parts of a distributed application is required. It can be used for the implementation of background task processing systems, communication between microservices, and event distribution, among other application scenarios. Its flexibility and scalability make it a powerful tool in distributed software architecture.

RabbitMQ is mainly composed of:

  • AMQP protocol
    RabbitMQ uses the AMQP protocol for communication between different components. AMQP is an industry standard that defines the structure and behavior of messages, queues, exchanges, and other key elements in messaging systems.
  • Producer
    A producer is an application or component that sends messages to RabbitMQ. These messages may contain data or instructions that must be processed by other components.
  • Queues: 
    Queues are containers where RabbitMQ stores messages that must be delivered to consumers. Producers send messages to queues, and consumers take them from there for processing. RabbitMQ manages the delivery of messages to consumers securely and efficiently.
  • Consumer
    A consumer is an application or component that takes messages from a queue and processes them. There can be multiple consumers competing for messages in the same queue, allowing load distribution and parallel processing of messages.
  • Exchanges
    Exchanges are RabbitMQ components that receive messages from producers and determine which queues they should send them to. Messages are published to an exchange, and the exchange directs the message to one or more queues based on certain routing rules.
  • Bindings: Bindings are the rules that connect an exchange to a specific queue. These rules define how messages are routed from the exchange to the queue.
  • Virtual Hosts: 
    RabbitMQ allows you to create multiple “Virtual Hosts” within the same server. Each of these virtual hosts acts as an independent messaging environment, making it easy to separate and manage different applications or environments on a single RabbitMQ server.
  • Administration and Monitoring:
    RabbitMQ offers a web administration interface that makes it easy to configure, monitor and manage queues, exchanges and other system components. It also provides metrics and statistics that allow monitoring of system activity.

Developing an example using Golang and RabbitMQ

This tutorial will be using Docker to run RabbitMQ. We need to follow the next steps:

Download the RabbitMQ image:
Open your terminal and run the following command to download the official RabbitMQ image from Docker Hub:

docker pull rabbitmq

This will download the latest version of the RabbitMQ image to your system.

Run a RabbitMQ container:
Once the RabbitMQ image has been downloaded, you can run a container with the following command:

docker run -d --name mi-rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq

An alternative using docker-compose:

version: "3.2"
services:
rabbitmq:
image: rabbitmq:3.13.0-rc.1-management-alpine
container_name: 'rabbitmq'
ports:
- 5672:5672
- 15672:15672
volumes:
- ~/.docker-conf/rabbitmq/data/:/var/lib/rabbitmq/
- ~/.docker-conf/rabbitmq/log/:/var/log/rabbitmq
networks:
- rabbitmq_go_net

networks:
rabbitmq_go_net:
driver: bridge

Access the RabbitMQ web interface:
Once RabbitMQ is up and running, you can access its administration web interface in your browser. Open a web browser and visit http://localhost:15672/ or http://127.0.0.1:15672/. You should see the login page. The default username and password are “guest” for both.

Stop and kill the container (optional): 
When you’re done using RabbitMQ in Docker, you can stop and kill the container with the following commands:

docker stop mi-rabbitmq
docker rm mi-rabbitmq

Now, you have RabbitMQ running in a Docker container on your system. You can use this RabbitMQ instance to communicate between applications that use the AMQP protocol.

The Golang code

AMQP (Advanced Message Queuing Protocol) is a messaging protocol used for communication between applications. In Go, you can use the github.com/streadway/amqp library to interact with AMQP servers, such as RabbitMQ. Here I will provide you with a simple example of how to communicate two services using AMQP in Go:

First, make sure you have the streadway/amqp library installed. You can do this using go get:

go get github.com/streadway/amqp

Producer

package main

import (
"log"

"github.com/streadway/amqp"
)

func failOnError(err error, msg string) {
if err != nil {
log.Fatalf("%s: %s", msg, err)
}
}

func main() {
conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
failOnError(err, "Failed to connect to RabbitMQ")
defer conn.Close()

ch, err := conn.Channel()
failOnError(err, "Failed to open a channel")
defer ch.Close()

queueName := "product_updates"
productQueue, err := ch.QueueDeclare(
queueName,
false,
false,
false,
false,
nil,
)
failOnError(err, "Failed to declare an exchange")

productMessage := "New product added message"
err = ch.Publish(
"",
productQueue.Name,
false,
false,
amqp.Publishing{
ContentType: "text/plain",
Body: []byte(productMessage),
})
failOnError(err, "Failed to publish a message")

log.Printf("Message sent: %s", productMessage)
}

To run the code we need to execute: go run producer/main.go

example output:

2023/10/25 17:30:41 Message sent: New product added message

Consumer

package main

import (
"log"

"github.com/streadway/amqp"
)

func failOnError(err error, msg string) {
if err != nil {
log.Fatalf("%s: %s", msg, err)
}
}

func main() {

conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
failOnError(err, "Failed to connect to RabbitMQ")
defer conn.Close()

ch, err := conn.Channel()
failOnError(err, "Failed to open a channel")
defer ch.Close()

queue, err := ch.QueueDeclare(
"product_updates",
false,
false,
false,
false,
nil,
)
failOnError(err, "Failed to declare a queue")

err = ch.QueueBind(
queue.Name,
"",
"product_updates",
false,
nil,
)
failOnError(err, "Failed to bind a queue")

msgs, err := ch.Consume(
queue.Name,
"",
true,
false,
false,
false,
nil,
)
failOnError(err, "Failed to register a consumer")

log.Printf("Order service waiting by message...")

for msg := range msgs {
log.Printf("New message: %s", msg.Body)
}
}

To run the code we need to execute: go run consumer/main.go

Example output:

2023/10/25 17:29:49 New message: New product added message
2023/10/25 17:29:50 New message: New product added message
2023/10/25 17:29:50 New message: New product added message
2023/10/25 17:29:51 New message: New product added message
2023/10/25 17:29:51 New message: New product added message
2023/10/25 17:29:53 New message: New product added message
2023/10/25 17:29:54 New message: New product added message

You can visualize the messages in the RabbitMQ page:


Conclusion

The combination of RabbitMQ and Golang represents a powerful solution for implementing messaging and asynchronous communication in distributed applications. Using RabbitMQ, a highly reliable and scalable messaging system, alongside Golang, an efficient and concurrent programming language, provides an ideal toolkit for developing applications that require communication and data exchange between different components or services.

In summary, the combination of RabbitMQ and Golang offers a powerful and flexible solution for implementing distributed systems and microservices-based applications that require efficient asynchronous communication. By leveraging the strengths of both technologies, developers can build robust and highly scalable systems that can adapt to a wide variety of use cases.