This is a creation in Article, where the information may have evolved or changed. 
 
 Why to use NSQ 
 
 has recently been looking for a high-performance, highly available message queue to do communication between internal services. At first think of using ZEROMQ, but in the process of finding information, accidentally found NSQ this Golang developed message queue, after all, is Golang original things, full-featured, the key is the performance is good. Which support dynamic expansion, eliminate the single point of failure and other characteristics, can be very good to meet my needs 
 
 The previous comparison between NSQ and other MQ looks really powerful. Here is a simple record of how NSQ is used 
 
 
 
 
 NSQ Service Side 
 
 NSQ Service-Side introduction 
 
 Before using the NSQ service, it is still necessary to understand several core components of NSQ 
 
 The entire NSQ service consists of three main parts 
 
 Nsqlookupd 
 
 Let's take a look at what the official words say: 
 
 NSQLOOKUPD is the daemon responsible for managing topology information. The client discovers the producer of the specified topic (topic) by querying NSQLOOKUPD, and the NSQD node broadcasts the topic (topic) and channel information 
 
 Simply put, NSQLOOKUPD is the central management Service, which uses TCP (default port 4160) to manage the NSQD service, using HTTP (the default port 4161) to manage the Nsqadmin service. Also provides query functionality for clients 
 
 
 
 
 In general, NSQLOOKUPD has the following features or features 
 
 
  
  -   Uniqueness, there is only one NSQLOOKUPD service in a NSQ service. It is also possible to deploy multiple nsqlookupd in the cluster, but there is no association between them  
-   De-NSQLOOKUPD, even if it crashes, will not affect the running NSQD service  
-   Serves as a middleware for NSQD and naqadmin information interactions  
-   Provides an HTTP query service to periodically update the NSQD address directory for clients  
 Nsqadmin 
 
 Official quote: A WEB UI that aggregates real-time statistics for a cluster and performs different management tasks 
 
 In general, Nsqadmin has the following features or features 
 
 
  
  -   Provide a unified management of topic and channel operation interface and a variety of real-time monitoring data display, interface design is very simple, easy to operate  
-   Show the number of all the message, uh .... Pack x Sharp  
-   Be able to create topic and channel in the background, this should not be used to  
-   All features of Nsqadmin must rely on nsqlookupd,nsqadmin to simply pass user actions to NSQLOOKUPD and show data from NSQLOOKUPD  
 
 
 
 Nsqd 
 
 Official quote: NSQD is a daemon that is responsible for receiving, queuing, and delivering messages to clients 
 
 Simply put, the real work is the service, it is mainly responsible for the message of the transceiver, queue maintenance. NSQD will listen to a TCP port (4150) and an HTTP port (4151) and an optional HTTPS port by default 
 
 In general, NSQD has the following features or features 
 
 
  
  -   For subscribers to the same topic, the same channel consumer uses a load balancing policy (not polling)  
-   As long as the channel exists, even consumers without the channel will cache the producer's message in the queue (note the expiration of the message)  
-   The message in the queue is guaranteed to be consumed at least once, even if NSQD exits, the messages in the queue are staged on the disk (except for unexpected cases such as ending the process)  
-   Limited memory consumption, ability to configure the number of message caches in memory for each channel queue in NSQD, and once exceeded, message will be cached to disk  
-   Topic,channel once established, will always exist, in a timely manner in the management station or in code to remove invalid topic and channel, to avoid waste of resources  
 This is the official figure, the first channel (meteics) because there are multiple consumers, so triggered the load balancing mechanism. After two channel because there is no consumer, all the message will be cached in the corresponding queue until the consumer appears
  
 
 
  
 
 One problem here is that if a channel is only being delivered by a producer, will it cause server resources to be exhausted? Perhaps the NSQD internally did the corresponding treatment, but to avoid the occurrence of this situation 
 
 NSQ server-to-client relationship 
 
 Understand the relationship between NSQLOOKUPD,NSQD and consumers and producers in the client 
 
 Consumers 
 
 Consumers have two ways of connecting with NSQD 
 
 
  
  -   Consumers directly connected to the NSQD, this is the simplest way, the disadvantage is that the NSQD service can not achieve dynamic scaling (of course, to achieve one is also possible)  
