go实现NSQ消息队列的集群部署

1 安装

官方下载页面根据自己的平台下载并解压即可。
我安装的是windows版本的
在这里插入图片描述
2 NSQ的工作模式
每个nsqd实例旨在一次处理多个数据流。这些数据流称为“topics”,一个topic具有1个或多个“channels”。每个channel都会收到topic所有消息的副本,实际上下游的服务是通过对应的channel来消费topic消息。

topic和channel不是预先配置的。topic在首次使用时创建,方法是将其发布到指定topic,或者订阅指定topic上的channel。channel是通过订阅指定的channel在第一次使用时创建的。

topic和channel都相互独立地缓冲数据,防止缓慢的消费者导致其他chennel的积压(同样适用于topic级别)。
在这里插入图片描述

3 集群部署

启动的exe文件均在下载目录bin下

  • 启动nsqlookupd
nsqlookupd.exe

nsqlookupd监听的是4160 4161对应tcp http端口

  • 启动3个nsqd
    我这里启动了三个nsqd,记得在.bin/datas下建立三个node目录,
    在这里插入图片描述
    如果启动单个测试,参考博客

一个端口就对应一个nsqd
第一个nsqd就算监听4150 4151端口的

nsqd.exe --lookupd-tcp-address 127.0.0.1:4160 --broadcast-address 127.0.0.1 --data-path=./datas/node1 -http-address 127.0.0.1:4151 -tcp-address 127.0.0.1:4150
nsqd.exe --lookupd-tcp-address 127.0.0.1:4160 --broadcast-address 127.0.0.1 --data-path=./datas/node2 -http-address 127.0.0.1:4251 -tcp-address 127.0.0.1:4250
nsqd.exe --lookupd-tcp-address 127.0.0.1:4160 --broadcast-address 127.0.0.1 --data-path=./datas/node3 -http-address 127.0.0.1:4351 -tcp-address 127.0.0.1:4350

测试代码

总共有四个生产者

  • 第1个生产者发给端口4150 topic == "topic_demo11"的nsqd
  • 第2个生产者发给端口4150 topic == "topic_demo12"的nsqd
  • 第3个生产者发给端口4250 topic == "topic_demo11"的nsqd
  • 第4个生产者发给端口4350 topic == "topic_demo11"的nsqd

生产者代码

// nsq_producer/main.go
package main

import (
	"fmt"
	"sync"
	"time"

	"github.com/nsqio/go-nsq"
)

// NSQ Producer Demo

var producer *nsq.Producer

var wg sync.WaitGroup
var mutex sync.Mutex
var k int64

// 初始化生产者
func initProducer(str string) (err error) {
	config := nsq.NewConfig()
	producer, err = nsq.NewProducer(str, config)
	if err != nil {
		fmt.Printf("create producer failed, err:%v\n", err)
		return err
	}
	return nil
}

