之前在一个 webrtc 的项目中,使用VerneMQ作为signal服务器进行通信的时候,发现每次连接的log都很难去跟进。而且 VerneMQ 的console.log 只能打出运行的一些基本状态,没法打印出每次连接的每一个事件节点的log,比如 pub 和 sub 之类的事件。
后面看来一下官方的文档 webhookplugins 才发现可以通过设置webhook来得到每一次连接的各个事件节点。
操作流程:
首先是将 配置的这个打开:
1 | plugins.vmq_webhooks = on |
然后刚开始测试的时候,可以动态添加:
1 | [kbz@VM_16_13_centos ~]$ sudo vmq-admin webhooks register hook=on_deliver endpoint="http://xxx.airdroid.com/mqtt/webhook" |
注意,这样添加的好处,就是进程不需要重启,就可以生效。但是缺点就是 如果进程重启了,那么这些设置就都没有了。
如果要想持久化,就要添加到 vernemq.conf 这个文件里面。因为我们只是测试,所以先不需要添加到 vernemq.conf 文件中。
就这样,我们直接添加了所有能够添加的 webhook, 查看目前所支持的 webhook 事件
这时候就查看:
1 | [kbz@VM_16_13_centos ~]$ sudo vmq-admin webhooks show |
如果是要注销掉这个webhook的话,那么就是:
1 | $ vmq-admin webhooks deregister hook=auth_on_register endpoint="http://xxx.airdroid.com/mqtt/webhook" |
接下来就是 写对应的接口了。 go 代码如下:
1 | // 获取webhook |
全部返回 ok, 数据很简单就是取出来, 然后入库。
测试程序如下:
1 | var mqtt = require('mqtt'); |
而且通过看 log, 也可以看到:
1 | [Info] [2018-07-11 03:38:04] [vernemq hook(auth_on_register): info:map[username:100 qos: topics: peerPort:53097 clientId:1528366636 password:xxx cleanSession:1 peerAddr:125.77.202.250 topic: payload: retain: mountpoint:]] |
而且入库也是可以查到:

这时候就可以从库里面查到某一个client连接的所有的触发的事件节点顺序。
添加到配置文件的话
1 | plugins.vmq_webhooks = on |
然后重启一下即可:
1 | [kbz@VM_0_6_centos ~]$ sudo service vernemq restart |
事件节点的含义
这些事件节点,主要涉及到三个事件,register, publish, subscribe
session 的生命周期
publish 事件流
subscribe 事件流
使用webhook cache的问题
从上面可以看到,每一个 on_register 都要伴随一个校验的 auth_on_register,同理, 每一次 on_publish 都要伴随一个校验的 auth_on_publish,每一次的 on_subscribe 都要伴随一个校验的 auth_on_subscribe,而且如果 publish 很多的时候,就会出现大量的 auth_on_publish。
其实从debug角度来说,这些 auth 的webhook,其实是没啥必要的。所以 VerneMQ 提供针对这三个 auth 事件的缓存: 传送门,原理也很简单,就是返回的时候, 加上这个头部 cache-control: max-age=AgeInSeconds 就行了。这样下次有auth的webhook的时候, VerneMQ 就会去查看 webhook cache 有没有这个缓存。如果有的话,就不抛送了。所以接口的代码要改下,返回的时候,加上:
1 | AUTH_ON_SUBSCRIBE = "auth_on_subscribe" |
还是那个测试程序, 可以看到 这边已经有缓存了:
1 | [kbz@VM_16_13_centos ~]$ sudo vmq-admin webhooks cache show |
然后我又换了一个新的测试程序测了一下:
1 | var mqtt = require('mqtt'); |
发现后面的每一次的pub,还是会有 auth, 跟我想象中有点差别???

