Nsq服务端简介

在使用Nsq服务之前,还是有必要了解一下Nsq的几个核心组件
整个Nsq服务包含三个主要部分

nsqlookupd

先看看官方的原话是怎么说:
nsqlookupd是守护进程负责管理拓扑信息。客户端通过查询 nsqlookupd 来发现指定话题(topic)的生产者,并且 nsqd 节点广播话题(topic)和通道(channel)信息

简单的说nsqlookupd就是中心管理服务,它使用tcp(默认端口4160)管理nsqd服务,使用http(默认端口4161)管理nsqadmin服务。同时为客户端提供查询功能

总的来说,nsqlookupd具有以下功能或特性

  • 唯一性,在一个Nsq服务中只有一个nsqlookupd服务。当然也可以在集群中部署多个nsqlookupd,但它们之间是没有关联的
  • 去中心化,即使nsqlookupd崩溃,也会不影响正在运行的nsqd服务
  • 充当nsqd和naqadmin信息交互的中间件
  • 提供一个http查询服务,给客户端定时更新nsqd的地址目录

nsqadmin

官方原话:是一套 WEB UI,用来汇集集群的实时统计,并执行不同的管理任务

总的来说,nsqadmin具有以下功能或特性

  • 提供一个对topic和channel统一管理的操作界面以及各种实时监控数据的展示,界面设计的很简洁,操作也很简单
  • 展示所有message的数量,恩....装X利器
  • 能够在后台创建topic和channel,这个应该不常用到
  • nsqadmin的所有功能都必须依赖于nsqlookupd,nsqadmin只是向nsqlookupd传递用户操作并展示来自nsqlookupd的数据

nsqadmin默认的访问地址是http://127.0.0.1:4171/

nsqd

官方原话:nsqd 是一个守护进程,负责接收,排队,投递消息给客户端

简单的说,真正干活的就是这个服务,它主要负责message的收发,队列的维护。nsqd会默认监听一个tcp端口(4150)和一个http端口(4151)以及一个可选的https端口

总的来说,nsqd 具有以下功能或特性

  • 对订阅了同一个topic,同一个channel的消费者使用负载均衡策略(不是轮询)
  • 只要channel存在,即使没有该channel的消费者,也会将生产者的message缓存到队列中(注意消息的过期处理)
  • 保证队列中的message至少会被消费一次,即使nsqd退出,也会将队列中的消息暂存磁盘上(结束进程等意外情况除外)
  • 限定内存占用,能够配置nsqd中每个channel队列在内存中缓存的message数量,一旦超出,message将被缓存到磁盘中
  • topic,channel一旦建立,将会一直存在,要及时在管理台或者用代码清除无效的topic和channel,避免资源的浪费

这是官方的图,第一个channel(meteics)因为有多个消费者,所以触发了负载均衡机制。后面两个channel由于没有消费者,所有的message均会被缓存在相应的队列里,直到消费者出现


这里想到一个问题是,如果一个channel只有生产者不停的在投递message,会不会导致服务器资源被耗尽?也许nsqd内部做了相应处理,但还是要避免这种情况的出现

Nsq服务端与客户端的关系

了解nsqlookupd,nsqd与客户端中消费者和生产者的关系

消费者

消费者有两种方式与nsqd建立连接

  • 消费者直连nsqd,这是最简单的方式,缺点是nsqd服务无法实现动态伸缩了(当然,自己去实现一个也是可以的)
  • 消费者通过http查询nsqlookupd获取该nsqlookupd上所有nsqd的连接地址,然后再分别和这些nsqd建立连接(官方推荐的做法),但是客户端会不停的向nsqlookupd查询最新的nsqd地址目录(不喜欢用http轮询这种方式...)
    还是看图更直接些 ,官方的消费者模型:

生产者

生产者必须直连nsqd去投递message(网上说,可以连接到nsqlookupd,让nsqlookupd自动选择一个nsqd去完成投递,但是我用Producer的tcp是连不上nsqlookupd的,不知道http可不可以...),

这里有一个问题就是如果生产者所连接的nsqd炸了,那么message就会投递失败,所以在客户端必须自己实现相应的备用方案

安装Nsq

方法一

  • 首先搭建golang开发环境,这里就不详细讲了

    • 注意一下,搭建golang环境时最好将bin目录添加到系统环境(path)里,省去了每次都要去bin目录里执行的麻烦
  • 安装包管理器godep
go get github.com/tools/godep

执行完后检查godep是否已经安装在bin目录下,一般都会自动安装,如果没有,用go install手动安装下

  • 安装依赖包assert
go get github.com/bmizerany/assert
  • 安装Nsq
godep get github.com/bitly/nsq/...

如果安装成功,bin目录里就会出现一大堆nsq_...开头的可执行文件

  • PS:如果安装失败

    • 像我一样出现了一大堆"use of internal package not allowed"错误,找了半天,才在一个角落里发现了这句话
      注意:NSQ 保持了 go get 兼容,但是不推荐,因为之后不能保证仍然能稳定编译。

    这时采用方法二安装

