During my work in Geniox mobile, I face responsibility to maintain Golang service that handle millions of request a day. Therefore, I have to undersand message queue concept to do this job.
Message Queue (MQ)
A message queue (MQ) is a form asynchronous service-to-service used in serverless and microservices architectures (or distributed systems) to communicate with one another. (source Baeldung, aws).
This term consist of two words, message and queue.
Message
The message might be:
data needs to get transmitted
types of data formats
Queue
kind of a line of things that a process sequentially.
Implementing MQ with Golang
This snippet I created based on this article from Vultr.
Prerequisites
To follow this tutorrial, you need to have
Docker for creating MySQL database and Redis container
Golang Package
Database Container
We will run container instances for Redis and MySQL. First, clone this repo https://github.com/aysf/example, then go to redis folder, pick the simple one redis-with-config, and run up the docker-compose.
For MySQL, do the similar steps as above.
Prepare SQL Database
Enter to docker container docker exec -it mysqldb /bin/sh
Run mysql -u root -p. If it doesn’t work, prepend sudo on the command and try again.
Enter root password that you’ve set on docker-compose.yaml and press enter
packagemainimport("bytes""context""fmt""net/http""github.com/go-redis/redis/v8")funcmain(){http.HandleFunc("/payments",paymentsHandler)http.ListenAndServe(":8080",nil)}funcpaymentsHandler(whttp.ResponseWriter,req*http.Request){redisClient:=redis.NewClient(&redis.Options{Addr:"localhost:6379",Password:"",DB:0,})ctx:=context.TODO()buf:=new(bytes.Buffer)// Include a Validation logic here to sanitize the req.Body when working in a production environment
buf.ReadFrom(req.Body)paymentDetails:=buf.String()err:=redisClient.RPush(ctx,"payments",paymentDetails).Err()iferr!=nil{fmt.Fprintf(w,err.Error()+"\r\n")}else{fmt.Fprintf(w,"Payment details accepted successfully\r\n")}}
Worker
Worker task is to process and dequeue data from Redis. This ‘mini-service’ have to connect to database and insert the request to database.
Open three terminals then run the worker, queue, and client
Checking Database
Now close the worker first, then follow with other services. Once the worker closed, the client still can send request to queue but the request stuck on the Redis.
Check Redis
To check data stucked in Redis, we can use Redis GUI. AnotherRedisDesktopManager is one of my favourite.
To check number of data stored on list, use LLEN payments in redis-cli
To clear all data in cache use FLUSHALL or FLUSHDB in redis-cli
Check MySQL
To check data that already written in SQL, follow this command line
~ 👉 docker exec -it mysqldb /bin/sh
sh-4.2# mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 4763Type 'help;' or '\h'for help. Type '\c' to clear the current input statement.
mysql> SHOW databases;+--------------------+
| Database |+--------------------+
| information_schema || appdb || mysql || performance_schema || sys || web_payments |+--------------------+
6 rows in set(0.04 sec)mysql> USE web_payments;Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> SELECT * FROM payments;
Then you’ll see tons of rows of request already recorded. If you wanna see only number of rows run SELECT COUNT(*) FROM payments;. If you want to clean up all the records, just run DELETE FROM payments;
Next Question
This simple service is good for learning purpose but still not enough to use in production. In the nest article, we’ll create five instances and Go apps with concurency feature.