nsq

一、nsq基础指南

1、nsq介绍

NSQ是分布式实时消息队列。NSQ是分布式的、拓扑结构,具有无单点故障、故障容错、高可用性和保证消息的可靠传递等特点,容易配置和部署。

官网:https://nsq.io/

 

2、nsq组件

组件/概念

端口

说明

nsqd

TCP端口: 4150

HTTP端口:4151

nsq的核心,负责消息的存储与分发。包括topic和channel的管理、producer和consumer的维护,简单的说,真正干活的就是这个服务.

nsqlookupd

TCP端口: 4160

HTTP端口:4161

主要功能是服务发现。每个nsqd启动时都会向配置中配置的lookupd发起register请求,lookupd维护着各各节点的topic+channel的meta信息。消费端可以通过这个组件发现nsq集群中指定topic的nsqd列表

nsqadmin HTTP端口:4171 网页界面,用于管理nsq,可以看到nsq的统计数据,包括队列积压数据,也可以新增/删除/暂停/清空topic和channel

 

3、nsq工具

nsq_stat  
nsq_tail Consumes the specified topic/channel and writes to stdout (in the spirit of tail(1))
nsq_to_file Consumes the specified topic/channel and writes out to a newline delimited file, optionally rolling and/or compressing the file.
nsq_to_http 用于将指定topic下指定channel的消息,使用发送http请求的方式分发到指定url,更多详见
nsq_to_nsq 用于将指定topic下指定channel的消息分发到指定nsqd的指定topic,更多详见
to_nsq Takes a stdin stream and splits on newlines (default) for re-publishing to destination nsqd via TCP

参考:https://nsq.io/components/utilities.html

 

4、nsq常用术语

参数

说明

topic

相当于消息队列名
channel

相当于消息队列子队列名,一个topic可以有多个channel,每个channel都会消费每一条发给topic的消息

  • 一个topic可以有多个channel
  • 一个channel只能对应一个topic
  • channel由消费者首次订阅产生,一个channel可以有多个消费者,起负载均衡的作用。
  • 一个topic的消息会复制到与topic关联的各个channel
  • channel的名称通常描述的是消费者的业务

message

当前分发(消费)中的消息数

图中,nsq上有一个叫”clicks“的topic,”clicks“下面有三条channel,其中channel名称为”metrics“的,有三个实例。消息A来到nsq后,被复制到三条channel,接着,在metrics上的那个A,被推送到了第二个实例上。接着,又来了一个叫B的消息,这一次,B被推送给了第一个实例进行处理。

 

主要有两个点
1. 多个Consumer消费同一个Topic和同一个Channel:将会轮训,按序分配给就绪(当前无处理任务)的消费者。因此,多消费者情况下,无法保证有序执行。(像上面动图的"metrics"所示)
2. 多个Consumer消费同一个Topic和不同的Channel:将会将同一个数据同时到不同的Channel中。(像上面动图的三个Channel所示)

注意:Consumer与Topic没有直接联系,而是通过具体的Channel接受数据。如果Consumer退出,Channel不会自动删除。 如果不再需要,需要通过http端口删除Channel,否则很可能会导致磁盘空间不足。

 

6、nsqadmin管理

 

 

 

 

参数

说明

Deferred

Current count of messages that were requeued and explicitly deferred which are not yet available for delivery.

重新入队或明确要延迟分发而未分发的消息数

Depth

Current sum of messages in memory + on disk (i.e. the “backlog” of messages pending delivery).

消息积压数,在一个topic下新建一个channel后,新推送给该topic的所有消息都会发送到该channel,如果没有消费或消费速度小于生产速度,会产生积压

In-Flight

Current count of messages delivered but not yet finished (FIN), requeued (REQ) or timed out.

当前分发(消费)中的消息数(发送给消费端,但是消费端还没有回应的数目)

Memory + Disk 内存+磁盘消息积压数,nsq消息会优先放入内存中,当消息数超过mem-queue-size值(nsqd配置,一般建议此值不要设太大,以防内存使用超标)后,消息会写入磁盘
Ready Count

Max number of messages that can be in-flight on this connection. This is controlled by a client’s max_in_flight setting.

当前连接最大并发消费数据,值为0时不会消费新的数据,最大值由消费配置的max_in_flight决定,一般对于nsq集群而言,消费使用nsqlookupd地址,max_in_flight数会被均匀地分到每个与nsqd建立的连接上,例如nsq集群有2个nsqd,与每个nsqd都建立一个连接,max_in_flight为20,则每个连接的最大Ready Count为10

Requeued Total times a message has been added back to the queue due to time outs or explicit requeues.
Timed Out

Total count of messages that were requeued after not receiving a response from the client before the configured timeout.

已重入队列但按配置的超时时间内还收到响应的消息数

Messages

Total count of new messages recieved since node startup.

Connections Current number of connected clients.

