Host NATS for message bus

# What is NATS (opens new window) ?

NATS messaging enables the exchange of data that is segmented into messages among computer applications and services. These messages are addressed by subjects and do not depend on network location. This provides an abstraction layer between the application or service and the underlying physical network. Data is encoded and framed as a message and sent by a publisher. The message is received, decoded, and processed by one or more subscribers.

NATS is a lightweight application wrote in golang, it is supposed to be easy to host as well. I've personally used RabbitMQ (opens new window) at work, an alternative of queue systems, however, the maintainability drive me away from it. I've also considered Kafka (opens new window) which is a wide solution with an industrial standard, even it has full support with event store architecture, it is costly somehow, in terms of hosting, understood the architecture and maintain it. To start it simple, I'd like to give NATS a shot.

You might found the intro on how NATS works in its official documentation (opens new window). The first few pages about the concept, publisher and subscriber is super easy to understood for about 3 mins read.

Only one thing to be reminded, NATS follows fire and forgot principle, it doesn't requires a storage for it is messages. If you looking for a message system with persistence messages, NATS may not be a good fit here.

Hence, I'm not going to touch in this article. In the follow parts, I will mainly talk about how to setup NATS and hence how to have it's account management config for production usage.

# How to setup NATS

NATS system composite three components:

  • Client

    • Which the Publisher/Consumer communicating to
  • Cluster/Server

    • By routing other clusters to a main cluster. The message published to client can be consumed by other client instances
  • Monitor

Here is more details about the NATS architecture (opens new window), you may found how NATS stream works as well (this is out of topic for now).

# NATS with docker-compose

You may found instruction here (opens new window), it only allows you to have NATS operating to one machine, but it is a good start for boilerplate NATS

# NATS with K8s

A simple version of NATS running on K8s can be found here (opens new window), it is really just a minimal setup. It is gonna to be a nightmare to maintain vanilla K8s yaml files

# NATS with Helm

A most recommended way

  • Helm community (opens new window)
    • Good:
      • easy to setup
      • easy to config
    • Missing:
      • not able to do accounts management/access control in configmap
      • accounts password stay in configmap, which is not able to get encrypted
  • Official from NATS (opens new window)
    • Good:
      • accounts management/access control in a secret
      • supporting multiple accounts
    • Missing:
      • no longer actively developing
      • not able to work with Helm 3.0
      • complex CRD control (probably legacy issue for helm 2.0)

# Use NATS

Publisher:

package main

import (
	"fmt"
	"time"

	nats "github.com/nats-io/go-nats"
)

func main() {

	// Connect to a server
	nc, _ := nats.Connect(nats.DefaultURL)

	for {
		time.Sleep(3 * time.Second)
		msg := fmt.Sprintf("sending the msg out %v", time.Now().Unix())
		fmt.Println(msg)
		// Simple Publisher
		nc.Publish("foo", []byte(msg))
	}

	// Drain connection (Preferred for responders)
	// Close() not needed if this is called.
	nc.Drain()

	// Close connection
	nc.Close()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

Consumer:

package main

import (
	"fmt"

	nats "github.com/nats-io/go-nats"
)

func main() {

	// Connect to a server
	nc, _ := nats.Connect(nats.DefaultURL)

	// Channel Subscriber
	ch := make(chan *nats.Msg, 64)
	sub, err := nc.ChanSubscribe("foo", ch)
	if err != nil {
		fmt.Println(err)
	}
	for a := range ch {
		fmt.Println("------------------")
		fmt.Println("a", a)
	}

	// Drain
	sub.Drain()

	// Drain connection (Preferred for responders)
	// Close() not needed if this is called.
	nc.Drain()

	// Close connection
	nc.Close()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

# Conclusion

NATS is really easy to setup and handy to use, as long as it fit in use case, it worth the time to play around with it. Let me try to get some production experience on it first, will get back from it sometime soon.

Worth a look in the future:

  • Accounts management (ACL) on with NATS during setup, especially with existing helm charts
  • Persistent message queue with NATS Streaming
First look at service worker

First look at service worker

A service worker is a script that your browser runs in the background, separate from a web page, opening the door to features that don't need a web page or user interaction.

Host Blog with Vuepress and Github pages