NSQ 簡介及教程
What is nsq
NSQ is a realtime distributed messaging platform.
IntroduceLinks
Why use nsq
How to use nsq
Example
Install
docker-compose.yaml
version: '3'
services:
nsqlookupd:
image: nsqio/nsq
command: /nsqlookupd
ports:
- "4160:4160"
- "4161:4161"
nsqd:
image: nsqio/nsq
command: /nsqd --lookupd-tcp-address=nsqlookupd:4160 --broadcast-address=10.1.4.130
depends_on:
- nsqlookupd
ports:
- "4150:4150"
- "4151:4151"
nsqadmin:
image: nsqio/nsq
command: /nsqadmin --lookupd-http-address=nsqlookupd:4161
depends_on:
- nsqlookupd
ports:
- "4171:4171"
TestCase
Consumer
consumer_test.go
package comsumer
import (
"github.com/nsqio/go-nsq"
"log"
"testing"
"time"
)
var (
nsqLookupdAddr = "10.1.4.130:4161"
)
func TestConsumer1(t *testing.T) {
config := nsq.NewConfig()
topic := "t1"
channel := "t1-c1"
c, err := nsq.NewConsumer(topic, channel, config)
if err != nil {
log.Fatalf("init consumer fail, err: %s", err.Error())
}
c.AddHandler(&msgHandler1{})
// Use nsqlookupd to discover nsqd instances.
// See also ConnectToNSQD, ConnectToNSQDs, ConnectToNSQLookupds.
err = c.ConnectToNSQLookupd(nsqLookupdAddr)
if err != nil {
log.Fatalf("ConnectToNSQLookupd fail, err: %s", err.Error())
}
time.Sleep(time.Duration(100) * time.Minute)
}
func TestConsumer2(t *testing.T) {
config := nsq.NewConfig()
config.MaxInFlight = 100
topic := "t1"
channel := "t1-c2"
c, err := nsq.NewConsumer(topic, channel, config)
if err != nil {
log.Fatalf("init consumer fail, err: %s", err.Error())
}
c.AddHandler(&msgHandler2{})
// Use nsqlookupd to discover nsqd instances.
// See also ConnectToNSQD, ConnectToNSQDs, ConnectToNSQLookupds.
err = c.ConnectToNSQLookupd(nsqLookupdAddr)
if err != nil {
log.Fatalf("ConnectToNSQLookupd fail, err: %s", err.Error())
}
time.Sleep(time.Duration(100) * time.Minute)
}
types.go
package comsumer
import (
"time"
"fmt"
"github.com/nsqio/go-nsq"
)
// ===
// msg handler 1
type msgHandler1 struct {
}
func (_ *msgHandler1) HandleMessage(m *nsq.Message) error {
handlerName := "msgHandler1"
var err error
if len(m.Body) == 0 {
// Returning nil will automatically send a FIN command to NSQ to mark the message as processed.
return nil
}
// handle msg
msg := m.Body
fmt.Printf("%s received msg: %s\n", handlerName, msg)
if err != nil {
// Returning a non-nil error will automatically send a REQ command to NSQ to re-queue the message.
return err
}
return nil
}
// ===
// msg handler 2
type msgHandler2 struct {
}
func (_ *msgHandler2) HandleMessage(m *nsq.Message) error {
handlerName := "msgHandler2"
if len(m.Body) == 0 {
// Returning nil will automatically send a FIN command to NSQ to mark the message as processed.
return nil
}
// handle msg
msg := string(m.Body)
if time.Now().Unix()%2 == 0 {
fmt.Printf("%s received msg: %s, attempts: %d\n", handlerName, msg, m.Attempts)
return nil
} else {
if m.Attempts >= 2 {
fmt.Printf("%s received msg: %s, attempts: %d\n", handlerName, msg, m.Attempts)
return nil
} else {
return fmt.Errorf("%s need re-queue msg: %s, attempts: %d\n", handlerName, msg, m.Attempts)
}
}
}
Producer
producer_test.go
package producer
import (
"github.com/nsqio/go-nsq"
"testing"
"log"
"time"
"fmt"
"encoding/json"
)
var (
nsqdAddr = "10.1.4.130:4150"
p *nsq.Producer
)
func init() {
newProducer()
}
func newProducer() (*nsq.Producer, error) {
config := nsq.NewConfig()
return nsq.NewProducer(nsqdAddr, config)
}
func TestMain(m *testing.M) {
if p == nil {
var err error
p, err = newProducer()
if err != nil {
panic(err)
}
}
m.Run()
}
func TestSimplePublish(t *testing.T) {
if err := p.Ping(); err != nil {
log.Fatalf("ping nsqd fail, err: %s", err.Error())
}
topic := "t1"
msg := []byte("this is simple msg")
p.Publish(topic, msg)
time.Sleep(100 * time.Minute)
}
func TestMultiPublish(t *testing.T) {
topic := "t1"
var msgs [][]byte
for i := 1; i <= 50; i ++ {
msg := fmt.Sprintf("msg-%d", i)
msgs = append(msgs, []byte(msg))
}
p.MultiPublish(topic, msgs)
}
func TestDeferredPublish(t *testing.T) {
topic := "t1"
delay := time.Duration(30) * time.Second
msg := []byte("deferred msg")
if err := p.DeferredPublish(topic, delay, msg); err != nil {
log.Fatalf("deferred publish fail, err: %s\n", err.Error())
}
p.Stop()
}
func TestPublishAsync(t *testing.T) {
topic := "t1"
msg := []byte("async msg")
doChan := make(chan *nsq.ProducerTransaction, 1)
if err := p.PublishAsync(topic, msg, doChan, "arg1", 2); err != nil {
log.Fatalf("publish async fail, err: %s\n", err.Error())
}
for {
select {
case res := <-doChan:
argsBytes, _ := json.Marshal(res.Args)
fmt.Printf("args: %s\n", string(argsBytes))
if res.Error != nil {
fmt.Printf("err: %s\n", res.Error.Error())
}
return
default:
}
}
p.Stop()
}