美文网首页
NSQ 设计

NSQ 设计

作者: FinaLone | 来源:发表于2020-12-13 15:36 被阅读0次

翻译自https://nsq.io/overview/design.html

NSQ是一个消息队列,其设计的目的如下(顺序无关):

  • 支持高可用和单点故障(SPOF)的拓扑
  • 满足健壮的消息传递保障需求
  • 限制内存
  • 对消息生产者和消费者都足够简单的配置
  • 简单的升级路径
  • 高效

简化配置和管理

只需要一个nsqd实例就可以同时处理多个数据流。数据流在NSQ中叫做topic,每一个topic有一个或多个channel。每一个channel接收来自一个topic的所有消息的拷贝。在实践中,一个channel对应于一个topic的下游消费者。

topic和channel不是同时被配置的:

  • 当上游生产者第一次发布消息到命名topic,或下游channel第一次订阅命名topic时,会创建一个对应的topic。
  • 当消费者订阅命名channel时,会创建一个对应的channel。

每个topic和channel之间都拥有相互独立的缓存队列,放置一个慢消费者造成整个系统的积压。

每个channel通常有多个消费者。假设所有的消费者都可以接收消息,每一条消息会被随机发送到一个消费者,如下:


topic,channel和consumer

在topic->channel之间,消息是广播的,但在channel和consumer之间,消息是分布式发送的。即每一个channel都从topic接收全量的消息,但每一个customer只从channel接收部分消息。

NSQ包含一个助手应用nsqlookupd,为消费者查找感兴趣的topic的的nsqd实例地址提供目录服务。这个服务让生产者和消费者解耦,相互独立,通过nsqlookupd来关联,降低了系统的复杂度。

在底层实现中,每一个nsqd实例和nsqlookupd之间维持了一条TCP长连接,周期性的发送它目前的状态。nsqlookupd使用该信息决策消费者应该使用哪个nsqd实例。

给一个topic添加一个新的消费者,只要启动一个配置了nsqlookupd地址的NSQ客户端即可。无需再针对生产者和消费者做任何配置,一切都由nsqlookupd来完成。

需要注意的是nsqd和nsqlookupd都是独立部署的,即多个nsqd之间没有关联,多个nsqlookupd之间也没有关联。

nsqadmin是用来监控和管理集群的工具,提供了web界面来浏览topcs/channels/consumers的拓扑和关键信息,并且可以执行删除或清空channel等任务。

nsqadmin

排除单点故障

NSQ被设计用于分布式环境。nsqd客户端通过TCP和所有提供相同topic的生产者连接。所以其中没有中间人,没有消息代理,也不存在单点故障。



对nsqlookupd来说,通过运行多个实例来达到高可用的目的。多个nsqlookupd之间不会通信,数据被认为是最终一致的。消费者查询它配置的所有nsqlookupd实例,并将返回值合并,得到最终结果。

消息传递保障

NSQ保证每条消息至少被传递成功一次,可能会重复传递多次。消费者应该对收到的消息做去重处理,或者保证收到消息后的处理是无副作用的。
消息保证的工作机制如下(设计客户端已经成功连接并订阅了一个topic):

  1. 客户端指示已经准备好接收消息
  2. NSQ发送消息,并临时存储在本地(在重传时使用)
  3. 客户端回复FIN或者REQ消息来指示消息接收成功或者失败。如果客户端没有回复消息,NSQ会在一定时间超时后,自动重传该消息。
    上述机制保证了导致消息丢失的唯一场景是nsqd实例的意外宕机,所有在内存中还未发送的消息,以及需要重传的消息都会丢失。
    如果防止消息丢失是重中之重的事情,针对上述场景也可以做一些事情。一种方式是配置冗余的nsqd组,来传递重复的消息。

限制内存使用

nsqd提供了一个配置选项--mem-queue-size,决定一个队列保存在内存中的消息数量。如果队列中消息数量超过阈值,消息会被写入到磁盘。这样,就先知了一个nsqd进程的内存使用量为mem-queue-size*#_of_channels_and_topics
通过将该选项设置的比较小(0或者1),也能得到更为可靠的消息传递服务。持久化到磁盘的消息在nsqd进程重启后依然有效。

高效

NSQ基于类memcached的通信机制实现,客户端只需要回复其容量信息。所有消息数据(包括尝试次数、时间戳等元数据)都保存在核心上。这样消除了重传时服务器和客户端之间消息的来回拷贝。同时也简化了客户端实现,不需要再维持消息状态。
在数据协议方面,为了最大化性能和吞吐量的一个关键设计是直接向客户端推送数据,而不是等待客户端来查询。这个概念被称为RDY状态,本质上是客户端侧的流控。
当一个客户端连接到nsqd,并订阅到一个channel时,它的RDY状态被置为0,表示目前还不能接收消息。当客户端准备好接收消息时,它会发送一条命令到nsqd,更新其RDY值到它可以接收的消息数量。nsqd就可以将100条消息推送给客户端,中间不需要其他的任何交互。

相关文章

网友评论

      本文标题:NSQ 设计

      本文链接:https://www.haomeiwen.com/subject/ozzugktx.html