每条消息有3种结果:消费成功(FIN)、消费失败(REQ)、消费超时(TIMEOUT)。若nsqd进程意外退出,则内存中以及还没来得及刷入硬盘的消息都会丢失。
若消息在msg_timeout内没消费,则会自动重新入队列REQ;若消息在max_msg_timeout内还没消费,则会记为TIMEOUT

参考:https://nsq.io/components/nsqadmin.html

二、nsq的使用

1、nsq部署

1)单点部署

下面的示意图清晰的展示了整个NSQ架构的端口关系:

 

 

1. Consumer1首先使用HTTP连接nsqlookupd的4161端口,获取Topic1相关nsqd的TCP4150端口。

2. 使用TCP连接到nsqd的4150端口,并生成对应的Channel1;

特别需要注意的是,当所需Topic不变的情况下,就算nsqlookupd和nsqadmin进程都杀掉,也不影响nsqd的生产和消费。

 

2)集群

1. 当开启多个nsqd才存在集群的意义。

2. 尽量避免多个nsqd存在相同的Topic。如果多个nsqd真的存在相同的Topic的情况下,通过nsqlookupd将会返回所有这个Topic的IP并都能进行读取处理。

 

2、nsq的监控

监控工具:Prometheus

监控指标:

  • 队列积压

 

3、nsq在QTT的实践

sdk: https://git.qutoutiao.net/gopher/nsqsdk 

基于go-nsq封装的NSQ库,支持:

 

  • 自动化集成trace
  • 生产端自动负载均衡
  • 消息高可靠
  • 事务消息(事务消息暂不支持自动trace)
  • 简单方便的扩缩容

 

三、nsq原理解读

1、nsq架构

2、nsq源码结构

 

 

 

nsq流程图:

在这里插入图片描述

 

3、nsq中的消息流转

messagePump: 

messagePump selects over the in-memory and backend queue and writes messages to every channel for this topic

(监听 message 的更新的一些状态,以及时将消息持久化,同时写入到此 topic 对应的channel)


queueScanLoop:

负责处理延迟消息

 


生产者发布一个消息之后,通过以下途径保证消息可靠性:

  • client连接上nsqd,并通过RDY参数告知可以处理的message数量
  • nsqd 把消息暂存起来或者推送到各个连接的channels,对于状态为REQ 和 timeout的都会被暂存起来
  • 客户端消费消息之后,回复nsqd一个FIN表示消息成功处理,或者REQ表示表示这个消息将会继续重新加入到队列中, 如果处理时间超过配置的timeout时间,则nsqd会把这个消息当成超时处理
  • 如果客户端一直没有回复直到超时,则这个消息会被当成超时消息重新加入到队列中

 

4、消息传输的可靠性和持久化

nsq-message-inflight

在NSQ中,使用inflight机制来保证NSQ中消息”at least once”(至少被消费一次)。

在消息发送给Client之后,会将消息以及消息的timeout时间存储到优先级队列中pqueue

如果客户端收到该消息,可以使用如下三个命令对此进行回复:

  • FIN: Finish a message,表示成功处理完成。
  • REQ: Re-queue a message,表示消息处理失败,需要重新入队再次进行处理。
  • TOUCH: Reset the timeout for an in-flight message,表示需要重置消息的timeout时间。

如果客户端没有收到消息或是收到消息后没有进行任何的回复,则随着到达消息的超时时间,NSQD会将超时的消息重新入队,再次发送给客户端。

NSQD只能保证消息的”at least once”,至于消息的”exactly once”则需要业务端配合来实现。例如通过messageID来判断消息是否被消费过。

 

5、TCP 协议规范

参考:

https://nsq.io/clients/tcp_protocol_spec.html

以下为nsqd与nsqlookupd的通信:

 

四、nsq使用注意事项 && 思考

使用注意事项:

1、消息处理失败或超时(可配置超时时间)时会重新入队(由配置的消息最大重试次数决定),所以要保证代码的幂等性,且消费处理时间不宜太久,如果消费处理时间超过设置的超时时间且没有办法缩短,建议采用异步处理的方式,避免消息因处理超时而再次入队。(参考:https://nsq.io/overview/design.html#message-delivery-guarantees)

 

参考:

NSQ   QTT-nsqd主流程  MQ

https://toutiao.io/posts/dboi02/preview

https://www.cnblogs.com/li-peng/p/11949258.html

https://blog.wongxinjie.com/2018/09/07/NSQ%E7%AC%94%E8%AE%B0/

https://qtozeng.top/2019/05/15/nsq-%E6%B6%88%E6%81%AF%E5%8F%91%E9%80%81%E8%AE%A2%E9%98%85%E6%BA%90%E7%A0%81%E7%AE%80%E6%9E%90/

走进 NSQ 源码细节

 

posted @ 2023-03-30 14:12  一束光  阅读(36)  评论(0编辑  收藏  举报

友情链接

CFC4N