-   The consumer obtains the connection address of all NSQD on the NSQLOOKUPD via HTTP query nsqlookupd and then establishes a connection with the NSQD (the official recommended practice), but the client constantly queries the NSQLOOKUPD for the latest NSQD address directory ( Don't like polling this way with http ...)
 Or take a closer look at the chart, the official consumer model:
 
  
 
 
 
 
 
 Producers 
 
 Producers must directly connect NSQD to deliver a message (online said, can connect to NSQLOOKUPD, let nsqlookupd automatically choose a nsqd to complete delivery, but I use producer TCP is not even nsqlookupd, I don't know if HTTP can ...), 
 
 One problem here is that if the producer is connected to the NSQD, then the message will fail, so the client must implement the corresponding fallback plan. 
 
 Installing NSQ 
 
 Method One 
 
 
go get github.com/tools/godep
 
 After the execution, check whether the GODEP is installed in the bin directory, the general will automatically install, if not, with Go install manual installation under 
 
 
go get github.com/bmizerany/assert
 
 
godep get github.com/bitly/nsq/...
 
 If the installation succeeds, a lot of nsq_ will appear in the Bin directory ... The beginning of the executable file 
 
 
 Method Two 
 
 
 Run NSQ 
 
 Running a standalone NSQD service 
 
 NSQD is an independent service, start a NSQD can complete message transceiver, start a single-machine nsqd, very simple 
 
nsqd
 
 The client can use HTTP, or TCP, where I use the official GO-NSQ package as the client, using TCP to send and receive message 
 
 
 Running the NSQ service cluster 
 
 
nsqlookupd
 
 
nsqd--lookupd-tcp-address=127.0.0.1:4160
         
            
nsqd --lookupd-tcp-address=127.0.0.1:4160 -tcp-address=0.0.0.0:4152 -http-address=0.0.0.0:4153
 
                                  
nsqd --lookupd-http-address=127.0.0.1:4161
  GO-NSQ-based client implementation 
  A few notable places 
 
                                  
                                   
                                   -   Producer will not be re-connected after disconnection, you need to manually re-connect, consumer disconnection will automatically re-connect  
-   Consumer's re-connect time configuration item has two functions (this design must be spit out, a bit better separately)   
                                     -   Consumer detects that a connection to the NSQD has been broken, and every x seconds to the NSQD request to reconnect  
-   Consumer every x seconds, HTTP polling to Nsqlookud to update their NSQD address directory  
-   The consumer time of the default is 60s (...). The dishes are cold), I changed to 1s  
 
-   Consumer can receive the same name topic data from different NSQD node at the same time, in order to avoid confusion, it must be processed on the client  
-   The interface callbacks set in Addconurrenthandlers and AddHandler are performed in a different goroutine  
-   Producer cannot publish (Publish) empty message, otherwise it will cause panic  
 Go_nsq-send.go 
 
//Nsq send test
Package main
Import (
 "bufio"
 "fmt"
 "github.com/nsqio/go-nsq"
 "os"
)
Var producer *nsq.Producer
// main function
Func main() {
 strIP1 := "127.0.0.1:4150"
 strIP2 := "127.0.0.1:4152"
 InitProducer(strIP1)
 Running := true
 / / Read the console input
 Reader := bufio.NewReader(os.Stdin)
 For running {
  Data, _, _ := reader.ReadLine()
  Command := string(data)
  If command == "stop" {
   Running = false
  }
  For err := Publish("test", command); err != nil; err = Publish("test", command) {
   / / Switch IP reconnection
   strIP1, strIP2 = strIP2, strIP1
   InitProducer(strIP1)
  }
 }
 //shut down
 producer.Stop()
}
// Initialize the producer
Func InitProducer(str string) {
 Var err error
 fmt.Println("address: ", str)
 Producer, err = nsq.NewProducer(str, nsq.NewConfig())
 If err != nil {
 Panic(err)
 }
}
//make an announcement
Func Publish(topic string, message string) error {
 Var err error
 If producer = nil {
  If message == "" { //Cannot post an empty string, otherwise it will cause error
   Return nil
  }
  Err = producer.Publish(topic, []byte(message)) // Post a message
  Return err
 }
 Return fmt.Errorf("producer is nil", err)
}
  go _nsq-receive.go 
 
//Nsq receiving test
Package main
Import (
 "fmt"
 "time"
 "github.com/nsqio/go-nsq"
)
// consumer
Type ConsumerT struct{}
// main function
Func main() {
 InitConsumer("test", "test-channel", "127.0.0.1:4161")
 For {
  time.Sleep(time.Second * 10)
 }
}
/ / Process the message
Func (*ConsumerT) HandleMessage(msg *nsq.Message) error {
 fmt.Println("receive", msg.NSQDAddress, "message:", string(msg.Body))
 Return nil
}
/ / Initialize the consumer
Func InitConsumer(topic string, channel string, address string) {
 Cfg := nsq.NewConfig()
 cfg.LookupdPollInterval = time.Second //Set the reconnection time
 c, err := nsq.NewConsumer(topic, channel, cfg) // Create a new consumer
 If err != nil {
 Panic(err)
 }
 c.SetLogger(nil, 0) //mask system logs
 c.AddHandler(&ConsumerT{}) // Add consumer interface
 / / Establish NSQLookupd connection
 If err := c.ConnectToNSQLookupd(address); err != nil {
 Panic(err)
 }
 / / Establish multiple nsqd connections
 // if err := c.ConnectToNSQDs([]string{"127.0.0.1:4150", "127.0.0.1:4152"}); err != nil {
 // panic(err)
 // }
 // Create a nsqd connection
 // if err := c.ConnectToNSQD("127.0.0.1:4150"); err != nil {
 // panic(err)
 // }
}