消息长度_nsq消息队列源码分析

a0f83ef273414b7d1c906b96e2fd5e0b.png

nsq的源码比较简单,值得一读,特别是golang开发人员,下面重点介绍nsqd,nsqd是nsq的核心,其他的都是辅助工具,看完这篇文章希望你能对消息队列的原理和实现有一定的了解。

nsqd是一个守护进程,负责接收,排队,投递消息给客户端,并不保证消息的严格顺序,nsqd默认监听一个tcp端口 (4150) 和一个http端口 (4151) 以及一个可选的https端口

对订阅了同一个topic的同一个channel的消费者使用负载均衡策略,其实就是多个协程消费同一个channel

只要channel存在,即使没有该channel的消费者,也会将生产者的message缓存到队列(内存队列和磁盘队列)中,当有新的消费者产生后,就开始消费队列中的所有消息

保证队列中的 message 至少会被消费一次(在进程意外退出的时候这点都保证不了),并不能保证成功消费一次,即使 nsqd退出,也会将队列中的消息暂存磁盘上(进程退出的时候会将缓存中的消息存到磁盘上,意外情况如掉电就不行了,缓存中的消息就没有机会存盘而丢失,在实战中一般不会使用缓存队列即内存buffer为0,全部使用磁盘队列)

限定内存占用,能够配置nsqd中每个channel队列在内存中缓存的message数量,一旦channel的buffer写满,就将message写到磁盘中,这点使用golang select的优先级功能,default优先级最低

topic,channel 一旦建立,将会一直存在,要及时在管理台或者用代码清除无效的 topic 和 channel,避免资源的浪费,每个topic和channel都有独立的协程处理自身的消息,默认的buffer和其他的一些信息

nsq消息没有备份,一旦出现进程意外情况退出,可能会出现消息丢失,如没有消费成功的消息,写入文件但没有真正落盘的消息,这种意外情况很难杜绝,像意外退出这种情况kafka,redis等都会遇到这样的问题,最后都会采用一个折中的策略,定时将数据落盘

//原文:https://www.cnblogs.com/hlxs/p/11445103.html 作者:啊汉
type Topic struct {
    
   // 64bit atomic vars need to be first for proper alignment on 32bit platforms
   messageCount uint64  //消息总数量
   messageBytes uint64  //消息总长度
   sync.RWMutex
   name              string   //topic name
   channelMap        map[string]*Channel //保存topic下面的所有channel
   backend           BackendQueue //磁盘队列
   memoryMsgChan     chan *Message //内存队列
   startChan         chan int
   exitChan          chan int
   channelUpdateChan chan int
   waitGroup         util.WaitGroupWrapper
   exitFlag          int32  //退出标记
   idFactory         *guidFactory //生成msg id的工厂
   ephemeral      bool  //是否临时topic
   deleteCallback func(*Topic)  //删除topic方法指针
   deleter        sync.Once
   paused    int32   //暂停标记,1暂停, 0正常
   pauseChan chan int
   ctx *context
}

Topic创建

nsqd用map[string]*Topic来保存所有topic,producter在发消息的时候回指定topic,nsqd在收到消息后会判断topic是否存在,不存在就会自动创建,每创建一个新的topic就会启动一个协程,用于处理topic相关的消息,如将内存/磁盘中的消息复制给topic中的每个channel、channel数量变化、channel暂停、topic退出

消息结构

// Command represents a command from a client to an NSQ daemon//原文:https://www.cnblogs.com/hlxs/p/11445103.html 作者:啊汉
type Command struct {
   Name   []byte   //命令名称,可选:IDENTIFY、FIN、RDY、REQ、PUB、MPUB、DPUB、NOP、TOUCH、SUB、CLS、AUTH
   Params [][]byte //不同的命令做不同解析,涉及到topic的,Params[0]为topic name
   Body   []byte   //消息内容
}
 
// WriteTo implements the WriterTo interface and
// serializes the Command to the supplied Writer.
//
// It is suggested that the target Writer is buffered
// to avoid performing many system calls.
func (c *Command) WriteTo(w io.Writer) (int64, error) {
   var total int64
   var buf [4]byte
 
   n, err := w.Write(c.Name)  //命名名称,nsqd根据这个名称执行相关功能
   total += int64(n)
   if err != nil {
      return total, err
   }
 
   for _, param := range c.Params {
      n, err := w.Write(byteSpace)  //空格
      total += int64(n)
      if err != nil {
         return total, err
      }
      n, err = w.Write(param)  //参数
      total += int64(n)
      if err != nil {
         return total, err
      }
   }
 
   n, err = w.Wr
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值