1.简介
2.应用场景
1.异步处理,把非关键流程异步化,提高系统的响应时间和健壮性
2.应用解耦
![]()
3.流量削峰
![]()
3.NSQ组件介绍
1.nsqd
- 负责消息接收,保存以及发送消息给消费者的进程(是接收、排队和传递消息到客户端的守护程序)
- 一个
nsqd可以有多个Topic
- 一个
Topic可以有多个Channel
2.nsqlookupd
- 负责维护所有nsqd的状态,提供服务发现的进程(是管理拓扑信息并提供最终一致性发现服务的守护程序)
3.nsqadmin
- 是一个web管理平台,实时监控集群以及执行各种管理任务
![]()
4.NSQ架构介绍
1.Topic
- 对应一个具体的队列,比如订单数据放到
order_queue这个topic
2.Channel
- 每个消费者对应一个
channel,实现消息可重复消费
![]()
5.NSQ特性
- 1.消息默认不持久化,可以通过配置修改为持久化
- 2.每条消息至少传递一次
- 3.消息不保证有序
6.NSQ接收和发送消息的流程
1.nsqd
- 1.生产者生产的消息通过
input chan存储到内存中
- 2.如果内存写满,则会由
goroutine将消息放入到磁盘中
- 3.消费者通过
output chan从内存中读取消息进行消费
- 4.可以通过修改内存队列大小为0,将所有消息写入磁盘,从而实现消息持久化
- 5.nsq还支持临时
Topic/Channel,它会丢弃内存溢出的消息,而不是写入磁盘,并且在不再订阅客户端时消失
![]()
6.NSQ搭建
1.下载地址
https://github.com/nsqio/nsq/releases
2.以windows为例
3.代码示例
go get github.com/nsqio/go-nsq
package main
import (
"bufio"
"fmt"
"github.com/nsqio/go-nsq"
"os"
"strings"
)
var producer *nsq.Producer
func initProducer(str string) error {
var err error
config := nsq.NewConfig()
producer, err = nsq.NewProducer(str, config)
if err != nil {
return err
}
return nil
}
func main() {
nsqAddr := "127.0.0.1:4150"
err := initProducer(nsqAddr)
if err != nil {
fmt.Println("init producer failed:", err)
return
}
reader := bufio.NewReader(os.Stdin)
for {
// 接收命令行输入
fmt.Println("请输入消息内容:>>>")
data, err := reader.ReadString('\n')
if err != nil {
fmt.Println("read string failed:", err)
continue
}
data = strings.TrimSpace(data)
if data == "stop" {
break
}
if data == "" {
fmt.Println("请输入有效内容...")
continue
}
// 向 Topic 写入消息
err = producer.Publish("user", []byte(data))
if err != nil {
fmt.Println("publish message failed:", err)
continue
}
fmt.Printf("publish data: %s success\n", data)
}
}
package main
import (
"fmt"
"github.com/nsqio/go-nsq"
"os"
"os/signal"
"syscall"
"time"
)
// 消费者
type Consumer struct {
}
// 消息处理
func (*Consumer) HandleMessage(msg *nsq.Message) error {
fmt.Println("receive >>>", msg.NSQDAddress, " message:", string(msg.Body))
return nil
}
// 初始化消费者
func initConsumer(topic, channel, address string) error {
config := nsq.NewConfig()
config.LookupdPollInterval = 15 * time.Second // 设置服务轮询时间
consume, err := nsq.NewConsumer(topic, channel, config) // 新建一个消费者
if err != nil {
return err
}
consumer := &Consumer{}
consume.AddHandler(consumer) // 添加消费者接口,该接口包含一个HandleMessage方法
// 建立NSQLookup连接
if err := consume.ConnectToNSQLookupd(address); err != nil {
return err
}
return nil
}
func main() {
// 连接的是NSQLookup HTTP端口
err := initConsumer("user", "logout", "127.0.0.1:4161")
if err != nil {
fmt.Println("init consumer failed:", err)
return
}
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT)
<-c
}