SI-MQTT集群消息处理

10 篇文章 2 订阅
1 篇文章 0 订阅

SI-MQTT MQTT v5 Broker

此si-mqtt提供了一种比较开放的集群消息处理方式:

集群消息发送只开放一个方法,负责发送publish、subscribe、unsubscribe msg.

// SendMsgToCluster 发送消息到集群
// shareName 共享主题组
// targetNode 目标节点
// 这两个参数用于集群共享主题消息发送到特定的节点
func SendMsgToCluster(msg messagev5.Message, shareName, targetNode string, allSuccess func(message messagev5.Message),
	oneNodeSendSucFunc func(name string, message messagev5.Message),
	oneNodeSendFailFunc func(name string, message messagev5.Message)) {
	if sender == nil {
		logger.Logger.Warnf("sender is nil")
		return
	}
	if targetNode != "" { // 单个发送,可能是共享消息
		sender.SendOneNode(msg, shareName, targetNode, oneNodeSendSucFunc, oneNodeSendFailFunc)
		return
	}
	// 发送全部节点
	sender.SendAllNode(msg, allSuccess, oneNodeSendSucFunc, oneNodeSendFailFunc)
}

而真正的消息发送只需实现一个接口接口并注册上去即可:

// Sender 只要实现此接口就可以通过SendMsgToCluster(...)方法发送集群消息
type Sender interface {
	// SendOneNode 主要是用来发送共享主题消息
	SendOneNode(msg messagev5.Message, shareName, targetNode string,
		oneNodeSendSucFunc func(name string, message messagev5.Message),
		oneNodeSendFailFunc func(name string, message messagev5.Message))
	// SendAllNode 发送除共享主题消息外的消息
	SendAllNode(msg messagev5.Message, allSuccess func(message messagev5.Message),
		oneNodeSendSucFunc func(name string, message messagev5.Message),
		oneNodeSendFailFunc func(name string, message messagev5.Message))
}

此mqtt broker目前提供了两种sender的实现,一种简单的直接发送数据到其它节点,一种通过存储组件实现【它只用了mongo,因为简单】

我们来看一下后者
client: 消息发送

func (this *dbSender) SendOneNode(msg messagev5.Message,
	shareName, targetNode string,
	oneNodeSendSucFunc func(name string, message messagev5.Message),
	oneNodeSendFailFunc func(name string, message messagev5.Message)) {
	var e error
	switch msg := msg.(type) {
	case *messagev5.PublishMessage:
		if targetNode != "" && shareName != "" {
			e = this.c.SaveSharePub(context.TODO(), "cluster_msg", targetNode, shareName, msg)
		} else {
			e = this.c.SavePub(context.TODO(), "cluster_msg", msg)
		}
	case *messagev5.SubscribeMessage:
		e = this.c.SaveSub(context.TODO(), "cluster_msg", msg)
	case *messagev5.UnsubscribeMessage:
		e = this.c.SaveUnSub(context.TODO(), "cluster_msg", msg)
	}
	if e != nil {
		go oneNodeSendSucFunc(targetNode, msg)
	} else {
		go oneNodeSendFailFunc(targetNode, msg)
	}
}

func (this *dbSender) SendAllNode(msg messagev5.Message,
	allSuccess func(message messagev5.Message),
	oneNodeSendSucFunc func(name string, message messagev5.Message),
	oneNodeSendFailFunc func(name string, message messagev5.Message)) {
	var e error
	switch msg := msg.(type) {
	case *messagev5.PublishMessage:
		e = this.c.SavePub(context.TODO(), "cluster_msg", msg)
	case *messagev5.SubscribeMessage:
		e = this.c.SaveSub(context.TODO(), "cluster_msg", msg)
	case *messagev5.UnsubscribeMessage:
		e = this.c.SaveUnSub(context.TODO(), "cluster_msg", msg)
	}
	if e != nil {
		go allSuccess(msg)
		go oneNodeSendSucFunc(colong.AllNodeName, msg)
	} else {
		go oneNodeSendFailFunc(colong.AllNodeName, msg)
	}
}

server: 消息消费

// period 获取数据周期,单位ms
// size 每次获取数据量
func (s *dbRcv) run(period, size int64) {
	go func() {
		for {
			select {
			case <-time.After(time.Duration(period) * time.Millisecond):
			case <-s.stop:
				return
			}
			ctx, cancel := context.WithTimeout(context.TODO(), 10*time.Second)
			go func() {
				defer func() {
					if e := recover(); e != nil {
						println(e)
					}
					cancel()
				}()
				select {
				case <-time.After(10 * time.Second):
					cancel()
				case <-ctx.Done():
				}
			}()
			msg, err := s.c.GetBatch(ctx, "cluster_msg", size)
			if err != nil {
				cancel()
				println(err)
			}
			for k := 0; k < len(msg); k++ {
				mg := msg[k]
				if mg.IsSub() {
					s.submit(func() {
						tpk := mg.Sub.topic
						node := mg.Sender
						for i := 0; i < len(tpk); i++ {
							// 解析share name
							shareName, top := shareTopic([]byte(tpk[i]))
							if shareName != "" {
								err = s.shareTopicMapNode.AddTopicMapNode(top, shareName, node)
								if err != nil {
									logger.Logger.Errorf("%s,共享订阅节点新增失败, shareName:%v , err: %v", node, shareName, err)
								} else {
									logger.Logger.Debugf("收到节点:%s 发来的 共享订阅:topic-%s, shareName-%s", node, top, shareName)
								}
							} else {
								logger.Logger.Warnf("收到非法订阅:%s", tpk[i])
							}
						}
					})
				} else if mg.IsUnSub() {
					s.submit(func() {
						tpk := mg.Sub.topic
						node := mg.Sender
						for i := 0; i < len(tpk); i++ {
							// 解析share name
							shareName, top := shareTopic([]byte(tpk[i]))
							if shareName != "" {
								err = s.shareTopicMapNode.RemoveTopicMapNode(top, shareName, node)
								if err != nil {
									logger.Logger.Errorf("%s,共享订阅节点减少失败, shareName:%v , err: %v", node, shareName, err)
								} else {
									logger.Logger.Debugf("收到节点:%s 发来的 取消共享订阅:topic-%s, shareName-%s", node, top, shareName)
								}
							} else {
								logger.Logger.Warnf("收到非法取消订阅:%s", string(tpk[i]))
							}
						}
					})
				} else if mg.IsShare() {
					s.submit(func() {
						msg1 := poToVo(mg.Msg)
						err = s.clusterInToPubShare(msg1, mg.ShareName)
						if err != nil {
							logger.Logger.Errorf("clusterInToPubShare: err %v", err)
						} else {
							logger.Logger.Debugf("收到节点:%s 发来的 共享消息:%s", mg.Sender, msg1)
						}
					})
				} else if mg.IsPub() {
					s.submit(func() {
						msg1 := poToVo(mg.Msg)
						err = s.clusterInToPub(msg1)
						if err != nil {
							logger.Logger.Errorf("clusterInToPub: err %v", err)
						} else {
							logger.Logger.Debugf("收到节点:%s 发来的 普通消息:%s", mg.Sender, msg1)
						}
					})
				} else {
					logger.Logger.Infof("OnMessage: %+v", mg)
				}
			}
		}
	}()
}

当然,此si-mqtt的处理还很毛糙,有比较大的优化空间。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值