//向指定ip port topic生产数据
func producerSendsData(ip string, port int, topic string) {
	//生产者往4150的nsqd上的dtopic_demo发信息
	nsqAddress := fmt.Sprintf("%s:%d", ip, port)
	//fmt.Println(nsqAddress)
	//一个端口就对应一个nsqd
	err := initProducer(nsqAddress)
	if err != nil {
		fmt.Printf("init producer failed, err:%v\n", err)
		return
	}

	for i := 0; i < 20; i++ {
		mutex.Lock()
		data := fmt.Sprintf("生产者发的数据:%d", k)
		// 向 'topic_demo' publish 数据
		err = producer.Publish(topic, []byte(data))
		if err != nil {
			fmt.Printf("publish msg to nsq failed, err:%v\n", err)
			continue
		}
		mutex.Unlock()
		k += 1
		//time.Sleep(time.Second)
		time.Sleep(time.Microsecond * 200)
		fmt.Println(data, nsqAddress)
	}
	defer wg.Done()
}
func main() {
	k = 0
	ip := "127.0.0.1"
	wg.Add(4)

	//一个端口就对应一个nsqd
	//第一个nsqd 端口4150 topic := "topic_demo"
	port1 := 4150
	topic11 := "topic_demo11"
	go producerSendsData(ip, port1, topic11)
	//第一个nsqd 端口4150 topic02 := "topic_demo02"
	topic12 := "topic_demo12"
	go producerSendsData(ip, port1, topic12)

	//第2个nsqd 端口4250 topic := "topic_demo11"
	//第2个nsqd我同样向topic_demo11中传输数据
	port2 := 4250
	topic21 := "topic_demo11" //"topic_demo21"
	go producerSendsData(ip, port2, topic21)

	//第3个nsqd 端口4350 topic02 := "topic_demo02"
	port3 := 4350
	topic31 := "topic_demo11"
	go producerSendsData(ip, port3, topic31)

	wg.Wait()

	//这部分代码是从标准输入读取了发送的
	/*
		reader := bufio.NewReader(os.Stdin) // 从标准输入读取
		for {
			data, err := reader.ReadString('\n')
			if err != nil {
				fmt.Printf("read string from stdin failed, err:%v\n", err)
				continue
			}
			data = strings.TrimSpace(data)
			if strings.ToUpper(data) == "Q" { // 输入Q退出
				break
			}
			// 向 'topic_demo' publish 数据
			err = producer.Publish("topic_demo", []byte(data))
			if err != nil {
				fmt.Printf("publish msg to nsq failed, err:%v\n", err)
				continue
			}
		}
	*/
}

总共有2个消费者

  • 第一个消费者去收topic==topic_demo11的数据
  • 第一个消费者去收topic==topic_demo12的数据

消费者代码

package main

import (
	"fmt"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"

	"github.com/nsqio/go-nsq"
)

// NSQ Consumer Demo
var wg sync.WaitGroup

// MyHandler 是一个消费者类型
type MyHandler struct {
	Title string
}

// HandleMessage 是需要实现的处理消息的方法
func (m *MyHandler) HandleMessage(msg *nsq.Message) (err error) {
	fmt.Printf("%s recv from %v, msg:%v\n", m.Title, msg.NSQDAddress, string(msg.Body))
	return
}

// 初始化消费者
func initConsumer(topic string, channel string, address string) {
	config := nsq.NewConfig()
	config.LookupdPollInterval = 15 * time.Second
	c, err := nsq.NewConsumer(topic, channel, config)
	if err != nil {
		fmt.Printf("create consumer failed, err:%v\n", err)
		return
	}

	consumer := &MyHandler{
		Title: topic + " " + channel,
	}
	c.AddHandler(consumer)

	// if err := c.ConnectToNSQD(address); err != nil { // 直接连NSQD
	if err := c.ConnectToNSQLookupd(address); err != nil { // 通过lookupd查询
		fmt.Printf("c.ConnectToNSQLookupd(address) failed, err:%v\n", err)
		return
	}
	//time.Sleep(time.Second)

	defer wg.Done()

}

func main() {
	wg.Add(2)
	//topic_demo就是topic second是channel
	//第一个nsqd 端口4150 topic := "topic_demo11"下的数据用两个消费者(first和second)消费
	go initConsumer("topic_demo11", "first", "127.0.0.1:4161")
	go initConsumer("topic_demo12", "first", "127.0.0.1:4161")

	// //第一个nsqd 端口4150 topic02 := "topic_demo02"下的数据用1个消费者(first)消费
	// go initConsumer("topic_demo12", "first", "127.0.0.1:4161")

	// //第2个nsqd 端口4250 topic := "topic_demo21"
	// go initConsumer("topic_demo21", "second", "127.0.0.1:4161")

	wg.Wait()
	c := make(chan os.Signal)        // 定义一个信号的通道
	signal.Notify(c, syscall.SIGINT) // 转发键盘中断信号到c
	<-c                              // 阻塞
}

测试结果演示

4个生产者总共发送了80个数据,2个消费者也接收到了80个数据
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

唐维康

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值