前言
因为最近项目需要用到边缘计算,结合百度的openedge进行开发,openedge目前主要功能为结合docker容器实现边缘计算,具体内容官网很多,其架构中,openedge-hub作为所有模块的通信中心节点(消息的接收和转发)是非常重要的,本篇主要介绍一下openedge-hub模块的启动以及在QOS=0的情况下消息的发送和转发,本文主要是为了记录下思路方便后续改造,因个人水平有限,对于MQTT了解有限,很多名词使用不当,中间若有错误劳烦告知,谢谢!
openedge-hub的启动
openedge-hub的开始的节点是在openedge/openedge-hub/main.go文件进行的,main函数如下所示:
openedge.Run(func(ctx openedge.Context) error {
m := mo{log: ctx.Log()}
defer m.close()
err := m.start()
if err != nil {
return err
}
ctx.Wait()
return nil
})
其作用主要是启动mo对象,mo结构如下:
type mo struct {
cfg config.Config
Rules *rule.Manager
Sessions *session.Manager
broker *broker.Broker
servers *server.Manager
factory *persist.Factory
log logger.Logger
}
- cfg是读取配置文件后保存配置的实体。
- Rules是消息转发使得“路由器”。
- Sessions保存着所有客户端的连接。
- broker中间带有channel,用于接收来自session发送的消息,并通过这个channel发送至路由器(这里说的有点欠妥,后面会讲到的),路由器找到对应的session,并将消息发送到session对应的客户端。
- factory是用于进行持久化的,暂不做解析。
- log进行日志的记录,暂不做解析。
刚刚main文件中有一行代码是:err := m.start()
,这个就是启动的入口,接下来看一下这个start方法:
func (m *mo) start() error {
err := utils.LoadYAML(openedge.DefaultConfFile, &m.cfg)
if err != nil {
m.log.Errorln("failed to load config:", err.Error())
return err
}
m.factory, err = persist.NewFactory(m.cfg.Storage.Dir)
if err != nil {
m.log.Errorln("failed to new factory:", err.Error())
return err
}
m.broker, err = broker.NewBroker(&m.cfg, m.factory)
if err != nil {
m.log.Errorln("failed to new broker:", err.Error())
return err
}
m.Rules, err = rule.NewManager(m.cfg.Subscriptions, m.broker)
if err != nil {
m.log.Errorln("failed to new rule manager:", err.Error())
return err
}
m.Sessions, err = session.NewManager(&m.cfg, m.broker.Flow, m.Rules, m.factory)
if err != nil {
m.log.Errorln("failed to new session manager:", err.Error())
return err
}
m.servers, err = server.NewManager(m.cfg.Listen, m.cfg.Certificate, m.Sessions.Handle)
if err != nil {
m.log.Errorln("failed to new server manager:", err.Error())
return err
}
m.Rules.Start()
m.servers.Start()
return nil
}
总体上就是分别对mo的各个属性进行初始化,下面分别对每一个属性的初始化进行解析。
cfg加载
cfg加载在main.go中start方法的代码如下:
err := utils.LoadYAML(openedge.DefaultConfFile, &m.cfg)
if err != nil {
m.log.Errorln("failed to load config:", err.Error())
return err
}
其实就是把yaml对应的属性填充到mo的cfg中,下面介绍一下cfg这个结构体的一些配置项:
// Config all config of edge
type Config struct {
Listen []string `yaml:"listen" json:"listen"`
Certificate utils.Certificate `yaml:"certificate" json:"certificate"`
Principals []Principal `yaml:"principals" json:"principals" validate:"principals"`
Subscriptions []Subscription `yaml:"subscriptions" json:"subscriptions" validate:"subscriptions"`
Message Message `yaml:"message" json:"message"`
Status struct {
Logging struct {
Enable bool `yaml:"enable" json:"enable"`
Interval time.Duration `yaml:"interval" json:"interval" default:"1m"`
} `yaml:"logging" json:"logging"`
} `yaml:"status" json:"status"`
Storage struct {
Dir string `yaml:"dir" json:"dir" default:"var/db/openedge"`
} `yaml:"storage" json:"storage"`
Shutdown struct {
Timeout time.Duration `yaml:"timeout" json:"timeout" default:"10m"`
} `yaml:"shutdown" json:"shutdown"`
}
附上一个源码中示例的文件:
name: localhub
listen:
- tcp://0.0.0.0:1883
principals:
- username: 'test'
password: '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08'
permissions:
- action: 'pub'
permit: ['#']
- action: 'sub'
permit: ['#']
subscriptions:
- source:
topic: 't'
target:
topic: 't/topic'
logger:
path: var/log/openedge/localhub/localhub.log
console: true
level: "debug"
- name是模块的名称,localhub的模块起名为localhub。
- listen是用于开启服务器后监听的地址(客户端连接的地址)。
- principals存放客户端连接的用户名、密码(密码是使用SHA-256加密的,客户端连接的时候使用解密后的明文密码)、权限等相关信息。
- subscriptions用于存放消息转发(订阅)的路由规则,source是发布消息时的地址,target是转发的地址(比如A发送的“t”主题消息就会转发到订阅“t/topic”主题的客户端中。
- logger是配置日志相关信息。
通过加载配置文件后,cfg中就存储了这些信息。
broker加载
使用淘宝的人既可以自己开店,也可以去买货,但是卖货的信息发布在什么地方呢?想要买东西从哪里浏览呢?当然是通过淘宝了,broker就是淘宝,所有连接到openedge-hub(后面简称为hub)的session既可以作为卖家发布消息,这个消息就发送到broker的channel(根据QOS不同对应了不同的channel)了,在生活中为了让买家能够买到称心如意的东西,淘宝一般会进行个性化推荐,在hub中每一个session会个性化的订阅主题,这时候路由器(Rule.Manager)就会把符合session需要的消息发送到session中了。<