那就奇怪了,不是说 auth 会缓存起来吗??? 怎么还是发过来了???? 如果是这样的话,那么代码得改一下了, 就是如果是这三个auth的话,那么就不入库了。
而且我看了一下文档,如果缓存如果过期了,还是会继续留在内存里面。不会删掉。 那这样会不会导致内存泄露?????
Note: cache entries are currently not actively disposed after expiry and will remain in memory.
而且用了一段时间,发现竟然还有副作用,那就是在连接mqtt 的时候,发现整个校验全部无效了。redis 的校验全部失效了。 无论是register 的 auth ,还是 publish auth 和 sub auth 全部没有用了。我怀疑就是因为 这三个 auth 被缓存起来了。 所以都没有经过 auth 这一步。重启也没有用, 因为还是缓存在内存里面。
1 | [kbz@VM_16_13_centos ~]$ sudo vmq-admin webhooks cache show |
只要这个东西还在,那么就是auth就会失效。
我后面的解决方法就是:先把webhook 的那个接口,返回的 cache-contol 的逻辑去掉了。但是发现还是不行,还是会绕过。后面把 webhook 的配置关掉 plugins.vmq_webhooks = off 然后重启 vernemq 才搞定。 权限校验才恢复。
总结: 这个功能跟我想象中的不太一样,可能是我理解错了,反正我后面就不用了。
订阅webhook的耗时问题
自从订阅了webhook之后,有测试反应最近signal的连接和pub会比之前没有校验的那一台机器来的慢。所以为了重现这种情况,需要把现在用的那一台hk中的 权限校验和 webhook都去掉。 让他们测下 速度上有没有提高上来。所以配置文件是要改的, 首先把权限校验去掉, 然后把webhook去掉。
1 | #关闭插件和redis校验 (原先都是on) |
这样改为之后,重启一下vernemq 就行了。 sudo service vernemq restart
后面试下了一下,果然差很多。原来连接要 20s的, 现在只要 6s。那么问题出现在哪里呢?
- 一个原因是 redis 校验的时候,很花时间。
- 另一个原因是 webhook 的请求,很花时间。
刚开始先测了一下redis校验的问题,把redis的权限校验开起来:
1 | plugins.vmq_diversity = on |
发现还是挺快的,基本没什么差别。 所以怀疑是webhook的问题。为什么会怀疑是webhook的问题。是因为webhook 是一个同步请求。尤其是 auth_on_register,auth_on_publish,auth_on_subscribe 这三个事件,如果接口那边返回的不是 200 和 ok。 那么是可以拒绝连接和拒绝 pub 和 sub 的。所以肯定是同步请求。至于其他的几个事件是不是也是同步的,这个得测下。首先在权限开启的时候,把 webhook 也开启来 plugins.vmq_webhooks = on
开了之后,重启了一下服务,果然发现连接的时长多了4,5s了。所以就是因为webhook的同步请求,导致速度变慢了。
而且后面如果把 auth_on_register,auth_on_publish,auth_on_subscribe 这三个事件注释掉,只监听其他事件的话,会不会时间会短点?? 数据证明,虽然比没有注释的时候快,但是还是比全部关掉的时候满了2s左右,所以应该也是同步请求。
解决webhook的耗时问题
后面发现有时候还是需要通过webhook来查看 pub, sub 的问题的,虽然可以通过以下这种方式,临时添加webhook,而不需要重启
1 | $ vmq-admin webhooks register hook=auth_on_register endpoint="http://localhost" |
前提就是这个配置要开着 plugins.vmq_webhooks = on
但是当问题出现了,再开的话,已经跟踪不到了。所以后面想了几种方式可以减少 webhook 接口的消耗:
- 将webhook的接口地址,部署在 vernemq 的本机环境,这样同一台机子访问,速度是非常快的,可以减少接口的响应消耗
- 因为webhook log 我们要入库,导致这边还会有数据库的插入时间的消耗,所以将入库操作放到异步队列,这样就不会有数据库的消耗了
通过这两个优化,后面我们实测,就算加了webhook,但是时间上还是相差无几的, 在可接受范围之类。