复习要点
- 为什么使用消息队列?
- 使用消息队列有什么缺点?
消息队列如何选型?- 如何保证消息队列是高可用的?
- 如何保证消息不被重复消费?
- 如何保证消费的可靠性传输?
- 如何保证消息的顺序性?
市场上存在的消息队列:kafaka、RabbitMQ,NSQ,RocketMq,ActiveMq等等。
各大厂也基于上述的MQ,升级改造成适合自己的MQ。例如:滴滴开源基于 RocketMQ 的分布式消息队列 DDMQ,有赞NSQ。
为了更好的学习golnag,从NSQ的源码开始研究。
NSQ
目的:NSQ 是实时的分布式消息处理平台,其设计的目的是用来大规模地处理每天数以十亿计级别的消息。
在开始学习前给自己提了几个问题:
1.NSQ消息虽然推送过去了,但是消费者处理失败了,【消息是丢失了,还是重新放进队列??】。2.NSQ消息虽然推送过去了,但是消费者现在很忙,没空处理消息 【消息可以待会再推送吗??】
3.消费着,是被pull,还是nsqd主动push消息?
4.nsq的集群部署,架构图是什么样,应该怎么部署?
5.消费者和nsqlookup 通过 sub命令 建立订阅连接 是 tcp还是http,连接建立后是长链接吗,有topic消息了,是主动推送吗?
6.nsq的消息策略,是 准确一次,至少一次,还是其他呢
初识:
- nsqd — nsq的核心,负责接收topic和处理转发topic
- nsqadmin — web操作界面,用来查看、管理消息
- nsqlookup — 服务注册和发现。
- topic,channel
nsqlookup
(1)消费者需要先连接nsqlookupd服务获取nsqd的地址,然后再连接nsqd;
(2)而consumer通过nsqlookupd获取到所有nsqd地址后,再向所有nsqd发起连接;
(3)当向某个topic发布一个消息时,producer会同时连上所有的nsqd,然后随机选择一个nsqd发送消息;
(4)nsqd通过心跳机制与nsqlookupd上报状态以及topic和channel信息;
详细如下:
nsqlookup提供了一个/lookup接口,比如你想知道哪些nsqd上面,有topic为test的消息,那么只需要调一下:
curl 'http://127.0.0.1:4161/lookup?topic=test'
nsqlookup就会给你返回对应topic的nsqd列表:
{
"channels": [
"xxx"
],
"producers": [
{
"remote_address": "127.0.0.1:52796",
"hostname": "hongzeyangdeMacBook-Pro",
"broadcast_address": "127.0.0.1",
"tcp_port": 4150,
"http_port": 4151,
"version": "1.0.0-compat"
}
]
}
首先,调用lookup接口,获取拥有对应topic的nsqd列表。
接着消费者只需要遍历返回的json串里的producers列表,把broadcast_address和tcp_port或者http_port拼起来,就可以拿到要建立连接的url地址。
消费者会和这些nsqd,逐个建立连接。nsqd收到对应topic的消息后,就会给和他们建立连接的消费者,推送消息。
nsqd
在nsqd的Main函数中开启了监听处理tcp和http两个服务的goroutine,与nsqlookupd不同的是,nsqd在Main函数中除了上述两个goroutine,还开启了其余三个goroutine
- lookupLoop 保持与nsqlookupd心跳连接,上报信息;
- queueScanLoop 扫描和处理InFlightQueue和DeferredQueue;
- statsdLoop 需要配置状态服务地址之后才开启;
工作流程:当producer向nsqd某个topic发送一条消息时,该消息会被复制发送到该topic下的所有channel。当某个channel对应着多个client时,这时channel随机选择一个client,并由该client处理该消息。
NSQ两次使用负载均衡,例如producer发送消息时,随机选择一个nsqd服务接收消息以及channel在多个client中随机选择一个处理消息。
推荐链接:
https://swanspouse.github.io/2018/11/26/nsq-main-concepts/ (NSQ简要介绍)
https://www.liwenzhou.com/posts/Go/go_nsq/ (nsqadmin 使用)
NSQ -- PHP代码实现