这是我参与「第三届青训营 -后端场」笔记创作活动的第1篇笔记。在简约版抖音项目中,想到加上消息队列的组件来加速对用户的响应,在此之前,也没有接触过消息队列,于是搜索资料后,选择了NSQ来作为我们项目的消息队列组件。
NSQ是一个基于Go语言的分布式实时消息平台,它基于MIT开源协议发布,由bitly公司开源出来的一款简单易用的消息中间件。NSQ可用于大规模系统中的实时消息服务,并且每天能够处理数亿级别的消息,其设计目标是为在分布式环境下运行的去中心化服务提供一个强大的基础架构。NSQ具有分布式、去中心化的拓扑结构,该结构具有无单点故障、故障容错、高可用性以及能够保证消息的可靠传递的特征。NSQ非常容易配置和部署,且具有最大的灵活性,支持众多消息协议。
那么如何快速的开启NSQ之旅呢?
- 首先,我们需要下载NSQ的SDK,点击此处下载对应版本
- 下载后将对应的安装路径添加到环境变量的PATH中。
- 然后输入以下命令,注意每个命令需要后台执行。
nsqlookupd # 开启nsq服务
nsqd --lookupd-tcp-address=127.0.0.1:4160 #启动nsqd,并接入刚刚启动的nsqlookud
nsqd --lookupd-tcp-address=127.0.0.1:4160 --tcp-address=0.0.0.0:4152 --http-address=0.0.0.0:4153
nsqadmin --lookupd-http-address=127.0.0.1:4161 # 启动nqsadmin, 这样可以通过http://localhost:4171/查看消息队列状态
- 使用官方的go-package
go get github.com/nsqio/go-nsq
-
编写demo代码
- 生产者代码
package main import ( "fmt" "log" "bufio" "os" "github.com/nsqio/go-nsq" ) func main() { strIP1 := "127.0.0.1:4150" strIP2 := "127.0.0.1:4152" producer1,err := initProducer(strIP1) if err != nil { log.Fatal("init producer1 error:",err) } producer2,err := initProducer(strIP2) if err != nil { log.Fatal("init producer2 error:",err) } defer producer1.Stop() defer producer2.Stop() //读取控制台输入 reader := bufio.NewReader(os.Stdin) count := 0 for { fmt.Print("please say:") data, _, _ := reader.ReadLine() command := string(data) if command == "stop" { fmt.Println("stop producer!") return } if count % 2 == 0 { err := producer1.public("test1",command) if err != nil { log.Fatal("producer1 public error:",err) } }else { err := producer2.public("test2",command) if err != nil { log.Fatal("producer2 public error:",err) } } count++ } } type nsqProducer struct { *nsq.Producer } //初始化生产者 func initProducer(addr string) (*nsqProducer, error) { fmt.Println("init producer address:",addr) producer,err := nsq.NewProducer(addr,nsq.NewConfig()) if err != nil { return nil,err } return &nsqProducer{producer},nil } //发布消息 func (np *nsqProducer)public(topic,message string) error { err := np.Publish(topic,[]byte(message)) if err != nil { log.Println("nsq public error:",err) return err } return nil }- 消费者代码
package main import ( "time" "fmt" "log" "github.com/nsqio/go-nsq" ) func main() { err := initConsumer("test1", "test-channel1", "127.0.0.1:4161") if err != nil { log.Fatal("init Consumer error") } err = initConsumer("test2","test-channel2","127.0.0.1:4161") if err != nil { log.Fatal("init Consumer error") } select { } } type nsqHandler struct { nsqConsumer *nsq.Consumer messagesReceived int } //处理消息 func (nh *nsqHandler)HandleMessage(msg *nsq.Message) error{ nh.messagesReceived++ fmt.Printf("receive ID:%s,addr:%s,message:%s",msg.ID, msg.NSQDAddress, string(msg.Body)) fmt.Println() return nil } func initConsumer(topic, channel, addr string) error { cfg := nsq.NewConfig() cfg.LookupdPollInterval = 3*time.Second c,err := nsq.NewConsumer(topic,channel,cfg) if err != nil { log.Println("init Consumer NewConsumer error:",err) return err } handler := &nsqHandler{nsqConsumer:c} c.AddHandler(handler) err = c.ConnectToNSQLookupd(addr) if err != nil { log.Println("init Consumer ConnectToNSQLookupd error:",err) return err } return nil } -
测试结果:
- 生产者
- 消费者
- 管理界面
- 谢谢~