nsq总结

  1. 基本组件

    (1) nsqd

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

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

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

    1. 对订阅了同一个topic,同一个channel的消费者使用负载均衡策略(不是轮询)

    2. 只要channel存在,即使没有该channel的消费者,也会将生产者的message缓存到队列中(注意消息的过期处理)

    3. 保证队列中的message至少会被消费一次,即使nsqd退出,也会将队列中的消息暂存磁盘上(结束进程等意外情况除外)

    4. 限定内存占用,能够配置nsqd中每个channel队列在内存中缓存的message数量,一旦超出,message将被缓存到磁盘中

    5. topic,channel一旦建立,将会一直存在,要及时在管理台或者用代码清除无效的topic和channel,避免资源的浪费

    6. 一个nsqd启动之后,会注册到nsqlookupd

    7. 每个nsqd管理自己的Topic/channel;不同nsqd,相同的topic下的channel不一定相同;

    8. Nsqd_to_nsqlookupd 信息更新

      1. nsqd 启动时会开启一个lookupLoop循环;
      2. topic/channel 创建删除的操作会加入到nsqd的notifyChan;
      3. lookupLoop循环中,nsqd从notifyChan取消息,向指定或新增的nsqlookupd 更新⾃己的Topic/channel信息;
      4. 如果nsqd进程挂了,nsqdlookupd在 5分钟 后断开连接;

    (2) nsqlookupd

    nsqlookupd是守护进程负责管理拓扑信息。客户端通过查询 nsqlookupd 来发现指定话题(topic)的所属nsqd集群,并且 nsqd 节点广播话题(topic)和通道(channel)信息

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

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

    1. 唯一性

      在一个Nsq服务中只有一个nsqlookupd服务,也可以在集群中部署多个nsqlookupd,但它们之间是没有关联的

    2. 去中心化

      即使nsqlookupd崩溃,也会不影响正在运行的nsqd服务

    3. 充当nsqd和naqadmin信息交互的中间件

    4. 提供一个http查询服务,给客户端定时更新nsqd的地址目录

    (3) nsqadmin

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

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

    1. 提供一个对topic和channel统一管理的操作界面以及各种实时监控数据的展示,界面设计的很简洁,操作也很简单

    2. 展示所有message的数量

    3. 能够在后台创建topic和channel,这个应该不常用到

    nsqadmin的所有功能都必须依赖于nsqlookupd,nsqadmin只是向nsqlookupd传递用户操作并展示来自nsqlookupd的数据

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

    nsqd/nsqlookupd/nsqadmin/consumer/producer的关系如图所示

    [外链图片转存失败(img-QELYLVf3-1563328390566)(…/resources/17tow1895918.png)]

  2. 生产消费过程

    (1) 生产者连接nsqd,通过http接口,写入消息到topic

    (2) topic把消息分发到所有的channel

    (3) 消费者通过nsqdlookupd发现topic对应的nsqd,连接到nsqd上,订阅指定的channel,当有消息到达时进行消费

    (4) 同一个channel下多个消费者协作消费,channel会自动做负载均衡把消息发给不同的消费者

    在 news_data_consumer 这个项目中,我们的配置中指定了一个topic和一个channel,而项目本身是单线程、多机器(多进程)运行的,所以不同机器构成了不同的consumer,然后同一个channel会自动做负载均衡交给多台机器消费

  3. 公司nsq双机房部署方案

    同一个topic会在LF和HL两个集群上部署,每个集群的生产者发现自己集群上的nsqd,并往里面写入消息。当一个集群的nsqd发生故障时,nsq组会手动把consul的地址切到另外一个集群上,后期会支持自动切换。

    [外链图片转存失败(img-L8GLX70s-1563328390567)(…/resources/jglkqjlktjlqkj.png)]

    [外链图片转存失败(img-ShaiwjBx-1563328390567)(…/resources/Lark20190716-164105.png)]

    生产者其实是先通过consul写到nsqd-proxy上,然后proxy决定往具体那个nsqd实例上写;

    每个nsqd实例会向两个集群中的nsqlookupd注册;

    消费者通过nsqlookupd,可发现两个集群上的所有nsqd,进行消费

  4. 消费者

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

    1. 消费者直连nsqd,这是最简单的方式,缺点是nsqd服务无法实现动态伸缩了(当然,自己去实现一个也是可以的)

    2. 消费者通过http查询nsqlookupd获取该nsqlookupd上所有nsqd的连接地址,然后再分别和这些nsqd建立连接(官方推荐的做法),但是客户端会不停的向nsqlookupd查询最新的nsqd地址目录

    consumer如果通过 nsqlookupd 节点自动发现,会默认自动订阅所有包含该topic的nsqd节点;会消费所有nsqd节点的消息,消息的顺序不保证有序;如果指定连接某一个nsqd,那么只会订阅这一个nsqd,只会消费该nsqd下的消息。官方推荐的是通过 nsqlookupd 发现

  5. 生产者

    生产者必须直连nsqd去投递message

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

  6. 生产者创建时要(1)指定ip+端口号(默认为4150),(2)publish消息的时候要指定topic

     // 新建 producer
     producer, err := nsq.NewProducer("127.0.0.1:4150", nsq.NewConfig())
    
     ...
    
     // 发布消息
     err := producer.Publish("my_topic", []byte(fmt.Sprintf("Hello World ")))
    
     ...
    

    消费者创建时要(1)指定topic和channel,并且(2)要指定消息处理的handler,然后(3)和nsqlookupd连接

    注:channel名字如果以gajgl(我忘了是啥)结尾的话,那么这个channel是临时的,否则就是永久的

     // 新建 consumer
     consumer, err := nsq.NewConsumer("my_topic", "channel-a", nsq.NewConfig())
    
     ...
    
     // 添加消息处理的具体实现
     consumer.AddHandler(nsq.HandlerFunc(func(msg *nsq.Message) error {
         fmt.Println("Consumer1:", string(msg.Body))
         return nil
     }))
    
     ...
    
     // 连接 nsqlookupd
     err := consumer.ConnectToNSQLookupd("127.0.0.1:4161")
    
     ...
    
  7. nsq集群运维

    (1)新集群nsqd允许的最大message是20M

    (2)nginx和nsqlookupd部署在同一个机器上,一般一个集群4个nginx和nsqlookupd的实例

  8. 生产者和nsqd实例连接靠HTTP,消费者和nsqlookupd连接(最终和nsqd连接)靠的是TCP长连接

  9. (1)GO可以使用tmq接入生产者,其他语言可以直接通过http post进行消息的写入

    (2)GO可通过tmq生成消费者代码,更改相应配置,重写handler方法,进行消费,其它代码可查找对应客户端

    重写handler.go中MessageHandler函数进行消费,函数返回非nil时,nsq会把消息重新放到channel里

  10. (1) 水平扩展

    多播消息路由和负载均衡的结合。

    多播是一个topic对应多个channel;
    负载均衡是每个channel对应多个consumer

    nsqlookupd运行时发现producer和consumer

    简单的TCP协议

    主内存并且可以透明地使用磁盘

    (2) nsq Guarantees

    1. 消息至少被传递一次,有可能被消费多次,这就要求consumer多次消费消息没有副作用

    2. 消息是无序的,首先在不同nsqd之间不共享信息,对于一个nsqd有可能因为一些原因导致消息重新排序,同时磁盘和内存的结合使用导致没有一定的先后顺序(代码中两个是通过select中间两个channel来实现,没有严格的先后顺序)

    3. nsqlookupd 能保证最终一致性,也就是说最终能够发现自己所需要所有的topic,nsqd和nsqdlookupd之间不会有一个强一致性的协议保证消息同步

    4. 消息可以放入内存中也可以放入到磁盘中,如果因为nsqd异常崩溃,导致一些数据丢失是无法恢复,可以通过将内存–mem-queue-size设置为0(以#ephemeral结尾的消息超过设置的内存之后就回直接被抛弃,不会写入到磁盘上去,可以做一些简单的测试或者对应的应用),这样可以将所有消息落盘,也可以通过启动多个nsqd实例,producer将消息的copy发送给两个nsqd作为备份,这样就需要下游consumer要能够接受消息具有幂等性(多次接受相同消息不会产生负面影响)

    (3) 组件介绍

    1. nsqd 将接收producer产生的消息,放入自己的队列(内存或者磁盘中),然后等待consumer连接自己,消费消息

    2. nsqlookupd 管理nsqd的拓扑结构信息,并且提供最终一致性的保证

    3. nsqadmin一个界面,起到实时查看集群状态的作用

      在每个nsqd中每个topic有多个channel,每个channel有自己的消息副本(减少因为某些channel消费太慢而影响其它channel)

      nsqlookup提供一个发现服务,consumer能够通过nsqdlookupd查询到自己订阅topic的nsqd实例的地址,通过nsqdlookup在producer和consumer做了个解耦,减少系统的复杂性和维护成本,对于nsqd来说,它和nsqlookupd之间有一个长连接的tcp协议定时push 自己的状态,这样无论是重新开启一个nsqd还是重新开启一个consumer都只需要配置一个nsqdlookup的地址就可以了

  11. Consumer

    1. Consumer订阅channel之后,NSQD通过Tcp的Handle函数启动两个循环:

      a. ⼀个监听consumer指令,处理consumer命令(SUB,NOP…);

      b. 另一个向consumer发送数据(message, heartbeat…):每30s,nsqd向consumer发送⼼跳,consumer收到heart会返回NOP,超过1分钟未收到consumer回复,则关闭这个连接;

    2. consumer连接NSQD之后会开启两个子进程readLoop/writeLoop,负责consumer的读写操作

    3. consumer与channel连接之后会一直消费消息,直到断开连接

    4. 与channel相连的所有consumer都会试图从channel的memoryMsgChan⾥面拿消息,一个消息只会被一个consumer拿到

    5. 如果消息超时未收到回复,需要重新排队的消息会从in-flight删除加入到deferred队列列,等待⼀段时间再加入到memoryMsgChan

  12. Kafka vs NSQ

    1. Kafka 因为replication机制需要维护controller;有额外消耗;
    2. Kafka 能保证消息的局部有序(partition);nsq消息⽆序;
    3. Kafka 按照一定策略略将消息发到不同的broker;nsq产⽣多个worker随机发到不同nsqd;
      4.Kafka 一个集群⼀一个ZooKeeper, nsq可以有多个nsqlookupd(现在的配置是一个集群4个nsqlookupd)
  13. NSQ 优缺点

    1. 优点

      (1). 部署⾮常简单,管理⽅便

      (2). 扩展⽅便

      (3). 去中心化,轻量级

      (4). 避免单点故障(nsqd之间独立)

      (5). 确保消息送达(At least Once)

      (6). 生产者消费者自动发现

      (7). 使用了简单的TCP协议且具有多种语言的客户端功能库

      (8). ⽅便⼆次开发

    2. 缺点

      (1). Nsqd挂了会丢内存数据(定时写磁盘/抛异常/双机备份)

      (2). 无法满足消息强时序要求

  14. 消费者是如何从nsq中读取消息的?

    (1). 消费者⾸首先需要发送SUB命令,告诉nsqd它想订阅哪个Channel,然后nsqd将该Client与Channel建⽴对应关系,channel将client加⼊到⾃己的client列表

    (2). 消费者发送RDY命令,告诉服务端它准备好接受count个消息,服务端则向消费者发送count个消息,如果消费者想继续接受消息就需要不断发送RDY命令告诉服务端⾃己准备好接受消息

    (3) 客户端回复消息处理结果FIN (finish) or REQ (re-queue),如果超时未收到客户端回复,消息会被重新加入到队尾;Nsqd挂了了,则内存中的数据会丢失

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值