NSQ消息发送机制

NSQ是Go语言编写的,开源的分布式消息队列中间件,其设计的目的是用来大规模地处理每天数以十亿计级别的消息。NSQ 具有分布式和去中心化拓扑结构,该结构具有无单点故障、故障容错、高可用性以及能够保证消息的可靠传递的特征,是一个成熟的、已在大规模生成环境下应用的产品。

nsq组件

nsqd

单个nsqd实例可以用来树立多个数据流。

topic

数据流也叫topic, 一个topic可以有多个channel。

channel

每一个channel都接收该topic下面的所有消息,然后发送给消费者。channel会均匀的发送消息给消费者,不重复消费。

Topics and channels 都没有优先级,topic在两种情况下会被使用到,在发送数据到一该topic时候首次使用,或者有消费者订阅该topic下的某个channel时候。channel在有消费者订阅了该channle的时候使用。


这里写图片描述

nsqlookupd

这是一个辅助应用,启动目录服务保存着nsqd的地址,consumer可以通过nsqlookupd查询到它消费的channel、topic对应的nsqd服务。consumer不需要了解producer的信息。

nsqadmin

提供了一个webUI,我们可以查询到topics/channels/consumers这些信息,便于监管。

nsq消息传递确保

nsq可以确保发送过来的消息至少被一个消费者消费;为了确保消息消费,重复消费是不可避免的。nsq通过以下来确保消息消费

  1. 客户端表示它们可以接收消息
  2. NSQ发送消息,暂时将消息存在本地
  3. 客户端回复FIN 或者 REQ 表示成功或者重发。如果客户端未能及时发送,则NSQ将重复发送消息给该客户端。

nsq的安装使用(mac)

安装: brew install nsq
使用(命令行):

启动

在一个shell中:nsqlookupd
另一个shell中:nsqd –lookupd-tcp-address=127.0.0.1:4160
第三个shell中:nsqadmin –lookupd-http-address=127.0.0.1:4161

发送接收

curl -d ‘hello world 1’ ‘http://127.0.0.1:4151/pub?topic=test’ //发送消息
nsq_to_file –topic=test –output-dir=/tmp –lookupd-http-address=127.0.0.1:4161

NSQ消息发送机制_第1张图片

值得注意的是:nsq_to_file并不会精确的告诉topic产生的位置,它从nsqlookupd获取信息,不会丢掉消息。

nsq go生产者和消费者

go get github.com/nsqio/go-nsq

发送端

package main

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

var producer *nsq.Producer

func main() {
    nsqd := "127.0.0.1:4150"
    producer, err := nsq.NewProducer(nsqd, nsq.NewConfig())
    producer.Publish("test", []byte("nihao"))  //topic, message
    if err != nil {
        panic(err)
    }
}

消费端

package main

import (
 "fmt"
 "sync"
 "github.com/nsqio/go-nsq"
)
type NSQHandler struct {
}

func (this *NSQHandler) HandleMessage(msg *nsq.Message) error {
    fmt.Println("receive", msg.NSQDAddress, "message:", string(msg.Body))
    return nil
}

func testNSQ() {
    waiter := sync.WaitGroup{}
    waiter.Add(1)

    go func() {
        defer waiter.Done()
        config:=nsq.NewConfig()
        config.MaxInFlight=9

    //建立多个连接
    for i := 0; i<5; i++ {
        consumer, err := nsq.NewConsumer("test", "zj", config)  //topic, channel, config
        if nil != err {
            fmt.Println("err", err)
            return
        }

        consumer.AddHandler(&NSQHandler{})
        err = consumer.ConnectToNSQD("127.0.0.1:4150")
        if nil != err {
            fmt.Println("err", err)
            return
        }
    }
        select{}

    }()

    waiter.Wait()
}
func main() {
        testNSQ();

}

NSQ消息发送机制_第2张图片

nsq性能介绍

Kafka自身服务与消息的生产和消费都依赖与Zookeeper,使用Scala语言开发。因为其消息的消费使用客户端Pull方式,消息可以被多个客户端消费,理论上消息会重复,但是不会丢失(除非消息过期)。因此比较常用的场景是作为日志传输的消息平台。

nsq默认是不保存消息,消息传递时候通常是无序的,可以保留信息去check时间戳,nsq更适合处理数据量大但是彼此间没有顺序关系的消息。

NSQ消息发送机制_第3张图片

参考文献

1.http://kuangjue.com/article/250
2.https://segmentfault.com/a/1190000009194607
3.https://blog.csdn.net/qq_26981997/article/details/56673522
4.https://nsq.io/overview/faq.html

附属学习资料(go)

Go 内置关键字 (25个均为小写)

break,default,func,interface,select,case,defer,go,map,struct,chan,else,goto,package,switch,const,fall,through,if,range,type,continue,for,import,return,var

Go 的注释方法

// : 单行注释
/**/ : 多行注释

Go 程序的一般结构

通过package来组织结构
只有package名称为main的包可以包含main函数
一个可执行程序有且只有一个main函数
通过import关键字来导入其他非main包
通过const关键字来进行常量的定义
通过在函数体外部使用var关键字来进行全局变量的声明与赋值
通过type关键字来进行结构(struct)或(interface)的声明
通过func关键字来进行函数的声明

导入package的方式和注意事项

逐个导入:

import "fmt"
import "os"
import "time"

统一导入

import (
"fmt"
"os"
"time"
)

导入包之后,就可以使用格式. 来对包中的函数进行调用
注意: 如果导入了包未被调用,则其中的函数或类型将会报出编译错误

可见性规则

在Go语言中通过大小写来决定该变量、常量、类型、接口、结构或函数是否可被外部所调用
根据约定,函数名首字母小写即为private, 大写即为public

package 别名的使用

当导入第三方包时,包名很可能非常接近或相同,需要使用别名来进行区别和调用如:

import std "fmt"
func main() {
    std.Println("HelloWorld!");
}

省略调用如:

import . "fmt"
func main() {
    Println("HelloWorld!");
}

省略调用的注意事项:不可与别名同时使用且不建议在实际项目中采用

注:以上附属简单学习资料来源于博客:https://blog.csdn.net/Tyro_java/article/details/76167601

你可能感兴趣的:(NSQ消息发送机制)