(原)NSQ源码阅读和分析(1)

 原文出处:https://www.cnblogs.com/lihaiping/p/12324371.html

本文记录自己在阅读和学习nsq源码的时候的一些学习笔记,主要目的是个人总结和方便后期查阅。

author:lihaiping1603@aliyun.com

date:2020/01/13

NSQ去中心化方案

 

NSQ内部的消息流转

首先明白:一个topic下有多个channel每个channel可以被多个客户端订阅。

消息处理的大概流程:当一个消息被nsq接收后,传给相应的topic,topic把消息传递给所有的channel ,channel根据算法选择一个订阅客户端,把消息发送给客户端进行处理。

从我看的nsq版本v0.2.15版本,channel根据算法选择这个过程,我看到的处理策略是这样的:

client会发送RDY消息来表示它已经准备好接受多少个消息了,那么发送给client传输中未被确认的消息数量>ready的数量时,说明这个client暂时不具备继续接收消息的能力,这时候,client自行退出新一轮消息流转中的接收。即只有具备接收能力的client才接收channel中的消息,如果多个client具备接收能力,这时候,就竞争,谁从channel拿到就是谁的。

而对于每个client网络链接,NSQ都会对此client网络链接新建一个IOLoop()的goroutine来处理一切和client的消息。当client发送SUB订阅命令之后,client会根据它订阅的topic和channel,再启动一个goroutine来推送channel中的msg到client,这个函数就是messagePump()函数。而在client的messagePump中,主要的任务就是发送心跳和和接收来自channel中clientMsgChan消息,然后将消息打包发送给client。

NSQ对于发送出去的消息,是如何保证可靠性的(网络传输的不确定性,比如超时;客户端处理消息时崩溃等,消息如何重传)

当然消息发送给client可能会失败,所以NSQ在这里做一个很好的容错失败的策略,当我们将消息推送给client的时候,既然消息可能会失败,所以我们就需要将消息存起来,于是client会将这个消息在它所在的channel中,启动一个超时策略,如果超时的话,消息会被再次以跟从topic流转到chanel这种同样的流程进入到channel的消息流转流程。

而client在发送网络消息之前,会通过调用client.Channel.StartInFlightTimeout(msg, client)函数,来将消息msg和client一起生成一个另外的消息对象inFlightMessage,然后再将这个消息对象增加超时时间,进一步封装成pqueue.Item,然后分别存储到 channel的inFlightMessages和inFlightPQ中,其中inFlightMessages是一个map,他以msg的id为key进行存储,方便等会当客户端收到消息应答以后,进行删除操作。同时在inFlightPQ中,这个主要是做超时用的,因为channel中会启动一个goroutine函数inFlightWorker来专门处理inFlightPQ中超时消息。

在inFlightWorker()中,主要根据超时时间来不断的从pq队列中取消息,如果超时时间到了,消息还没有从inFlightPQ队列中删除掉,说明这个消息可能丢失或者出现什么问题了,我们就需要重新流转这个消息。

所以为了保证网络中发送出去消息的可靠性,NSQ也是用了ACK+超时机制这种ARQ来进行的。

 

NSQ如何标识消息被客户端成功处理完毕

client成功接收消息以后,发送FIN消息。

 

消息的持久化,NSQ服务重新启动时,消息不丢失

 

posted @ 2020-02-17 23:33  lihaiping  阅读(539)  评论(0编辑  收藏  举报