方法二

运行Nsq服务集群

  • 首先启动nsqlookud
nsqlookupd
  • 启动nsqd,并接入刚刚启动的nsqlookud。这里为了方便接下来的测试,启动了两个nsqd
nsqd --lookupd-tcp-address=127.0.0.1:4160
nsqd --lookupd-tcp-address=127.0.0.1:4160 -tcp-address=0.0.0.0:4152 -http-address=0.0.0.0:4153

这里有个小问题,在windows上直接执行就能启动多个nsqd,但是在linux下(我自己用的是ubuntu),需要切换路径执行,不然会出现如下错误

[nsqd] 2019/02/12 18:46:31.761875 FATAL: --data-path=/home/miracle in use (possibly by another instance of nsqd)
  • 启动nqsadmin
nsqadmin --lookupd-http-address=127.0.0.1:4161

基于go-nsq的客户端实现

几个值得注意的地方

  • Producer断线后不会重连,需要自己手动重连,Consumer断线后会自动重连
  • Consumer的重连时间配置项有两个功能(这个设计必须吐槽一下,分开配置更好一点)

    • Consumer检测到与nsqd的连接断开后,每隔x秒向nsqd请求重连
    • Consumer每隔x秒,向nsqlookud进行http轮询,用来更新自己的nsqd地址目录
    • Consumer的重连时间默认是60s(...菜都凉了),我改成了1s
  • Consumer可以同时接收不同nsqd node的同名topic数据,为了避免混淆,就必须在客户端进行处理
  • 在AddConurrentHandlers和 AddHandler中设置的接口回调是在另外的goroutine中执行的
  • Producer不能发布(Publish)空message,否则会导致panic

go_nsq-send.go

//Nsq发送测试
package main import (
"bufio"
"fmt"
"github.com/nsqio/go-nsq"
"os"
) var producer *nsq.Producer // 主函数
func main() {
strIP1 := "127.0.0.1:4150"
strIP2 := "127.0.0.1:4152"
InitProducer(strIP1) running := true //读取控制台输入
reader := bufio.NewReader(os.Stdin)
for running {
data, _, _ := reader.ReadLine()
command := string(data)
if command == "stop" {
running = false
} for err := Publish("test", command); err != nil; err = Publish("test", command) {
//切换IP重连
strIP1, strIP2 = strIP2, strIP1
InitProducer(strIP1)
}
}
//关闭
producer.Stop()
} // 初始化生产者
func InitProducer(str string) {
var err error
fmt.Println("address: ", str)
producer, err = nsq.NewProducer(str, nsq.NewConfig())
if err != nil {
panic(err)
}
} //发布消息
func Publish(topic string, message string) error {
var err error
if producer != nil {
if message == "" { //不能发布空串,否则会导致error
return nil
}
err = producer.Publish(topic, []byte(message)) // 发布消息
return err
}
return fmt.Errorf("producer is nil", err)
}

go_nsq-receive.go

 
//Nsq接收测试
package main import (
"fmt"
"time" "github.com/nsqio/go-nsq"
) // 消费者
type ConsumerT struct{} // 主函数
func main() {
InitConsumer("test", "test-channel", "127.0.0.1:4161")
for {
time.Sleep(time.Second * 10)
}
} //处理消息
func (*ConsumerT) HandleMessage(msg *nsq.Message) error {
fmt.Println("receive", msg.NSQDAddress, "message:", string(msg.Body))
return nil
} //初始化消费者
func InitConsumer(topic string, channel string, address string) {
cfg := nsq.NewConfig()
cfg.LookupdPollInterval = time.Second          //设置重连时间
c, err := nsq.NewConsumer(topic, channel, cfg) // 新建一个消费者
if err != nil {
panic(err)
}
c.SetLogger(nil, 0)        //屏蔽系统日志
c.AddHandler(&ConsumerT{}) // 添加消费者接口 //建立NSQLookupd连接
if err := c.ConnectToNSQLookupd(address); err != nil {
panic(err)
} //建立多个nsqd连接
// if err := c.ConnectToNSQDs([]string{"127.0.0.1:4150", "127.0.0.1:4152"}); err != nil {
//  panic(err)
// } // 建立一个nsqd连接
// if err := c.ConnectToNSQD("127.0.0.1:4150"); err != nil {
//  panic(err)
// }
}

Go:Nsq消息队列的更多相关文章

  1. 剖析nsq消息队列(一) 简介及去中心化实现原理

    分布式消息队列nsq,简单易用,去中心化的设计使nsq更健壮,nsq充分利用了go语言的goroutine和channel来实现的消息处理,代码量也不大,读不了多久就没了.后期的文章我会把nsq的源码 ...

  2. 剖析nsq消息队列(二) 去中心化代码源码解析

    在上一篇帖子剖析nsq消息队列(一) 简介及去中心化实现原理中,我介绍了nsq的两种使用方式,一种是直接连接,还有一种是通过nslookup来实现去中心化的方式使用,并大概说了一下实现原理,没有什么难 ...

  3. 剖析nsq消息队列(四) 消息的负载处理

    剖析nsq消息队列-目录 实际应用中,一部分服务集群可能会同时订阅同一个topic,并且处于同一个channel下.当nsqd有消息需要发送给订阅客户端去处理时,发给哪个客户端是需要考虑的,也就是我要 ...

  4. 剖析nsq消息队列目录

    剖析nsq消息队列(一) 简介及去中心化实现原理 剖析nsq消息队列(二) 去中心化源码解析 剖析nsq消息队列(三) 消息传输的可靠性和持久化[一] 剖析nsq消息队列(三) 消息传输的可靠性和持久 ...

  5. NSQ消息队列

    前面的总结中提到过这个玩意,所以简单说说,win上面的测试验证 网上有比较合适的博文,我先推荐几篇 https://blog.csdn.net/a2247889821/article/details/ ...

  6. 消息队列 NSQ 源码学习笔记 (一)

    nsqlookupd 用于Topic, Channel, Node 三类信息的一致性分发 概要 nsqlookup 知识点总结 功能定位 为node 节点和客户端节点提供一致的topic, chann ...

  7. 消息队列性能对比——ActiveMQ、RabbitMQ与ZeroMQ(译文)

    Dissecting Message Queues 概述: 我花了一些时间解剖各种库执行分布式消息.在这个分析中,我看了几个不同的方面,包括API特性,易于部署和维护,以及性能质量..消息队列已经被分 ...

  8. 消息队列Queue大全

    消息队列Queue大全 (http://queues.io/) 作业队列,消息队列和其他队列.几乎所有你能想到的都在这. 关于 那里有很多排队系统.他们每个人都不同,是为解决某些问题而创建的.这个页面 ...

  9. 消息队列&Celery&RabbitMQ&zeromq

    一.消息队列 什么是消息队列? “消息队列”是在消息的传输过程中保存消息的容器. “消息”是在两台计算机间传送的数据单位.消息可以非常简单,例如只包含文本字符串:也可以更复杂,可能包含嵌入对象. 消息 ...

随机推荐

  1. BZOJ 3296 [USACO2011 Open] Learning Languages:并查集

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3296 题意: 农夫约翰的N(2 <= N <= 10,000)头奶牛,编号为1 ...

  2. html怎样可是使文本框内容不可修改

    html怎样可是使文本框内容不可修改 <input type="text" readonly="readonly" onfocus="alert ...

  3. ssm+dubbo/zk

    1.原始 Connection conn = null; String url = "jdbc:mysql://localhost:3306/emps?user=root&passw ...

  4. Python基础-redis模块使用

    redis是一个数据库,他的数据全都是存放在内存里面的,redis每秒能支持30w次的读写,存放有两种格式,一种string类型,一种是hash类型 一,操作string类型 r=redis.Redi ...

  5. Android多点触控技术

    1 简介 Android多点触控在本质上需要LCD驱动和程序本身设计上支持,目前市面上HTC.Motorola和Samsung等知名厂商只要使用电容屏触控原理的手机均可以支持多点触控Multitouc ...

  6. xxx was built without full bitcode" 编译错误解决

    xxx was built without full bitcode" 编译错误解决 iOS 打包上线 All object files and libraries for bitcode ...

  7. ACM学习历程—Hihocoder 1289 403 Forbidden(字典树 || (离线 && 排序 && 染色))

    http://hihocoder.com/problemset/problem/1289 这题是这次微软笔试的第二题,过的人比第三题少一点,这题一眼看过去就是字符串匹配问题,应该可以使用字典树解决.不 ...

  8. Error Domain=NSURLErrorDomain Code=-1202,Https服务器证书无效

    错误:“此服务器的证书无效.您可能正在连接到一个伪装成“www.xxxxxx.com”的服务器, 这会威胁到您的机密信息的安全 原因:安全证书是自建证书,没有得到认证. 解决方法: 1.导入NSURL ...

  9. 电子商务网站SQL注入项目实战一例(转载)

    故事A段:发现整站SQL对外输出: 有个朋友的网站,由于是外包项目,深圳某公司开发的,某天我帮他检测了一下网站相关情况. 我查看了页面源代码,发现了个惊人的事情,竟然整站打印SQL到Html里,着实吓 ...

  10. DNS Doctoring

    NAT的应用可以让路由器在不同地址域内路由数据包.一个暴露在外的应用服务器,通常同时拥有了内网和外网的IP地址.这在DNS解析时可能带来麻烦. 根据DNS服务器的部署位置和配置,对同一内网中的应用服务 ...